diff --git a/.eslintrc.json b/.eslintrc.json index 2a16144c..7e4337ee 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,6 +13,7 @@ "arrow-spacing": ["error"], "no-const-assign": ["error"], "prefer-const": ["error"], + "prefer-arrow-callback": ["error"], "spaced-comment": ["error", "always"], "semi": ["error", "always"] } diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b619cd36..ee2c87f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: node-version: - - 10.x + - 14.x steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 @@ -24,18 +24,18 @@ jobs: uses: actions/cache@v1 with: path: ~/.npm - key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package.json') }} - name: Install dependencies run: | npm install - npm run lerna-bootstrap + npm run bootstrap - name: Lint snippets run: npm run lint - name: Compile snippets - run: npm run lerna-compile + run: npm run compile - name: Check generated snippets run: | diff --git a/.gitignore b/.gitignore index c3bf3b13..435f90ea 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ node_modules tsconfig.json dist/ +.DS_Store +.idea +pnpm-lock.yaml diff --git a/README.md b/README.md index f0f7a3bc..b45ac156 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,21 @@ + # Firebase Web Snippets This repository holds code snippets used in Web documentation on [firebase.google.com](https://firebase.google.com/docs/). +These snippets are part of our documentation and best read in the context of a documentation page rather than used directly. If you're looking to get started with the Firebase Web SDK the best place to start is [quickstart-js](https://github.com/firebase/quickstart-js). + +## Example + +Consider this page: +https://firebase.google.com/docs/database/web/lists-of-data + +Each snippet in the page is dynamically included from the source in this repository, in this case mostly from this file: +https://github.com/firebase/snippets-web/blob/master/database/lists-of-data.js + +Each snippet has a "region tag" which is defined by `// [START tag]` and `// [END tag]` comments. The code between the tags can be included in our documentation. Keeping the code on GitHub, rather than hard-coded into the HTML of our documentation, allows us to ensure the code is correct and up to date. + ## Contributing We love contributions! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines. diff --git a/analytics-next/ecommerce.js b/analytics-next/ecommerce.js new file mode 100644 index 00000000..081aad48 --- /dev/null +++ b/analytics-next/ecommerce.js @@ -0,0 +1,284 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +// [START analytics_ecommerce_items] +// A pair of jeggings +const item_jeggings = { + item_id: 'SKU_123', + item_name: 'jeggings', + item_category: 'pants', + item_variant: 'black', + item_brand: 'Google', + price: 9.99 +}; + +// A pair of boots +const item_boots = { + item_id: 'SKU_456', + item_name: 'boots', + item_category: 'shoes', + item_variant: 'brown', + item_brand: 'Google', + price: 24.99 +}; + +// A pair of socks +const item_socks = { + item_id: 'SKU_789', + item_name: 'ankle_socks', + item_category: 'socks', + item_variant: 'red', + item_brand: 'Google', + price: 5.99 +}; +// [END analytics_ecommerce_items] + +function ecommerceViewItemList() { + // [START analytics_ecommerce_view_item_list] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce params + const params1 = { + item_list_id: 'L001', + item_list_name: 'Related products', + items: [item_jeggings, item_boots, item_socks] + }; + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'view_item_list', params1); + // [END analytics_ecommerce_view_item_list] +} + +function ecommerceSelectItem() { + // [START analytics_ecommerce_select_item] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce event params + const params2 = { + item_list_id: 'L001', + item_list_name: 'Related products', + items: [item_jeggings] + }; + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'select_item', params2); + // [END analytics_ecommerce_select_item] +} + +function ecommerceViewItemDetails() { + // [START analytics_ecommerce_view_item_details] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce event params + const params3 = { + currency: 'USD', + value: 9.99, + items: [item_jeggings] + }; + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'view_item', params3); + // [END analytics_ecommerce_view_item_details] +} + +function ecommerceAddCart() { + // [START analytics_ecommerce_add_cart] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Specify order quantity + const item_jeggings_quantity = { + ...item_jeggings, + quantity: 2 + }; + + // Prepare ecommerce bundle + const params4 = { + currency: 'USD', + value: 19.98, + items: [item_jeggings_quantity] + }; + + // Log event when a product is added to a wishlist + const analytics = getAnalytics(); + logEvent(analytics, 'add_to_wishlist', params4); + + // Log event when a product is added to the cart + logEvent(analytics, 'add_to_cart', params4); + // [END analytics_ecommerce_add_cart] +} + +function ecommerceViewCart() { + // [START analytics_ecommerce_view_cart] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Specify order quantity + const item_jeggings_quantity = { + ...item_jeggings, + quantity: 2 + }; + + const item_boots_quantity = { + ...item_boots, + quantity: 1 + }; + + // Prepare ecommerce params + const params5 = { + currency: 'USD', + value: 44.97, + items: [item_jeggings_quantity, item_boots_quantity] + }; + + // Log event when the cart is viewed + const analytics = getAnalytics(); + logEvent(analytics, 'view_cart', params5); + // [END analytics_ecommerce_view_cart] +} + +function ecommerceRemoveCart() { + // [START analytics_ecommerce_remove_cart] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce params + const params6 = { + currency: 'USD', + value: 24.99, + items: [item_jeggings] + }; + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'remove_from_cart', params6); + // [END analytics_ecommerce_remove_cart] +} + +function ecommerceCheckout() { + // [START analytics_ecommerce_checkout] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce params + const params7 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + items: [item_jeggings] + }; + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'begin_checkout', params7); + // [END analytics_ecommerce_checkout] +} + +function ecommerceShippingInfo() { + // [START analytics_ecommerce_shipping_info] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce params + const params8 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + shipping_tier: 'Ground', + items: [item_jeggings] + }; + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'add_shipping_info', params8); + // [END analytics_ecommerce_shipping_info] +} + +function ecommercePaymentInfo() { + // [START analytics_ecommerce_payment_info] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce params + const params9 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + payment_type: 'Visa', + items: [item_jeggings] + }; + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'add_payment_info', params9); + // [END analytics_ecommerce_payment_info] +} + +function ecommercePurchase() { + // [START analytics_ecommerce_purchase] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce bundle + const params10 = { + transaction_id: 'T12345', + affiliation: 'Google Store', + currency: 'USD', + value: 14.98, // Total Revenue + tax: 2.85, + shipping: 5.34, + coupon: 'SUMMER_FUN', + items: [item_jeggings] + }; + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'purchase', params10); + // [END analytics_ecommerce_purchase] +} + +function ecommerceRefund() { + // [START analytics_ecommerce_refund] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce params + const params11 = { + transaction_id: 'T12345', // Required + affiliation: 'Google Store', + currency: 'USD', + value: 9.99, + items: [] + }; + + // (Optional) For partial refunds, define the item_id and quantity of refunded items + const refundedProduct = { + item_id: 'SKU_123', // Required + quantity: 1 // Required + }; + + params11.items.push(refundedProduct); + + // Log event + const analytics = getAnalytics(); + logEvent(analytics, 'refund', params11); + // [END analytics_ecommerce_refund] +} + +function ecommercePromotions() { + // [START analytics_ecommerce_promotions] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + // Prepare ecommerce params + const params12 = { + promotion_id: 'ABC123', + promotion_name: 'Summer Sale', + creative_name: 'summer2020_promo.jpg', + creative_slot: 'featured_app_1', + location_id: 'HERO_BANNER', + items: [item_jeggings] + }; + + // Log event when a promotion is displayed + const analytics = getAnalytics(); + logEvent(analytics, 'view_promotion', params12); + + // Log event when a promotion is selected + logEvent(analytics, 'select_promotion', params12); + // [END analytics_ecommerce_promotions] +} diff --git a/analytics-next/index.js b/analytics-next/index.js new file mode 100644 index 00000000..2b736cde --- /dev/null +++ b/analytics-next/index.js @@ -0,0 +1,66 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +import { initializeApp } from "firebase/app"; + +function initialize() { + // [START analytics_initialize] + const { getAnalytics } = require("firebase/analytics"); + + const analytics = getAnalytics(); + // [END analytics_initialize] +} + +function logEvent() { + // [START analytics_log_event] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + const analytics = getAnalytics(); + logEvent(analytics, 'notification_received'); + // [END analytics_log_event] +} + +function logEventParams() { + // [START analytics_log_event_params] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + const analytics = getAnalytics(); + logEvent(analytics, 'select_content', { + content_type: 'image', + content_id: 'P12453' + }); + // [END analytics_log_event_params] +} + +function logEventCustomParams() { + // [START analytics_log_event_custom_params] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + const analytics = getAnalytics(); + logEvent(analytics, 'goal_completion', { name: 'lever_puzzle'}); + // [END analytics_log_event_custom_params] +} + +function setUserProperties() { + // [START analytics_set_user_properties] + const { getAnalytics, setUserProperties } = require("firebase/analytics"); + + const analytics = getAnalytics(); + setUserProperties(analytics, { favorite_food: 'apples' }); + // [END analytics_set_user_properties] +} + +function recordScreenView() { + const screenName = ''; + const screenClass = ''; + + // [START analytics_record_screen_view] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + const analytics = getAnalytics(); + logEvent(analytics, 'screen_view', { + firebase_screen: screenName, + firebase_screen_class: screenClass + }); + // [END analytics_record_screen_view] +} diff --git a/analytics-next/package.json b/analytics-next/package.json new file mode 100644 index 00000000..ee4e36ff --- /dev/null +++ b/analytics-next/package.json @@ -0,0 +1,11 @@ +{ + "name": "analytics-next", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^10.0.0" + } +} diff --git a/analytics/ecommerce.js b/analytics/ecommerce.js new file mode 100644 index 00000000..6e5216bd --- /dev/null +++ b/analytics/ecommerce.js @@ -0,0 +1,248 @@ +import firebase from "firebase/app"; +import "firebase/analytics"; + +// [START analytics_ecommerce_items] +// A pair of jeggings +const item_jeggings = { + item_id: 'SKU_123', + item_name: 'jeggings', + item_category: 'pants', + item_variant: 'black', + item_brand: 'Google', + price: 9.99 +}; + +// A pair of boots +const item_boots = { + item_id: 'SKU_456', + item_name: 'boots', + item_category: 'shoes', + item_variant: 'brown', + item_brand: 'Google', + price: 24.99 +}; + +// A pair of socks +const item_socks = { + item_id: 'SKU_789', + item_name: 'ankle_socks', + item_category: 'socks', + item_variant: 'red', + item_brand: 'Google', + price: 5.99 +}; +// [END analytics_ecommerce_items] + +function ecommerceViewItemList() { + // [START analytics_ecommerce_view_item_list] + // Prepare ecommerce params + const params1 = { + item_list_id: 'L001', + item_list_name: 'Related products', + items: [item_jeggings, item_boots, item_socks] + }; + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.VIEW_ITEM_LIST, params1); + // [END analytics_ecommerce_view_item_list] +} + +function ecommerceSelectItem() { + // [START analytics_ecommerce_select_item] + // Prepare ecommerce event params + const params2 = { + item_list_id: 'L001', + item_list_name: 'Related products', + items: [item_jeggings] + }; + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.SELECT_ITEM, params2); + // [END analytics_ecommerce_select_item] +} + +function ecommerceViewItemDetails() { + // [START analytics_ecommerce_view_item_details] + // Prepare ecommerce event params + const params3 = { + currency: 'USD', + value: 9.99, + items: [item_jeggings] + }; + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.VIEW_ITEM, params3); + // [END analytics_ecommerce_view_item_details] +} + +function ecommerceAddCart() { + // [START analytics_ecommerce_add_cart] + // Specify order quantity + const item_jeggings_quantity = { + ...item_jeggings, + quantity: 2 + }; + + // Prepare ecommerce bundle + const params4 = { + currency: 'USD', + value: 19.98, + items: [item_jeggings_quantity] + }; + + // Log event when a product is added to a wishlist + firebase.analytics().logEvent(firebase.analytics.EventName.ADD_TO_WISHLIST, params4); + + // Log event when a product is added to the cart + firebase.analytics().logEvent(firebase.analytics.EventName.ADD_TO_CART, params4); + // [END analytics_ecommerce_add_cart] +} + +function ecommerceViewCart() { + // [START analytics_ecommerce_view_cart] + // Specify order quantity + const item_jeggings_quantity = { + ...item_jeggings, + quantity: 2 + }; + + const item_boots_quantity = { + ...item_boots, + quantity: 1 + }; + + // Prepare ecommerce params + const params5 = { + currency: 'USD', + value: 44.97, + items: [item_jeggings_quantity, item_boots_quantity] + }; + + // Log event when the cart is viewed + firebase.analytics().logEvent(firebase.analytics.EventName.VIEW_CART, params5); + // [END analytics_ecommerce_view_cart] +} + +function ecommerceRemoveCart() { + // [START analytics_ecommerce_remove_cart] + // Prepare ecommerce params + const params6 = { + currency: 'USD', + value: 24.99, + items: [item_jeggings] + }; + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.REMOVE_FROM_CART, params6); + // [END analytics_ecommerce_remove_cart] +} + +function ecommerceCheckout() { + // [START analytics_ecommerce_checkout] + // Prepare ecommerce params + const params7 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + items: [item_jeggings] + }; + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.BEGIN_CHECKOUT, params7); + // [END analytics_ecommerce_checkout] +} + +function ecommerceShippingInfo() { + // [START analytics_ecommerce_shipping_info] + // Prepare ecommerce params + const params8 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + shipping_tier: 'Ground', + items: [item_jeggings] + }; + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.ADD_SHIPPING_INFO, params8); + // [END analytics_ecommerce_shipping_info] +} + +function ecommercePaymentInfo() { + // [START analytics_ecommerce_payment_info] + // Prepare ecommerce params + const params9 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + payment_type: 'Visa', + items: [item_jeggings] + }; + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.ADD_PAYMENT_INFO, params9); + // [END analytics_ecommerce_payment_info] +} + +function ecommercePurchase() { + // [START analytics_ecommerce_purchase] + // Prepare ecommerce bundle + const params10 = { + transaction_id: 'T12345', + affiliation: 'Google Store', + currency: 'USD', + value: 14.98, // Total Revenue + tax: 2.85, + shipping: 5.34, + coupon: 'SUMMER_FUN', + items: [item_jeggings] + }; + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.PURCHASE, params10); + // [END analytics_ecommerce_purchase] +} + +function ecommerceRefund() { + // [START analytics_ecommerce_refund] + // Prepare ecommerce params + const params11 = { + transaction_id: 'T12345', // Required + affiliation: 'Google Store', + currency: 'USD', + value: 9.99, + items: [] + }; + + // (Optional) For partial refunds, define the item_id and quantity of refunded items + const refundedProduct = { + item_id: 'SKU_123', // Required + quantity: 1 // Required + }; + + params11.items.push(refundedProduct); + + // Log event + firebase.analytics().logEvent(firebase.analytics.EventName.REFUND, params11); + // [END analytics_ecommerce_refund] +} + +function ecommercePromotions() { + // [START analytics_ecommerce_promotions] + // Prepare ecommerce params + const params12 = { + promotion_id: 'ABC123', + promotion_name: 'Summer Sale', + creative_name: 'summer2020_promo.jpg', + creative_slot: 'featured_app_1', + location_id: 'HERO_BANNER', + items: [item_jeggings] + }; + + // Log event when a promotion is displayed + firebase.analytics().logEvent(firebase.analytics.EventName.VIEW_PROMOTION, params12); + + // Log event when a promotion is selected + firebase.analytics().logEvent(firebase.analytics.EventName.SELECT_PROMOTION, params12); + // [END analytics_ecommerce_promotions] +} diff --git a/analytics/index.js b/analytics/index.js new file mode 100644 index 00000000..76d2c289 --- /dev/null +++ b/analytics/index.js @@ -0,0 +1,52 @@ +import firebase from "firebase/app"; +import "firebase/analytics"; + +function initialize() { + // [START analytics_initialize] + const analytics = firebase.analytics(); + // [END analytics_initialize] +} + +function logEvent() { + // [START analytics_log_event] + firebase.analytics().logEvent('notification_received'); + // [END analytics_log_event] +} + +function logEventParams() { + const analytics = firebase.analytics(); + + // [START analytics_log_event_params] + analytics.logEvent('select_content', { + content_type: 'image', + content_id: 'P12453', + items: [{ name: 'Kittens' }] + }); + // [END analytics_log_event_params] +} + +function logEventCustomParams() { + const analytics = firebase.analytics(); + + // [START analytics_log_event_custom_params] + analytics.logEvent('goal_completion', { name: 'lever_puzzle'}); + // [END analytics_log_event_custom_params] +} + +function setUserProperties() { + // [START analytics_set_user_properties] + firebase.analytics().setUserProperties({favorite_food: 'apples'}); + // [END analytics_set_user_properties] +} + +function recordScreenView() { + const screenName = ''; + const screenClass = ''; + + // [START analytics_record_screen_view] + firebase.analytics().logEvent('screen_view', { + firebase_screen: screenName, + firebase_screen_class: screenClass + }); + // [END analytics_record_screen_view] +} diff --git a/analytics/package.json b/analytics/package.json new file mode 100644 index 00000000..b344a8a6 --- /dev/null +++ b/analytics/package.json @@ -0,0 +1,11 @@ +{ + "name": "analytics", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^8.10.0" + } +} diff --git a/appcheck-next/index.js b/appcheck-next/index.js new file mode 100644 index 00000000..f5598ebd --- /dev/null +++ b/appcheck-next/index.js @@ -0,0 +1,110 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function initialize() { + // [START appcheck_initialize] + const { initializeApp } = require("firebase/app"); + const { initializeAppCheck, ReCaptchaV3Provider } = require("firebase/app-check"); + + const app = initializeApp({ + // Your firebase configuration object + }); + + // Pass your reCAPTCHA v3 site key (public key) to activate(). Make sure this + // key is the counterpart to the secret key you set in the Firebase console. + const appCheck = initializeAppCheck(app, { + provider: new ReCaptchaV3Provider('abcdefghijklmnopqrstuvwxy-1234567890abcd'), + + // Optional argument. If true, the SDK automatically refreshes App Check + // tokens as needed. + isTokenAutoRefreshEnabled: true + }); + // [END appcheck_initialize] +} + +function customProvider() { + // [START appcheck_custom_provider] + const { CustomProvider } = require("firebase/app-check"); + + const appCheckCustomProvider = new CustomProvider({ + getToken: () => { + return new Promise((resolve, _reject) => { + // TODO: Logic to exchange proof of authenticity for an App Check token and + // expiration time. + + // [START_EXCLUDE] + const tokenFromServer = "abc1234"; + const expirationFromServer = 1234; + // [END_EXCLUDE] + + const appCheckToken = { + token: tokenFromServer, + expireTimeMillis: expirationFromServer * 1000 + }; + + resolve(appCheckToken); + }); + } + }); + // [END appcheck_custom_provider] + + return appCheckCustomProvider; +} + +function initializeCustomProvider() { + const appCheckCustomProvider = customProvider(); + + // [START appcheck_initialize_custom_provider] + const { initializeApp } = require("firebase/app"); + const { initializeAppCheck } = require("firebase/app-check"); + + const app = initializeApp({ + // Your firebase configuration object + }); + + const appCheck = initializeAppCheck(app, { + provider: appCheckCustomProvider, + + // Optional argument. If true, the SDK automatically refreshes App Check + // tokens as needed. + isTokenAutoRefreshEnabled: true + }); + // [END appcheck_initialize_custom_provider] +} + +function nonFirebase() { + const { initializeApp } = require("firebase/app"); + const app = initializeApp({ + // Your firebase configuration object + }); + const { ReCaptchaV3Provider } = require('firebase/app-check'); + const provider = new ReCaptchaV3Provider(''); + + // [START appcheck_nonfirebase] + const { initializeAppCheck, getToken } = require('firebase/app-check'); + + const appCheck = initializeAppCheck( + app, + { provider: provider } // ReCaptchaV3Provider or CustomProvider + ); + + const callApiWithAppCheckExample = async () => { + let appCheckTokenResponse; + try { + appCheckTokenResponse = await getToken(appCheck, /* forceRefresh= */ false); + } catch (err) { + // Handle any errors if the token was not retrieved. + return; + } + + // Include the App Check token with requests to your server. + const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', { + headers: { + 'X-Firebase-AppCheck': appCheckTokenResponse.token, + } + }); + + // Handle response from your backend. + }; + // [END appcheck_nonfirebase] +} diff --git a/appcheck-next/package.json b/appcheck-next/package.json new file mode 100644 index 00000000..e863723e --- /dev/null +++ b/appcheck-next/package.json @@ -0,0 +1,11 @@ +{ + "name": "appcheck-next", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^10.0.0" + } +} diff --git a/appcheck/index.js b/appcheck/index.js new file mode 100644 index 00000000..3721b16c --- /dev/null +++ b/appcheck/index.js @@ -0,0 +1,86 @@ +import firebase from "firebase/app"; +import "firebase/app-check"; + +function initialize() { + // [START appcheck_initialize] + firebase.initializeApp({ + // Your firebase configuration object + }); + + const appCheck = firebase.appCheck(); + // Pass your reCAPTCHA v3 site key (public key) to activate(). Make sure this + // key is the counterpart to the secret key you set in the Firebase console. + appCheck.activate( + 'abcdefghijklmnopqrstuvwxy-1234567890abcd', + + // Optional argument. If true, the SDK automatically refreshes App Check + // tokens as needed. + true); + // [END appcheck_initialize] +} + +function customProvider() { + // [START appcheck_custom_provider] + const appCheckCustomProvider = { + getToken: () => { + return new Promise((resolve, _reject) => { + // TODO: Logic to exchange proof of authenticity for an App Check token and + // expiration time. + + // [START_EXCLUDE] + const tokenFromServer = "abc1234"; + const expirationFromServer = 1234; + // [END_EXCLUDE] + + const appCheckToken = { + token: tokenFromServer, + expireTimeMillis: expirationFromServer * 1000 + }; + + resolve(appCheckToken); + }); + } + }; + // [END appcheck_custom_provider] + + return appCheckCustomProvider; +} + +function initializeCustomProvider() { + const appCheckCustomProvider = customProvider(); + + // [START appcheck_initialize_custom_provider] + firebase.initializeApp({ + // Your firebase configuration object + }); + + const appCheck = firebase.appCheck(); + appCheck.activate( + appCheckCustomProvider, + + // Optional argument. If true, the SDK automatically refreshes App Check + // tokens as needed. + true); + // [END appcheck_initialize_custom_provider] +} + +// [START appcheck_nonfirebase] +const callApiWithAppCheckExample = async () => { + let appCheckTokenResponse; + try { + appCheckTokenResponse = await firebase.appCheck().getToken(/* forceRefresh= */ false); + } catch (err) { + // Handle any errors if the token was not retrieved. + return; + } + + // Include the App Check token with requests to your server. + const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', { + headers: { + 'X-Firebase-AppCheck': appCheckTokenResponse.token, + } + }); + + // Handle response from your backend. +}; +// [END appcheck_nonfirebase] diff --git a/appcheck/package.json b/appcheck/package.json new file mode 100644 index 00000000..d9d819fa --- /dev/null +++ b/appcheck/package.json @@ -0,0 +1,11 @@ +{ + "name": "appcheck", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^8.10.0" + } +} diff --git a/auth-next/anonymous.js b/auth-next/anonymous.js index 56a56c39..33d5a936 100644 --- a/auth-next/anonymous.js +++ b/auth-next/anonymous.js @@ -1,19 +1,11 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - function anonSignIn() { // [START auth_anon_sign_in] const { getAuth, signInAnonymously } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInAnonymously(auth) .then(() => { // Signed in.. diff --git a/auth-next/apple.js b/auth-next/apple.js index 177aa065..2777a085 100644 --- a/auth-next/apple.js +++ b/auth-next/apple.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/apple.md function appleProvider() { @@ -35,7 +27,7 @@ function appleSignInPopup(provider) { // [START auth_apple_signin_popup] const { getAuth, signInWithPopup, OAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // The signed-in user info. @@ -46,6 +38,7 @@ function appleSignInPopup(provider) { const accessToken = credential.accessToken; const idToken = credential.idToken; + // IdP data available using getAdditionalUserInfo(result) // ... }) .catch((error) => { @@ -53,7 +46,7 @@ function appleSignInPopup(provider) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); @@ -66,7 +59,7 @@ function appleSignInRedirect(provider) { // [START auth_apple_signin_redirect] const { getAuth, signInWithRedirect } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithRedirect(auth, provider); // [END auth_apple_signin_redirect] } @@ -76,7 +69,7 @@ function appleSignInRedirectResult() { const { getAuth, getRedirectResult, OAuthProvider } = require("firebase/auth"); // Result from Redirect auth flow. - const auth = getAuth(firebaseApp); + const auth = getAuth(); getRedirectResult(auth) .then((result) => { const credential = OAuthProvider.credentialFromResult(result); @@ -93,7 +86,7 @@ function appleSignInRedirectResult() { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); @@ -107,7 +100,7 @@ function appleReauthenticatePopup() { const { getAuth, reauthenticateWithPopup, OAuthProvider } = require("firebase/auth"); // Result from Redirect auth flow. - const auth = getAuth(firebaseApp); + const auth = getAuth(); const provider = new OAuthProvider('apple.com'); reauthenticateWithPopup(auth.currentUser, provider) @@ -131,7 +124,7 @@ function appleReauthenticatePopup() { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); @@ -144,7 +137,7 @@ function appleLinkFacebook() { // [START auth_apple_link_facebook] const { getAuth, linkWithPopup, FacebookAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); const provider = new FacebookAuthProvider(); provider.addScope('user_birthday'); @@ -177,7 +170,7 @@ function appleNonceNode() { crypto.randomFillSync(buf); nonce = decoder.write(buf); } - return nonce.substr(0, length); + return nonce.slice(0, length); }; const unhashedNonce = generateNonce(10); @@ -192,7 +185,7 @@ function appleSignInNonce(appleIdToken, unhashedNonce,) { // [START auth_apple_signin_nonce] const { getAuth, signInWithCredential, OAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); // Build Firebase credential with the Apple ID token. const provider = new OAuthProvider('apple.com'); diff --git a/auth-next/auth-state-persistence.js b/auth-next/auth-state-persistence.js index cef52522..2d36c429 100644 --- a/auth-next/auth-state-persistence.js +++ b/auth-next/auth-state-persistence.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - function setPersistenceSession() { const email = "..."; const password = "..."; @@ -16,7 +8,7 @@ function setPersistenceSession() { // [START auth_set_persistence_session] const { getAuth, setPersistence, signInWithEmailAndPassword, browserSessionPersistence } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); setPersistence(auth, browserSessionPersistence) .then(() => { // Existing and future Auth states are now persisted in the current @@ -38,7 +30,7 @@ function setPersistenceNone() { // [START auth_set_persistence_none] const { getAuth, setPersistence, signInWithRedirect, inMemoryPersistence, GoogleAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); setPersistence(auth, inMemoryPersistence) .then(() => { const provider = new GoogleAuthProvider(); diff --git a/auth-next/cordova.js b/auth-next/cordova.js index ec637576..ff91dfcc 100644 --- a/auth-next/cordova.js +++ b/auth-next/cordova.js @@ -1,19 +1,11 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/cordova.md function createGoogleProvider() { // [START auth_create_google_provider] - const { GoogleAuthProvider } = require("firebase/auth"); + const { GoogleAuthProvider } = require("firebase/auth/cordova"); const provider = new GoogleAuthProvider(); // [END auth_create_google_provider] @@ -21,9 +13,9 @@ function createGoogleProvider() { function cordovaSignInRedirect() { // [START auth_cordova_sign_in_redirect] - const { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } = require("firebase/auth"); + const { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } = require("firebase/auth/cordova"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithRedirect(auth, new GoogleAuthProvider()) .then(() => { return getRedirectResult(auth); @@ -48,9 +40,9 @@ function cordovaSignInRedirect() { function cordovaRedirectResult() { // [START auth_cordova_redirect_result] - const { getAuth, getRedirectResult, GoogleAuthProvider } = require("firebase/auth"); + const { getAuth, getRedirectResult, GoogleAuthProvider } = require("firebase/auth/cordova"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); getRedirectResult(auth) .then((result) => { const credential = GoogleAuthProvider.credentialFromResult(result); diff --git a/auth-next/custom-dependencies.js b/auth-next/custom-dependencies.js new file mode 100644 index 00000000..209b6767 --- /dev/null +++ b/auth-next/custom-dependencies.js @@ -0,0 +1,58 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +// Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/custom-dependencies.md + +function getAuthEquivalent() { + // [START auth_get_auth_equivalent] + const {initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, browserSessionPersistence, indexedDBLocalPersistence} = require("firebase/auth"); + const {initializeApp} = require("firebase/app"); + + const app = initializeApp({/** Your app config */}); + const auth = initializeAuth(app, { + persistence: [indexedDBLocalPersistence, browserLocalPersistence, browserSessionPersistence], + popupRedirectResolver: browserPopupRedirectResolver, + }); + // [END auth_get_auth_equivalent] +} + +function onlyBrowserLocal() { + // [START auth_only_browser_local] + const {initializeAuth, browserLocalPersistence} = require("firebase/auth"); + const {initializeApp} = require("firebase/app"); + + const app = initializeApp({/** Your app config */}); + const auth = initializeAuth(app, { + persistence: browserLocalPersistence, + // No popupRedirectResolver defined + }); + // [END auth_only_browser_local] +} + +function onlyIndexedDB() { + // [START auth_only_indexed_db] + const {initializeAuth, indexedDBLocalPersistence} = require("firebase/auth"); + const {initializeApp} = require("firebase/app"); + + const app = initializeApp({/** Your app config */}); + const auth = initializeAuth(app, { + persistence: indexedDBLocalPersistence, + // No popupRedirectResolver defined + }); + // [END auth_only_indexed_db] +} + +function signInRedirectManualDeps() { + // [START auth_sign_in_redirect_manual_deps] + const {initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, indexedDBLocalPersistence, signInWithRedirect, GoogleAuthProvider} = require("firebase/auth"); + const {initializeApp} = require("firebase/app"); + + const app = initializeApp({/** Your app config */}); + const auth = initializeAuth(app, { + persistence: [indexedDBLocalPersistence, browserLocalPersistence], + }); + + // Later + signInWithRedirect(auth, new GoogleAuthProvider(), browserPopupRedirectResolver); + // [END auth_sign_in_redirect_manual_deps] +} \ No newline at end of file diff --git a/auth-next/custom-email-handler.js b/auth-next/custom-email-handler.js index eccb9219..5fcc1f71 100644 --- a/auth-next/custom-email-handler.js +++ b/auth-next/custom-email-handler.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/custom-email-handler.md function handleUserManagementQueryParams() { @@ -36,8 +28,8 @@ function handleUserManagementQueryParams() { // Configure the Firebase SDK. // This is the minimum configuration required for the API to be used. const config = { - 'apiKey': "YOU_API_KEY" // Copy this key from the web initialization - // snippet found in the Firebase console. + 'apiKey': "YOUR_API_KEY" // Copy this key from the web initialization + // snippet found in the Firebase console. }; const app = initializeApp(config); const auth = getAuth(app); diff --git a/auth-next/custom.js b/auth-next/custom.js index 6ecdbe18..8975672e 100644 --- a/auth-next/custom.js +++ b/auth-next/custom.js @@ -1,24 +1,17 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - function signInCustom() { const token = "token123"; // [START auth_sign_in_custom] const { getAuth, signInWithCustomToken } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithCustomToken(auth, token) - .then((user) => { + .then((userCredential) => { // Signed in + const user = userCredential.user; // ... }) .catch((error) => { diff --git a/auth-next/email-link-auth.js b/auth-next/email-link-auth.js index a2ec5cf5..fde67663 100644 --- a/auth-next/email-link-auth.js +++ b/auth-next/email-link-auth.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/email-link-auth.md function emailLinkActionCodeSettings() { @@ -27,7 +19,8 @@ function emailLinkActionCodeSettings() { installApp: true, minimumVersion: '12' }, - dynamicLinkDomain: 'example.page.link' + // The domain must be configured in Firebase Hosting and owned by the project. + linkDomain: 'custom-domain.com' }; // [END auth_email_link_actioncode_settings] } @@ -36,7 +29,7 @@ function emailLinkSend(email, actionCodeSettings) { // [START auth_email_link_send] const { getAuth, sendSignInLinkToEmail } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); sendSignInLinkToEmail(auth, email, actionCodeSettings) .then(() => { // The link was successfully sent. Inform the user. @@ -58,7 +51,7 @@ function emailLinkComplete() { const { getAuth, isSignInWithEmailLink, signInWithEmailLink } = require("firebase/auth"); // Confirm the link is a sign-in with email link. - const auth = getAuth(firebaseApp); + const auth = getAuth(); if (isSignInWithEmailLink(auth, window.location.href)) { // Additional state parameters can also be passed via URL. // This can be used to continue the user's intended action before triggering @@ -76,11 +69,13 @@ function emailLinkComplete() { .then((result) => { // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); - // You can access the new user via result.user - // Additional user info profile not available via: - // result.additionalUserInfo.profile == null + // You can access the new user by importing getAdditionalUserInfo + // and calling it with result: + // getAdditionalUserInfo(result) + // You can access the user's profile via: + // getAdditionalUserInfo(result)?.profile // You can check if the user is new or existing: - // result.additionalUserInfo.isNewUser + // getAdditionalUserInfo(result)?.isNewUser }) .catch((error) => { // Some error occurred, you can inspect the code: error.code @@ -99,7 +94,7 @@ function emailLinkLink(email) { email, window.location.href); // Link the credential to the current user. - const auth = getAuth(firebaseApp); + const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { // The provider is now successfully linked. @@ -120,7 +115,7 @@ function emailLinkReauth(email) { email, window.location.href); // Re-authenticate the user with this credential. - const auth = getAuth(firebaseApp); + const auth = getAuth(); reauthenticateWithCredential(auth.currentUser, credential) .then((usercred) => { // The user is now successfully re-authenticated and can execute sensitive @@ -139,7 +134,7 @@ function emailLinkDifferentiate() { // After asking the user for their email. const email = window.prompt('Please provide your email'); - const auth = getAuth(firebaseApp); + const auth = getAuth(); fetchSignInMethodsForEmail(auth, email) .then((signInMethods) => { // This returns the same array as fetchProvidersForEmail but for email diff --git a/auth-next/email.js b/auth-next/email.js index 368ad8a8..26391f81 100644 --- a/auth-next/email.js +++ b/auth-next/email.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - function signInWithEmailPassword() { const email = "test@example.com"; const password = "hunter2"; @@ -16,10 +8,11 @@ function signInWithEmailPassword() { // [START auth_signin_password] const { getAuth, signInWithEmailAndPassword } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithEmailAndPassword(auth, email, password) - .then((user) => { + .then((userCredential) => { // Signed in + const user = userCredential.user; // ... }) .catch((error) => { @@ -29,17 +22,18 @@ function signInWithEmailPassword() { // [END auth_signin_password] } -function signUpWithEmailPasswoerd() { +function signUpWithEmailPassword() { const email = "test@example.com"; const password = "hunter2"; // [START auth_signup_password] const { getAuth, createUserWithEmailAndPassword } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); createUserWithEmailAndPassword(auth, email, password) - .then((user) => { - // Signed in + .then((userCredential) => { + // Signed up + const user = userCredential.user; // ... }) .catch((error) => { @@ -54,7 +48,7 @@ function sendEmailVerification() { // [START auth_send_email_verification] const { getAuth, sendEmailVerification } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); sendEmailVerification(auth.currentUser) .then(() => { // Email verification sent! @@ -69,7 +63,7 @@ function sendPasswordReset() { // [START auth_send_password_reset] const { getAuth, sendPasswordResetEmail } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); sendPasswordResetEmail(auth, email) .then(() => { // Password reset email sent! diff --git a/auth-next/emulator-suite.js b/auth-next/emulator-suite.js new file mode 100644 index 00000000..13b1ba95 --- /dev/null +++ b/auth-next/emulator-suite.js @@ -0,0 +1,24 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function emulatorConnect() { + // [START auth_emulator_connect] + const { getAuth, connectAuthEmulator } = require("firebase/auth"); + + const auth = getAuth(); + connectAuthEmulator(auth, "http://127.0.0.1:9099"); + // [END auth_emulator_connect] +} + +function emulatorGoogleCredential() { + // [START auth_emulator_google_credential] + const { getAuth, signInWithCredential, GoogleAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + signInWithCredential(auth, GoogleAuthProvider.credential( + '{"sub": "abc123", "email": "foo@example.com", "email_verified": true}' + )); + // [END auth_emulator_google_credential] +} + + diff --git a/auth-next/facebook.js b/auth-next/facebook.js index 0ec084bd..3c6feb8a 100644 --- a/auth-next/facebook.js +++ b/auth-next/facebook.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - function facebookProvider() { // [START auth_facebook_provider_create] const { FacebookAuthProvider } = require("firebase/auth"); @@ -31,7 +23,7 @@ function facebookSignInPopup(provider) { // [START auth_facebook_signin_popup] const { getAuth, signInWithPopup, FacebookAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // The signed-in user info. @@ -41,6 +33,7 @@ function facebookSignInPopup(provider) { const credential = FacebookAuthProvider.credentialFromResult(result); const accessToken = credential.accessToken; + // IdP data available using getAdditionalUserInfo(result) // ... }) .catch((error) => { @@ -48,7 +41,7 @@ function facebookSignInPopup(provider) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); @@ -61,7 +54,7 @@ function facebookSignInRedirectResult() { // [START auth_facebook_signin_redirect_result] const { getAuth, getRedirectResult, FacebookAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); getRedirectResult(auth) .then((result) => { // This gives you a Facebook Access Token. You can use it to access the Facebook API. @@ -69,12 +62,14 @@ function facebookSignInRedirectResult() { const token = credential.accessToken; const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... @@ -90,7 +85,7 @@ function checkLoginState_wrapper() { // [START auth_facebook_callback] const { getAuth, onAuthStateChanged, signInWithCredential, signOut, FacebookAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); function checkLoginState(response) { if (response.authResponse) { @@ -110,7 +105,7 @@ function checkLoginState_wrapper() { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... @@ -153,7 +148,7 @@ function authWithCredential(credential) { const { getAuth, signInWithCredential, FacebookAuthProvider } = require("firebase/auth"); // Sign in with the credential from the Facebook user. - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithCredential(auth, credential) .then((result) => { // Signed in @@ -164,10 +159,19 @@ function authWithCredential(credential) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... }); // [END auth_facebook_signin_credential] } + +function facebookProviderCredential(accessToken) { + // [START auth_facebook_provider_credential] + const { FacebookAuthProvider } = require("firebase/auth"); + + const credential = FacebookAuthProvider.credential(accessToken); + // [END auth_facebook_provider_credential] +} + diff --git a/auth-next/github.js b/auth-next/github.js index d59b0f42..4c128721 100644 --- a/auth-next/github.js +++ b/auth-next/github.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - function githubProvider() { // [START auth_github_provider_create] const { GithubAuthProvider } = require("firebase/auth"); @@ -27,11 +19,19 @@ function githubProvider() { // [END auth_github_provider_params] } +function githubProviderCredential(token) { + // [START auth_github_provider_credential] + const { GithubAuthProvider } = require("firebase/auth"); + + const credential = GithubAuthProvider.credential(token); + // [END auth_github_provider_credential] +} + function githubSignInPopup(provider) { // [START auth_github_signin_popup] const { getAuth, signInWithPopup, GithubAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // This gives you a GitHub Access Token. You can use it to access the GitHub API. @@ -40,13 +40,14 @@ function githubSignInPopup(provider) { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GithubAuthProvider.credentialFromError(error); // ... @@ -58,7 +59,7 @@ function githubSignInRedirectResult() { // [START auth_github_signin_redirect_result] const { getAuth, getRedirectResult, GithubAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); getRedirectResult(auth) .then((result) => { const credential = GithubAuthProvider.credentialFromResult(result); @@ -70,12 +71,14 @@ function githubSignInRedirectResult() { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GithubAuthProvider.credentialFromError(error); // ... diff --git a/auth-next/google-signin.js b/auth-next/google-signin.js index 4661212b..025eebd6 100644 --- a/auth-next/google-signin.js +++ b/auth-next/google-signin.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/google-signin.md function googleProvider() { @@ -33,7 +25,7 @@ function googleSignInPopup(provider) { // [START auth_google_signin_popup] const { getAuth, signInWithPopup, GoogleAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // This gives you a Google Access Token. You can use it to access the Google API. @@ -41,13 +33,14 @@ function googleSignInPopup(provider) { const token = credential.accessToken; // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... @@ -59,7 +52,7 @@ function googleSignInRedirectResult() { // [START auth_google_signin_redirect_result] const { getAuth, getRedirectResult, GoogleAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); getRedirectResult(auth) .then((result) => { // This gives you a Google Access Token. You can use it to access Google APIs. @@ -68,12 +61,14 @@ function googleSignInRedirectResult() { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... @@ -89,13 +84,13 @@ function googleBuildAndSignIn(id_token) { const credential = GoogleAuthProvider.credential(id_token); // Sign in with credential from the Google user. - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithCredential(auth, credential).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... @@ -111,7 +106,7 @@ function onSignIn_wrapper() { // [START auth_google_callback] const { getAuth, onAuthStateChanged, signInWithCredential, GoogleAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); function onSignIn(googleUser) { console.log('Google Auth Response', googleUser); @@ -131,7 +126,7 @@ function onSignIn_wrapper() { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... @@ -165,4 +160,13 @@ function isUserEqual_wrapper() { // [END auth_google_checksameuser] } +function googleProviderCredential(idToken) { + // [START auth_google_provider_credential] + const { GoogleAuthProvider } = require("firebase/auth"); + + const credential = GoogleAuthProvider.credential(idToken); + // [END auth_google_provider_credential] +} + + diff --git a/auth-next/index.js b/auth-next/index.js index bf5bec57..04ac7d03 100644 --- a/auth-next/index.js +++ b/auth-next/index.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // ========================================================================================== // Docs: Snippets in this file are "general purpose" and are used on more than one docs page // ========================================================================================== @@ -34,7 +26,7 @@ function makeFacebookCredential(response) { function makeEmailCredential(email, password) { // [START auth_make_email_credential] const { EmailAuthProvider } = require("firebase/auth"); - + const credential = EmailAuthProvider.credential(email, password); // [END auth_make_email_credential] } @@ -43,7 +35,7 @@ function signOut() { // [START auth_sign_out] const { getAuth, signOut } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signOut(auth).then(() => { // Sign-out successful. }).catch((error) => { @@ -56,11 +48,11 @@ function authStateListener() { // [START auth_state_listener] const { getAuth, onAuthStateChanged } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); onAuthStateChanged(auth, (user) => { if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/v8/firebase.User const uid = user.uid; // ... } else { @@ -71,14 +63,31 @@ function authStateListener() { // [END auth_state_listener] } +function currentUser() { + // [START auth_current_user] + const { getAuth } = require("firebase/auth"); + + const auth = getAuth(); + const user = auth.currentUser; + + if (user) { + // User is signed in, see docs for a list of available properties + // https://firebase.google.com/docs/reference/js/v8/firebase.User + // ... + } else { + // No user is signed in. + } + // [END auth_current_user] +} + function setLanguageCode() { // [START auth_set_language_code] const { getAuth } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); auth.languageCode = 'it'; // To apply the default browser preference instead of explicitly setting it. - // firebase.auth().useDeviceLanguage(); + // auth.useDeviceLanguage(); // [END auth_set_language_code] } @@ -87,7 +96,7 @@ function authWithCredential(credential) { const { getAuth, signInWithCredential } = require("firebase/auth"); // Sign in with the credential from the user. - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithCredential(auth, credential) .then((result) => { // Signed in @@ -98,7 +107,7 @@ function authWithCredential(credential) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // ... }); // [END auth_signin_credential] @@ -108,7 +117,21 @@ function signInRedirect(provider) { // [START auth_signin_redirect] const { getAuth, signInWithRedirect } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithRedirect(auth, provider); // [END auth_signin_redirect] } + +function initializeWithCustomDomain() { + // [START auth_init_custom_domain] + const { initializeApp } = require("firebase/app"); + + const firebaseConfig = { + apiKey: "...", + // By default, authDomain is '[YOUR_APP].firebaseapp.com'. + // You may replace it with a custom domain. + authDomain: '[YOUR_CUSTOM_DOMAIN]' + }; + const firebaseApp = initializeApp(firebaseConfig); + // [END auth_init_custom_domain] +} diff --git a/auth-next/link-multiple-accounts.js b/auth-next/link-multiple-accounts.js index 0c612af9..1938aafc 100644 --- a/auth-next/link-multiple-accounts.js +++ b/auth-next/link-multiple-accounts.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - const MyUserDataRepo = function() {}; MyUserDataRepo.prototype.merge = function(data1, data2) { @@ -47,7 +39,7 @@ function simpleLink(credential) { // [START auth_simple_link] const { getAuth, linkWithCredential } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { const user = usercred.user; @@ -62,7 +54,7 @@ function anonymousLink(credential) { // [START auth_anonymous_link] const { getAuth, linkWithCredential } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { const user = usercred.user; @@ -78,7 +70,7 @@ function linkWithPopup() { const { getAuth, linkWithPopup, GoogleAuthProvider } = require("firebase/auth"); const provider = new GoogleAuthProvider(); - const auth = getAuth(firebaseApp); + const auth = getAuth(); linkWithPopup(auth.currentUser, provider).then((result) => { // Accounts successfully linked. const credential = GoogleAuthProvider.credentialFromResult(result); @@ -96,7 +88,7 @@ function linkWithRedirect() { const { getAuth, linkWithRedirect, GoogleAuthProvider } = require("firebase/auth"); const provider = new GoogleAuthProvider(); - const auth = getAuth(firebaseApp); + const auth = getAuth(); linkWithRedirect(auth.currentUser, provider) .then(/* ... */) .catch(/* ... */); @@ -126,7 +118,7 @@ function mergeAccounts(newCredential) { const repo = new MyUserDataRepo(); // Get reference to the currently signed-in user - const auth = getAuth(firebaseApp); + const auth = getAuth(); const prevUser = auth.currentUser; // Get the data which you will want to merge. This should be done now @@ -180,7 +172,7 @@ function unlink(providerId) { // [START auth_unlink_provider] const { getAuth, unlink } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); unlink(auth.currentUser, providerId).then(() => { // Auth provider unlinked from account // ... @@ -190,3 +182,61 @@ function unlink(providerId) { }); // [END auth_unlink_provider] } + +function accountExistsPopup(auth, facebookProvider, goToApp, promptUserForPassword, promptUserForSignInMethod, getProviderForProviderId) { + // [START account_exists_popup] + const { signInWithPopup, signInWithEmailAndPassword, linkWithCredential } = require("firebase/auth"); + + // User tries to sign in with Facebook. + signInWithPopup(auth, facebookProvider).catch((error) => { + // User's email already exists. + if (error.code === 'auth/account-exists-with-different-credential') { + // The pending Facebook credential. + const pendingCred = error.credential; + // The provider account's email address. + const email = error.customData.email; + + // Present the user with a list of providers they might have + // used to create the original account. + // Then, ask the user to sign in with the existing provider. + const method = promptUserForSignInMethod(); + + if (method === 'password') { + // TODO: Ask the user for their password. + // In real scenario, you should handle this asynchronously. + const password = promptUserForPassword(); + signInWithEmailAndPassword(auth, email, password).then((result) => { + return linkWithCredential(result.user, pendingCred); + }).then(() => { + // Facebook account successfully linked to the existing user. + goToApp(); + }); + return; + } + + // All other cases are external providers. + // Construct provider object for that provider. + // TODO: Implement getProviderForProviderId. + const provider = getProviderForProviderId(method); + // At this point, you should let the user know that they already have an + // account with a different provider, and validate they want to sign in + // with the new provider. + // Note: Browsers usually block popups triggered asynchronously, so in + // real app, you should ask the user to click on a "Continue" button + // that will trigger signInWithPopup(). + signInWithPopup(auth, provider).then((result) => { + // Note: Identity Platform doesn't control the provider's sign-in + // flow, so it's possible for the user to sign in with an account + // with a different email from the first one. + + // Link the Facebook credential. We have access to the pending + // credential, so we can directly call the link method. + linkWithCredential(result.user, pendingCred).then((userCred) => { + // Success. + goToApp(); + }); + }); + } +}); +// [END account_exists_popup] +} diff --git a/auth-next/manage.js b/auth-next/manage.js new file mode 100644 index 00000000..bf603ccc --- /dev/null +++ b/auth-next/manage.js @@ -0,0 +1,168 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function getUserProfile() { + // [START auth_get_user_profile] + const { getAuth } = require("firebase/auth"); + + const auth = getAuth(); + const user = auth.currentUser; + if (user !== null) { + // The user object has basic properties such as display name, email, etc. + const displayName = user.displayName; + const email = user.email; + const photoURL = user.photoURL; + const emailVerified = user.emailVerified; + + // The user's ID, unique to the Firebase project. Do NOT use + // this value to authenticate with your backend server, if + // you have one. Use User.getToken() instead. + const uid = user.uid; + } + // [END auth_get_user_profile] +} + +function getUserProfileProvider() { + // [START auth_get_user_profile_provider] + const { getAuth } = require("firebase/auth"); + + const auth = getAuth(); + const user = auth.currentUser; + + if (user !== null) { + user.providerData.forEach((profile) => { + console.log("Sign-in provider: " + profile.providerId); + console.log(" Provider-specific UID: " + profile.uid); + console.log(" Name: " + profile.displayName); + console.log(" Email: " + profile.email); + console.log(" Photo URL: " + profile.photoURL); + }); + } + // [END auth_get_user_profile_provider] +} + +function updateUserProfile() { + // [START auth_update_user_profile] + const { getAuth, updateProfile } = require("firebase/auth"); + const auth = getAuth(); + updateProfile(auth.currentUser, { + displayName: "Jane Q. User", photoURL: "https://example.com/jane-q-user/profile.jpg" + }).then(() => { + // Profile updated! + // ... + }).catch((error) => { + // An error occurred + // ... + }); + // [END auth_update_user_profile] +} + +function updateUserEmail() { + // [START auth_update_user_email] + const { getAuth, updateEmail } = require("firebase/auth"); + const auth = getAuth(); + updateEmail(auth.currentUser, "user@example.com").then(() => { + // Email updated! + // ... + }).catch((error) => { + // An error occurred + // ... + }); + // [END auth_update_user_email] +} + +function sendEmailVerification() { + // [START send_email_verification] + const { getAuth, sendEmailVerification } = require("firebase/auth"); + + const auth = getAuth(); + const user = auth.currentUser; + + sendEmailVerification(user).then(() => { + // Email sent. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END send_email_verification] +} + +function updatePassword() { + function getASecureRandomPassword() { + return "correcthorsebatterystaple"; + } + + // [START auth_update_password] + const { getAuth, updatePassword } = require("firebase/auth"); + + const auth = getAuth(); + + const user = auth.currentUser; + const newPassword = getASecureRandomPassword(); + + updatePassword(user, newPassword).then(() => { + // Update successful. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END auth_update_password] +} + +function sendPasswordReset() { + // [START auth_send_password_reset] + const { getAuth, sendPasswordResetEmail } = require("firebase/auth"); + + const auth = getAuth(); + const emailAddress = "user@example.com"; + + sendPasswordResetEmail(auth, emailAddress).then(() => { + // Email sent. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END auth_send_password_reset] +} + +function deleteUser() { + // [START auth_delete_user] + const { getAuth, deleteUser } = require("firebase/auth"); + + const auth = getAuth(); + const user = auth.currentUser; + + deleteUser(user).then(() => { + // User deleted. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END auth_delete_user] +} + +function reauthenticateWithCredential() { + /** + * @returns {object} + */ + function promptForCredentials() { + return {}; + } + + // [START auth_reauth_with_credential] + const { getAuth, reauthenticateWithCredential } = require("firebase/auth"); + + const auth = getAuth(); + const user = auth.currentUser; + + // TODO(you): prompt the user to re-provide their sign-in credentials + const credential = promptForCredentials(); + + reauthenticateWithCredential(user, credential).then(() => { + // User re-authenticated. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END auth_reauth_with_credential] +} diff --git a/auth-next/microsoft-oauth.js b/auth-next/microsoft-oauth.js index 0179ffc6..be0abffd 100644 --- a/auth-next/microsoft-oauth.js +++ b/auth-next/microsoft-oauth.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/microsoft-oauth.md function msftCreateProvider() { @@ -47,7 +39,7 @@ function msftSignInPopup(provider) { // [START auth_msft_signin_popup] const { getAuth, signInWithPopup, OAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // User is signed in. @@ -68,7 +60,7 @@ function msftSignInRedirect(provider) { // [START auth_msft_signin_redirect] const { getAuth, signInWithRedirect } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithRedirect(auth, provider); // [END auth_msft_signin_redirect] } @@ -77,7 +69,7 @@ function msftSignInRedirectResult() { // [START auth_msft_signin_redirect_result] const { getAuth, getRedirectResult, OAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); getRedirectResult(auth) .then((result) => { // User is signed in. @@ -99,7 +91,7 @@ function msftLinkWithPopup() { const { getAuth, linkWithPopup, OAuthProvider } = require("firebase/auth"); const provider = new OAuthProvider('microsoft.com'); - const auth = getAuth(firebaseApp); + const auth = getAuth(); linkWithPopup(auth.currentUser, provider) .then((result) => { @@ -122,7 +114,7 @@ function msftReauthPopup() { const { getAuth, reauthenticateWithPopup, OAuthProvider } = require("firebase/auth"); const provider = new OAuthProvider('microsoft.com'); - const auth = getAuth(firebaseApp); + const auth = getAuth(); reauthenticateWithPopup(auth.currentUser, provider) .then((result) => { // User is re-authenticated with fresh tokens minted and diff --git a/auth-next/multi-tenancy.js b/auth-next/multi-tenancy.js new file mode 100644 index 00000000..d7577f34 --- /dev/null +++ b/auth-next/multi-tenancy.js @@ -0,0 +1,347 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function setTenant() { + // [START multitenant_set_tenant] + const { getAuth } = require("firebase/auth"); + const auth = getAuth(); + const tenantId = "TENANT_ID1"; + auth.tenantId = tenantId; + // [END multitenant_set_tenant] +} + +function switchTenantSingleAuth(auth) { + // [START multitenant_switch_tenant] + // One Auth instance + // Switch to tenant1 + auth.tenantId = "TENANT_ID1"; + // Switch to tenant2 + auth.tenantId = "TENANT_ID2"; + // Switch back to project level IdPs + auth.tenantId = null; + // [END multitenant_switch_tenant] +} + +function switchTenantMultiAuth(firebaseConfig1, firebaseConfig2) { + // [START multitenant_switch_tenant_multiinstance] + // Multiple Auth instances + const { initializeApp } = require("firebase/app"); + const { getAuth } = require("firebase/auth"); + const firebaseApp1 = initializeApp(firebaseConfig1, 'app1_for_tenantId1'); + const firebaseApp2 = initializeApp(firebaseConfig2, 'app2_for_tenantId2'); + + const auth1 = getAuth(firebaseApp1); + const auth2 = getAuth(firebaseApp2); + + auth1.tenantId = "TENANT_ID1"; + auth2.tenantId = "TENANT_ID2"; + // [END multitenant_switch_tenant_multiinstance] +} + +function passwordSignInWithTenantDemo(auth, email, password) { + // [START multitenant_signin_password_demo] + const { signInWithEmailAndPassword, onAuthStateChanged } = require("firebase/auth"); + // Switch to TENANT_ID1 + auth.tenantId = 'TENANT_ID1'; + + // Sign in with tenant + signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + const user = userCredential.user; + // user.tenantId is set to 'TENANT_ID1'. + // Switch to 'TENANT_ID2'. + auth.tenantId = 'TENANT_ID2'; + // auth.currentUser still points to the user. + // auth.currentUser.tenantId is 'TENANT_ID1'. + }); + + // You could also get the current user from Auth state observer. + onAuthStateChanged(auth, (user) => { + if (user) { + // User is signed in. + // user.tenantId is set to 'TENANT_ID1'. + } else { + // No user is signed in. + } + }); + // [END multitenant_signin_password_demo] +} + +function signUpWithTenant(auth, email, password) { + // [START multitenant_signup_password] + const { createUserWithEmailAndPassword } = require("firebase/auth"); + auth.tenantId = 'TENANT_ID'; + + createUserWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + // userCredential.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signup_password] +} + + +function passwordSignInWithTenant(auth, email, password) { + // [START multitenant_signin_password] + const { signInWithEmailAndPassword } = require("firebase/auth"); + auth.tenantId = 'TENANT_ID'; + + signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + // userCredential.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signin_password] +} + +function samlSignInPopupTenant(auth, provider) { + // [START multitenant_signin_saml_popup] + const { signInWithPopup } = require("firebase/auth"); + // Switch to TENANT_ID1. + auth.tenantId = 'TENANT_ID1'; + + // Sign-in with popup. + signInWithPopup(auth, provider) + .then((userCredential) => { + // User is signed in. + const user = userCredential.user; + // user.tenantId is set to 'TENANT_ID1'. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signin_saml_popup] +} + +function samlSignInRedirectTenant(auth, provider) { + // [START multitenant_signin_saml_redirect] + const { signInWithRedirect, getRedirectResult } = require("firebase/auth"); + // Switch to TENANT_ID1. + auth.tenantId = 'TENANT_ID1'; + + // Sign-in with redirect. + signInWithRedirect(auth, provider); + + // After the user completes sign-in and returns to the app, you can get + // the sign-in result by calling getRedirectResult. However, if they sign out + // and sign in again with an IdP, no tenant is used. + getRedirectResult(auth) + .then((result) => { + // User is signed in. + // The tenant ID available in result.user.tenantId. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signin_saml_redirect] +} + +function sendSignInLinkToEmailTenant(auth, email, actionCodeSettings) { + // [START multitenant_send_emaillink] + const { sendSignInLinkToEmail } = require("firebase/auth"); + // Switch to TENANT_ID1 + auth.tenantId = 'TENANT_ID1'; + + sendSignInLinkToEmail(auth, email, actionCodeSettings) + .then(() => { + // The link was successfully sent. Inform the user. + // Save the email locally so you don't need to ask the user for it again + // if they open the link on the same device. + window.localStorage.setItem('emailForSignIn', email); + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_send_emaillink] +} + +function signInWithEmailLinkTenant(auth) { + // [START multitenant_signin_emaillink] + const { isSignInWithEmailLink, parseActionCodeURL, signInWithEmailLink } = require("firebase/auth"); + if (isSignInWithEmailLink(auth, window.location.href)) { + const actionCodeUrl = parseActionCodeURL(window.location.href); + if (actionCodeUrl.tenantId) { + auth.tenantId = actionCodeUrl.tenantId; + } + let email = window.localStorage.getItem('emailForSignIn'); + if (!email) { + // User opened the link on a different device. To prevent session fixation + // attacks, ask the user to provide the associated email again. For example: + email = window.prompt('Please provide your email for confirmation'); + } + // The client SDK will parse the code from the link for you. + signInWithEmailLink(auth, email, window.location.href) + .then((result) => { + // User is signed in. + // tenant ID available in result.user.tenantId. + // Clear email from storage. + window.localStorage.removeItem('emailForSignIn'); + }); + } + // [END multitenant_signin_emaillink] +} + +// Same as the code in auth/ since this is the admin SDK. +function createCustomTokenTenant(admin, uid) { + // [START multitenant_create_custom_token] + // Ensure you're using a tenant-aware auth instance + const tenantManager = admin.auth().tenantManager(); + const tenantAuth = tenantManager.authForTenant('TENANT_ID1'); + + // Create a custom token in the usual manner + tenantAuth.createCustomToken(uid) + .then((customToken) => { + // Send token back to client + }) + .catch((error) => { + console.log('Error creating custom token:', error); + }); + // [END multitenant_create_custom_token] +} + +function signInWithCustomTokenTenant(auth, token) { + // [START multitenant_signin_custom_token] + const { signInWithCustomToken } = require("firebase/auth"); + auth.tenantId = 'TENANT_ID1'; + + signInWithCustomToken(auth, token) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signin_custom_token] +} + +function linkAccountTenant(auth, provider, email, password) { + // [START multitenant_account_linking] + const { signInWithPopup, EmailAuthProvider, linkWithCredential, SAMLAuthProvider, signInWithCredential } = require("firebase/auth"); + // Switch to TENANT_ID1 + auth.tenantId = 'TENANT_ID1'; + + // Sign-in with popup + signInWithPopup(auth, provider) + .then((userCredential) => { + // Existing user with e.g. SAML provider. + const prevUser = userCredential.user; + const emailCredential = + EmailAuthProvider.credential(email, password); + return linkWithCredential(prevUser, emailCredential) + .then((linkResult) => { + // Sign in with the newly linked credential + const linkCredential = SAMLAuthProvider.credentialFromResult(linkResult); + return signInWithCredential(auth, linkCredential); + }) + .then((signInResult) => { + // Handle sign in of merged user + // ... + }); + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_account_linking] +} + +function accountExistsPopupTenant(auth, samlProvider, googleProvider, goToApp) { + // [START multitenant_account_exists_popup] + const { signInWithPopup, fetchSignInMethodsForEmail, linkWithCredential } = require("firebase/auth"); + // Step 1. + // User tries to sign in to the SAML provider in that tenant. + auth.tenantId = 'TENANT_ID'; + signInWithPopup(auth, samlProvider) + .catch((error) => { + // An error happened. + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + // The pending SAML credential. + const pendingCred = error.credential; + // The credential's tenantId if needed: error.tenantId + // The provider account's email address. + const email = error.customData.email; + // Get sign-in methods for this email. + fetchSignInMethodsForEmail(email, auth) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + signInWithPopup(auth, googleProvider) + .then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + linkWithCredential(result.user, pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + } + }); + } + }); + // [END multitenant_account_exists_popup] +} + +function accountExistsRedirectTenant(auth, samlProvider, googleProvider, goToApp) { + // [START multitenant_account_exists_redirect] + const { signInWithRedirect, getRedirectResult, fetchSignInMethodsForEmail, linkWithCredential } = require("firebase/auth"); + // Step 1. + // User tries to sign in to SAML provider. + auth.tenantId = 'TENANT_ID'; + signInWithRedirect(auth, samlProvider); + var pendingCred; + // Redirect back from SAML IDP. auth.tenantId is null after redirecting. + getRedirectResult(auth).catch((error) => { + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + const tenantId = error.tenantId; + // The pending SAML credential. + pendingCred = error.credential; + // The provider account's email address. + const email = error.customData.email; + // Need to set the tenant ID again as the page was reloaded and the + // previous setting was reset. + auth.tenantId = tenantId; + // Get sign-in methods for this email. + fetchSignInMethodsForEmail(auth, email) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + signInWithRedirect(auth, googleProvider); + } + }); + } + }); + + // Redirect back from Google. auth.tenantId is null after redirecting. + getRedirectResult(auth).then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + // result.user.tenantId is 'TENANT_ID'. + linkWithCredential(result.user, pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + // [END multitenant_account_exists_redirect] +} \ No newline at end of file diff --git a/auth-next/oidc.js b/auth-next/oidc.js new file mode 100644 index 00000000..dae69fe9 --- /dev/null +++ b/auth-next/oidc.js @@ -0,0 +1,96 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function oidcProvider() { + // [START auth_oidc_provider_create] + const { OAuthProvider } = require("firebase/auth"); + + const provider = new OAuthProvider("oidc.myProvider"); + // [END auth_oidc_provider_create] +} + +function oidcSignInPopup(provider) { + // [START auth_oidc_signin_popup] + const { getAuth, signInWithPopup, OAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + signInWithPopup(auth, provider) + .then((result) => { + // User is signed in. + const credential = OAuthProvider.credentialFromResult(result); + // This gives you an access token for the OIDC provider. You can use it to directly interact with that provider + }).catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_oidc_signin_popup] +} + +function oidcSignInRedirect(provider) { + // [START auth_oidc_signin_redirect] + const { getAuth, signInWithRedirect } = require("firebase/auth"); + + const auth = getAuth(); + signInWithRedirect(auth, provider); + // [END auth_oidc_signin_redirect] +} + +function oidcSignInRedirectResult(provider) { + // [START auth_oidc_signin_redirect_result] + const { getAuth, getRedirectResult, OAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + getRedirectResult(auth) + .then((result) => { + // User is signed in. + const credential = OAuthProvider.credentialFromResult(result); + // This gives you an access token for the OIDC provider. You can use it to directly interact with that provider + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_oidc_signin_redirect_result] +} + +function oidcDirectSignIn(provider, oidcIdToken) { + // [START auth_oidc_direct_sign_in] + const { getAuth, OAuthProvider, signInWithCredential } = require("firebase/auth"); + + const auth = getAuth(); + const credential = provider.credential({ + idToken: oidcIdToken, + }); + signInWithCredential(auth, credential) + .then((result) => { + // User is signed in. + const newCredential = OAuthProvider.credentialFromResult(result); + // This gives you a new access token for the OIDC provider. You can use it to directly interact with that provider. + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_oidc_direct_sign_in] +} \ No newline at end of file diff --git a/auth-next/package.json b/auth-next/package.json index 058a14c8..8d43bad1 100644 --- a/auth-next/package.json +++ b/auth-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "exp" + "firebase": "^10.0.0" } } diff --git a/auth-next/phone-auth.js b/auth-next/phone-auth.js index 510dd219..99492f99 100644 --- a/auth-next/phone-auth.js +++ b/auth-next/phone-auth.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Mask the global 'window' for this snippet file const window = { recaptchaVerifier: undefined @@ -22,14 +14,14 @@ function recaptchaVerifierInvisible() { // [START auth_phone_recaptcha_verifier_invisible] const { getAuth, RecaptchaVerifier } = require("firebase/auth"); - const auth = getAuth(firebaseApp); - window.recaptchaVerifier = new RecaptchaVerifier('sign-in-button', { + const auth = getAuth(); + window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', { 'size': 'invisible', 'callback': (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. onSignInSubmit(); } - }, auth); + }); // [END auth_phone_recaptcha_verifier_invisible] } @@ -37,8 +29,8 @@ function recaptchaVerifierVisible() { // [START auth_phone_recaptcha_verifier_visible] const { getAuth, RecaptchaVerifier } = require("firebase/auth"); - const auth = getAuth(firebaseApp); - window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', { + const auth = getAuth(); + window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', { 'size': 'normal', 'callback': (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. @@ -48,7 +40,7 @@ function recaptchaVerifierVisible() { // Response expired. Ask user to solve reCAPTCHA again. // ... } - }, auth); + }); // [END auth_phone_recaptcha_verifier_visible] } @@ -56,8 +48,8 @@ function recaptchaVerifierSimple() { // [START auth_phone_recaptcha_verifier_simple] const { getAuth, RecaptchaVerifier } = require("firebase/auth"); - const auth = getAuth(firebaseApp); - window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {}, auth); + const auth = getAuth(); + window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {}); // [END auth_phone_recaptcha_verifier_simple] } @@ -85,7 +77,7 @@ function phoneSignIn() { const phoneNumber = getPhoneNumberFromUserInput(); const appVerifier = window.recaptchaVerifier; - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithPhoneNumber(auth, phoneNumber, appVerifier) .then((confirmationResult) => { // SMS sent. Prompt user to type the code from the message, then sign the diff --git a/auth-next/saml.js b/auth-next/saml.js new file mode 100644 index 00000000..cdecce56 --- /dev/null +++ b/auth-next/saml.js @@ -0,0 +1,68 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function samlProvider() { + // [START auth_saml_provider_create] + const { SAMLAuthProvider } = require("firebase/auth"); + + const provider = new SAMLAuthProvider("saml.myProvider"); + // [END auth_saml_provider_create] +} + +function samlSignInPopup(provider) { + // [START auth_saml_signin_popup] + const { getAuth, signInWithPopup, SAMLAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + signInWithPopup(auth, provider) + .then((result) => { + // User is signed in. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }).catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = SAMLAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_saml_signin_popup] +} + +function samlSignInRedirect(provider) { + // [START auth_saml_signin_redirect] + const { getAuth, signInWithRedirect } = require("firebase/auth"); + + const auth = getAuth(); + signInWithRedirect(auth, provider); + // [END auth_saml_signin_redirect] +} + +function samlSignInRedirectResult(provider) { + // [START auth_saml_signin_redirect_result] + const { getAuth, getRedirectResult, SAMLAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + getRedirectResult(auth) + .then((result) => { + // User is signed in. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = SAMLAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_saml_signin_redirect_result] +} \ No newline at end of file diff --git a/auth-next/service-worker-sessions.js b/auth-next/service-worker-sessions.js index b9d87cbf..abef386b 100644 --- a/auth-next/service-worker-sessions.js +++ b/auth-next/service-worker-sessions.js @@ -1,21 +1,13 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/service-worker-sessions.md function svcGetIdToken() { // [START auth_svc_get_idtoken] const { getAuth, getIdToken } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); getIdToken(auth.currentUser) .then((idToken) => { // idToken can be passed back to server. @@ -39,7 +31,7 @@ function svcSubscribe(config) { * @return {!Promise} The promise that resolves with an ID token if * available. Otherwise, the promise resolves with null. */ - const auth = getAuth(firebaseApp); + const auth = getAuth(); const getIdTokenPromise = () => { return new Promise((resolve, reject) => { const unsubscribe = onAuthStateChanged(auth, (user) => { @@ -165,7 +157,7 @@ function svcSignInEmail(email, password) { const { getAuth, signInWithEmailAndPassword } = require("firebase/auth"); // Sign in screen. - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithEmailAndPassword(auth, email, password) .then((result) => { // Redirect to profile page after sign-in. The service worker will detect diff --git a/auth-next/twitter.js b/auth-next/twitter.js index 6e204cb3..f96e574b 100644 --- a/auth-next/twitter.js +++ b/auth-next/twitter.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - function twitterProvider() { // [START auth_twitter_provider_create] const { TwitterAuthProvider } = require("firebase/auth"); @@ -27,7 +19,7 @@ function twitterSignInPopup(provider) { // [START auth_twitter_signin_popup] const { getAuth, signInWithPopup, TwitterAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // This gives you a the Twitter OAuth 1.0 Access Token and Secret. @@ -38,13 +30,14 @@ function twitterSignInPopup(provider) { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = TwitterAuthProvider.credentialFromError(error); // ... @@ -56,7 +49,7 @@ function twitterSignInRedirectResult() { // [START auth_twitter_signin_redirect_result] const { getAuth, getRedirectResult, TwitterAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); getRedirectResult(auth) .then((result) => { // This gives you a the Twitter OAuth 1.0 Access Token and Secret. @@ -68,12 +61,14 @@ function twitterSignInRedirectResult() { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = TwitterAuthProvider.credentialFromError(error); // ... @@ -81,3 +76,10 @@ function twitterSignInRedirectResult() { // [END auth_twitter_signin_redirect_result] } +function twitterProviderCredential(accessToken, secret) { + // [START auth_twitter_provider_credential] + const { TwitterAuthProvider } = require("firebase/auth"); + + const credential = TwitterAuthProvider.credential(accessToken, secret); + // [END auth_twitter_provider_credential] +} \ No newline at end of file diff --git a/auth-next/yahoo-oauth.js b/auth-next/yahoo-oauth.js index e03c9bba..e08150e7 100644 --- a/auth-next/yahoo-oauth.js +++ b/auth-next/yahoo-oauth.js @@ -1,14 +1,6 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); - // Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/yahoo-oauth.md function yahooProvider() { @@ -40,7 +32,7 @@ function yahooSignInPopup(provider) { // [START auth_yahoo_signin_popup] const { getAuth, signInWithPopup, OAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // IdP data available in result.additionalUserInfo.profile @@ -61,7 +53,7 @@ function yahooSignInRedirect(provider) { // [START auth_yahoo_signin_redirect] const { getAuth, signInWithRedirect } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); signInWithRedirect(auth, provider); // [END auth_yahoo_signin_redirect] } @@ -70,7 +62,7 @@ function yahooSigninRedirectResult() { // [START auth_yahoo_signin_redirect_result] const { getAuth, getRedirectResult, OAuthProvider } = require("firebase/auth"); - const auth = getAuth(firebaseApp); + const auth = getAuth(); getRedirectResult(auth) .then((result) => { // IdP data available in result.additionalUserInfo.profile @@ -92,7 +84,7 @@ function yahooLinkPopup() { const { getAuth, linkWithPopup, OAuthProvider } = require("firebase/auth"); const provider = new OAuthProvider('yahoo.com'); - const auth = getAuth(firebaseApp); + const auth = getAuth(); linkWithPopup(auth.currentUser, provider) .then((result) => { // Yahoo credential is linked to the current user. @@ -114,7 +106,7 @@ function yahooReauthPopup() { const { getAuth, reauthenticateWithPopup, OAuthProvider } = require("firebase/auth"); const provider = new OAuthProvider('yahoo.com'); - const auth = getAuth(firebaseApp); + const auth = getAuth(); reauthenticateWithPopup(auth.currentUser, provider) .then((result) => { // User is re-authenticated with fresh tokens minted and diff --git a/auth/apple.js b/auth/apple.js index ad65ef08..00e2598e 100644 --- a/auth/apple.js +++ b/auth/apple.js @@ -40,7 +40,8 @@ function appleSignInPopup(provider) { var accessToken = credential.accessToken; var idToken = credential.idToken; - // ... + // IdP data available using getAdditionalUserInfo(result) + // ... }) .catch((error) => { // Handle Errors here. @@ -77,6 +78,7 @@ function appleSignInRedirectResult() { var accessToken = credential.accessToken; var idToken = credential.idToken; + // IdP data available in result.additionalUserInfo.profile. // ... } // The signed-in user info. @@ -117,7 +119,8 @@ function appleReauthenticatePopup() { var accessToken = credential.accessToken; var idToken = credential.idToken; - // ... + // IdP data available in result.additionalUserInfo.profile. + // ... }) .catch((error) => { // Handle Errors here. @@ -170,7 +173,7 @@ function appleNonceNode() { crypto.randomFillSync(buf); nonce = decoder.write(buf); } - return nonce.substr(0, length); + return nonce.slice(0, length); }; const unhashedNonce = generateNonce(10); diff --git a/auth/cordova.js b/auth/cordova.js index 1da36ef1..e7c3fc40 100644 --- a/auth/cordova.js +++ b/auth/cordova.js @@ -14,7 +14,7 @@ function createGoogleProvider() { function cordovaSignInRedirect(provider) { // [START auth_cordova_sign_in_redirect] - firebase.auth().signInWithRedirect(provider).then(function() { + firebase.auth().signInWithRedirect(provider).then(() => { return firebase.auth().getRedirectResult(); }).then((result) => { /** @type {firebase.auth.OAuthCredential} */ diff --git a/auth/custom.js b/auth/custom.js index dc02990e..97713714 100644 --- a/auth/custom.js +++ b/auth/custom.js @@ -8,8 +8,9 @@ function signInCustom() { var token = "token123"; // [START auth_sign_in_custom] firebase.auth().signInWithCustomToken(token) - .then((user) => { + .then((userCredential) => { // Signed in + var user = userCredential.user; // ... }) .catch((error) => { diff --git a/auth/email.js b/auth/email.js index ba919819..5520f71c 100644 --- a/auth/email.js +++ b/auth/email.js @@ -9,8 +9,9 @@ function signInWithEmailPassword() { var password = "hunter2"; // [START auth_signin_password] firebase.auth().signInWithEmailAndPassword(email, password) - .then((user) => { - // Signed in + .then((userCredential) => { + // Signed in + var user = userCredential.user; // ... }) .catch((error) => { @@ -20,13 +21,14 @@ function signInWithEmailPassword() { // [END auth_signin_password] } -function signUpWithEmailPasswoerd() { +function signUpWithEmailPassword() { var email = "test@example.com"; var password = "hunter2"; // [START auth_signup_password] firebase.auth().createUserWithEmailAndPassword(email, password) - .then((user) => { + .then((userCredential) => { // Signed in + var user = userCredential.user; // ... }) .catch((error) => { diff --git a/auth/emulator-suite.js b/auth/emulator-suite.js new file mode 100644 index 00000000..b0f815e2 --- /dev/null +++ b/auth/emulator-suite.js @@ -0,0 +1,18 @@ +import firebase from "firebase/app"; +import "firebase/auth"; + +function emulatorConnect() { + // [START auth_emulator_connect] + const auth = firebase.auth(); + auth.useEmulator("http://127.0.0.1:9099"); + // [END auth_emulator_connect] +} + +function emulatorGoogleCredential() { + // [START auth_emulator_google_credential] + const auth = firebase.auth(); + auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential( + '{"sub": "abc123", "email": "foo@example.com", "email_verified": true}' + )); + // [END auth_emulator_google_credential] +} diff --git a/auth/facebook.js b/auth/facebook.js index 3e5c5b14..75e99d43 100644 --- a/auth/facebook.js +++ b/auth/facebook.js @@ -31,6 +31,8 @@ function facebookSignInPopup(provider) { // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... // This gives you a Facebook Access Token. You can use it to access the Facebook API. var accessToken = credential.accessToken; @@ -66,6 +68,8 @@ function facebookSignInRedirectResult() { } // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -151,3 +155,9 @@ function authWithCredential(credential) { }); // [END auth_facebook_signin_credential] } + +function facebookProviderCredential(accessToken) { + // [START auth_facebook_provider_credential] + var credential = firebase.auth.FacebookAuthProvider.credential(accessToken); + // [END auth_facebook_provider_credential] +} diff --git a/auth/firebaseui.js b/auth/firebaseui.js index 2a359d5a..dbbf9031 100644 --- a/auth/firebaseui.js +++ b/auth/firebaseui.js @@ -218,13 +218,13 @@ function fuiConfig() { // [START auth_fui_config] var uiConfig = { callbacks: { - signInSuccessWithAuthResult: function(authResult, redirectUrl) { + signInSuccessWithAuthResult: (authResult, redirectUrl) => { // User successfully signed in. // Return type determines whether we continue the redirect automatically // or whether we leave that to developer to handle. return true; }, - uiShown: function() { + uiShown: () => { // The widget is rendered. // Hide the loader. document.getElementById('loader').style.display = 'none'; diff --git a/auth/github.js b/auth/github.js index bf2db5bf..8ae9b39c 100644 --- a/auth/github.js +++ b/auth/github.js @@ -20,6 +20,12 @@ function githubProvider() { // [END auth_github_provider_params] } +function githubProviderCredential(token) { + // [START auth_github_provider_credential] + var credential = firebase.auth.GithubAuthProvider.credential(token); + // [END auth_github_provider_credential] +} + function githubSignInPopup(provider) { // [START auth_github_signin_popup] firebase @@ -34,7 +40,8 @@ function githubSignInPopup(provider) { // The signed-in user info. var user = result.user; - // ... + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -64,6 +71,8 @@ function githubSignInRedirectResult() { // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; diff --git a/auth/google-signin.js b/auth/google-signin.js index 908a32e1..06a488e4 100644 --- a/auth/google-signin.js +++ b/auth/google-signin.js @@ -34,7 +34,8 @@ function googleSignInPopup(provider) { var token = credential.accessToken; // The signed-in user info. var user = result.user; - // ... + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -63,6 +64,8 @@ function googleSignInRedirectResult() { } // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -142,3 +145,9 @@ function isUserEqual(googleUser, firebaseUser) { return false; } // [END auth_google_checksameuser] + +function googleProviderCredential(idToken) { + // [START auth_google_provider_credential] + var credential = firebase.auth.GoogleAuthProvider.credential(idToken); + // [END auth_google_provider_credential] +} diff --git a/auth/index.js b/auth/index.js index cae8831b..35546aa3 100644 --- a/auth/index.js +++ b/auth/index.js @@ -43,7 +43,7 @@ function authStateListener() { firebase.auth().onAuthStateChanged((user) => { if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/v8/firebase.User var uid = user.uid; // ... } else { @@ -54,6 +54,20 @@ function authStateListener() { // [END auth_state_listener] } +function currentUser() { + // [START auth_current_user] + const user = firebase.auth().currentUser; + + if (user) { + // User is signed in, see docs for a list of available properties + // https://firebase.google.com/docs/reference/js/v8/firebase.User + // ... + } else { + // No user is signed in. + } + // [END auth_current_user] +} + function setLanguageCode() { // [START auth_set_language_code] firebase.auth().languageCode = 'it'; @@ -87,3 +101,14 @@ function signInRedirect(provider) { firebase.auth().signInWithRedirect(provider); // [END auth_signin_redirect] } + +function initializeWithCustomDomain() { + // [START auth_init_custom_domain] + firebase.initializeApp({ + apiKey: '...', + // By default, authDomain is '[YOUR_APP].firebaseapp.com'. + // You may replace it with a custom domain. + authDomain: '[YOUR_CUSTOM_DOMAIN]' + }); + // [END auth_init_custom_domain] +} diff --git a/auth/initialization.txt b/auth/initialization.txt new file mode 100644 index 00000000..bccb0571 --- /dev/null +++ b/auth/initialization.txt @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/auth/link-multiple-accounts.js b/auth/link-multiple-accounts.js index b6419431..8eed77b8 100644 --- a/auth/link-multiple-accounts.js +++ b/auth/link-multiple-accounts.js @@ -41,10 +41,10 @@ function getProviders() { function simpleLink(credential) { // [START auth_simple_link] auth.currentUser.linkWithCredential(credential) - .then(function(usercred) { + .then((usercred) => { var user = usercred.user; console.log("Account linking success", user); - }).catch(function(error) { + }).catch((error) => { console.log("Account linking error", error); }); // [END auth_simple_link] @@ -53,10 +53,10 @@ function simpleLink(credential) { function anonymousLink(credential) { // [START auth_anonymous_link] auth.currentUser.linkWithCredential(credential) - .then(function(usercred) { + .then((usercred) => { var user = usercred.user; console.log("Anonymous account successfully upgraded", user); - }).catch(function(error) { + }).catch((error) => { console.log("Error upgrading anonymous account", error); }); // [END auth_anonymous_link] @@ -66,12 +66,12 @@ function linkWithPopup() { var provider = new firebase.auth.GoogleAuthProvider(); // [START auth_link_with_popup] - auth.currentUser.linkWithPopup(provider).then(function(result) { + auth.currentUser.linkWithPopup(provider).then((result) => { // Accounts successfully linked. var credential = result.credential; var user = result.user; // ... - }).catch(function(error) { + }).catch((error) => { // Handle Errors here. // ... }); @@ -88,14 +88,14 @@ function linkWithRedirect() { // [END auth_link_with_redirect] // [START auth_get_redirect_result] - auth.getRedirectResult().then(function(result) { + auth.getRedirectResult().then((result) => { if (result.credential) { // Accounts successfully linked. var credential = result.credential; var user = result.user; // ... } - }).catch(function(error) { + }).catch((error) => { // Handle Errors here. // ... }); @@ -118,7 +118,7 @@ function mergeAccounts(newCredential) { repo.delete(prevUser); // Sign in user with the account you want to link to - auth.signInWithCredential(newCredential).then(function(result) { + auth.signInWithCredential(newCredential).then((result) => { console.log("Sign In Success", result); var currentUser = result.user; var currentUserData = repo.get(currentUser); @@ -128,15 +128,15 @@ function mergeAccounts(newCredential) { var mergedData = repo.merge(prevUserData, currentUserData); return prevUser.linkWithCredential(result.credential) - .then(function(linkResult) { + .then((linkResult) => { // Sign in with the newly linked credential return auth.signInWithCredential(linkResult.credential); }) - .then(function(signInResult) { + .then((signInResult) => { // Save the merged data to the new user repo.set(signInResult.user, mergedData); }); - }).catch(function(error) { + }).catch((error) => { // If there are errors we want to undo the data merge/deletion console.log("Sign In Error", error); repo.set(prevUser, prevUserData); @@ -157,12 +157,68 @@ function unlink(providerId) { var user = auth.currentUser; // [START auth_unlink_provider] - user.unlink(providerId).then(function() { + user.unlink(providerId).then(() => { // Auth provider unlinked from account // ... - }).catch(function(error) { + }).catch((error) => { // An error happened // ... }); // [END auth_unlink_provider] } + +function accountExistsPopup(facebookProvider, goToApp, promptUserForPassword, promptUserForSignInMethod, getProviderForProviderId) { + // [START account_exists_popup] + // User tries to sign in with Facebook. + auth.signInWithPopup(facebookProvider).catch((error) => { + // User's email already exists. + if (error.code === 'auth/account-exists-with-different-credential') { + // The pending Facebook credential. + const pendingCred = error.credential; + // The provider account's email address. + const email = error.email; + + // Present the user with a list of providers they might have + // used to create the original account. + // Then, ask the user to sign in with the existing provider. + const method = promptUserForSignInMethod(); + + if (method === 'password') { + // TODO: Ask the user for their password. + // In real scenario, you should handle this asynchronously. + const password = promptUserForPassword(); + auth.signInWithEmailAndPassword(email, password).then((result) => { + return result.user.linkWithCredential(pendingCred); + }).then(() => { + // Facebook account successfully linked to the existing user. + goToApp(); + }); + return; + } + + // All other cases are external providers. + // Construct provider object for that provider. + // TODO: Implement getProviderForProviderId. + const provider = getProviderForProviderId(method); + // At this point, you should let the user know that they already have an + // account with a different provider, and validate they want to sign in + // with the new provider. + // Note: Browsers usually block popups triggered asynchronously, so in + // real app, you should ask the user to click on a "Continue" button + // that will trigger signInWithPopup(). + auth.signInWithPopup(provider).then((result) => { + // Note: Identity Platform doesn't control the provider's sign-in + // flow, so it's possible for the user to sign in with an account + // with a different email from the first one. + + // Link the Facebook credential. We have access to the pending + // credential, so we can directly call the link method. + result.user.linkWithCredential(pendingCred).then((userCred) => { + // Success. + goToApp(); + }); + }); + } +}); +// [END account_exists_popup] +} diff --git a/auth/manage.js b/auth/manage.js new file mode 100644 index 00000000..0e1f0e7b --- /dev/null +++ b/auth/manage.js @@ -0,0 +1,151 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/auth"; + +function getUserProfile() { + // [START auth_get_user_profile] + const user = firebase.auth().currentUser; + if (user !== null) { + // The user object has basic properties such as display name, email, etc. + const displayName = user.displayName; + const email = user.email; + const photoURL = user.photoURL; + const emailVerified = user.emailVerified; + + // The user's ID, unique to the Firebase project. Do NOT use + // this value to authenticate with your backend server, if + // you have one. Use User.getIdToken() instead. + const uid = user.uid; + } + // [END auth_get_user_profile] +} + +function getUserProfileProvider() { + // [START auth_get_user_profile_provider] + const user = firebase.auth().currentUser; + + if (user !== null) { + user.providerData.forEach((profile) => { + console.log("Sign-in provider: " + profile.providerId); + console.log(" Provider-specific UID: " + profile.uid); + console.log(" Name: " + profile.displayName); + console.log(" Email: " + profile.email); + console.log(" Photo URL: " + profile.photoURL); + }); + } + // [END auth_get_user_profile_provider] +} + +function updateUserProfile() { + // [START auth_update_user_profile] + const user = firebase.auth().currentUser; + + user.updateProfile({ + displayName: "Jane Q. User", + photoURL: "https://example.com/jane-q-user/profile.jpg" + }).then(() => { + // Update successful + // ... + }).catch((error) => { + // An error occurred + // ... + }); + // [END auth_update_user_profile] +} + +function updateUserEmail() { + // [START auth_update_user_email] + const user = firebase.auth().currentUser; + + user.updateEmail("user@example.com").then(() => { + // Update successful + // ... + }).catch((error) => { + // An error occurred + // ... + }); + // [END auth_update_user_email] +} + +function sendEmailVerification() { + // [START send_email_verification] + const user = firebase.auth().currentUser; + + user.sendEmailVerification().then(() => { + // Email sent. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END send_email_verification] +} + +function updatePassword() { + function getASecureRandomPassword() { + return "correcthorsebatterystaple"; + } + + // [START auth_update_password] + const user = firebase.auth().currentUser; + const newPassword = getASecureRandomPassword(); + + user.updatePassword(newPassword).then(() => { + // Update successful. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END auth_update_password] +} + +function sendPasswordReset() { + // [START auth_send_password_reset] + const auth = firebase.auth(); + const emailAddress = "user@example.com"; + + auth.sendPasswordResetEmail(emailAddress).then(() => { + // Email sent. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END auth_send_password_reset] +} + +function deleteUser() { + // [START auth_delete_user] + const user = firebase.auth().currentUser; + + user.delete().then(() => { + // User deleted. + }).catch((error) => { + // An error ocurred + // ... + }); + // [END auth_delete_user] +} + +function reauthenticateWithCredential() { + /** + * @returns {object} + */ + function promptForCredentials() { + return {}; + } + + // [START auth_reauth_with_credential] + const user = firebase.auth().currentUser; + + // TODO(you): prompt the user to re-provide their sign-in credentials + const credential = promptForCredentials(); + + user.reauthenticateWithCredential(credential).then(() => { + // User re-authenticated. + }).catch((error) => { + // An error occurred + // ... + }); + // [END auth_reauth_with_credential] +} diff --git a/auth/multi-tenancy.js b/auth/multi-tenancy.js new file mode 100644 index 00000000..8b31e145 --- /dev/null +++ b/auth/multi-tenancy.js @@ -0,0 +1,312 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/auth"; + +function setTenant() { + // [START multitenant_set_tenant] + const tenantId = "TENANT_ID1"; + firebase.auth().tenantId = tenantId; + // [END multitenant_set_tenant] +} + +function switchTenantSingleAuth() { + // [START multitenant_switch_tenant] + // One Auth instance + // Switch to tenant1 + firebase.auth().tenantId = "TENANT_ID1"; + // Switch to tenant2 + firebase.auth().tenantId = "TENANT_ID2"; + // Switch back to project level IdPs + firebase.auth().tenantId = null; + // [END multitenant_switch_tenant] +} + +function switchTenantMultiAuth(config) { + // [START multitenant_switch_tenant_multiinstance] + // Multiple Auth instances + firebase.initializeApp(config, 'app1_for_tenantId1'); + firebase.initializeApp(config, 'app2_for_tenantId2'); + + const auth1 = firebase.app('app1').auth(); + const auth2 = firebase.app('app2').auth(); + + auth1.tenantId = "TENANT_ID1"; + auth2.tenantId = "TENANT_ID2"; + // [END multitenant_switch_tenant_multiinstance] +} + +function passwordSignInWithTenantDemo(email, password) { + // [START multitenant_signin_password_demo] + // Switch to TENANT_ID1 + firebase.auth().tenantId = 'TENANT_ID1'; + + // Sign in with tenant + firebase.auth().signInWithEmailAndPassword(email, password) + .then((result) => { + const user = result.user; + // user.tenantId is set to 'TENANT_ID1'. + // Switch to 'TENANT_ID2'. + firebase.auth().tenantId = 'TENANT_ID2'; + // firebase.auth().currentUser still point to the user. + // firebase.auth().currentUser.tenantId is 'TENANT_ID1'. + }); + + // You could also get the current user from Auth state observer. + firebase.auth().onAuthStateChanged((user) => { + if (user) { + // User is signed in. + // user.tenantId is set to 'TENANT_ID1'. + } else { + // No user is signed in. + } + }); + // [END multitenant_signin_password_demo] +} + +function signUpWithTenant(email, password) { + // [START multitenant_signup_password] + firebase.auth().tenantId = 'TENANT_ID'; + + firebase.auth().createUserWithEmailAndPassword(email, password) + .then((result) => { + // result.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle error. + }); + // [END multitenant_signup_password] +} + + +function passwordSignInWithTenant(email, password) { + // [START multitenant_signin_password] + firebase.auth().tenantId = 'TENANT_ID'; + + firebase.auth().signInWithEmailAndPassword(email, password) + .then((result) => { + // result.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle error. + }); + // [END multitenant_signin_password] +} + +function samlSignInPopupTenant(provider) { + // [START multitenant_signin_saml_popup] + // Switch to TENANT_ID1. + firebase.auth().tenantId = 'TENANT_ID1'; + + // Sign-in with popup. + firebase.auth().signInWithPopup(provider) + .then((result) => { + // User is signed in. + // tenant ID is available in result.user.tenantId. + // Identity provider data is available in result.additionalUserInfo.profile. + }) + .catch((error) => { + // Handle error. + }); + // [END multitenant_signin_saml_popup] +} + +function samlSignInRedirectTenant(provider) { + // [START multitenant_signin_saml_redirect] + // Switch to TENANT_ID1. + firebase.auth().tenantId = 'TENANT_ID1'; + + // Sign-in with redirect. + firebase.auth().signInWithRedirect(provider); + + // After the user completes sign-in and returns to the app, you can get + // the sign-in result by calling getRedirectResult. However, if they sign out + // and sign in again with an IdP, no tenant is used. + firebase.auth().getRedirectResult() + .then((result) => { + // User is signed in. + // The tenant ID available in result.user.tenantId. + // Identity provider data is available in result.additionalUserInfo.profile. + }) + .catch((error) => { + // Handle error. + }); + // [END multitenant_signin_saml_redirect] +} + +function sendSignInLinkToEmailTenant(email, actionCodeSettings) { + // [START multitenant_send_emaillink] + // Switch to TENANT_ID1 + firebase.auth().tenantId = 'TENANT_ID1'; + + firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings) + .then(() => { + // The link was successfully sent. Inform the user. + // Save the email locally so you don't need to ask the user for it again + // if they open the link on the same device. + window.localStorage.setItem('emailForSignIn', email); + }) + .catch((error) => { + // Some error occurred, you can inspect the code: error.code + }); + // [END multitenant_send_emaillink] +} + +function signInWithEmailLinkTenant() { + // [START multitenant_signin_emaillink] + if (firebase.auth().isSignInWithEmailLink(window.location.href)) { + const actionCodeUrl = firebase.auth.ActionCodeURL.parseLink(window.location.href); + if (actionCodeUrl.tenantId) { + firebase.auth().tenantId = actionCodeUrl.tenantId; + } + let email = window.localStorage.getItem('emailForSignIn'); + if (!email) { + // User opened the link on a different device. To prevent session fixation + // attacks, ask the user to provide the associated email again. For example: + email = window.prompt('Please provide your email for confirmation'); + } + firebase.auth().signInWithEmailLink(email, window.location.href) + .then((result) => { + // User is signed in. + // tenant ID available in result.user.tenantId. + }); + } + // [END multitenant_signin_emaillink] +} + +function createCustomTokenTenant(admin, uid) { + // [START multitenant_create_custom_token] + // Ensure you're using a tenant-aware auth instance + const tenantManager = admin.auth().tenantManager(); + const tenantAuth = tenantManager.authForTenant('TENANT_ID1'); + + // Create a custom token in the usual manner + tenantAuth.createCustomToken(uid) + .then((customToken) => { + // Send token back to client + }) + .catch((error) => { + console.log('Error creating custom token:', error); + }); + // [END multitenant_create_custom_token] +} + +function signInWithCustomTokenTenant(token) { + // [START multitenant_signin_custom_token] + firebase.auth().tenantId = 'TENANT_ID1'; + + firebase.auth().signInWithCustomToken(token) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // ... + }); + // [END multitenant_signin_custom_token] +} + +function linkAccountTenant(provider, email, password) { + // [START multitenant_account_linking] + // Switch to TENANT_ID1 + firebase.auth().tenantId = 'TENANT_ID1'; + + // Sign-in with popup + firebase.auth().signInWithPopup(provider) + .then((result) => { + // Existing user with e.g. SAML provider. + const user = result.user; + const emailCredential = + firebase.auth.EmailAuthProvider.credential(email, password); + return user.linkWithCredential(emailCredential); + }) + .then((linkResult) => { + // The user can sign in with both SAML and email/password now. + }); + // [END multitenant_account_linking] +} + +function accountExistsPopupTenant(samlProvider, googleProvider, goToApp) { + // [START multitenant_account_exists_popup] + // Step 1. + // User tries to sign in to the SAML provider in that tenant. + firebase.auth().tenantId = 'TENANT_ID'; + firebase.auth().signInWithPopup(samlProvider) + .catch((error) => { + // An error happened. + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + // The pending SAML credential. + const pendingCred = error.credential; + // The credential's tenantId if needed: error.tenantId + // The provider account's email address. + const email = error.email; + // Get sign-in methods for this email. + firebase.auth().fetchSignInMethodsForEmail(email) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + firebase.auth().signInWithPopup(googleProvider) + .then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + result.user.linkWithCredential(pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + } + }); + } + }); + // [END multitenant_account_exists_popup] +} + +function accountExistsRedirectTenant(samlProvider, googleProvider, goToApp) { + // [START multitenant_account_exists_redirect] + // Step 1. + // User tries to sign in to SAML provider. + firebase.auth().tenantId = 'TENANT_ID'; + firebase.auth().signInWithRedirect(samlProvider); + var pendingCred; + // Redirect back from SAML IDP. auth.tenantId is null after redirecting. + firebase.auth().getRedirectResult().catch((error) => { + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + const tenantId = error.tenantId; + // The pending SAML credential. + pendingCred = error.credential; + // The provider account's email address. + const email = error.email; + // Need to set the tenant ID again as the page was reloaded and the + // previous setting was reset. + firebase.auth().tenantId = tenantId; + // Get sign-in methods for this email. + firebase.auth().fetchSignInMethodsForEmail(email) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + firebase.auth().signInWithRedirect(googleProvider); + } + }); + } + }); + + // Redirect back from Google. auth.tenantId is null after redirecting. + firebase.auth().getRedirectResult().then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + // result.user.tenantId is 'TENANT_ID'. + result.user.linkWithCredential(pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + // [END multitenant_account_exists_redirect] +} \ No newline at end of file diff --git a/auth/oidc.js b/auth/oidc.js new file mode 100644 index 00000000..e3a3e01e --- /dev/null +++ b/auth/oidc.js @@ -0,0 +1,68 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/auth"; + +function oidcProvider() { + // [START auth_oidc_provider_create] + const provider = new firebase.auth.OAuthProvider('oidc.myProvider'); + // [END auth_oidc_provider_create] +} + +function oidcSignInPopup(provider) { + // [START auth_oidc_signin_popup] + firebase.auth().signInWithPopup(provider) + .then((result) => { + // User is signed in. + // result.credential is a firebase.auth().OAuthCredential object. + // result.credential.providerId is equal to 'oidc.myProvider'. + // result.credential.idToken is the OIDC provider's ID token. + }) + .catch((error) => { + // Handle error. + }); + // [END auth_oidc_signin_popup] +} + +function oidcSignInRedirect(provider) { + // [START auth_oidc_signin_redirect] + firebase.auth().signInWithRedirect(provider).catch((error) => { + // Handle error. + }); + // [END auth_oidc_signin_redirect] +} + +function oidcSignInRedirectResult(provider) { + // [START auth_oidc_signin_redirect_result] + // On return. + firebase.auth().getRedirectResult() + .then((result) => { + // User is signed in. + // result.credential is a firebase.auth().OAuthCredential object. + // result.credential.providerId is equal to 'oidc.myProvider'. + // result.credential.idToken is the OIDC provider's ID token. + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END auth_oidc_signin_redirect_result] +} + +function oidcDirectSignIn(provider, oidcIdToken) { + // [START auth_oidc_direct_sign_in] + const credential = provider.credential(oidcIdToken, null); + + firebase.auth().signInWithCredential(credential) + .then((result) => { + // User is signed in. + // User now has a odic.myProvider UserInfo in providerData. + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END auth_oidc_direct_sign_in] +} + diff --git a/auth/package.json b/auth/package.json index 6af79a47..b4b13f01 100644 --- a/auth/package.json +++ b/auth/package.json @@ -6,7 +6,8 @@ }, "license": "Apache 2.0", "dependencies": { - "firebase": "^8.2.2", - "firebaseui": "^4.7.1" + "firebase": "^8.10.0", + "firebase-admin": "^12.0.0", + "firebaseui": "^5.0.0" } } diff --git a/auth/saml.js b/auth/saml.js new file mode 100644 index 00000000..e3a99cde --- /dev/null +++ b/auth/saml.js @@ -0,0 +1,53 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/auth"; + +function samlProvider() { + // [START auth_saml_provider_create] + const provider = new firebase.auth.SAMLAuthProvider('saml.myProvider'); + // [END auth_saml_provider_create] +} + +function samlSignInPopup(provider) { + // [START auth_saml_signin_popup] + firebase.auth().signInWithPopup(provider) + .then((result) => { + // User is signed in. + // Identity provider data available in result.additionalUserInfo.profile, + // or from the user's ID token obtained from result.user.getIdToken() + // as an object in the firebase.sign_in_attributes custom claim + // This is also available from result.user.getIdTokenResult() + // idTokenResult.claims.firebase.sign_in_attributes. + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END auth_saml_signin_popup] +} + +function samlSignInRedirect(provider) { + // [START auth_saml_signin_redirect] + firebase.auth().signInWithRedirect(provider); + // [END auth_saml_signin_redirect] +} + +function samlSignInRedirectResult(provider) { + // [START auth_saml_signin_redirect_result] + firebase.auth().getRedirectResult() + .then((result) => { + // User is signed in. + // Provider data available in result.additionalUserInfo.profile, + // or from the user's ID token obtained from result.user.getIdToken() + // as an object in the firebase.sign_in_attributes custom claim + // This is also available from result.user.getIdTokenResult() + // idTokenResult.claims.firebase.sign_in_attributes. + }).catch((error) => { + // Handle / display error. + // ... + }); + // [END auth_saml_signin_redirect_result] +} + diff --git a/auth/service-worker-sessions.js b/auth/service-worker-sessions.js index babbf91e..05791463 100644 --- a/auth/service-worker-sessions.js +++ b/auth/service-worker-sessions.js @@ -162,3 +162,46 @@ function svcSignInEmail(email, password) { }); // [END auth_svc_sign_in_email] } + +function svcRedirectAdmin() { + const app = { use: (a) => {} }; + + // [START auth_svc_admin] + // Server side code. + const admin = require('firebase-admin'); + + // The Firebase Admin SDK is used here to verify the ID token. + admin.initializeApp(); + + function getIdToken(req) { + // Parse the injected ID token from the request header. + const authorizationHeader = req.headers.authorization || ''; + const components = authorizationHeader.split(' '); + return components.length > 1 ? components[1] : ''; + } + + function checkIfSignedIn(url) { + return (req, res, next) => { + if (req.url == url) { + const idToken = getIdToken(req); + // Verify the ID token using the Firebase Admin SDK. + // User already logged in. Redirect to profile page. + admin.auth().verifyIdToken(idToken).then((decodedClaims) => { + // User is authenticated, user claims can be retrieved from + // decodedClaims. + // In this sample code, authenticated users are always redirected to + // the profile page. + res.redirect('/profile'); + }).catch((error) => { + next(); + }); + } else { + next(); + } + }; + } + + // If a user is signed in, redirect to profile page. + app.use(checkIfSignedIn('/')); + // [END auth_svc_admin] +} diff --git a/auth/twitter.js b/auth/twitter.js index b1ca2581..68ed6f35 100644 --- a/auth/twitter.js +++ b/auth/twitter.js @@ -32,7 +32,8 @@ function twitterSignInPopup(provider) { // The signed-in user info. var user = result.user; - // ... + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -64,6 +65,8 @@ function twitterSignInRedirectResult() { // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -76,3 +79,9 @@ function twitterSignInRedirectResult() { }); // [END auth_twitter_signin_redirect_result] } + +function twitterProviderCredential(accessToken, secret) { + // [START auth_twitter_provider_credential] + var credential = firebase.auth.TwitterAuthProvider.credential(accessToken, secret); + // [END auth_twitter_provider_credential] +} \ No newline at end of file diff --git a/database-next/emulator-suite.js b/database-next/emulator-suite.js new file mode 100644 index 00000000..f94d3c89 --- /dev/null +++ b/database-next/emulator-suite.js @@ -0,0 +1,24 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function onDocumentReady() { + // [START rtdb_emulator_connect] + const { getDatabase, connectDatabaseEmulator } = require("firebase/database"); + + const db = getDatabase(); + if (location.hostname === "localhost") { + // Point to the RTDB emulator running on localhost. + connectDatabaseEmulator(db, "127.0.0.1", 9000); + } + // [END rtdb_emulator_connect] +} + +function flushRealtimeDatabase() { + // [START rtdb_emulator_flush] + const { getDatabase, ref, set } = require("firebase/database"); + + // With a database Reference, write null to clear the database. + const db = getDatabase(); + set(ref(db), null); + // [END rtdb_emulator_flush] +} diff --git a/database-next/index.js b/database-next/index.js new file mode 100644 index 00000000..b0a3400e --- /dev/null +++ b/database-next/index.js @@ -0,0 +1,10 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function getReference() { + // [START rtdb_get_reference] + const { getDatabase } = require("firebase/database"); + + const database = getDatabase(); + // [END rtdb_get_reference] +} diff --git a/database-next/lists-of-data.js b/database-next/lists-of-data.js new file mode 100644 index 00000000..53afbc08 --- /dev/null +++ b/database-next/lists-of-data.js @@ -0,0 +1,93 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function socialPush() { + // [START rtdb_social_push] + const { getDatabase, ref, push, set } = require("firebase/database"); + + // Create a new post reference with an auto-generated id + const db = getDatabase(); + const postListRef = ref(db, 'posts'); + const newPostRef = push(postListRef); + set(newPostRef, { + // ... + }); + // [END rtdb_social_push] +} + +function socialListenChildren() { + const postElement = document.querySelector("#post"); + const postId = "1234"; + function addCommentElement(el, key, text, author) {} + function setCommentValues(el, key, text, author) {}; + function deleteComment(el, key) {}; + + // [START rtdb_social_listen_children] + const { getDatabase, ref, onChildAdded, onChildChanged, onChildRemoved } = require("firebase/database"); + + const db = getDatabase(); + const commentsRef = ref(db, 'post-comments/' + postId); + onChildAdded(commentsRef, (data) => { + addCommentElement(postElement, data.key, data.val().text, data.val().author); + }); + + onChildChanged(commentsRef, (data) => { + setCommentValues(postElement, data.key, data.val().text, data.val().author); + }); + + onChildRemoved(commentsRef, (data) => { + deleteComment(postElement, data.key); + }); + // [END rtdb_social_listen_children] +} + +function socialListenValue() { + + // [START rtdb_social_listen_value] + const { getDatabase, ref, onValue } = require("firebase/database"); + + const db = getDatabase(); + const dbRef = ref(db, '/a/b/c'); + + onValue(dbRef, (snapshot) => { + snapshot.forEach((childSnapshot) => { + const childKey = childSnapshot.key; + const childData = childSnapshot.val(); + // ... + }); + }, { + onlyOnce: true + }); + // [END rtdb_social_listen_value] +} + +function socialMostStarred() { + // [START rtdb_social_most_starred] + const { getDatabase, ref, query, orderByChild } = require("firebase/database"); + const { getAuth } = require("firebase/auth"); + + const db = getDatabase(); + const auth = getAuth(); + + const myUserId = auth.currentUser.uid; + const topUserPostsRef = query(ref(db, 'user-posts/' + myUserId), orderByChild('starCount')); + // [END rtdb_social_most_starred] +} + +function socialMostViewed() { + // [START rtdb_social_most_viewed] + const { getDatabase, ref, query, orderByChild } = require("firebase/database"); + + const db = getDatabase(); + const mostViewedPosts = query(ref(db, 'posts'), orderByChild('metrics/views')); + // [END rtdb_social_most_viewed] +} + +function socialRecent() { + // [START rtdb_social_recent] + const { getDatabase, ref, query, limitToLast } = require("firebase/database"); + + const db = getDatabase(); + const recentPostsRef = query(ref(db, 'posts'), limitToLast(100)); + // [END rtdb_social_recent] +} diff --git a/database-next/offline.js b/database-next/offline.js new file mode 100644 index 00000000..3dd9e22b --- /dev/null +++ b/database-next/offline.js @@ -0,0 +1,113 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function onDisconnectSimple() { + // [START rtdb_ondisconnect_simple] + const { getDatabase, ref, onDisconnect } = require("firebase/database"); + + const db = getDatabase(); + const presenceRef = ref(db, "disconnectmessage"); + // Write a string when this client loses connection + onDisconnect(presenceRef).set("I disconnected!"); + // [END rtdb_ondisconnect_simple] +} + +function onDisconnectCallback() { + const { getDatabase, ref, onDisconnect } = require("firebase/database"); + + const db = getDatabase(); + const presenceRef = ref(db, "disconnectmessage"); + + // [START rtdb_ondisconnect_callback] + onDisconnect(presenceRef).remove().catch((err) => { + if (err) { + console.error("could not establish onDisconnect event", err); + } + }); + // [END rtdb_ondisconnect_callback] +} + +function onDisconnectCancel() { + const { getDatabase, ref, onDisconnect } = require("firebase/database"); + + const db = getDatabase(); + const presenceRef = ref(db, "disconnectmessage"); + + // [START rtdb_ondisconnect_cancel] + const onDisconnectRef = onDisconnect(presenceRef); + onDisconnectRef.set("I disconnected"); + // some time later when we change our minds + onDisconnectRef.cancel(); + // [END rtdb_ondisconnect_cancel] +} + +function detectConnectionState() { + // [START rtdb_detect_connection_state] + const { getDatabase, ref, onValue } = require("firebase/database"); + + const db = getDatabase(); + const connectedRef = ref(db, ".info/connected"); + onValue(connectedRef, (snap) => { + if (snap.val() === true) { + console.log("connected"); + } else { + console.log("not connected"); + } + }); + // [END rtdb_detect_connection_state] +} + +function setServerTimestamp() { + // [START rtdb_set_server_timestamp] + const { getDatabase, ref, onDisconnect, serverTimestamp } = require("firebase/database"); + + const db = getDatabase(); + const userLastOnlineRef = ref(db, "users/joe/lastOnline"); + onDisconnect(userLastOnlineRef).set(serverTimestamp()); + // [END rtdb_set_server_timestamp] +} + +function estimateClockSkew() { + // [START rtdb_estimate_clock_skew] + const { getDatabase, ref, onValue } = require("firebase/database"); + + const db = getDatabase(); + const offsetRef = ref(db, ".info/serverTimeOffset"); + onValue(offsetRef, (snap) => { + const offset = snap.val(); + const estimatedServerTimeMs = new Date().getTime() + offset; + }); + // [END rtdb_estimate_clock_skew] +} + +function samplePresenceApp() { + // [START rtdb_sample_presence_app] + const { getDatabase, ref, onValue, push, onDisconnect, set, serverTimestamp } = require("firebase/database"); + + // Since I can connect from multiple devices or browser tabs, we store each connection instance separately + // any time that connectionsRef's value is null (i.e. has no children) I am offline + const db = getDatabase(); + const myConnectionsRef = ref(db, 'users/joe/connections'); + + // stores the timestamp of my last disconnect (the last time I was seen online) + const lastOnlineRef = ref(db, 'users/joe/lastOnline'); + + const connectedRef = ref(db, '.info/connected'); + onValue(connectedRef, (snap) => { + if (snap.val() === true) { + // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) + const con = push(myConnectionsRef); + + // When I disconnect, remove this device + onDisconnect(con).remove(); + + // Add this device to my connections list + // this value could contain info about the device or a timestamp too + set(con, true); + + // When I disconnect, update the last time I was seen online + onDisconnect(lastOnlineRef).set(serverTimestamp()); + } + }); + // [END rtdb_sample_presence_app] +} diff --git a/database-next/package.json b/database-next/package.json new file mode 100644 index 00000000..eb16e2d5 --- /dev/null +++ b/database-next/package.json @@ -0,0 +1,11 @@ +{ + "name": "database-next", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^10.0.0" + } +} diff --git a/database-next/read-and-write.js b/database-next/read-and-write.js new file mode 100644 index 00000000..c06c66b4 --- /dev/null +++ b/database-next/read-and-write.js @@ -0,0 +1,189 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function writeUserData_wrapped() { + // [START rtdb_write_new_user] + const { getDatabase, ref, set } = require("firebase/database"); + + function writeUserData(userId, name, email, imageUrl) { + const db = getDatabase(); + set(ref(db, 'users/' + userId), { + username: name, + email: email, + profile_picture : imageUrl + }); + } + // [END rtdb_write_new_user] +} + + +function writeUserDataWithCompletion(userId, name, email, imageUrl) { + // [START rtdb_write_new_user_completion] + const { getDatabase, ref, set } = require("firebase/database"); + + const db = getDatabase(); + set(ref(db, 'users/' + userId), { + username: name, + email: email, + profile_picture : imageUrl + }) + .then(() => { + // Data saved successfully! + }) + .catch((error) => { + // The write failed... + }); + // [END rtdb_write_new_user_completion] +} + +function socialListenStarCount() { + const postElement = document.querySelector('#post'); + const postId = "1234"; + function updateStarCount(a, b) { + // ... + } + + // [START rtdb_social_listen_star_count] + const { getDatabase, ref, onValue } = require("firebase/database"); + + const db = getDatabase(); + const starCountRef = ref(db, 'posts/' + postId + '/starCount'); + onValue(starCountRef, (snapshot) => { + const data = snapshot.val(); + updateStarCount(postElement, data); + }); + // [END rtdb_social_listen_star_count] +} + +function socialSingleValueRead() { + // [START rtdb_social_single_value_read] + const { getDatabase, ref, onValue } = require("firebase/database"); + const { getAuth } = require("firebase/auth"); + + const db = getDatabase(); + const auth = getAuth(); + + const userId = auth.currentUser.uid; + return onValue(ref(db, '/users/' + userId), (snapshot) => { + const username = (snapshot.val() && snapshot.val().username) || 'Anonymous'; + // ... + }, { + onlyOnce: true + }); + // [END rtdb_social_single_value_read] +} + +function writeNewPost_wrapped() { + // [START rtdb_social_write_fan_out] + const { getDatabase, ref, child, push, update } = require("firebase/database"); + + function writeNewPost(uid, username, picture, title, body) { + const db = getDatabase(); + + // A post entry. + const postData = { + author: username, + uid: uid, + body: body, + title: title, + starCount: 0, + authorPic: picture + }; + + // Get a key for a new Post. + const newPostKey = push(child(ref(db), 'posts')).key; + + // Write the new post's data simultaneously in the posts list and the user's post list. + const updates = {}; + updates['/posts/' + newPostKey] = postData; + updates['/user-posts/' + uid + '/' + newPostKey] = postData; + + return update(ref(db), updates); + } + // [END rtdb_social_write_fan_out] +} + +function socialCompletionCallback() { + const userId = "123"; + const email = "test@example.com"; + const imageUrl = "https://example.com/image.png"; + + // [START rtdb_social_completion_callback] + const { getDatabase, ref, set } = require("firebase/database"); + + const db = getDatabase(); + set(ref(db, 'users/' + userId), { + username: name, + email: email, + profile_picture : imageUrl + }) + .then(() => { + // Data saved successfully! + }) + .catch((error) => { + // The write failed... + }); + // [END rtdb_social_completion_callback] +} + +function toggleStar_wrapped() { + // [START rtdb_social_star_transaction] + const { getDatabase, ref, runTransaction } = require("firebase/database"); + + function toggleStar(uid) { + const db = getDatabase(); + const postRef = ref(db, '/posts/foo-bar-123'); + + runTransaction(postRef, (post) => { + if (post) { + if (post.stars && post.stars[uid]) { + post.starCount--; + post.stars[uid] = null; + } else { + post.starCount++; + if (!post.stars) { + post.stars = {}; + } + post.stars[uid] = true; + } + } + return post; + }); + } + // [END rtdb_social_star_transaction] +} + +/** + * @param {string} uid + * @param {string} key + */ +// [START rtdb_social_star_increment] +function addStar(uid, key) { + const { getDatabase, increment, ref, update } = require("firebase/database"); + const dbRef = ref(getDatabase()); + + const updates = {}; + updates[`posts/${key}/stars/${uid}`] = true; + updates[`posts/${key}/starCount`] = increment(1); + updates[`user-posts/${key}/stars/${uid}`] = true; + updates[`user-posts/${key}/starCount`] = increment(1); + update(dbRef, updates); +} +// [END rtdb_social_star_increment] + +function readOnceWithGet(userId) { + // [START rtdb_read_once_get] + const { getDatabase, ref, child, get } = require("firebase/database"); + + const dbRef = ref(getDatabase()); + get(child(dbRef, `users/${userId}`)).then((snapshot) => { + if (snapshot.exists()) { + console.log(snapshot.val()); + } else { + console.log("No data available"); + } + }).catch((error) => { + console.error(error); + }); + // [END rtdb_read_once_get] +} diff --git a/database-next/sharding.js b/database-next/sharding.js new file mode 100644 index 00000000..509503ef --- /dev/null +++ b/database-next/sharding.js @@ -0,0 +1,31 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +import { initializeApp } from "firebase/app"; + +const firebaseApp = initializeApp({ + apiKey: '### FIREBASE API KEY ###', + appId: '### FIREBASE APP ID ###', + projectId: '### FIREBASE PROJECT ID ###' +}); + +function multipleInstances() { + // [START rtdb_multiple_instances] + const { initializeApp } = require("firebase/app"); + const { getDatabase } = require("firebase/database"); + + const app1 = initializeApp({ + databaseURL: "https://testapp-1234-1.firebaseio.com" + }); + + const app2 = initializeApp({ + databaseURL: "https://testapp-1234-2.firebaseio.com" + }, 'app2'); + + // Get the default database instance for an app1 + const database1 = getDatabase(app1); + + // Get a database instance for app2 + const database2 = getDatabase(app2); + // [END rtdb_multiple_instances] +} diff --git a/database/emulator-suite.js b/database/emulator-suite.js index 8fe739e4..8da23e25 100644 --- a/database/emulator-suite.js +++ b/database/emulator-suite.js @@ -10,7 +10,7 @@ function onDocumentReady() { var db = firebase.database(); if (location.hostname === "localhost") { // Point to the RTDB emulator running on localhost. - db.useEmulator("localhost", 9000); + db.useEmulator("127.0.0.1", 9000); } // [END rtdb_emulator_connect] } diff --git a/database/offline.js b/database/offline.js new file mode 100644 index 00000000..66df4825 --- /dev/null +++ b/database/offline.js @@ -0,0 +1,95 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/database"; + +function onDisconnectSimple() { + // [START rtdb_ondisconnect_simple] + var presenceRef = firebase.database().ref("disconnectmessage"); + // Write a string when this client loses connection + presenceRef.onDisconnect().set("I disconnected!"); + // [END rtdb_ondisconnect_simple] +} + +function onDisconnectCallback() { + var presenceRef = firebase.database().ref("disconnectmessage"); + + // [START rtdb_ondisconnect_callback] + presenceRef.onDisconnect().remove((err) => { + if (err) { + console.error("could not establish onDisconnect event", err); + } + }); + // [END rtdb_ondisconnect_callback] +} + +function onDisconnectCancel() { + var presenceRef = firebase.database().ref("disconnectmessage"); + + // [START rtdb_ondisconnect_cancel] + var onDisconnectRef = presenceRef.onDisconnect(); + onDisconnectRef.set("I disconnected"); + // some time later when we change our minds + onDisconnectRef.cancel(); + // [END rtdb_ondisconnect_cancel] +} + +function detectConnectionState() { + // [START rtdb_detect_connection_state] + var connectedRef = firebase.database().ref(".info/connected"); + connectedRef.on("value", (snap) => { + if (snap.val() === true) { + console.log("connected"); + } else { + console.log("not connected"); + } + }); + // [END rtdb_detect_connection_state] +} + +function setServerTimestamp() { + // [START rtdb_set_server_timestamp] + var userLastOnlineRef = firebase.database().ref("users/joe/lastOnline"); + userLastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP); + // [END rtdb_set_server_timestamp] +} + +function estimateClockSkew() { + // [START rtdb_estimate_clock_skew] + var offsetRef = firebase.database().ref(".info/serverTimeOffset"); + offsetRef.on("value", (snap) => { + var offset = snap.val(); + var estimatedServerTimeMs = new Date().getTime() + offset; + }); + // [END rtdb_estimate_clock_skew] +} + +function samplePresenceApp() { + // [START rtdb_sample_presence_app] + // Since I can connect from multiple devices or browser tabs, we store each connection instance separately + // any time that connectionsRef's value is null (i.e. has no children) I am offline + var myConnectionsRef = firebase.database().ref('users/joe/connections'); + + // stores the timestamp of my last disconnect (the last time I was seen online) + var lastOnlineRef = firebase.database().ref('users/joe/lastOnline'); + + var connectedRef = firebase.database().ref('.info/connected'); + connectedRef.on('value', (snap) => { + if (snap.val() === true) { + // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) + var con = myConnectionsRef.push(); + + // When I disconnect, remove this device + con.onDisconnect().remove(); + + // Add this device to my connections list + // this value could contain info about the device or a timestamp too + con.set(true); + + // When I disconnect, update the last time I was seen online + lastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP); + } + }); + // [END rtdb_sample_presence_app] +} diff --git a/database/package.json b/database/package.json index 763ebb14..ea21b973 100644 --- a/database/package.json +++ b/database/package.json @@ -6,6 +6,6 @@ }, "license": "Apache 2.0", "dependencies": { - "firebase": "^8.2.2" + "firebase": "^8.10.0" } } diff --git a/database/read-and-write.js b/database/read-and-write.js index 24b87b61..bcae4ccc 100644 --- a/database/read-and-write.js +++ b/database/read-and-write.js @@ -20,14 +20,14 @@ function writeUserDataWithCompletion(userId, name, email, imageUrl) { username: name, email: email, profile_picture : imageUrl - }, function(error) { + }, (error) => { if (error) { // The write failed... } else { // Data saved successfully! } }); - // [START rtdb_write_new_user_completion] + // [END rtdb_write_new_user_completion] } function socialListenStarCount() { @@ -123,3 +123,33 @@ function toggleStar(postRef, uid) { }); } // [END rtdb_social_star_transaction] + +/** + * @param {string} uid + * @param {string} key + */ +// [START rtdb_social_star_increment] +function addStar(uid, key) { + const updates = {}; + updates[`posts/${key}/stars/${uid}`] = true; + updates[`posts/${key}/starCount`] = firebase.database.ServerValue.increment(1); + updates[`user-posts/${key}/stars/${uid}`] = true; + updates[`user-posts/${key}/starCount`] = firebase.database.ServerValue.increment(1); + firebase.database().ref().update(updates); +} +// [END rtdb_social_star_increment] + +function readOnceWithGet(userId) { + // [START rtdb_read_once_get] + const dbRef = firebase.database().ref(); + dbRef.child("users").child(userId).get().then((snapshot) => { + if (snapshot.exists()) { + console.log(snapshot.val()); + } else { + console.log("No data available"); + } + }).catch((error) => { + console.error(error); + }); + // [END rtdb_read_once_get] +} diff --git a/firebaseapp-next/firebaseapp.js b/firebaseapp-next/firebaseapp.js new file mode 100644 index 00000000..54aa3137 --- /dev/null +++ b/firebaseapp-next/firebaseapp.js @@ -0,0 +1,85 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function multpleFirebaseApps() { + // [START firebase_options] + const { initializeApp } = require("firebase/app"); + + // The following fields are REQUIRED: + // - Project ID + // - App ID + // - API Key + const secondaryAppConfig = { + projectId: "", + appId: "", + apiKey: "", + // databaseURL: "...", + // storageBucket: "...", + }; + // [END firebase_options] + + // [START firebase_secondary] + // Initialize another app with a different config + const secondaryApp = initializeApp(secondaryAppConfig, "secondary"); + // Access services, such as the Realtime Database + // getDatabase(secondaryApp) + // [END firebase_secondary] +} + +function defaultInitOptions() { + const firebaseConfig = { + // ... + }; + + // [START app_default_init_options] + const { initializeApp } = require("firebase/app"); + const { getStorage } = require("firebase/storage"); + const { getFirestore } = require("firebase/firestore"); + + // Initialize Firebase with a "default" Firebase project + const defaultProject = initializeApp(firebaseConfig); + + console.log(defaultProject.name); // "[DEFAULT]" + + // Option 1: Access Firebase services via the defaultProject variable + let defaultStorage = getStorage(defaultProject); + let defaultFirestore = getFirestore(defaultProject); + + // Option 2: Access Firebase services using shorthand notation + defaultStorage = getStorage(); + defaultFirestore = getFirestore(); + // [END app_default_init_options] +} + +function multiProjectInitOptions() { + const firebaseConfig = { + // ... + }; + + const otherProjectFirebaseConfig = { + // ... + }; + + // [START app_multi_project_init_options] + const { initializeApp, getApp } = require("firebase/app"); + const { getStorage } = require("firebase/storage"); + const { getFirestore } = require("firebase/firestore"); + + // Initialize Firebase with a default Firebase project + initializeApp(firebaseConfig); + + // Initialize Firebase with a second Firebase project + const otherProject = initializeApp(otherProjectFirebaseConfig, "other"); + + console.log(getApp().name); // "[DEFAULT]" + console.log(otherProject.name); // "otherProject" + + // Use the shorthand notation to access the default project's Firebase services + const defaultStorage = getStorage(); + const defaultFirestore = getFirestore(); + + // Use the otherProject variable to access the second project's Firebase services + const otherStorage = getStorage(otherProject); + const otherFirestore = getFirestore(otherProject); + // [END app_multi_project_init_options] +} diff --git a/firebaseapp-next/package.json b/firebaseapp-next/package.json new file mode 100644 index 00000000..13cc74cd --- /dev/null +++ b/firebaseapp-next/package.json @@ -0,0 +1,11 @@ +{ + "name": "firebaseapp-next", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^10.0.0" + } +} diff --git a/firebaseapp/firebaseapp.js b/firebaseapp/firebaseapp.js index 88eedd46..e030583f 100644 --- a/firebaseapp/firebaseapp.js +++ b/firebaseapp/firebaseapp.js @@ -6,7 +6,7 @@ function multpleFirebaseApps() { // - Project ID // - App ID // - API Key - var secondaryAppConfig = { + const secondaryAppConfig = { projectId: "", appId: "", apiKey: "", @@ -17,8 +17,58 @@ function multpleFirebaseApps() { // [START firebase_secondary] // Initialize another app with a different config - var secondaryApp = firebase.initializeApp(secondaryAppConfig, "secondary"); + const secondaryApp = firebase.initializeApp(secondaryAppConfig, "secondary"); // Access services, such as the Realtime Database // secondaryApp.database(); // [END firebase_secondary] } + +function defaultInitOptions() { + const firebaseConfig = { + // ... + }; + + // [START app_default_init_options] + // Initialize Firebase with a "default" Firebase project + const defaultProject = firebase.initializeApp(firebaseConfig); + + console.log(defaultProject.name); // "[DEFAULT]" + + // Option 1: Access Firebase services via the defaultProject variable + let defaultStorage = defaultProject.storage(); + let defaultFirestore = defaultProject.firestore(); + + // Option 2: Access Firebase services using shorthand notation + defaultStorage = firebase.storage(); + defaultFirestore = firebase.firestore(); + // [END app_default_init_options] +} + +function multiProjectInitOptions() { + const firebaseConfig = { + // ... + }; + + const otherProjectFirebaseConfig = { + // ... + }; + + // [START app_multi_project_init_options] + // Initialize Firebase with a default Firebase project + firebase.initializeApp(firebaseConfig); + + // Initialize Firebase with a second Firebase project + const otherProject = firebase.initializeApp(otherProjectFirebaseConfig, "other"); + + console.log(firebase.app().name); // "[DEFAULT]" + console.log(otherProject.name); // "otherProject" + + // Use the shorthand notation to access the default project's Firebase services + const defaultStorage = firebase.storage(); + const defaultFirestore = firebase.firestore(); + + // Use the otherProject variable to access the second project's Firebase services + const otherStorage = otherProject.storage(); + const otherFirestore = otherProject.firestore(); + // [END app_multi_project_init_options] +} diff --git a/firebaseapp/package.json b/firebaseapp/package.json index f2483182..5226e2a0 100644 --- a/firebaseapp/package.json +++ b/firebaseapp/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.2.2" + "firebase": "^8.10.0" } } diff --git a/firebaseserverapp-next/firebaseserverapp.js b/firebaseserverapp-next/firebaseserverapp.js new file mode 100644 index 00000000..d0ab338c --- /dev/null +++ b/firebaseserverapp-next/firebaseserverapp.js @@ -0,0 +1,27 @@ +// @ts-nocheck +// [START serverapp_auth] +import { initializeServerApp } from 'firebase/app'; +import { getAuth } from 'firebase/auth'; +import { headers } from 'next/headers'; +import { redirect } from 'next/navigation'; + +export default function MyServerComponent() { + + // Get relevant request headers (in Next.JS) + const authIdToken = headers().get('Authorization')?.split('Bearer ')[1]; + + // Initialize the FirebaseServerApp instance. + const serverApp = initializeServerApp(firebaseConfig, { authIdToken }); + + // Initialize Firebase Authentication using the FirebaseServerApp instance. + const auth = getAuth(serverApp); + + if (auth.currentUser) { + redirect('/profile'); + } + + // ... +} +// [END serverapp_auth] + +const firebaseConfig = {}; diff --git a/firebaseserverapp-next/package.json b/firebaseserverapp-next/package.json new file mode 100644 index 00000000..0836b0b2 --- /dev/null +++ b/firebaseserverapp-next/package.json @@ -0,0 +1,12 @@ +{ + "name": "firebaseserverapp-next", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^10.0.0", + "next": "^14.1.3" + } +} diff --git a/firestore-next/emulator-suite.js b/firestore-next/emulator-suite.js index cbcea744..edc900c1 100644 --- a/firestore-next/emulator-suite.js +++ b/firestore-next/emulator-suite.js @@ -1,19 +1,12 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -function onDocumentReady(firebaseApp) { +function onDocumentReady() { // [START fs_emulator_connect] - const { initializeFirestore } = require("firebase/firestore"); - - let settings = {}; - if (location.hostname === "localhost") { - settings = { - host: "localhost:8080", - ssl: false - }; - } + const { getFirestore, connectFirestoreEmulator } = require("firebase/firestore"); // firebaseApps previously initialized using initializeApp() - const db = initializeFirestore(firebaseApp, settings); + const db = getFirestore(); + connectFirestoreEmulator(db, '127.0.0.1', 8080); // [END fs_emulator_connect] } diff --git a/firestore-next/package.json b/firestore-next/package.json index 8289e346..ef3b8708 100644 --- a/firestore-next/package.json +++ b/firestore-next/package.json @@ -6,7 +6,7 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "exp", + "firebase": "^10.0.0", "geofire-common": "^5.1.0" }, "devDependencies": { diff --git a/firestore-next/test.firestore.js b/firestore-next/test.firestore.js index 0be9c3ef..969c1654 100644 --- a/firestore-next/test.firestore.js +++ b/firestore-next/test.firestore.js @@ -16,15 +16,15 @@ class City { } // Firestore data converter -var cityConverter = { - toFirestore: function(city) { +const cityConverter = { + toFirestore: (city) => { return { name: city.name, state: city.state, country: city.country }; }, - fromFirestore: function(snapshot, options){ + fromFirestore: (snapshot, options) => { const data = snapshot.data(options); return new City(data.name, data.state, data.country); } @@ -32,9 +32,9 @@ var cityConverter = { // [END city_custom_object] describe("firestore", () => { - const { FirebaseFirestore } = require("firebase/firestore"); + const { Firestore } = require("firebase/firestore"); - /** @type {FirebaseFirestore} */ + /** @type {Firestore} */ let db; let app; @@ -190,7 +190,7 @@ describe("firestore", () => { const q = query(collection(db, "users"), where("born", "<", 1900)); const unsubscribe = onSnapshot(q, (snapshot) => { console.log("Current users born before 1900:"); - snapshot.forEach(function (userSnapshot) { + snapshot.forEach((userSnapshot) => { console.log(userSnapshot.data()); }); }); @@ -204,9 +204,9 @@ describe("firestore", () => { it("should reference a specific document", () => { // [START doc_reference] - const { collection, doc } = require("firebase/firestore"); + const { doc } = require("firebase/firestore"); - const alovelaceDocumentRef = doc(collection(db, 'users'), 'alovelace'); + const alovelaceDocumentRef = doc(db, 'users', 'alovelace'); // [END doc_reference] }); @@ -228,18 +228,18 @@ describe("firestore", () => { it("should reference a document in a subcollection", () => { // [START subcollection_reference] - const { doc, collection } = require("firebase/firestore"); + const { doc } = require("firebase/firestore"); - const messageRef = doc(collection(doc(collection(db, "rooms"), "roomA"), "messages"), "message1"); + const messageRef = doc(db, "rooms", "roomA", "messages", "message1"); // [END subcollection_reference] }); it("should set a document", async () => { // [START set_document] - const { doc, collection, setDoc } = require("firebase/firestore"); + const { doc, setDoc } = require("firebase/firestore"); // Add a new document in collection "cities" - await setDoc(doc(collection(db, "cities"), "LA"), { + await setDoc(doc(db, "cities", "LA"), { name: "Los Angeles", state: "CA", country: "USA" @@ -249,19 +249,19 @@ describe("firestore", () => { it("should set document with a custom object converter", async () => { // [START set_custom_object] - const { doc, collection, setDoc } = require("firebase/firestore"); + const { doc, setDoc } = require("firebase/firestore"); // Set with cityConverter - const ref = doc(collection(db, "cities"), "LA").withConverter(cityConverter); + const ref = doc(db, "cities", "LA").withConverter(cityConverter); await setDoc(ref, new City("Los Angeles", "CA", "USA")); // [END set_custom_object] }); it("should get document with a custom object converter", async () => { // [START get_custom_object] - const { doc, collection, getDoc} = require("firebase/firestore"); + const { doc, getDoc} = require("firebase/firestore"); - const ref = doc(collection(db, "cities"), "LA").withConverter(cityConverter); + const ref = doc(db, "cities", "LA").withConverter(cityConverter); const docSnap = await getDoc(ref); if (docSnap.exists()) { // Convert to City object @@ -276,21 +276,21 @@ describe("firestore", () => { it("should support batch writes", async () => { // [START write_batch] - const { writeBatch, doc, collection } = require("firebase/firestore"); + const { writeBatch, doc } = require("firebase/firestore"); // Get a new write batch const batch = writeBatch(db); // Set the value of 'NYC' - const nycRef = doc(collection(db, "cities"), "NYC"); + const nycRef = doc(db, "cities", "NYC"); batch.set(nycRef, {name: "New York City"}); // Update the population of 'SF' - const sfRef = doc(collection(db, "cities"), "SF"); + const sfRef = doc(db, "cities", "SF"); batch.update(sfRef, {"population": 1000000}); // Delete the city 'LA' - const laRef = doc(collection(db, "cities"), "LA"); + const laRef = doc(db, "cities", "LA"); batch.delete(laRef); // Commit the batch @@ -300,7 +300,7 @@ describe("firestore", () => { it("should set a document with every datatype #UNVERIFIED", async () => { // [START data_types] - const { doc, collection, setDoc, Timestamp } = require("firebase/firestore"); + const { doc, setDoc, Timestamp } = require("firebase/firestore"); const docData = { stringExample: "Hello world!", @@ -316,25 +316,25 @@ describe("firestore", () => { } } }; - await setDoc(doc(collection(db, "data"), "one"), docData); + await setDoc(doc(db, "data", "one"), docData); // [END data_types] }); it("should allow set with merge", async () => { // [START set_with_merge] - const { doc, collection, setDoc } = require("firebase/firestore"); + const { doc, setDoc } = require("firebase/firestore"); - const cityRef = doc(collection(db, 'cities'), 'BJ'); + const cityRef = doc(db, 'cities', 'BJ'); setDoc(cityRef, { capital: true }, { merge: true }); // [END set_with_merge] }); it("should update a document's nested fields #UNVERIFIED", async () => { // [START update_document_nested] - const { doc, collection, setDoc, updateDoc } = require("firebase/firestore"); + const { doc, setDoc, updateDoc } = require("firebase/firestore"); // Create an initial document to update. - const frankDocRef = doc(collection(db, "users"), "frank"); + const frankDocRef = doc(db, "users", "frank"); await setDoc(frankDocRef, { name: "Frank", favorites: { food: "Pizza", color: "Blue", subject: "recess" }, @@ -360,7 +360,7 @@ describe("firestore", () => { function deleteCollection(db, collectionRef, batchSize) { const q = query(collectionRef, orderBy('__name__'), limit(batchSize)); - return new Promise(function(resolve) { + return new Promise((resolve) => { deleteQueryBatch(db, q, batchSize, resolve); }); } @@ -431,9 +431,9 @@ describe("firestore", () => { const data = {}; // [START cities_document_set] - const { collection, doc, setDoc } = require("firebase/firestore"); + const { doc, setDoc } = require("firebase/firestore"); - await setDoc(doc(collection(db, "cities"), "new-city-id"), data); + await setDoc(doc(db, "cities", "new-city-id"), data); // [END cities_document_set] }); @@ -466,9 +466,9 @@ describe("firestore", () => { it("should update a document", async () => { const data = {}; // [START update_document] - const { collection, doc, updateDoc } = require("firebase/firestore"); + const { doc, updateDoc } = require("firebase/firestore"); - const washingtonRef = doc(collection(db, "cities"), "DC"); + const washingtonRef = doc(db, "cities", "DC"); // Set the "capital" field of the city 'DC' await updateDoc(washingtonRef, { @@ -479,9 +479,9 @@ describe("firestore", () => { it("should update an array field in a document", async () => { // [START update_document_array] - const { collection, doc, updateDoc, arrayUnion, arrayRemove } = require("firebase/firestore"); + const { doc, updateDoc, arrayUnion, arrayRemove } = require("firebase/firestore"); - const washingtonRef = doc(collection(db, "cities"), "DC"); + const washingtonRef = doc(db, "cities", "DC"); // Atomically add a new region to the "regions" array field. await updateDoc(washingtonRef, { @@ -497,9 +497,9 @@ describe("firestore", () => { it("should update a document using numeric transforms", async () => { // [START update_document_increment] - const { collection, doc, updateDoc, increment } = require("firebase/firestore"); + const { doc, updateDoc, increment } = require("firebase/firestore"); - const washingtonRef = doc(collection(db, "cities"), "DC"); + const washingtonRef = doc(db, "cities", "DC"); // Atomically increment the population of the city by 50. await updateDoc(washingtonRef, { @@ -510,16 +510,16 @@ describe("firestore", () => { it("should delete a document", async () => { // [START delete_document] - const { collection, doc, deleteDoc } = require("firebase/firestore"); + const { doc, deleteDoc } = require("firebase/firestore"); - await deleteDoc(doc(collection(db, "cities"), "DC")); + await deleteDoc(doc(db, "cities", "DC")); // [END delete_document] }); it("should handle transactions", async () => { - const { collection, doc, setDoc } = require("firebase/firestore"); + const { doc, setDoc } = require("firebase/firestore"); - const sfDocRef = doc(collection(db, "cities"), "SF"); + const sfDocRef = doc(db, "cities", "SF"); await setDoc(sfDocRef, { population: 0 }); // [START transaction] @@ -544,10 +544,10 @@ describe("firestore", () => { it("should handle transaction which bubble out data", async () => { // [START transaction_promise] - const { collection, doc, runTransaction } = require("firebase/firestore"); + const { doc, runTransaction } = require("firebase/firestore"); // Create a reference to the SF doc. - const sfDocRef = doc(collection(db, "cities"), "SF"); + const sfDocRef = doc(db, "cities", "SF"); try { const newPopulation = await runTransaction(db, async (transaction) => { @@ -559,6 +559,7 @@ describe("firestore", () => { const newPop = sfDoc.data().population + 1; if (newPop <= 1000000) { transaction.update(sfDocRef, { population: newPop }); + return newPop; } else { return Promise.reject("Sorry! Population is too big"); } @@ -574,15 +575,15 @@ describe("firestore", () => { it("should get a single document", async () => { // [START get_document] - const { collection, doc, getDoc } = require("firebase/firestore"); + const { doc, getDoc } = require("firebase/firestore"); - const docRef = doc(collection(db, "cities"), "SF"); + const docRef = doc(db, "cities", "SF"); const docSnap = await getDoc(docRef); if (docSnap.exists()) { console.log("Document data:", docSnap.data()); } else { - // doc.data() will be undefined in this case + // docSnap.data() will be undefined in this case console.log("No such document!"); } // [END get_document] @@ -590,9 +591,9 @@ describe("firestore", () => { it("should get a document with options", async () => { // [START get_document_options] - const { collection, doc, getDocFromCache } = require("firebase/firestore"); + const { doc, getDocFromCache } = require("firebase/firestore"); - const docRef = doc(collection(db, "cities"), "SF"); + const docRef = doc(db, "cities", "SF"); // Get a document, forcing the SDK to fetch from the offline cache. try { @@ -609,14 +610,14 @@ describe("firestore", () => { it("should listen on a single document", (done) => { // [START listen_document] - const { collection, doc, onSnapshot } = require("firebase/firestore"); + const { doc, onSnapshot } = require("firebase/firestore"); - const unsub = onSnapshot(doc(collection(db, "cities"), "SF"), (doc) => { + const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => { console.log("Current data: ", doc.data()); }); // [END listen_document] - setTimeout(function() { + setTimeout(() => { unsub(); done(); }, 3000); @@ -624,15 +625,15 @@ describe("firestore", () => { it("should listen on a single document with metadata", (done) => { // [START listen_document_local] - const { collection, doc, onSnapshot } = require("firebase/firestore"); + const { doc, onSnapshot } = require("firebase/firestore"); - const unsub = onSnapshot(doc(collection(db, "cities"), "SF"), (doc) => { + const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => { const source = doc.metadata.hasPendingWrites ? "Local" : "Server"; console.log(source, " data: ", doc.data()); }); // [END listen_document_local] - setTimeout(function() { + setTimeout(() => { unsub(); done(); }, 3000); @@ -640,17 +641,17 @@ describe("firestore", () => { it("should listen on a single document with options #UNVERIFIED", (done) => { // [START listen_with_metadata] - const { collection, doc, onSnapshot } = require("firebase/firestore"); + const { doc, onSnapshot } = require("firebase/firestore"); const unsub = onSnapshot( - doc(collection(db, "cities"), "SF"), + doc(db, "cities", "SF"), { includeMetadataChanges: true }, (doc) => { // ... }); // [END listen_with_metadata] - setTimeout(function() { + setTimeout(() => { unsub(); done(); }, 3000); @@ -682,6 +683,18 @@ describe("firestore", () => { // [END get_multiple_all] }); + it("should get all documents from a subcollection", async () => { + // [START firestore_query_subcollection] + const { collection, getDocs } = require("firebase/firestore"); + // Query a reference to a subcollection + const querySnapshot = await getDocs(collection(db, "cities", "SF", "landmarks")); + querySnapshot.forEach((doc) => { + // doc.data() is never undefined for query doc snapshots + console.log(doc.id, " => ", doc.data()); + }); + // [END firestore_query_subcollection] + }); + it("should listen on multiple documents #UNVERIFIED", (done) => { // [START listen_multiple] const { collection, query, where, onSnapshot } = require("firebase/firestore"); @@ -695,7 +708,7 @@ describe("firestore", () => { console.log("Current cities in CA: ", cities.join(", ")); }); // [END listen_multiple] - setTimeout(function() { + setTimeout(() => { unsubscribe(); done(); }, 2500); @@ -720,7 +733,7 @@ describe("firestore", () => { }); }); // [END listen_diffs] - setTimeout(function() { + setTimeout(() => { unsubscribe(); done(); }, 2500); @@ -761,9 +774,9 @@ describe("firestore", () => { it("should update a document with server timestamp", async () => { async function update() { // [START update_with_server_timestamp] - const { collection, updateDoc, serverTimestamp } = require("firebase/firestore"); + const { updateDoc, serverTimestamp } = require("firebase/firestore"); - const docRef = doc(collection(db, 'objects'), 'some-id'); + const docRef = doc(db, 'objects', 'some-id'); // Update the timestamp field with the value from the server const updateTimestamp = await updateDoc(docRef, { @@ -774,21 +787,21 @@ describe("firestore", () => { return updateTimestamp; } - const { collection, doc, setDoc } = require("firebase/firestore"); + const { doc, setDoc } = require("firebase/firestore"); - await setDoc(doc(collection(db, 'objects'), 'some-id'), {}); + await setDoc(doc(db, 'objects', 'some-id'), {}); await update(); console.log('Document updated with server timestamp'); }); it("should use options to control server timestamp resolution", async () => { // [START server_timestamp_resolution_options] - const { collection, doc, updateDoc, serverTimestamp, onSnapshot } = require("firebase/firestore"); + const { doc, updateDoc, serverTimestamp, onSnapshot } = require("firebase/firestore"); // Perform an update followed by an immediate read without // waiting for the update to complete. Due to the snapshot // options we will get two results: one with an estimate // timestamp and one with the resolved server timestamp. - const docRef = doc(collection(db, 'objects'), 'some-id'); + const docRef = doc(db, 'objects', 'some-id'); updateDoc(docRef, { timestamp: serverTimestamp() }); @@ -808,9 +821,9 @@ describe("firestore", () => { it("should delete a document field", async () => { async function update() { // [START update_delete_field] - const { doc, collection, updateDoc, deleteField } = require("firebase/firestore"); + const { doc, updateDoc, deleteField } = require("firebase/firestore"); - const cityRef = doc(collection(db, 'cities'), 'BJ'); + const cityRef = doc(db, 'cities', 'BJ'); // Remove the 'capital' field from the document await updateDoc(cityRef, { @@ -819,9 +832,9 @@ describe("firestore", () => { // [END update_delete_field] } - const { doc, collection, setDoc } = require("firebase/firestore"); + const { doc, setDoc } = require("firebase/firestore"); - await setDoc(doc(collection(db,'cities'), 'BJ'), { capital: true }); + await setDoc(doc(db, 'cities', 'BJ'), { capital: true }); await update(); }); @@ -851,13 +864,13 @@ describe("firestore", () => { const citiesRef = collection(db, "cities"); // [START example_filters] - const q1 = query(citiesRef, where("state", "==", "CA")); - const q2 = query(citiesRef, where("population", "<", 100000)); - const q3 = query(citiesRef, where("name", ">=", "San Francisco")); + const stateQuery = query(citiesRef, where("state", "==", "CA")); + const populationQuery = query(citiesRef, where("population", "<", 100000)); + const nameQuery = query(citiesRef, where("name", ">=", "San Francisco")); // [END example_filters] // [START simple_query_not_equal] - const q4 = query(citiesRef, where("capital", "!=", false)); + const notCapitalQuery = query(citiesRef, where("capital", "!=", false)); // [END simple_query_not_equal] }); @@ -907,7 +920,7 @@ describe("firestore", () => { // [START in_filter_with_array] const { query, where } = require("firebase/firestore"); - const q = query(citiesRef, where('regions', 'in', [['west_coast', 'east_coast']])); + const q = query(citiesRef, where('regions', 'in', [['west_coast'], ['east_coast']])); // [END in_filter_with_array] } }); @@ -1047,7 +1060,7 @@ describe("firestore", () => { const docSnap = await getDoc(doc(citiesRef, "SF")); // Get all cities with a population bigger than San Francisco - const biggerThanSf = query(citiesRef, orderBy("popuation"), startAt(docSnap)); + const biggerThanSf = query(citiesRef, orderBy("population"), startAt(docSnap)); // ... // [END start_doc] }); @@ -1094,48 +1107,48 @@ describe("firestore", () => { describe('collectionGroup(landmarks)', () => { it("should setup example data", async () => { // [START fs_collection_group_query_data_setup] - const { collection, doc, setDoc } = require("firebase/firestore"); + const { collection, addDoc } = require("firebase/firestore"); const citiesRef = collection(db, 'cities'); await Promise.all([ - setDoc(doc(collection(doc(citiesRef, 'SF'), 'landmarks')), { + addDoc(collection(citiesRef, 'SF', 'landmarks'), { name: 'Golden Gate Bridge', type: 'bridge' }), - setDoc(doc(collection(doc(citiesRef, 'SF'), 'landmarks')), { + addDoc(collection(citiesRef, 'SF', 'landmarks'), { name: 'Legion of Honor', type: 'museum' }), - setDoc(doc(collection(doc(citiesRef, 'LA'), 'landmarks')), { + addDoc(collection(citiesRef, 'LA', 'landmarks'), { name: 'Griffith Park', type: 'park' }), - setDoc(doc(collection(doc(citiesRef, 'LA'), 'landmarks')), { + addDoc(collection(citiesRef, 'LA', 'landmarks'), { name: 'The Getty', type: 'museum' }), - setDoc(doc(collection(doc(citiesRef, 'DC'), 'landmarks')), { + addDoc(collection(citiesRef, 'DC', 'landmarks'), { name: 'Lincoln Memorial', type: 'memorial' }), - setDoc(doc(collection(doc(citiesRef, 'DC'), 'landmarks')), { + addDoc(collection(citiesRef, 'DC', 'landmarks'), { name: 'National Air and Space Museum', type: 'museum' }), - setDoc(doc(collection(doc(citiesRef, 'TOK'), 'landmarks')), { + addDoc(collection(citiesRef, 'TOK', 'landmarks'), { name: 'Ueno Park', type: 'park' }), - setDoc(doc(collection(doc(citiesRef, 'TOK'), 'landmarks')), { + addDoc(collection(citiesRef, 'TOK', 'landmarks'), { name: 'National Museum of Nature and Science', type: 'museum' }), - setDoc(doc(collection(doc(citiesRef, 'BJ'), 'landmarks')), { + addDoc(collection(citiesRef, 'BJ', 'landmarks'), { name: 'Jingshan Park', type: 'park' }), - setDoc(doc(collection(doc(citiesRef, 'BJ'), 'landmarks')), { + addDoc(collection(citiesRef, 'BJ', 'landmarks'), { name: 'Beijing Ancient Observatory', type: 'museum' }) @@ -1157,11 +1170,32 @@ describe("firestore", () => { }); }); + describe("aggregate queries", () => { + it("should fetch the count of documents in a collection", async () => { + const { collection, getCountFromServer } = require("firebase/firestore"); + // [START count_aggregate_collection] + const coll = collection(db, "cities"); + const snapshot = await getCountFromServer(coll); + console.log('count: ', snapshot.data().count); + // [END count_aggregate_collection] + }); + + it("should fetch the count of documents in a query", async () => { + const { collection, getCountFromServer, where, query } = require("firebase/firestore"); + // [START count_aggregate_query] + const coll = collection(db, "cities"); + const q = query(coll, where("state", "==", "CA")); + const snapshot = await getCountFromServer(q); + console.log('count: ', snapshot.data().count); + // [END count_aggregate_query] + }); + }); + // TODO: Break out into separate file describe("solution-aggregation", () => { it("should update a restaurant in a transaction #UNVERIFIED", async () => { // [START add_rating_transaction] - const { collection, doc, runTransaction} = require("firebase/firestore"); + const { collection, doc, runTransaction } = require("firebase/firestore"); async function addRating(restaurantRef, rating) { // Create a reference for a new rating, for use inside the transaction @@ -1193,7 +1227,7 @@ describe("firestore", () => { // Create document and add a rating const { setDoc } = require("firebase/firestore"); - const ref = doc(collection(db, 'restaurants'), ('arinell-pizza')); + const ref = doc(db, 'restaurants', 'arinell-pizza'); await setDoc(ref, { name: 'Arinell Pizza', avgRating: 4.63, diff --git a/firestore-next/test.solution-aggregation.js b/firestore-next/test.solution-aggregation.js index 82e1d602..7106a0c9 100644 --- a/firestore-next/test.solution-aggregation.js +++ b/firestore-next/test.solution-aggregation.js @@ -10,9 +10,9 @@ const arinellDoc = { // [END sample_doc] describe("firestore-solution-arrays", () => { - const { FirebaseFirestore } = require("firebase/firestore"); + const { Firestore } = require("firebase/firestore"); - /** @type {FirebaseFirestore} */ + /** @type {Firestore} */ let db; before(async () => { @@ -27,15 +27,15 @@ describe("firestore-solution-arrays", () => { const app = initializeApp(config, "solution-arrays"); db = getFirestore(app); - await setDoc(doc(collection(db, "restaurants"), "arinell-pizza"), arinellDoc); + await setDoc(doc(db, "restaurants", "arinell-pizza"), arinellDoc); }); describe("solution-arrays", () => { it("should get a collection of ratings", async () => { // [START get_collection_ratings] - const { collection, doc, getDocs } = require("firebase/firestore"); + const { collection, getDocs } = require("firebase/firestore"); - const ratingsRef = collection(doc(collection(db, "restaurants"), "arinell-pizza"), "ratings"); + const ratingsRef = collection(db, "restaurants", "arinell-pizza", "ratings"); const ratingsDocs = await getDocs(ratingsRef); // [END get_collection_ratings] }); diff --git a/firestore-next/test.solution-arrays.js b/firestore-next/test.solution-arrays.js index 7986ef6f..3746a8d1 100644 --- a/firestore-next/test.solution-arrays.js +++ b/firestore-next/test.solution-arrays.js @@ -44,9 +44,9 @@ const postsWithMapAdvanced = [ ]; describe("firestore-solution-arrays", () => { - const { FirebaseFirestore } = require("firebase/firestore"); + const { Firestore } = require("firebase/firestore"); - /** @type {FirebaseFirestore} */ + /** @type {Firestore} */ let db; before(() => { @@ -78,7 +78,7 @@ describe("firestore-solution-arrays", () => { it("should query in a category by timestamp", () => { function queryOne() { // [START query_in_category_timestamp_invalid] - const { collection, query, where, orderBy, FirebaseFirestore } = require("@firebase/firestore"); + const { collection, query, where, orderBy, Firestore } = require("firebase/firestore"); const q = query(collection(db, "posts"), where("categories.cats", "==", true), @@ -89,7 +89,7 @@ describe("firestore-solution-arrays", () => { function queryTwo() { // [START query_in_category_timestamp] - const { collection, query, where, orderBy } = require("@firebase/firestore"); + const { collection, query, where, orderBy } = require("firebase/firestore"); const q = query(collection(db, "posts"), where("categories.cats", ">", 0), diff --git a/firestore-next/test.solution-bundles.js b/firestore-next/test.solution-bundles.js new file mode 100644 index 00000000..94bf7ff2 --- /dev/null +++ b/firestore-next/test.solution-bundles.js @@ -0,0 +1,50 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +const { Firestore } = require('firebase/firestore'); + +/** + * @type Firestore + */ +var db; + +// [START fs_bundle_load] +const { loadBundle, namedQuery, getDocsFromCache } = require("firebase/firestore"); + +async function fetchFromBundle() { + // Fetch the bundle from Firebase Hosting, if the CDN cache is hit the 'X-Cache' + // response header will be set to 'HIT' + const resp = await fetch('/createBundle'); + + // Load the bundle contents into the Firestore SDK + await loadBundle(db, resp.body); + + // Query the results from the cache + const query = await namedQuery(db, 'latest-stories-query'); + const storiesSnap = await getDocsFromCache(query); + + // Use the results + // ... +} +// [END fs_bundle_load] + +describe("firestore-solution-bundles", () => { + before(() => { + const { initializeApp } = require("firebase/app"); + const { getFirestore} = require("firebase/firestore"); + + const config = { + apiKey: "AIzaSyArvVh6VSdXicubcvIyuB-GZs8ua0m0DTI", + authDomain: "firestorequickstarts.firebaseapp.com", + projectId: "firestorequickstarts", + }; + const app = initializeApp(config, "solution-bundles"); + db = getFirestore(app); + }); + + describe("solution-bundles", () => { + it("should fetch a bundle", (done) => { + fetchFromBundle().finally(done); + }); + }); +}); diff --git a/firestore-next/test.solution-counters.js b/firestore-next/test.solution-counters.js index a76cfc24..da854797 100644 --- a/firestore-next/test.solution-counters.js +++ b/firestore-next/test.solution-counters.js @@ -1,14 +1,14 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -const { FirebaseFirestore } = require('firebase/firestore'); +const { Firestore } = require('firebase/firestore'); -/** @type {FirebaseFirestore} */ +/** @type {Firestore} */ let db; // [START create_counter] function createCounter(ref, num_shards) { - const { collection, doc, writeBatch } = require("firebase/firestore"); + const { doc, writeBatch } = require("firebase/firestore"); const batch = writeBatch(db); @@ -17,7 +17,7 @@ function createCounter(ref, num_shards) { // Initialize each shard with count=0 for (let i = 0; i < num_shards; i++) { - const shardRef = doc(collection(ref, 'shards'), i.toString()); + const shardRef = doc(ref, 'shards', i.toString()); batch.set(shardRef, { count: 0 }); } @@ -28,11 +28,11 @@ function createCounter(ref, num_shards) { // [START increment_counter] function incrementCounter(db, ref, num_shards) { - const { collection, doc, updateDoc, increment, FirebaseFirestore } = require("@firebase/firestore"); + const { doc, updateDoc, increment } = require("firebase/firestore"); // Select a shard of the counter at random const shardId = Math.floor(Math.random() * num_shards).toString(); - const shardRef = doc(collection(ref, 'shards'), shardId); + const shardRef = doc(ref, 'shards', shardId); // Update count return updateDoc(shardRef, "count", increment(1)); @@ -41,7 +41,7 @@ function incrementCounter(db, ref, num_shards) { // [START get_count] async function getCount(ref) { - const { collection, getDocs } = require("@firebase/firestore"); + const { collection, getDocs } = require("firebase/firestore"); // Sum the count of each shard in the subcollection const snapshot = await getDocs(collection(ref, 'shards')); diff --git a/firestore-next/test.solution-geoqueries.js b/firestore-next/test.solution-geoqueries.js index 1293229e..507c6178 100644 --- a/firestore-next/test.solution-geoqueries.js +++ b/firestore-next/test.solution-geoqueries.js @@ -1,11 +1,11 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -const { FirebaseFirestore } = require('firebase/firestore'); +const { Firestore } = require('firebase/firestore'); const geofire = require('geofire-common'); -/** @type {FirebaseFirestore} */ +/** @type {Firestore} */ let db; async function addHash(done) { diff --git a/firestore/emulator-suite.js b/firestore/emulator-suite.js index 714d38e7..03aef1e9 100644 --- a/firestore/emulator-suite.js +++ b/firestore/emulator-suite.js @@ -6,7 +6,7 @@ function onDocumentReady() { // Firebase previously initialized using firebase.initializeApp(). var db = firebase.firestore(); if (location.hostname === "localhost") { - db.useEmulator("localhost", 8080); + db.useEmulator("127.0.0.1", 8080); } // [END fs_emulator_connect] } diff --git a/firestore/index.html b/firestore/index.html index 54ff25bd..3599ca13 100644 --- a/firestore/index.html +++ b/firestore/index.html @@ -12,8 +12,8 @@ - - + + diff --git a/firestore/package.json b/firestore/package.json index df5faf59..73bbb88c 100644 --- a/firestore/package.json +++ b/firestore/package.json @@ -6,7 +6,7 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.2.2", + "firebase": "^8.10.0", "geofire-common": "^5.1.0" }, "devDependencies": { diff --git a/firestore/test.firestore.js b/firestore/test.firestore.js index fe600769..20032d36 100644 --- a/firestore/test.firestore.js +++ b/firestore/test.firestore.js @@ -61,7 +61,7 @@ describe("firestore", () => { // [START initialize_persistence] firebase.firestore().enablePersistence() - .catch(function(err) { + .catch((err) => { if (err.code == 'failed-precondition') { // Multiple tabs open, persistence can only be enabled // in one tab at a a time. @@ -80,7 +80,7 @@ describe("firestore", () => { var disable = // [START disable_network] firebase.firestore().disableNetwork() - .then(function() { + .then(() => { // Do offline actions // [START_EXCLUDE] console.log("Network disabled!"); @@ -91,7 +91,7 @@ describe("firestore", () => { var enable = // [START enable_network] firebase.firestore().enableNetwork() - .then(function() { + .then(() => { // Do online actions // [START_EXCLUDE] console.log("Network enabled!"); @@ -105,8 +105,8 @@ describe("firestore", () => { it("should reply with .fromCache fields", () => { // [START use_from_cache] db.collection("cities").where("state", "==", "CA") - .onSnapshot({ includeMetadataChanges: true }, function(snapshot) { - snapshot.docChanges().forEach(function(change) { + .onSnapshot({ includeMetadataChanges: true }, (snapshot) => { + snapshot.docChanges().forEach((change) => { if (change.type === "added") { console.log("New city: ", change.doc.data()); } @@ -127,10 +127,10 @@ describe("firestore", () => { last: "Lovelace", born: 1815 }) - .then(function(docRef) { + .then((docRef) => { console.log("Document written with ID: ", docRef.id); }) - .catch(function(error) { + .catch((error) => { console.error("Error adding document: ", error); }); // [END add_ada_lovelace] @@ -159,10 +159,10 @@ describe("firestore", () => { last: "Turing", born: 1912 }) - .then(function(docRef) { + .then((docRef) => { console.log("Document written with ID: ", docRef.id); }) - .catch(function(error) { + .catch((error) => { console.error("Error adding document: ", error); }); // [END add_alan_turing] @@ -176,9 +176,9 @@ describe("firestore", () => { // [START listen_for_users] db.collection("users") .where("born", "<", 1900) - .onSnapshot(function(snapshot) { + .onSnapshot((snapshot) => { console.log("Current users born before 1900:"); - snapshot.forEach(function (userSnapshot) { + snapshot.forEach((userSnapshot) => { console.log(userSnapshot.data()); }); }); @@ -224,10 +224,10 @@ describe("firestore", () => { state: "CA", country: "USA" }) - .then(function() { + .then(() => { console.log("Document successfully written!"); }) - .catch(function(error) { + .catch((error) => { console.error("Error writing document: ", error); }); // [END set_document] @@ -250,7 +250,7 @@ describe("firestore", () => { // [START get_custom_object] db.collection("cities").doc("LA") .withConverter(cityConverter) - .get().then(function(doc) { + .get().then((doc) => { if (doc.exists){ // Convert to City object var city = doc.data(); @@ -258,7 +258,7 @@ describe("firestore", () => { console.log(city.toString()); } else { console.log("No such document!"); - }}).catch(function(error) { + }}).catch((error) => { console.log("Error getting document:", error); }); // [END get_custom_object] @@ -283,7 +283,7 @@ describe("firestore", () => { batch.delete(laRef); // Commit the batch - batch.commit().then(function () { + batch.commit().then(() => { // [START_EXCLUDE] done(); // [END_EXCLUDE] @@ -307,7 +307,7 @@ describe("firestore", () => { } } }; - db.collection("data").doc("one").set(docData).then(function() { + db.collection("data").doc("one").set(docData).then(() => { console.log("Document successfully written!"); }); // [END data_types] @@ -339,7 +339,7 @@ describe("firestore", () => { "age": 13, "favorites.color": "Red" }) - .then(function() { + .then(() => { console.log("Document successfully updated!"); }); // [END update_document_nested] @@ -354,7 +354,7 @@ describe("firestore", () => { function deleteCollection(db, collectionRef, batchSize) { var query = collectionRef.orderBy('__name__').limit(batchSize); - return new Promise(function(resolve, reject) { + return new Promise((resolve, reject) => { deleteQueryBatch(db, query, batchSize, resolve, reject); }); } @@ -369,14 +369,14 @@ describe("firestore", () => { // Delete documents in a batch var batch = db.batch(); - snapshot.docs.forEach(function(doc) { + snapshot.docs.forEach((doc) => { batch.delete(doc.ref); }); - return batch.commit().then(function() { + return batch.commit().then(() => { return snapshot.size; }); - }).then(function(numDeleted) { + }).then((numDeleted) => { if (numDeleted < batchSize) { resolve(); return; @@ -384,7 +384,7 @@ describe("firestore", () => { // Recurse on the next process tick, to avoid // exploding the stack. - setTimeout(function() { + setTimeout(() => { deleteQueryBatch(db, query, batchSize, resolve, reject); }, 0); }) @@ -440,10 +440,10 @@ describe("firestore", () => { name: "Tokyo", country: "Japan" }) - .then(function(docRef) { + .then((docRef) => { console.log("Document written with ID: ", docRef.id); }) - .catch(function(error) { + .catch((error) => { console.error("Error adding document: ", error); }); // [END add_document] @@ -470,10 +470,10 @@ describe("firestore", () => { return washingtonRef.update({ capital: true }) - .then(function() { + .then(() => { console.log("Document successfully updated!"); }) - .catch(function(error) { + .catch((error) => { // The document probably doesn't exist. console.error("Error updating document: ", error); }); @@ -510,9 +510,9 @@ describe("firestore", () => { it("should delete a document", () => { var output = // [START delete_document] - db.collection("cities").doc("DC").delete().then(function() { + db.collection("cities").doc("DC").delete().then(() => { console.log("Document successfully deleted!"); - }).catch(function(error) { + }).catch((error) => { console.error("Error removing document: ", error); }); // [END delete_document] @@ -528,9 +528,9 @@ describe("firestore", () => { // Uncomment to initialize the doc. // sfDocRef.set({ population: 0 }); - return db.runTransaction(function(transaction) { + return db.runTransaction((transaction) => { // This code may get re-run multiple times if there are conflicts. - return transaction.get(sfDocRef).then(function(sfDoc) { + return transaction.get(sfDocRef).then((sfDoc) => { if (!sfDoc.exists) { throw "Document does not exist!"; } @@ -541,9 +541,9 @@ describe("firestore", () => { var newPopulation = sfDoc.data().population + 1; transaction.update(sfDocRef, { population: newPopulation }); }); - }).then(function() { + }).then(() => { console.log("Transaction successfully committed!"); - }).catch(function(error) { + }).catch((error) => { console.log("Transaction failed: ", error); }); // [END transaction] @@ -555,8 +555,8 @@ describe("firestore", () => { // Create a reference to the SF doc. var sfDocRef = db.collection("cities").doc("SF"); - db.runTransaction(function(transaction) { - return transaction.get(sfDocRef).then(function(sfDoc) { + db.runTransaction((transaction) => { + return transaction.get(sfDocRef).then((sfDoc) => { if (!sfDoc.exists) { throw "Document does not exist!"; } @@ -569,9 +569,9 @@ describe("firestore", () => { return Promise.reject("Sorry! Population is too big."); } }); - }).then(function(newPopulation) { + }).then((newPopulation) => { console.log("Population increased to ", newPopulation); - }).catch(function(err) { + }).catch((err) => { // This will be an "population is too big" error. console.error(err); }); @@ -582,14 +582,14 @@ describe("firestore", () => { // [START get_document] var docRef = db.collection("cities").doc("SF"); - docRef.get().then(function(doc) { + docRef.get().then((doc) => { if (doc.exists) { console.log("Document data:", doc.data()); } else { // doc.data() will be undefined in this case console.log("No such document!"); } - }).catch(function(error) { + }).catch((error) => { console.log("Error getting document:", error); }); // [END get_document] @@ -600,18 +600,18 @@ describe("firestore", () => { var docRef = db.collection("cities").doc("SF"); // Valid options for source are 'server', 'cache', or - // 'default'. See https://firebase.google.com/docs/reference/js/firebase.firestore.GetOptions + // 'default'. See https://firebase.google.com/docs/reference/js/v8/firebase.firestore.GetOptions // for more information. var getOptions = { source: 'cache' }; // Get a document, forcing the SDK to fetch from the offline cache. - docRef.get(getOptions).then(function(doc) { + docRef.get(getOptions).then((doc) => { // Document was found in the cache. If no cached document exists, // an error will be returned to the 'catch' block below. console.log("Cached document data:", doc.data()); - }).catch(function(error) { + }).catch((error) => { console.log("Error getting cached document:", error); }); // [END get_document_options] @@ -621,12 +621,12 @@ describe("firestore", () => { var unsub = // [START listen_document] db.collection("cities").doc("SF") - .onSnapshot(function(doc) { + .onSnapshot((doc) => { console.log("Current data: ", doc.data()); }); // [END listen_document] - setTimeout(function() { + setTimeout(() => { unsub(); done(); }, 3000); @@ -636,13 +636,13 @@ describe("firestore", () => { var unsub = // [START listen_document_local] db.collection("cities").doc("SF") - .onSnapshot(function(doc) { + .onSnapshot((doc) => { var source = doc.metadata.hasPendingWrites ? "Local" : "Server"; console.log(source, " data: ", doc.data()); }); // [END listen_document_local] - setTimeout(function() { + setTimeout(() => { unsub(); done(); }, 3000); @@ -655,12 +655,12 @@ describe("firestore", () => { .onSnapshot({ // Listen for document metadata changes includeMetadataChanges: true - }, function(doc) { + }, (doc) => { // ... }); // [END listen_with_metadata] - setTimeout(function() { + setTimeout(() => { unsub(); done(); }, 3000); @@ -671,13 +671,13 @@ describe("firestore", () => { // [START get_multiple] db.collection("cities").where("capital", "==", true) .get() - .then(function(querySnapshot) { - querySnapshot.forEach(function(doc) { + .then((querySnapshot) => { + querySnapshot.forEach((doc) => { // doc.data() is never undefined for query doc snapshots console.log(doc.id, " => ", doc.data()); }); }) - .catch(function(error) { + .catch((error) => { console.log("Error getting documents: ", error); }); // [END get_multiple] @@ -687,8 +687,8 @@ describe("firestore", () => { it("should get all documents from a collection", () => { var output = // [START get_multiple_all] - db.collection("cities").get().then(function(querySnapshot) { - querySnapshot.forEach(function(doc) { + db.collection("cities").get().then((querySnapshot) => { + querySnapshot.forEach((doc) => { // doc.data() is never undefined for query doc snapshots console.log(doc.id, " => ", doc.data()); }); @@ -701,15 +701,15 @@ describe("firestore", () => { var unsubscribe = // [START listen_multiple] db.collection("cities").where("state", "==", "CA") - .onSnapshot(function(querySnapshot) { + .onSnapshot((querySnapshot) => { var cities = []; - querySnapshot.forEach(function(doc) { + querySnapshot.forEach((doc) => { cities.push(doc.data().name); }); console.log("Current cities in CA: ", cities.join(", ")); }); // [END listen_multiple] - setTimeout(function() { + setTimeout(() => { unsubscribe(); done(); }, 2500); @@ -719,8 +719,8 @@ describe("firestore", () => { var unsubscribe = // [START listen_diffs] db.collection("cities").where("state", "==", "CA") - .onSnapshot(function(snapshot) { - snapshot.docChanges().forEach(function(change) { + .onSnapshot((snapshot) => { + snapshot.docChanges().forEach((change) => { if (change.type === "added") { console.log("New city: ", change.doc.data()); } @@ -733,7 +733,7 @@ describe("firestore", () => { }); }); // [END listen_diffs] - setTimeout(function() { + setTimeout(() => { unsubscribe(); done(); }, 2500); @@ -742,7 +742,7 @@ describe("firestore", () => { it("should unsubscribe a listener", () => { // [START detach_listener] var unsubscribe = db.collection("cities") - .onSnapshot(function (){ + .onSnapshot(() => { // Respond to data // ... }); @@ -758,9 +758,9 @@ describe("firestore", () => { var unsubscribe = // [START handle_listen_errors] db.collection("cities") - .onSnapshot(function(snapshot) { + .onSnapshot((snapshot) => { // ... - }, function(error) { + }, (error) => { // ... }); // [END handle_listen_errors] @@ -803,7 +803,7 @@ describe("firestore", () => { docRef.update({ timestamp: firebase.firestore.FieldValue.serverTimestamp() }); - docRef.onSnapshot(function(snapshot) { + docRef.onSnapshot((snapshot) => { var data = snapshot.data(options); console.log( 'Timestamp: ' + data.timestamp + @@ -856,9 +856,9 @@ describe("firestore", () => { it("should handle other wheres", () => { var citiesRef = db.collection("cities"); // [START example_filters] - citiesRef.where("state", "==", "CA"); - citiesRef.where("population", "<", 100000); - citiesRef.where("name", ">=", "San Francisco"); + const stateQuery = citiesRef.where("state", "==", "CA"); + const populationQuery = citiesRef.where("population", "<", 100000); + const nameQuery = citiesRef.where("name", ">=", "San Francisco"); // [END example_filters] // [START simple_query_not_equal] @@ -893,23 +893,23 @@ describe("firestore", () => { // [START in_filter_with_array] citiesRef.where('regions', 'in', - [['west_coast', 'east_coast']]); + [['west_coast'], ['east_coast']]); // [END in_filter_with_array] }); it("should handle compound queries", () => { var citiesRef = db.collection("cities"); // [START chain_filters] - citiesRef.where("state", "==", "CO").where("name", "==", "Denver"); - citiesRef.where("state", "==", "CA").where("population", "<", 1000000); + const q1 = citiesRef.where("state", "==", "CO").where("name", "==", "Denver"); + const q2 = citiesRef.where("state", "==", "CA").where("population", "<", 1000000); // [END chain_filters] }); it("should handle range filters on one field", () => { var citiesRef = db.collection("cities"); // [START valid_range_filters] - citiesRef.where("state", ">=", "CA").where("state", "<=", "IN"); - citiesRef.where("state", "==", "CA").where("population", ">", 1000000); + const q1 = citiesRef.where("state", ">=", "CA").where("state", "<=", "IN"); + const q2 = citiesRef.where("state", "==", "CA").where("population", ">", 1000000); // [END valid_range_filters] }); @@ -984,7 +984,7 @@ describe("firestore", () => { // [START start_doc] var citiesRef = db.collection("cities"); - return citiesRef.doc("SF").get().then(function(doc) { + return citiesRef.doc("SF").get().then((doc) => { // Get all cities with a population bigger than San Francisco var biggerThanSf = citiesRef .orderBy("population") @@ -1011,13 +1011,13 @@ describe("firestore", () => { // [END start_multiple_orderby] }); - it("shoud paginate", () => { + it("should paginate", () => { // [START paginate] var first = db.collection("cities") .orderBy("population") .limit(25); - return first.get().then(function (documentSnapshots) { + return first.get().then((documentSnapshots) => { // Get the last visible document var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1]; console.log("last", lastVisible); @@ -1087,8 +1087,8 @@ describe("firestore", () => { it("should query a collection group", () => { // [START fs_collection_group_query] var museums = db.collectionGroup('landmarks').where('type', '==', 'museum'); - museums.get().then(function (querySnapshot) { - querySnapshot.forEach(function (doc) { + museums.get().then((querySnapshot) => { + querySnapshot.forEach((doc) => { console.log(doc.id, ' => ', doc.data()); }); }); diff --git a/firestore/test.solution-bundles.js b/firestore/test.solution-bundles.js new file mode 100644 index 00000000..4bece2c8 --- /dev/null +++ b/firestore/test.solution-bundles.js @@ -0,0 +1,48 @@ +// [START fs_bundle_load] +// If you are using module bundlers. +import firebase from "firebase/app"; +import "firebase/firestore"; +import "firebase/firestore/bundle"; // This line enables bundle loading as a side effect. + +// [START_EXCLUDE] +/** + * @type firebase.firestore.Firestore + */ +var db; +// [END_EXCLUDE] + +async function fetchFromBundle() { + // Fetch the bundle from Firebase Hosting, if the CDN cache is hit the 'X-Cache' + // response header will be set to 'HIT' + const resp = await fetch('/createBundle'); + + // Load the bundle contents into the Firestore SDK + await db.loadBundle(resp.body); + + // Query the results from the cache + // Note: omitting "source: cache" will query the Firestore backend. + const query = await db.namedQuery('latest-stories-query'); + const storiesSnap = await query.get({ source: 'cache' }); + + // Use the results + // ... +} +// [END fs_bundle_load] + +describe("firestore-solution-bundles", () => { + before(() => { + var config = { + apiKey: "AIzaSyArvVh6VSdXicubcvIyuB-GZs8ua0m0DTI", + authDomain: "firestorequickstarts.firebaseapp.com", + projectId: "firestorequickstarts", + }; + var app = firebase.initializeApp(config, "solution-bundles"); + db = firebase.firestore(app); + }); + + describe("solution-bundles", () => { + it("should fetch a bundle", (done) => { + fetchFromBundle().finally(done); + }); + }); +}); diff --git a/firestore/test.solution-counters.js b/firestore/test.solution-counters.js index c8c62fe6..c7c51cff 100644 --- a/firestore/test.solution-counters.js +++ b/firestore/test.solution-counters.js @@ -22,7 +22,7 @@ function createCounter(ref, num_shards) { // [END create_counter] // [START increment_counter] -function incrementCounter(db, ref, num_shards) { +function incrementCounter(ref, num_shards) { // Select a shard of the counter at random const shard_id = Math.floor(Math.random() * num_shards).toString(); const shard_ref = ref.collection('shards').doc(shard_id); @@ -67,7 +67,7 @@ describe("firestore-solution-counters", () => { // Create a counter, then increment it const ref = db.collection('counters').doc(); return createCounter(ref, 10).then(() => { - return incrementCounter(db, ref, 10); + return incrementCounter(ref, 10); }); }); @@ -75,7 +75,7 @@ describe("firestore-solution-counters", () => { // Create a counter, increment it, then get the count const ref = db.collection('counters').doc(); return createCounter(ref, 10).then(() => { - return incrementCounter(db, ref, 10); + return incrementCounter(ref, 10); }).then(() => { return getCount(ref); }); diff --git a/functions-next/callable.js b/functions-next/callable.js index 193a3c2e..5ebc03d9 100644 --- a/functions-next/callable.js +++ b/functions-next/callable.js @@ -1,34 +1,55 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -export function callAddMessage(firebaseApp) { +export function initialize() { + // [START fb_functions_initialize] + const { initializeApp } = require("firebase/app"); + const { getFunctions } = require("firebase/functions"); + + initializeApp({ + // Your Firebase Web SDK configuration + // [START_EXCLUDE] + projectId: "", + apiKey: "", + // [END_EXCLUDE] + }); + + const functions = getFunctions(); + // [END fb_functions_initialize] +} + +export function callAddMessage() { const messageText = "Hello, World!"; - // [START functions_call_add_message] + // [START fb_functions_call_add_message] const { getFunctions, httpsCallable } = require("firebase/functions"); - const functions = getFunctions(firebaseApp); + const functions = getFunctions(); const addMessage = httpsCallable(functions, 'addMessage'); addMessage({ text: messageText }) .then((result) => { // Read result of the Cloud Function. - const sanitizedMessage = result.data.text; + /** @type {any} */ + const data = result.data; + const sanitizedMessage = data.text; }); - // [END functions_call_add_message] + // [END fb_functions_call_add_message] } export function callAddMessageError(firebaseApp) { const messageText = "Hello, World!"; - // [START functions_call_add_message_error] + // [START fb_functions_call_add_message_error] const { getFunctions, httpsCallable } = require("firebase/functions"); - const functions = getFunctions(firebaseApp); + const functions = getFunctions(); const addMessage = httpsCallable(functions, 'addMessage'); addMessage({ text: messageText }) .then((result) => { // Read result of the Cloud Function. - const sanitizedMessage = result.data.text; + /** @type {any} */ + const data = result.data; + const sanitizedMessage = data.text; }) .catch((error) => { // Getting the Error details. @@ -37,5 +58,5 @@ export function callAddMessageError(firebaseApp) { const details = error.details; // ... }); - // [END functions_call_add_message_error] + // [END fb_functions_call_add_message_error] } diff --git a/functions-next/emulator-suite.js b/functions-next/emulator-suite.js index 48b6c681..db7fd49d 100644 --- a/functions-next/emulator-suite.js +++ b/functions-next/emulator-suite.js @@ -10,17 +10,17 @@ initializeApp({ }); export function emulatorSettings() { - // [START functions_emulator_connect] + // [START fb_functions_emulator_connect] const { getApp } = require("firebase/app"); - const { getFunctions, useFunctionsEmulator } = require("firebase/functions"); + const { getFunctions, connectFunctionsEmulator } = require("firebase/functions"); const functions = getFunctions(getApp()); - useFunctionsEmulator(functions, "localhost", 5001); - // [END functions_emulator_connect] + connectFunctionsEmulator(functions, "127.0.0.1", 5001); + // [END fb_functions_emulator_connect] } export async function callFunction() { - // [START functions_callable_call] + // [START fb_functions_callable_call] const { getApp } = require("firebase/app"); const { getFunctions, httpsCallable } = require("firebase/functions"); @@ -28,7 +28,9 @@ export async function callFunction() { const addMessage = httpsCallable(functions, 'addMessage'); const result = await addMessage({ text: ''}); - const sanitizedMessage = result.data.text; + /** @type {any} */ + const data = result.data; + const sanitizedMessage = data.text; // ... - // [END functions_callable_call] + // [END fb_functions_callable_call] } diff --git a/functions-next/package.json b/functions-next/package.json index 85e91e5d..14f097ee 100644 --- a/functions-next/package.json +++ b/functions-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "exp" + "firebase": "^10.0.0" } } diff --git a/functions/callable.js b/functions/callable.js index 5cb6a515..66b576d5 100644 --- a/functions/callable.js +++ b/functions/callable.js @@ -1,23 +1,39 @@ +// [START fb_functions_imports] import firebase from "firebase/app"; import "firebase/functions"; +// [END fb_functions_imports] + +function initialize() { + // [START fb_functions_initialize] + firebase.initializeApp({ + // Your Firebase Web SDK configuration + // [START_EXCLUDE] + projectId: "", + apiKey: "", + // [END_EXCLUDE] + }); + + const functions = firebase.functions(); + // [END fb_functions_initialize] +} function callAddMessage() { const messageText = "Hello, World!"; - // [START functions_call_add_message] + // [START fb_functions_call_add_message] var addMessage = firebase.functions().httpsCallable('addMessage'); addMessage({ text: messageText }) .then((result) => { // Read result of the Cloud Function. var sanitizedMessage = result.data.text; }); - // [END functions_call_add_message] + // [END fb_functions_call_add_message] } function callAddMessageError() { const messageText = "Hello, World!"; - // [START functions_call_add_message_error] + // [START fb_functions_call_add_message_error] var addMessage = firebase.functions().httpsCallable('addMessage'); addMessage({ text: messageText }) .then((result) => { @@ -31,5 +47,5 @@ function callAddMessageError() { var details = error.details; // ... }); - // [END functions_call_add_message_error] + // [END fb_functions_call_add_message_error] } diff --git a/functions/emulator-suite.js b/functions/emulator-suite.js index e2c244ca..e0413370 100644 --- a/functions/emulator-suite.js +++ b/functions/emulator-suite.js @@ -2,7 +2,7 @@ import firebase from "firebase/app"; import "firebase/functions"; function emulatorSettings() { - // [START functions_emulator_connect] - firebase.functions().useEmulator("localhost", 5001); - // [END functions_emulator_connect] + // [START fb_functions_emulator_connect] + firebase.functions().useEmulator("127.0.0.1", 5001); + // [END fb_functions_emulator_connect] } diff --git a/functions/package.json b/functions/package.json index aa09b8f3..653086c9 100644 --- a/functions/package.json +++ b/functions/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.2.2" + "firebase": "^8.10.0" } } diff --git a/installations/package.json b/installations/package.json index 64ac9086..1395fca3 100644 --- a/installations/package.json +++ b/installations/package.json @@ -4,6 +4,6 @@ "scripts": {}, "license": "Apache 2.0", "dependencies": { - "firebase": "^8.2.2" + "firebase": "^8.10.0" } } diff --git a/lerna.json b/lerna.json deleted file mode 100644 index 6397cfbf..00000000 --- a/lerna.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "lerna": "2.8.0", - "packages": [ - "auth", - "auth-next", - "database", - "firebaseapp", - "firestore", - "firestore-next", - "functions", - "functions-next", - "installations", - "perf", - "perf-next", - "remoteconfig", - "remoteconfig-next" - ], - "version": "1.0.0" -} diff --git a/messaging-next/index.js b/messaging-next/index.js new file mode 100644 index 00000000..491ff84e --- /dev/null +++ b/messaging-next/index.js @@ -0,0 +1,77 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function getMessagingObject() { + // [START messaging_get_messaging_object] + const { getMessaging } = require("firebase/messaging"); + + const messaging = getMessaging(); + // [END messaging_get_messaging_object] +} + +function receiveMessage() { + // [START messaging_receive_message] + // Handle incoming messages. Called when: + // - a message is received while the app has focus + // - the user clicks on an app notification created by a service worker + // `messaging.onBackgroundMessage` handler. + const { getMessaging, onMessage } = require("firebase/messaging"); + + const messaging = getMessaging(); + onMessage(messaging, (payload) => { + console.log('Message received. ', payload); + // ... + }); + // [END messaging_receive_message] +} + +function getToken() { + // [START messaging_get_token] + const { getMessaging, getToken } = require("firebase/messaging"); + + // Get registration token. Initially this makes a network call, once retrieved + // subsequent calls to getToken will return from cache. + const messaging = getMessaging(); + getToken(messaging, { vapidKey: '' }).then((currentToken) => { + if (currentToken) { + // Send the token to your server and update the UI if necessary + // ... + } else { + // Show permission request UI + console.log('No registration token available. Request permission to generate one.'); + // ... + } + }).catch((err) => { + console.log('An error occurred while retrieving token. ', err); + // ... + }); + // [END messaging_get_token] +} + +function requestPermission() { + // [START messaging_request_permission] + Notification.requestPermission().then((permission) => { + if (permission === 'granted') { + console.log('Notification permission granted.'); + // TODO(developer): Retrieve a registration token for use with FCM. + // ... + } else { + console.log('Unable to get permission to notify.'); + } + }); + // [END messaging_request_permission] +} + +function deleteToken() { + // [START messaging_delete_token] + const { getMessaging, deleteToken } = require("firebase/messaging"); + + const messaging = getMessaging(); + deleteToken(messaging).then(() => { + console.log('Token deleted.'); + // ... + }).catch((err) => { + console.log('Unable to delete token. ', err); + }); + // [END messaging_delete_token] +} diff --git a/messaging-next/package.json b/messaging-next/package.json new file mode 100644 index 00000000..e4887a2a --- /dev/null +++ b/messaging-next/package.json @@ -0,0 +1,11 @@ +{ + "name": "messaging-next", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^10.0.0" + } +} diff --git a/messaging-next/service-worker.js b/messaging-next/service-worker.js new file mode 100644 index 00000000..55f07524 --- /dev/null +++ b/messaging-next/service-worker.js @@ -0,0 +1,60 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +import { initializeApp } from "firebase/app"; + +const firebaseApp = initializeApp({ + apiKey: '### FIREBASE API KEY ###', + appId: '### FIREBASE APP ID ###', + projectId: '### FIREBASE PROJECT ID ###' +}); + +// See: https://github.com/microsoft/TypeScript/issues/14877 +/** @type {ServiceWorkerGlobalScope} */ +let self; + +function initInSw() { + // [START messaging_init_in_sw] + const { initializeApp } = require("firebase/app"); + const { getMessaging } = require("firebase/messaging/sw"); + + // Initialize the Firebase app in the service worker by passing in + // your app's Firebase config object. + // https://firebase.google.com/docs/web/setup#config-object + const firebaseApp = initializeApp({ + apiKey: 'api-key', + authDomain: 'project-id.firebaseapp.com', + databaseURL: 'https://project-id.firebaseio.com', + projectId: 'project-id', + storageBucket: 'project-id.appspot.com', + messagingSenderId: 'sender-id', + appId: 'app-id', + measurementId: 'G-measurement-id', + }); + + // Retrieve an instance of Firebase Messaging so that it can handle background + // messages. + const messaging = getMessaging(firebaseApp); + // [END messaging_init_in_sw] +} + +function onBackgroundMessage() { + // [START messaging_on_background_message] + const { getMessaging } = require("firebase/messaging/sw"); + const { onBackgroundMessage } = require("firebase/messaging/sw"); + + const messaging = getMessaging(); + onBackgroundMessage(messaging, (payload) => { + console.log('[firebase-messaging-sw.js] Received background message ', payload); + // Customize notification here + const notificationTitle = 'Background Message Title'; + const notificationOptions = { + body: 'Background Message body.', + icon: '/firebase-logo.png' + }; + + self.registration.showNotification(notificationTitle, + notificationOptions); + }); + // [END messaging_on_background_message] +} diff --git a/messaging/index.js b/messaging/index.js new file mode 100644 index 00000000..073d8c2a --- /dev/null +++ b/messaging/index.js @@ -0,0 +1,70 @@ +import firebase from "firebase/app"; +import "firebase/messaging"; + +function getMessagingObject() { + // [START messaging_get_messaging_object] + const messaging = firebase.messaging(); + // [END messaging_get_messaging_object] +} + +function receiveMessage() { + const messaging = firebase.messaging(); + // [START messaging_receive_message] + // Handle incoming messages. Called when: + // - a message is received while the app has focus + // - the user clicks on an app notification created by a service worker + // `messaging.onBackgroundMessage` handler. + messaging.onMessage((payload) => { + console.log('Message received. ', payload); + // ... + }); + // [END messaging_receive_message] +} + +function getToken() { + const messaging = firebase.messaging(); + // [START messaging_get_token] + // Get registration token. Initially this makes a network call, once retrieved + // subsequent calls to getToken will return from cache. + messaging.getToken({ vapidKey: '' }).then((currentToken) => { + if (currentToken) { + // Send the token to your server and update the UI if necessary + // ... + } else { + // Show permission request UI + console.log('No registration token available. Request permission to generate one.'); + // ... + } + }).catch((err) => { + console.log('An error occurred while retrieving token. ', err); + // ... + }); + // [END messaging_get_token] +} + +function requestPermission() { + // [START messaging_request_permission] + Notification.requestPermission().then((permission) => { + if (permission === 'granted') { + console.log('Notification permission granted.'); + // TODO(developer): Retrieve a registration token for use with FCM. + // ... + } else { + console.log('Unable to get permission to notify.'); + } + }); + // [END messaging_request_permission] +} + +function deleteToken() { + const messaging = firebase.messaging(); + + // [START messaging_delete_token] + messaging.deleteToken().then(() => { + console.log('Token deleted.'); + // ... + }).catch((err) => { + console.log('Unable to delete token. ', err); + }); + // [END messaging_delete_token] +} diff --git a/messaging/package.json b/messaging/package.json new file mode 100644 index 00000000..96a5720d --- /dev/null +++ b/messaging/package.json @@ -0,0 +1,11 @@ +{ + "name": "messaging", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^8.10.0" + } +} diff --git a/messaging/service-worker.js b/messaging/service-worker.js new file mode 100644 index 00000000..1a202159 --- /dev/null +++ b/messaging/service-worker.js @@ -0,0 +1,56 @@ +import firebase from 'firebase/app'; +import 'firebase/messaging'; + +// See: https://github.com/microsoft/TypeScript/issues/14877 +/** @type {ServiceWorkerGlobalScope} */ +let self; + +function initInSw() { + // [START messaging_init_in_sw] + // Give the service worker access to Firebase Messaging. + // Note that you can only use Firebase Messaging here. Other Firebase libraries + // are not available in the service worker. + // Replace 10.13.2 with latest version of the Firebase JS SDK. + importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-app-compat.js'); + importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-messaging-compat.js'); + + // Initialize the Firebase app in the service worker by passing in + // your app's Firebase config object. + // https://firebase.google.com/docs/web/setup#config-object + firebase.initializeApp({ + apiKey: 'api-key', + authDomain: 'project-id.firebaseapp.com', + databaseURL: 'https://project-id.firebaseio.com', + projectId: 'project-id', + storageBucket: 'project-id.appspot.com', + messagingSenderId: 'sender-id', + appId: 'app-id', + measurementId: 'G-measurement-id', + }); + + // Retrieve an instance of Firebase Messaging so that it can handle background + // messages. + const messaging = firebase.messaging(); + // [END messaging_init_in_sw] +} + +function onBackgroundMessage() { + const messaging = firebase.messaging(); + + // [START messaging_on_background_message] + messaging.onBackgroundMessage((payload) => { + console.log( + '[firebase-messaging-sw.js] Received background message ', + payload + ); + // Customize notification here + const notificationTitle = 'Background Message Title'; + const notificationOptions = { + body: 'Background Message body.', + icon: '/firebase-logo.png' + }; + + self.registration.showNotification(notificationTitle, notificationOptions); + }); + // [END messaging_on_background_message] +} diff --git a/package.json b/package.json index 6eb29b72..cb7d9157 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,16 @@ "snippets": "rimraf snippets && ts-node scripts/separate-snippets.ts", "lint": "git ls-files | grep -v 'snippets/' | grep '.js$' | xargs npx eslint", "format": "npm run lint -- --fix", - "lerna-bootstrap": "lerna bootstrap --no-ci", - "lerna-compile": "lerna run compile" + "bootstrap": "pnpm recursive install", + "compile": "pnpm recursive run compile --workspace-concurrency=4" }, "license": "Apache-2.0", "devDependencies": { - "eslint": "^7.16.0", - "lerna": "^3.22.1", + "@types/node": "^16.7.10", + "eslint": "^7.32.0", + "pnpm": "^6.14.6", "rimraf": "^3.0.2", - "ts-node": "^9.0.0", - "typescript": "^3.8.3" + "ts-node": "^10.2.1", + "typescript": "^4.4.2" } } diff --git a/perf-next/index.js b/perf-next/index.js index 96545d31..e41aa1b0 100644 --- a/perf-next/index.js +++ b/perf-next/index.js @@ -1,19 +1,37 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; +const perf = getInstance(); -const firebaseApp = initializeApp({ - projectId: '### PROJECT ID ###', - apiKey: '### FIREBASE API KEY ###', - authDomain: '### FIREBASE AUTH DOMAIN ###', -}); -const perf = getInstance(firebaseApp); +function intialize() { + // [START perf_import_app] + const { initializeApp } = require("firebase/app"); + // [END perf_import_app] + // [START perf_import] + const { getPerformance } = require("firebase/performance"); + // [END perf_import] + + // [START perf_initialize_app] + // TODO: Replace the following with your app's Firebase project configuration + // See: https://firebase.google.com/docs/web/learn-more#config-object + const firebaseConfig = { + // ... + }; + + // Initialize Firebase + const app = initializeApp(firebaseConfig); + // [END perf_initialize_app] + + // [START perf_singleton] + // Initialize Performance Monitoring and get a reference to the service + const perf = getPerformance(app); + // [END perf_singleton] +} -export function getInstance(firebaseApp) { +export function getInstance() { // [START perf_get_instance] const { getPerformance } = require("firebase/performance"); - const perf = getPerformance(firebaseApp); + const perf = getPerformance(); // [END perf_get_instance] return perf; diff --git a/perf-next/package.json b/perf-next/package.json index 3a04b696..688f6db0 100644 --- a/perf-next/package.json +++ b/perf-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "exp" + "firebase": "^10.0.0" } } diff --git a/perf/index.js b/perf/index.js index 9ef0dd9c..c5ae8b22 100644 --- a/perf/index.js +++ b/perf/index.js @@ -1,8 +1,30 @@ +// [START perf_import_app] import firebase from "firebase/app"; +// [END perf_import_app] +// [START perf_import] import "firebase/performance"; +// [END perf_import] const perf = firebase.performance(); +function intialize() { + // [START perf_initialize_app] + // TODO: Replace the following with your app's Firebase project configuration + // See: https://firebase.google.com/docs/web/learn-more#config-object + const firebaseConfig = { + // ... + }; + + // Initialize Firebase + firebase.initializeApp(firebaseConfig); + // [END perf_initialize_app] + + // [START perf_singleton] + // Initialize Performance Monitoring and get a reference to the service + const perf = firebase.performance(); + // [END perf_singleton] +} + function addCustomTrace() { // [START perf_add_custom_trace] const trace = perf.trace("CUSTOM_TRACE_NAME"); diff --git a/perf/package.json b/perf/package.json index 1c259bef..61906b8e 100644 --- a/perf/package.json +++ b/perf/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.2.2" + "firebase": "^8.10.0" } } diff --git a/remoteconfig-next/index.js b/remoteconfig-next/index.js index 364bcd17..287f3c99 100644 --- a/remoteconfig-next/index.js +++ b/remoteconfig-next/index.js @@ -1,19 +1,11 @@ // [SNIPPET_REGISTRY disabled] // [SNIPPETS_SEPARATION enabled] -import { initializeApp } from "firebase/app"; - -const firebaseApp = initializeApp({ - apiKey: '### FIREBASE API KEY ###', - appId: '### FIREBASE APP ID ###', - projectId: '### FIREBASE PROJECT ID ###' -}); - function getInstance() { // [START rc_get_instance] const { getRemoteConfig } = require("firebase/remote-config"); - const remoteConfig = getRemoteConfig(firebaseApp); + const remoteConfig = getRemoteConfig(); // [END rc_get_instance] return remoteConfig; @@ -22,6 +14,7 @@ function getInstance() { function setMinimumFetchTime() { const remoteConfig = getInstance(); // [START rc_set_minimum_fetch_time] + // The default and recommended production fetch interval for Remote Config is 12 hours remoteConfig.settings.minimumFetchIntervalMillis = 3600000; // [END rc_set_minimum_fetch_time] } diff --git a/remoteconfig-next/package.json b/remoteconfig-next/package.json index 8977d454..952b1540 100644 --- a/remoteconfig-next/package.json +++ b/remoteconfig-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "exp" + "firebase": "^10.0.0" } } diff --git a/remoteconfig/package.json b/remoteconfig/package.json index db3c3182..8437cbd2 100644 --- a/remoteconfig/package.json +++ b/remoteconfig/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.2.2" + "firebase": "^8.10.0" } } diff --git a/scripts/separate-snippets.ts b/scripts/separate-snippets.ts index dbc89c52..b2f41de3 100644 --- a/scripts/separate-snippets.ts +++ b/scripts/separate-snippets.ts @@ -18,6 +18,15 @@ const RE_END_SNIPPET = /\[END\s+([A-Za-z_]+)\s*\]/; // TODO: Handle multiline imports? const RE_REQUIRE = /const {(.+?)} = require\((.+?)\)/; +// Regex for ref docs URLs +// eg. "https://firebase.google.com/docs/reference/js/v8/firebase.User" +const RE_REF_DOCS = /https:\/\/firebase\.google\.com\/docs\/reference\/js\/(.*)/; + +// Maps v8 ref docs URLs to their v9 counterpart +const REF_DOCS_MAPPINGS: { [key: string]: string } = { + "v8/firebase.User" : "auth.user" +}; + type SnippetsConfig = { enabled: boolean; suffix: string; @@ -30,6 +39,23 @@ function isBlank(line: string) { return line.trim().length === 0; } +/** + * Replace all v8 ref doc urls with their v9 counterpart. + */ +function replaceRefDocsUrls(lines: string[]) { + const outputLines = []; + for (const line of lines) { + if (line.match(RE_REF_DOCS)) { + outputLines.push(line.replace(RE_REF_DOCS, (match: string, p1?: string) => { + return p1 ? `https://firebase.google.com/docs/reference/js/${REF_DOCS_MAPPINGS[p1]}` : match; + })); + } else { + outputLines.push(line); + } + } + return outputLines; +} + /** * Replace all const { foo } = require('bar') with import { foo } from 'bar'; */ @@ -77,7 +103,7 @@ function adjustIndentation(lines: string[]) { if (isBlank(line)) { outputLines.push(""); } else { - outputLines.push(line.substr(minIndent)); + outputLines.push(line.slice(minIndent)); } } return outputLines; @@ -119,13 +145,15 @@ function processSnippet( outputLines = addSuffixToSnippetNames(outputLines, snippetSuffix); outputLines = adjustIndentation(outputLines); outputLines = removeFirstLineAfterComments(outputLines); + outputLines = replaceRefDocsUrls(outputLines); // Add a preamble to every snippet const preambleLines = [ `// This snippet file was generated by processing the source file:`, `// ${sourceFile}`, `//`, - `// To make edits to the snippets in this file, please edit the source`, + `// To update the snippets in this file, edit the source and then run`, + `// 'npm run snippets'.`, ``, ]; const content = [...preambleLines, ...outputLines].join("\n"); @@ -170,12 +198,15 @@ function collectSnippets(filePath: string): SnippetsConfig { const suffixLine = lines.find((l) => !!l.match(RE_SNIPPETS_SUFFIX)); if (suffixLine) { const m = suffixLine.match(RE_SNIPPETS_SUFFIX); - config.suffix = m[1]; + + if (m && m[1]) { + config.suffix = m[1]; + } } // A temporary array holding the names of snippets we're currently within. // This allows for handling nested snippets. - let inSnippetNames = []; + let inSnippetNames: string[] = []; for (const line of lines) { const startMatch = line.match(RE_START_SNIPPET); diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_add_cart.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_add_cart.js new file mode 100644 index 00000000..8f0e68bd --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_add_cart.js @@ -0,0 +1,29 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_add_cart_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Specify order quantity +const item_jeggings_quantity = { + ...item_jeggings, + quantity: 2 +}; + +// Prepare ecommerce bundle +const params4 = { + currency: 'USD', + value: 19.98, + items: [item_jeggings_quantity] +}; + +// Log event when a product is added to a wishlist +const analytics = getAnalytics(); +logEvent(analytics, 'add_to_wishlist', params4); + +// Log event when a product is added to the cart +logEvent(analytics, 'add_to_cart', params4); +// [END analytics_ecommerce_add_cart_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_checkout.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_checkout.js new file mode 100644 index 00000000..beaae722 --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_checkout.js @@ -0,0 +1,21 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_checkout_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce params +const params7 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + items: [item_jeggings] +}; + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'begin_checkout', params7); +// [END analytics_ecommerce_checkout_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_items.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_items.js new file mode 100644 index 00000000..03b27b47 --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_items.js @@ -0,0 +1,37 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_items_modular] +// A pair of jeggings +const item_jeggings = { + item_id: 'SKU_123', + item_name: 'jeggings', + item_category: 'pants', + item_variant: 'black', + item_brand: 'Google', + price: 9.99 +}; + +// A pair of boots +const item_boots = { + item_id: 'SKU_456', + item_name: 'boots', + item_category: 'shoes', + item_variant: 'brown', + item_brand: 'Google', + price: 24.99 +}; + +// A pair of socks +const item_socks = { + item_id: 'SKU_789', + item_name: 'ankle_socks', + item_category: 'socks', + item_variant: 'red', + item_brand: 'Google', + price: 5.99 +}; +// [END analytics_ecommerce_items_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_payment_info.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_payment_info.js new file mode 100644 index 00000000..048ad5da --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_payment_info.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_payment_info_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce params +const params9 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + payment_type: 'Visa', + items: [item_jeggings] +}; + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'add_payment_info', params9); +// [END analytics_ecommerce_payment_info_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_promotions.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_promotions.js new file mode 100644 index 00000000..d0577a18 --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_promotions.js @@ -0,0 +1,26 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_promotions_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce params +const params12 = { + promotion_id: 'ABC123', + promotion_name: 'Summer Sale', + creative_name: 'summer2020_promo.jpg', + creative_slot: 'featured_app_1', + location_id: 'HERO_BANNER', + items: [item_jeggings] +}; + +// Log event when a promotion is displayed +const analytics = getAnalytics(); +logEvent(analytics, 'view_promotion', params12); + +// Log event when a promotion is selected +logEvent(analytics, 'select_promotion', params12); +// [END analytics_ecommerce_promotions_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_purchase.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_purchase.js new file mode 100644 index 00000000..12b6d02d --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_purchase.js @@ -0,0 +1,25 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_purchase_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce bundle +const params10 = { + transaction_id: 'T12345', + affiliation: 'Google Store', + currency: 'USD', + value: 14.98, // Total Revenue + tax: 2.85, + shipping: 5.34, + coupon: 'SUMMER_FUN', + items: [item_jeggings] +}; + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'purchase', params10); +// [END analytics_ecommerce_purchase_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_refund.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_refund.js new file mode 100644 index 00000000..706e1d7d --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_refund.js @@ -0,0 +1,30 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_refund_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce params +const params11 = { + transaction_id: 'T12345', // Required + affiliation: 'Google Store', + currency: 'USD', + value: 9.99, + items: [] +}; + +// (Optional) For partial refunds, define the item_id and quantity of refunded items +const refundedProduct = { + item_id: 'SKU_123', // Required + quantity: 1 // Required +}; + +params11.items.push(refundedProduct); + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'refund', params11); +// [END analytics_ecommerce_refund_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_remove_cart.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_remove_cart.js new file mode 100644 index 00000000..1ad9790f --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_remove_cart.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_remove_cart_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce params +const params6 = { + currency: 'USD', + value: 24.99, + items: [item_jeggings] +}; + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'remove_from_cart', params6); +// [END analytics_ecommerce_remove_cart_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_select_item.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_select_item.js new file mode 100644 index 00000000..d4eda55c --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_select_item.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_select_item_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce event params +const params2 = { + item_list_id: 'L001', + item_list_name: 'Related products', + items: [item_jeggings] +}; + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'select_item', params2); +// [END analytics_ecommerce_select_item_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_shipping_info.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_shipping_info.js new file mode 100644 index 00000000..a4f43cbe --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_shipping_info.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_shipping_info_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce params +const params8 = { + currency: 'USD', + value: 14.98, // Total Revenue + coupon: 'SUMMER_FUN', + shipping_tier: 'Ground', + items: [item_jeggings] +}; + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'add_shipping_info', params8); +// [END analytics_ecommerce_shipping_info_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_view_cart.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_view_cart.js new file mode 100644 index 00000000..cc2359dc --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_view_cart.js @@ -0,0 +1,31 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_view_cart_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Specify order quantity +const item_jeggings_quantity = { + ...item_jeggings, + quantity: 2 +}; + +const item_boots_quantity = { + ...item_boots, + quantity: 1 +}; + +// Prepare ecommerce params +const params5 = { + currency: 'USD', + value: 44.97, + items: [item_jeggings_quantity, item_boots_quantity] +}; + +// Log event when the cart is viewed +const analytics = getAnalytics(); +logEvent(analytics, 'view_cart', params5); +// [END analytics_ecommerce_view_cart_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_view_item_details.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_view_item_details.js new file mode 100644 index 00000000..83f3474e --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_view_item_details.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_view_item_details_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce event params +const params3 = { + currency: 'USD', + value: 9.99, + items: [item_jeggings] +}; + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'view_item', params3); +// [END analytics_ecommerce_view_item_details_modular] \ No newline at end of file diff --git a/snippets/analytics-next/ecommerce/analytics_ecommerce_view_item_list.js b/snippets/analytics-next/ecommerce/analytics_ecommerce_view_item_list.js new file mode 100644 index 00000000..fb2fec01 --- /dev/null +++ b/snippets/analytics-next/ecommerce/analytics_ecommerce_view_item_list.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/ecommerce.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_ecommerce_view_item_list_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +// Prepare ecommerce params +const params1 = { + item_list_id: 'L001', + item_list_name: 'Related products', + items: [item_jeggings, item_boots, item_socks] +}; + +// Log event +const analytics = getAnalytics(); +logEvent(analytics, 'view_item_list', params1); +// [END analytics_ecommerce_view_item_list_modular] \ No newline at end of file diff --git a/snippets/analytics-next/index/analytics_initialize.js b/snippets/analytics-next/index/analytics_initialize.js new file mode 100644 index 00000000..42a9578d --- /dev/null +++ b/snippets/analytics-next/index/analytics_initialize.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_initialize_modular] +import { getAnalytics } from "firebase/analytics"; + +const analytics = getAnalytics(); +// [END analytics_initialize_modular] \ No newline at end of file diff --git a/snippets/analytics-next/index/analytics_log_event.js b/snippets/analytics-next/index/analytics_log_event.js new file mode 100644 index 00000000..7bd74243 --- /dev/null +++ b/snippets/analytics-next/index/analytics_log_event.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_log_event_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +const analytics = getAnalytics(); +logEvent(analytics, 'notification_received'); +// [END analytics_log_event_modular] \ No newline at end of file diff --git a/snippets/analytics-next/index/analytics_log_event_custom_params.js b/snippets/analytics-next/index/analytics_log_event_custom_params.js new file mode 100644 index 00000000..7d76b3f5 --- /dev/null +++ b/snippets/analytics-next/index/analytics_log_event_custom_params.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_log_event_custom_params_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +const analytics = getAnalytics(); +logEvent(analytics, 'goal_completion', { name: 'lever_puzzle'}); +// [END analytics_log_event_custom_params_modular] \ No newline at end of file diff --git a/snippets/analytics-next/index/analytics_log_event_params.js b/snippets/analytics-next/index/analytics_log_event_params.js new file mode 100644 index 00000000..e79d7ec0 --- /dev/null +++ b/snippets/analytics-next/index/analytics_log_event_params.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_log_event_params_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +const analytics = getAnalytics(); +logEvent(analytics, 'select_content', { + content_type: 'image', + content_id: 'P12453' +}); +// [END analytics_log_event_params_modular] \ No newline at end of file diff --git a/snippets/analytics-next/index/analytics_record_screen_view.js b/snippets/analytics-next/index/analytics_record_screen_view.js new file mode 100644 index 00000000..2eef20b3 --- /dev/null +++ b/snippets/analytics-next/index/analytics_record_screen_view.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_record_screen_view_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +const analytics = getAnalytics(); +logEvent(analytics, 'screen_view', { + firebase_screen: screenName, + firebase_screen_class: screenClass +}); +// [END analytics_record_screen_view_modular] \ No newline at end of file diff --git a/snippets/analytics-next/index/analytics_set_user_properties.js b/snippets/analytics-next/index/analytics_set_user_properties.js new file mode 100644 index 00000000..f432e5bf --- /dev/null +++ b/snippets/analytics-next/index/analytics_set_user_properties.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_set_user_properties_modular] +import { getAnalytics, setUserProperties } from "firebase/analytics"; + +const analytics = getAnalytics(); +setUserProperties(analytics, { favorite_food: 'apples' }); +// [END analytics_set_user_properties_modular] \ No newline at end of file diff --git a/snippets/appcheck-next/index/appcheck_custom_provider.js b/snippets/appcheck-next/index/appcheck_custom_provider.js new file mode 100644 index 00000000..35c7bc99 --- /dev/null +++ b/snippets/appcheck-next/index/appcheck_custom_provider.js @@ -0,0 +1,30 @@ +// This snippet file was generated by processing the source file: +// ./appcheck-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START appcheck_custom_provider_modular] +import { CustomProvider } from "firebase/app-check"; + +const appCheckCustomProvider = new CustomProvider({ + getToken: () => { + return new Promise((resolve, _reject) => { + // TODO: Logic to exchange proof of authenticity for an App Check token and + // expiration time. + + // [START_EXCLUDE] + const tokenFromServer = "abc1234"; + const expirationFromServer = 1234; + // [END_EXCLUDE] + + const appCheckToken = { + token: tokenFromServer, + expireTimeMillis: expirationFromServer * 1000 + }; + + resolve(appCheckToken); + }); + } +}); +// [END appcheck_custom_provider_modular] \ No newline at end of file diff --git a/snippets/appcheck-next/index/appcheck_initialize.js b/snippets/appcheck-next/index/appcheck_initialize.js new file mode 100644 index 00000000..f7763562 --- /dev/null +++ b/snippets/appcheck-next/index/appcheck_initialize.js @@ -0,0 +1,24 @@ +// This snippet file was generated by processing the source file: +// ./appcheck-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START appcheck_initialize_modular] +import { initializeApp } from "firebase/app"; +import { initializeAppCheck, ReCaptchaV3Provider } from "firebase/app-check"; + +const app = initializeApp({ + // Your firebase configuration object +}); + +// Pass your reCAPTCHA v3 site key (public key) to activate(). Make sure this +// key is the counterpart to the secret key you set in the Firebase console. +const appCheck = initializeAppCheck(app, { + provider: new ReCaptchaV3Provider('abcdefghijklmnopqrstuvwxy-1234567890abcd'), + + // Optional argument. If true, the SDK automatically refreshes App Check + // tokens as needed. + isTokenAutoRefreshEnabled: true +}); +// [END appcheck_initialize_modular] \ No newline at end of file diff --git a/snippets/appcheck-next/index/appcheck_initialize_custom_provider.js b/snippets/appcheck-next/index/appcheck_initialize_custom_provider.js new file mode 100644 index 00000000..03f2baa8 --- /dev/null +++ b/snippets/appcheck-next/index/appcheck_initialize_custom_provider.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./appcheck-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START appcheck_initialize_custom_provider_modular] +import { initializeApp } from "firebase/app"; +import { initializeAppCheck } from "firebase/app-check"; + +const app = initializeApp({ + // Your firebase configuration object +}); + +const appCheck = initializeAppCheck(app, { + provider: appCheckCustomProvider, + + // Optional argument. If true, the SDK automatically refreshes App Check + // tokens as needed. + isTokenAutoRefreshEnabled: true +}); +// [END appcheck_initialize_custom_provider_modular] \ No newline at end of file diff --git a/snippets/appcheck-next/index/appcheck_nonfirebase.js b/snippets/appcheck-next/index/appcheck_nonfirebase.js new file mode 100644 index 00000000..275891f8 --- /dev/null +++ b/snippets/appcheck-next/index/appcheck_nonfirebase.js @@ -0,0 +1,33 @@ +// This snippet file was generated by processing the source file: +// ./appcheck-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START appcheck_nonfirebase_modular] +import { initializeAppCheck, getToken } from 'firebase/app-check'; + +const appCheck = initializeAppCheck( + app, + { provider: provider } // ReCaptchaV3Provider or CustomProvider +); + +const callApiWithAppCheckExample = async () => { + let appCheckTokenResponse; + try { + appCheckTokenResponse = await getToken(appCheck, /* forceRefresh= */ false); + } catch (err) { + // Handle any errors if the token was not retrieved. + return; + } + + // Include the App Check token with requests to your server. + const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', { + headers: { + 'X-Firebase-AppCheck': appCheckTokenResponse.token, + } + }); + + // Handle response from your backend. +}; +// [END appcheck_nonfirebase_modular] \ No newline at end of file diff --git a/snippets/auth-next/anonymous/auth_anon_sign_in.js b/snippets/auth-next/anonymous/auth_anon_sign_in.js index 7195632f..3db81772 100644 --- a/snippets/auth-next/anonymous/auth_anon_sign_in.js +++ b/snippets/auth-next/anonymous/auth_anon_sign_in.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/anonymous.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_anon_sign_in_modular] import { getAuth, signInAnonymously } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInAnonymously(auth) .then(() => { // Signed in.. diff --git a/snippets/auth-next/apple/auth_apple_link_facebook.js b/snippets/auth-next/apple/auth_apple_link_facebook.js index 431f2621..1ed9d764 100644 --- a/snippets/auth-next/apple/auth_apple_link_facebook.js +++ b/snippets/auth-next/apple/auth_apple_link_facebook.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_link_facebook_modular] import { getAuth, linkWithPopup, FacebookAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); const provider = new FacebookAuthProvider(); provider.addScope('user_birthday'); diff --git a/snippets/auth-next/apple/auth_apple_nonce_node.js b/snippets/auth-next/apple/auth_apple_nonce_node.js index 27b08552..9dd417a5 100644 --- a/snippets/auth-next/apple/auth_apple_nonce_node.js +++ b/snippets/auth-next/apple/auth_apple_nonce_node.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_nonce_node_modular] const crypto = require("crypto"); @@ -16,7 +17,7 @@ const generateNonce = (length) => { crypto.randomFillSync(buf); nonce = decoder.write(buf); } - return nonce.substr(0, length); + return nonce.slice(0, length); }; const unhashedNonce = generateNonce(10); diff --git a/snippets/auth-next/apple/auth_apple_provider_create.js b/snippets/auth-next/apple/auth_apple_provider_create.js index 9612b2c3..b6c0aefd 100644 --- a/snippets/auth-next/apple/auth_apple_provider_create.js +++ b/snippets/auth-next/apple/auth_apple_provider_create.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_provider_create_modular] import { OAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/apple/auth_apple_provider_params.js b/snippets/auth-next/apple/auth_apple_provider_params.js index f0f914a2..775ab94b 100644 --- a/snippets/auth-next/apple/auth_apple_provider_params.js +++ b/snippets/auth-next/apple/auth_apple_provider_params.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_provider_params_modular] provider.setCustomParameters({ diff --git a/snippets/auth-next/apple/auth_apple_provider_scopes.js b/snippets/auth-next/apple/auth_apple_provider_scopes.js index 306853bd..86da8bbc 100644 --- a/snippets/auth-next/apple/auth_apple_provider_scopes.js +++ b/snippets/auth-next/apple/auth_apple_provider_scopes.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_provider_scopes_modular] provider.addScope('email'); diff --git a/snippets/auth-next/apple/auth_apple_reauthenticate_popup.js b/snippets/auth-next/apple/auth_apple_reauthenticate_popup.js index 2023c2cf..cd40151d 100644 --- a/snippets/auth-next/apple/auth_apple_reauthenticate_popup.js +++ b/snippets/auth-next/apple/auth_apple_reauthenticate_popup.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_reauthenticate_popup_modular] import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth"; // Result from Redirect auth flow. -const auth = getAuth(firebaseApp); +const auth = getAuth(); const provider = new OAuthProvider('apple.com'); reauthenticateWithPopup(auth.currentUser, provider) @@ -31,7 +32,7 @@ reauthenticateWithPopup(auth.currentUser, provider) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); diff --git a/snippets/auth-next/apple/auth_apple_signin_nonce.js b/snippets/auth-next/apple/auth_apple_signin_nonce.js index 7f7dd884..ffa3a3d2 100644 --- a/snippets/auth-next/apple/auth_apple_signin_nonce.js +++ b/snippets/auth-next/apple/auth_apple_signin_nonce.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_signin_nonce_modular] import { getAuth, signInWithCredential, OAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); // Build Firebase credential with the Apple ID token. const provider = new OAuthProvider('apple.com'); diff --git a/snippets/auth-next/apple/auth_apple_signin_popup.js b/snippets/auth-next/apple/auth_apple_signin_popup.js index 1c5cc27f..e3a0f11b 100644 --- a/snippets/auth-next/apple/auth_apple_signin_popup.js +++ b/snippets/auth-next/apple/auth_apple_signin_popup.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_signin_popup_modular] import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // The signed-in user info. @@ -17,6 +18,7 @@ signInWithPopup(auth, provider) const accessToken = credential.accessToken; const idToken = credential.idToken; + // IdP data available using getAdditionalUserInfo(result) // ... }) .catch((error) => { @@ -24,7 +26,7 @@ signInWithPopup(auth, provider) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); diff --git a/snippets/auth-next/apple/auth_apple_signin_redirect.js b/snippets/auth-next/apple/auth_apple_signin_redirect.js index e00445f0..f000195d 100644 --- a/snippets/auth-next/apple/auth_apple_signin_redirect.js +++ b/snippets/auth-next/apple/auth_apple_signin_redirect.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_signin_redirect_modular] import { getAuth, signInWithRedirect } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithRedirect(auth, provider); // [END auth_apple_signin_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/apple/auth_apple_signin_redirect_result.js b/snippets/auth-next/apple/auth_apple_signin_redirect_result.js index 8872d0f7..654f95e5 100644 --- a/snippets/auth-next/apple/auth_apple_signin_redirect_result.js +++ b/snippets/auth-next/apple/auth_apple_signin_redirect_result.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/apple.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_apple_signin_redirect_result_modular] import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth"; // Result from Redirect auth flow. -const auth = getAuth(firebaseApp); +const auth = getAuth(); getRedirectResult(auth) .then((result) => { const credential = OAuthProvider.credentialFromResult(result); @@ -24,7 +25,7 @@ getRedirectResult(auth) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); diff --git a/snippets/auth-next/auth-state-persistence/auth_set_persistence_none.js b/snippets/auth-next/auth-state-persistence/auth_set_persistence_none.js index 5a1ce6fe..5224cc21 100644 --- a/snippets/auth-next/auth-state-persistence/auth_set_persistence_none.js +++ b/snippets/auth-next/auth-state-persistence/auth_set_persistence_none.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/auth-state-persistence.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_set_persistence_none_modular] import { getAuth, setPersistence, signInWithRedirect, inMemoryPersistence, GoogleAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); setPersistence(auth, inMemoryPersistence) .then(() => { const provider = new GoogleAuthProvider(); diff --git a/snippets/auth-next/auth-state-persistence/auth_set_persistence_session.js b/snippets/auth-next/auth-state-persistence/auth_set_persistence_session.js index 26917559..d21183ff 100644 --- a/snippets/auth-next/auth-state-persistence/auth_set_persistence_session.js +++ b/snippets/auth-next/auth-state-persistence/auth_set_persistence_session.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/auth-state-persistence.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_set_persistence_session_modular] import { getAuth, setPersistence, signInWithEmailAndPassword, browserSessionPersistence } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); setPersistence(auth, browserSessionPersistence) .then(() => { // Existing and future Auth states are now persisted in the current diff --git a/snippets/auth-next/cordova/auth_cordova_redirect_result.js b/snippets/auth-next/cordova/auth_cordova_redirect_result.js index d86e7672..f1c87596 100644 --- a/snippets/auth-next/cordova/auth_cordova_redirect_result.js +++ b/snippets/auth-next/cordova/auth_cordova_redirect_result.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/cordova.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_cordova_redirect_result_modular] -import { getAuth, getRedirectResult, GoogleAuthProvider } from "firebase/auth"; +import { getAuth, getRedirectResult, GoogleAuthProvider } from "firebase/auth/cordova"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); getRedirectResult(auth) .then((result) => { const credential = GoogleAuthProvider.credentialFromResult(result); diff --git a/snippets/auth-next/cordova/auth_cordova_sign_in_redirect.js b/snippets/auth-next/cordova/auth_cordova_sign_in_redirect.js index bd7a0360..ed3cc8d1 100644 --- a/snippets/auth-next/cordova/auth_cordova_sign_in_redirect.js +++ b/snippets/auth-next/cordova/auth_cordova_sign_in_redirect.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/cordova.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_cordova_sign_in_redirect_modular] -import { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } from "firebase/auth"; +import { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } from "firebase/auth/cordova"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithRedirect(auth, new GoogleAuthProvider()) .then(() => { return getRedirectResult(auth); diff --git a/snippets/auth-next/cordova/auth_create_google_provider.js b/snippets/auth-next/cordova/auth_create_google_provider.js index 7fb88bc9..fcf96401 100644 --- a/snippets/auth-next/cordova/auth_create_google_provider.js +++ b/snippets/auth-next/cordova/auth_create_google_provider.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./auth-next/cordova.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_create_google_provider_modular] -import { GoogleAuthProvider } from "firebase/auth"; +import { GoogleAuthProvider } from "firebase/auth/cordova"; const provider = new GoogleAuthProvider(); // [END auth_create_google_provider_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-dependencies/auth_get_auth_equivalent.js b/snippets/auth-next/custom-dependencies/auth_get_auth_equivalent.js new file mode 100644 index 00000000..37292487 --- /dev/null +++ b/snippets/auth-next/custom-dependencies/auth_get_auth_equivalent.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/custom-dependencies.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_get_auth_equivalent_modular] +import {initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, browserSessionPersistence, indexedDBLocalPersistence} from "firebase/auth"; +import {initializeApp} from "firebase/app"; + +const app = initializeApp({/** Your app config */}); +const auth = initializeAuth(app, { + persistence: [indexedDBLocalPersistence, browserLocalPersistence, browserSessionPersistence], + popupRedirectResolver: browserPopupRedirectResolver, +}); +// [END auth_get_auth_equivalent_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-dependencies/auth_only_browser_local.js b/snippets/auth-next/custom-dependencies/auth_only_browser_local.js new file mode 100644 index 00000000..549307ac --- /dev/null +++ b/snippets/auth-next/custom-dependencies/auth_only_browser_local.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/custom-dependencies.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_only_browser_local_modular] +import {initializeAuth, browserLocalPersistence} from "firebase/auth"; +import {initializeApp} from "firebase/app"; + +const app = initializeApp({/** Your app config */}); +const auth = initializeAuth(app, { + persistence: browserLocalPersistence, + // No popupRedirectResolver defined +}); +// [END auth_only_browser_local_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-dependencies/auth_only_indexed_db.js b/snippets/auth-next/custom-dependencies/auth_only_indexed_db.js new file mode 100644 index 00000000..1427ae6b --- /dev/null +++ b/snippets/auth-next/custom-dependencies/auth_only_indexed_db.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/custom-dependencies.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_only_indexed_db_modular] +import {initializeAuth, indexedDBLocalPersistence} from "firebase/auth"; +import {initializeApp} from "firebase/app"; + +const app = initializeApp({/** Your app config */}); +const auth = initializeAuth(app, { + persistence: indexedDBLocalPersistence, + // No popupRedirectResolver defined +}); +// [END auth_only_indexed_db_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-dependencies/auth_sign_in_redirect_manual_deps.js b/snippets/auth-next/custom-dependencies/auth_sign_in_redirect_manual_deps.js new file mode 100644 index 00000000..75fd0d5d --- /dev/null +++ b/snippets/auth-next/custom-dependencies/auth_sign_in_redirect_manual_deps.js @@ -0,0 +1,18 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/custom-dependencies.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_sign_in_redirect_manual_deps_modular] +import {initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, indexedDBLocalPersistence, signInWithRedirect, GoogleAuthProvider} from "firebase/auth"; +import {initializeApp} from "firebase/app"; + +const app = initializeApp({/** Your app config */}); +const auth = initializeAuth(app, { + persistence: [indexedDBLocalPersistence, browserLocalPersistence], +}); + +// Later +signInWithRedirect(auth, new GoogleAuthProvider(), browserPopupRedirectResolver); +// [END auth_sign_in_redirect_manual_deps_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-email-handler/auth_handle_mgmt_query_params.js b/snippets/auth-next/custom-email-handler/auth_handle_mgmt_query_params.js index 8810372f..d0a22696 100644 --- a/snippets/auth-next/custom-email-handler/auth_handle_mgmt_query_params.js +++ b/snippets/auth-next/custom-email-handler/auth_handle_mgmt_query_params.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/custom-email-handler.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_handle_mgmt_query_params_modular] import { initializeApp } from "firebase/app"; @@ -22,8 +23,8 @@ document.addEventListener('DOMContentLoaded', () => { // Configure the Firebase SDK. // This is the minimum configuration required for the API to be used. const config = { - 'apiKey': "YOU_API_KEY" // Copy this key from the web initialization - // snippet found in the Firebase console. + 'apiKey': "YOUR_API_KEY" // Copy this key from the web initialization + // snippet found in the Firebase console. }; const app = initializeApp(config); const auth = getAuth(app); diff --git a/snippets/auth-next/custom-email-handler/auth_handle_recover_email.js b/snippets/auth-next/custom-email-handler/auth_handle_recover_email.js index db2bdea8..a4351a50 100644 --- a/snippets/auth-next/custom-email-handler/auth_handle_recover_email.js +++ b/snippets/auth-next/custom-email-handler/auth_handle_recover_email.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/custom-email-handler.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_handle_recover_email_modular] import { checkActionCode, applyActionCode, sendPasswordResetEmail } from "firebase/auth"; diff --git a/snippets/auth-next/custom-email-handler/auth_handle_reset_password.js b/snippets/auth-next/custom-email-handler/auth_handle_reset_password.js index 85f32168..95a3faea 100644 --- a/snippets/auth-next/custom-email-handler/auth_handle_reset_password.js +++ b/snippets/auth-next/custom-email-handler/auth_handle_reset_password.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/custom-email-handler.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_handle_reset_password_modular] import { verifyPasswordResetCode, confirmPasswordReset } from "firebase/auth"; diff --git a/snippets/auth-next/custom-email-handler/auth_handle_verify_email.js b/snippets/auth-next/custom-email-handler/auth_handle_verify_email.js index ca0089f0..730d4601 100644 --- a/snippets/auth-next/custom-email-handler/auth_handle_verify_email.js +++ b/snippets/auth-next/custom-email-handler/auth_handle_verify_email.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/custom-email-handler.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_handle_verify_email_modular] function handleVerifyEmail(auth, actionCode, continueUrl, lang) { diff --git a/snippets/auth-next/custom/auth_sign_in_custom.js b/snippets/auth-next/custom/auth_sign_in_custom.js index c22ed725..c345c0ce 100644 --- a/snippets/auth-next/custom/auth_sign_in_custom.js +++ b/snippets/auth-next/custom/auth_sign_in_custom.js @@ -1,15 +1,17 @@ // This snippet file was generated by processing the source file: // ./auth-next/custom.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_sign_in_custom_modular] import { getAuth, signInWithCustomToken } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithCustomToken(auth, token) - .then((user) => { + .then((userCredential) => { // Signed in + const user = userCredential.user; // ... }) .catch((error) => { diff --git a/snippets/auth-next/email-link-auth/auth_email_link_actioncode_settings.js b/snippets/auth-next/email-link-auth/auth_email_link_actioncode_settings.js index dd6f4de2..010b5c09 100644 --- a/snippets/auth-next/email-link-auth/auth_email_link_actioncode_settings.js +++ b/snippets/auth-next/email-link-auth/auth_email_link_actioncode_settings.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/email-link-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_email_link_actioncode_settings_modular] const actionCodeSettings = { @@ -18,6 +19,7 @@ const actionCodeSettings = { installApp: true, minimumVersion: '12' }, - dynamicLinkDomain: 'example.page.link' + // The domain must be configured in Firebase Hosting and owned by the project. + linkDomain: 'custom-domain.com' }; // [END auth_email_link_actioncode_settings_modular] \ No newline at end of file diff --git a/snippets/auth-next/email-link-auth/auth_email_link_link.js b/snippets/auth-next/email-link-auth/auth_email_link_link.js index 8c0147ed..a49b979f 100644 --- a/snippets/auth-next/email-link-auth/auth_email_link_link.js +++ b/snippets/auth-next/email-link-auth/auth_email_link_link.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/email-link-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_email_link_link_modular] import { getAuth, linkWithCredential, EmailAuthProvider } from "firebase/auth"; @@ -11,7 +12,7 @@ const credential = EmailAuthProvider.credentialWithLink( email, window.location.href); // Link the credential to the current user. -const auth = getAuth(firebaseApp); +const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { // The provider is now successfully linked. diff --git a/snippets/auth-next/email-link-auth/auth_email_link_reauth.js b/snippets/auth-next/email-link-auth/auth_email_link_reauth.js index e72b1c24..128650cb 100644 --- a/snippets/auth-next/email-link-auth/auth_email_link_reauth.js +++ b/snippets/auth-next/email-link-auth/auth_email_link_reauth.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/email-link-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_email_link_reauth_modular] import { getAuth, reauthenticateWithCredential, EmailAuthProvider } from "firebase/auth"; @@ -11,7 +12,7 @@ const credential = EmailAuthProvider.credentialWithLink( email, window.location.href); // Re-authenticate the user with this credential. -const auth = getAuth(firebaseApp); +const auth = getAuth(); reauthenticateWithCredential(auth.currentUser, credential) .then((usercred) => { // The user is now successfully re-authenticated and can execute sensitive diff --git a/snippets/auth-next/email-link-auth/auth_email_link_send.js b/snippets/auth-next/email-link-auth/auth_email_link_send.js index 6fe2c15e..5b97d87f 100644 --- a/snippets/auth-next/email-link-auth/auth_email_link_send.js +++ b/snippets/auth-next/email-link-auth/auth_email_link_send.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/email-link-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_email_link_send_modular] import { getAuth, sendSignInLinkToEmail } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); sendSignInLinkToEmail(auth, email, actionCodeSettings) .then(() => { // The link was successfully sent. Inform the user. diff --git a/snippets/auth-next/email-link-auth/email_link_complete.js b/snippets/auth-next/email-link-auth/email_link_complete.js index af6b28ef..dbe1143d 100644 --- a/snippets/auth-next/email-link-auth/email_link_complete.js +++ b/snippets/auth-next/email-link-auth/email_link_complete.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/email-link-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START email_link_complete_modular] import { getAuth, isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth"; // Confirm the link is a sign-in with email link. -const auth = getAuth(firebaseApp); +const auth = getAuth(); if (isSignInWithEmailLink(auth, window.location.href)) { // Additional state parameters can also be passed via URL. // This can be used to continue the user's intended action before triggering @@ -25,11 +26,13 @@ if (isSignInWithEmailLink(auth, window.location.href)) { .then((result) => { // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); - // You can access the new user via result.user - // Additional user info profile not available via: - // result.additionalUserInfo.profile == null + // You can access the new user by importing getAdditionalUserInfo + // and calling it with result: + // getAdditionalUserInfo(result) + // You can access the user's profile via: + // getAdditionalUserInfo(result)?.profile // You can check if the user is new or existing: - // result.additionalUserInfo.isNewUser + // getAdditionalUserInfo(result)?.isNewUser }) .catch((error) => { // Some error occurred, you can inspect the code: error.code diff --git a/snippets/auth-next/email-link-auth/email_link_diferentiate.js b/snippets/auth-next/email-link-auth/email_link_diferentiate.js index 53bc1f32..4fc06b41 100644 --- a/snippets/auth-next/email-link-auth/email_link_diferentiate.js +++ b/snippets/auth-next/email-link-auth/email_link_diferentiate.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/email-link-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START email_link_diferentiate_modular] import { getAuth, fetchSignInMethodsForEmail, EmailAuthProvider} from "firebase/auth"; @@ -9,7 +10,7 @@ import { getAuth, fetchSignInMethodsForEmail, EmailAuthProvider} from "firebase/ // After asking the user for their email. const email = window.prompt('Please provide your email'); -const auth = getAuth(firebaseApp); +const auth = getAuth(); fetchSignInMethodsForEmail(auth, email) .then((signInMethods) => { // This returns the same array as fetchProvidersForEmail but for email diff --git a/snippets/auth-next/email/auth_send_email_verification.js b/snippets/auth-next/email/auth_send_email_verification.js index a5e310c4..9290a421 100644 --- a/snippets/auth-next/email/auth_send_email_verification.js +++ b/snippets/auth-next/email/auth_send_email_verification.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/email.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_send_email_verification_modular] import { getAuth, sendEmailVerification } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); sendEmailVerification(auth.currentUser) .then(() => { // Email verification sent! diff --git a/snippets/auth-next/email/auth_send_password_reset.js b/snippets/auth-next/email/auth_send_password_reset.js index 86458fa1..e8e18a58 100644 --- a/snippets/auth-next/email/auth_send_password_reset.js +++ b/snippets/auth-next/email/auth_send_password_reset.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/email.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_send_password_reset_modular] import { getAuth, sendPasswordResetEmail } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); sendPasswordResetEmail(auth, email) .then(() => { // Password reset email sent! diff --git a/snippets/auth-next/email/auth_signin_password.js b/snippets/auth-next/email/auth_signin_password.js index d04a492e..f0a211d5 100644 --- a/snippets/auth-next/email/auth_signin_password.js +++ b/snippets/auth-next/email/auth_signin_password.js @@ -1,15 +1,17 @@ // This snippet file was generated by processing the source file: // ./auth-next/email.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_signin_password_modular] import { getAuth, signInWithEmailAndPassword } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithEmailAndPassword(auth, email, password) - .then((user) => { + .then((userCredential) => { // Signed in + const user = userCredential.user; // ... }) .catch((error) => { diff --git a/snippets/auth-next/email/auth_signup_password.js b/snippets/auth-next/email/auth_signup_password.js index de1e38bb..936b64ce 100644 --- a/snippets/auth-next/email/auth_signup_password.js +++ b/snippets/auth-next/email/auth_signup_password.js @@ -1,15 +1,17 @@ // This snippet file was generated by processing the source file: // ./auth-next/email.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_signup_password_modular] import { getAuth, createUserWithEmailAndPassword } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); createUserWithEmailAndPassword(auth, email, password) - .then((user) => { - // Signed in + .then((userCredential) => { + // Signed up + const user = userCredential.user; // ... }) .catch((error) => { diff --git a/snippets/auth-next/emulator-suite/auth_emulator_connect.js b/snippets/auth-next/emulator-suite/auth_emulator_connect.js new file mode 100644 index 00000000..525a92b8 --- /dev/null +++ b/snippets/auth-next/emulator-suite/auth_emulator_connect.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/emulator-suite.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_emulator_connect_modular] +import { getAuth, connectAuthEmulator } from "firebase/auth"; + +const auth = getAuth(); +connectAuthEmulator(auth, "http://127.0.0.1:9099"); +// [END auth_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/auth-next/emulator-suite/auth_emulator_google_credential.js b/snippets/auth-next/emulator-suite/auth_emulator_google_credential.js new file mode 100644 index 00000000..d3683bb0 --- /dev/null +++ b/snippets/auth-next/emulator-suite/auth_emulator_google_credential.js @@ -0,0 +1,14 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/emulator-suite.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_emulator_google_credential_modular] +import { getAuth, signInWithCredential, GoogleAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +signInWithCredential(auth, GoogleAuthProvider.credential( + '{"sub": "abc123", "email": "foo@example.com", "email_verified": true}' +)); +// [END auth_emulator_google_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/facebook/auth_facebook_callback.js b/snippets/auth-next/facebook/auth_facebook_callback.js index 489cabf9..63106871 100644 --- a/snippets/auth-next/facebook/auth_facebook_callback.js +++ b/snippets/auth-next/facebook/auth_facebook_callback.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./auth-next/facebook.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_facebook_callback_modular] import { getAuth, onAuthStateChanged, signInWithCredential, signOut, FacebookAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); function checkLoginState(response) { if (response.authResponse) { @@ -25,7 +26,7 @@ function checkLoginState(response) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/facebook/auth_facebook_checksameuser.js b/snippets/auth-next/facebook/auth_facebook_checksameuser.js index e4ed4845..0b1d170b 100644 --- a/snippets/auth-next/facebook/auth_facebook_checksameuser.js +++ b/snippets/auth-next/facebook/auth_facebook_checksameuser.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/facebook.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_facebook_checksameuser_modular] import { FacebookAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/facebook/auth_facebook_provider_create.js b/snippets/auth-next/facebook/auth_facebook_provider_create.js index 93913be7..403abcd2 100644 --- a/snippets/auth-next/facebook/auth_facebook_provider_create.js +++ b/snippets/auth-next/facebook/auth_facebook_provider_create.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/facebook.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_facebook_provider_create_modular] import { FacebookAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/facebook/auth_facebook_provider_credential.js b/snippets/auth-next/facebook/auth_facebook_provider_credential.js new file mode 100644 index 00000000..b7bbca25 --- /dev/null +++ b/snippets/auth-next/facebook/auth_facebook_provider_credential.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/facebook.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_facebook_provider_credential_modular] +import { FacebookAuthProvider } from "firebase/auth"; + +const credential = FacebookAuthProvider.credential(accessToken); +// [END auth_facebook_provider_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/facebook/auth_facebook_provider_params.js b/snippets/auth-next/facebook/auth_facebook_provider_params.js index 04c8532b..308fadd4 100644 --- a/snippets/auth-next/facebook/auth_facebook_provider_params.js +++ b/snippets/auth-next/facebook/auth_facebook_provider_params.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/facebook.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_facebook_provider_params_modular] provider.setCustomParameters({ diff --git a/snippets/auth-next/facebook/auth_facebook_provider_scopes.js b/snippets/auth-next/facebook/auth_facebook_provider_scopes.js index ba67a6f3..06386449 100644 --- a/snippets/auth-next/facebook/auth_facebook_provider_scopes.js +++ b/snippets/auth-next/facebook/auth_facebook_provider_scopes.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/facebook.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // / [START auth_facebook_provider_scopes_modular] provider.addScope('user_birthday'); diff --git a/snippets/auth-next/facebook/auth_facebook_signin_credential.js b/snippets/auth-next/facebook/auth_facebook_signin_credential.js index a5d8e551..3b784f24 100644 --- a/snippets/auth-next/facebook/auth_facebook_signin_credential.js +++ b/snippets/auth-next/facebook/auth_facebook_signin_credential.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/facebook.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_facebook_signin_credential_modular] import { getAuth, signInWithCredential, FacebookAuthProvider } from "firebase/auth"; // Sign in with the credential from the Facebook user. -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithCredential(auth, credential) .then((result) => { // Signed in @@ -18,7 +19,7 @@ signInWithCredential(auth, credential) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/facebook/auth_facebook_signin_popup.js b/snippets/auth-next/facebook/auth_facebook_signin_popup.js index 65cc1fd1..524a11ac 100644 --- a/snippets/auth-next/facebook/auth_facebook_signin_popup.js +++ b/snippets/auth-next/facebook/auth_facebook_signin_popup.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/facebook.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_facebook_signin_popup_modular] import { getAuth, signInWithPopup, FacebookAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // The signed-in user info. @@ -16,6 +17,7 @@ signInWithPopup(auth, provider) const credential = FacebookAuthProvider.credentialFromResult(result); const accessToken = credential.accessToken; + // IdP data available using getAdditionalUserInfo(result) // ... }) .catch((error) => { @@ -23,7 +25,7 @@ signInWithPopup(auth, provider) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); diff --git a/snippets/auth-next/facebook/auth_facebook_signin_redirect_result.js b/snippets/auth-next/facebook/auth_facebook_signin_redirect_result.js index a70191dc..c65c47d7 100644 --- a/snippets/auth-next/facebook/auth_facebook_signin_redirect_result.js +++ b/snippets/auth-next/facebook/auth_facebook_signin_redirect_result.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/facebook.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_facebook_signin_redirect_result_modular] import { getAuth, getRedirectResult, FacebookAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); getRedirectResult(auth) .then((result) => { // This gives you a Facebook Access Token. You can use it to access the Facebook API. @@ -14,12 +15,14 @@ getRedirectResult(auth) const token = credential.accessToken; const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/github/auth_github_provider_create.js b/snippets/auth-next/github/auth_github_provider_create.js index eb5250d9..92cc4171 100644 --- a/snippets/auth-next/github/auth_github_provider_create.js +++ b/snippets/auth-next/github/auth_github_provider_create.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/github.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_github_provider_create_modular] import { GithubAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/github/auth_github_provider_credential.js b/snippets/auth-next/github/auth_github_provider_credential.js new file mode 100644 index 00000000..ca122a35 --- /dev/null +++ b/snippets/auth-next/github/auth_github_provider_credential.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/github.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_github_provider_credential_modular] +import { GithubAuthProvider } from "firebase/auth"; + +const credential = GithubAuthProvider.credential(token); +// [END auth_github_provider_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/github/auth_github_provider_params.js b/snippets/auth-next/github/auth_github_provider_params.js index 159dcd8c..e2d4f341 100644 --- a/snippets/auth-next/github/auth_github_provider_params.js +++ b/snippets/auth-next/github/auth_github_provider_params.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/github.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_github_provider_params_modular] provider.setCustomParameters({ diff --git a/snippets/auth-next/github/auth_github_provider_scopes.js b/snippets/auth-next/github/auth_github_provider_scopes.js index 09f26298..b9237208 100644 --- a/snippets/auth-next/github/auth_github_provider_scopes.js +++ b/snippets/auth-next/github/auth_github_provider_scopes.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/github.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_github_provider_scopes_modular] provider.addScope('repo'); diff --git a/snippets/auth-next/github/auth_github_signin_popup.js b/snippets/auth-next/github/auth_github_signin_popup.js index b5ac46a2..3839a70f 100644 --- a/snippets/auth-next/github/auth_github_signin_popup.js +++ b/snippets/auth-next/github/auth_github_signin_popup.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/github.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_github_signin_popup_modular] import { getAuth, signInWithPopup, GithubAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // This gives you a GitHub Access Token. You can use it to access the GitHub API. @@ -15,13 +16,14 @@ signInWithPopup(auth, provider) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GithubAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/github/auth_github_signin_redirect_result.js b/snippets/auth-next/github/auth_github_signin_redirect_result.js index 423440fa..fb5f7ca2 100644 --- a/snippets/auth-next/github/auth_github_signin_redirect_result.js +++ b/snippets/auth-next/github/auth_github_signin_redirect_result.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/github.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_github_signin_redirect_result_modular] import { getAuth, getRedirectResult, GithubAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); getRedirectResult(auth) .then((result) => { const credential = GithubAuthProvider.credentialFromResult(result); @@ -18,12 +19,14 @@ getRedirectResult(auth) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GithubAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_build_signin.js b/snippets/auth-next/google-signin/auth_google_build_signin.js index a462cb9e..98f35eb2 100644 --- a/snippets/auth-next/google-signin/auth_google_build_signin.js +++ b/snippets/auth-next/google-signin/auth_google_build_signin.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_build_signin_modular] import { getAuth, signInWithCredential, GoogleAuthProvider } from "firebase/auth"; @@ -10,13 +11,13 @@ import { getAuth, signInWithCredential, GoogleAuthProvider } from "firebase/auth const credential = GoogleAuthProvider.credential(id_token); // Sign in with credential from the Google user. -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithCredential(auth, credential).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_callback.js b/snippets/auth-next/google-signin/auth_google_callback.js index c79fc89f..873778dd 100644 --- a/snippets/auth-next/google-signin/auth_google_callback.js +++ b/snippets/auth-next/google-signin/auth_google_callback.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_callback_modular] import { getAuth, onAuthStateChanged, signInWithCredential, GoogleAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); function onSignIn(googleUser) { console.log('Google Auth Response', googleUser); @@ -24,7 +25,7 @@ function onSignIn(googleUser) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_checksameuser.js b/snippets/auth-next/google-signin/auth_google_checksameuser.js index e2a7cad9..cc451991 100644 --- a/snippets/auth-next/google-signin/auth_google_checksameuser.js +++ b/snippets/auth-next/google-signin/auth_google_checksameuser.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_checksameuser_modular] import { GoogleAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/google-signin/auth_google_provider_create.js b/snippets/auth-next/google-signin/auth_google_provider_create.js index 6d696d21..76b356d6 100644 --- a/snippets/auth-next/google-signin/auth_google_provider_create.js +++ b/snippets/auth-next/google-signin/auth_google_provider_create.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_provider_create_modular] import { GoogleAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/google-signin/auth_google_provider_credential.js b/snippets/auth-next/google-signin/auth_google_provider_credential.js new file mode 100644 index 00000000..924aa167 --- /dev/null +++ b/snippets/auth-next/google-signin/auth_google_provider_credential.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/google-signin.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_google_provider_credential_modular] +import { GoogleAuthProvider } from "firebase/auth"; + +const credential = GoogleAuthProvider.credential(idToken); +// [END auth_google_provider_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/google-signin/auth_google_provider_params.js b/snippets/auth-next/google-signin/auth_google_provider_params.js index 4799da72..25f1ea99 100644 --- a/snippets/auth-next/google-signin/auth_google_provider_params.js +++ b/snippets/auth-next/google-signin/auth_google_provider_params.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_provider_params_modular] provider.setCustomParameters({ diff --git a/snippets/auth-next/google-signin/auth_google_provider_scopes.js b/snippets/auth-next/google-signin/auth_google_provider_scopes.js index f370a854..346b6432 100644 --- a/snippets/auth-next/google-signin/auth_google_provider_scopes.js +++ b/snippets/auth-next/google-signin/auth_google_provider_scopes.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_provider_scopes_modular] provider.addScope('https://www.googleapis.com/auth/contacts.readonly'); diff --git a/snippets/auth-next/google-signin/auth_google_signin_credential.js b/snippets/auth-next/google-signin/auth_google_signin_credential.js index 6c8a5641..25c6f3ba 100644 --- a/snippets/auth-next/google-signin/auth_google_signin_credential.js +++ b/snippets/auth-next/google-signin/auth_google_signin_credential.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_signin_credential_modular] signInWithCredential(auth, credential).catch((error) => { @@ -9,7 +10,7 @@ signInWithCredential(auth, credential).catch((error) => { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_signin_popup.js b/snippets/auth-next/google-signin/auth_google_signin_popup.js index b5763bf8..433bb88e 100644 --- a/snippets/auth-next/google-signin/auth_google_signin_popup.js +++ b/snippets/auth-next/google-signin/auth_google_signin_popup.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_signin_popup_modular] import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // This gives you a Google Access Token. You can use it to access the Google API. @@ -14,13 +15,14 @@ signInWithPopup(auth, provider) const token = credential.accessToken; // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_signin_redirect_result.js b/snippets/auth-next/google-signin/auth_google_signin_redirect_result.js index 410eae3f..2953ab5f 100644 --- a/snippets/auth-next/google-signin/auth_google_signin_redirect_result.js +++ b/snippets/auth-next/google-signin/auth_google_signin_redirect_result.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/google-signin.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_google_signin_redirect_result_modular] import { getAuth, getRedirectResult, GoogleAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); getRedirectResult(auth) .then((result) => { // This gives you a Google Access Token. You can use it to access Google APIs. @@ -15,12 +16,14 @@ getRedirectResult(auth) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/index/auth_current_user.js b/snippets/auth-next/index/auth_current_user.js new file mode 100644 index 00000000..6925b021 --- /dev/null +++ b/snippets/auth-next/index/auth_current_user.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_current_user_modular] +import { getAuth } from "firebase/auth"; + +const auth = getAuth(); +const user = auth.currentUser; + +if (user) { + // User is signed in, see docs for a list of available properties + // https://firebase.google.com/docs/reference/js/auth.user + // ... +} else { + // No user is signed in. +} +// [END auth_current_user_modular] \ No newline at end of file diff --git a/snippets/auth-next/index/auth_init_custom_domain.js b/snippets/auth-next/index/auth_init_custom_domain.js new file mode 100644 index 00000000..971e5c56 --- /dev/null +++ b/snippets/auth-next/index/auth_init_custom_domain.js @@ -0,0 +1,17 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_init_custom_domain_modular] +import { initializeApp } from "firebase/app"; + +const firebaseConfig = { + apiKey: "...", + // By default, authDomain is '[YOUR_APP].firebaseapp.com'. + // You may replace it with a custom domain. + authDomain: '[YOUR_CUSTOM_DOMAIN]' +}; +const firebaseApp = initializeApp(firebaseConfig); +// [END auth_init_custom_domain_modular] \ No newline at end of file diff --git a/snippets/auth-next/index/auth_make_email_credential.js b/snippets/auth-next/index/auth_make_email_credential.js index 7009633b..6487fe62 100644 --- a/snippets/auth-next/index/auth_make_email_credential.js +++ b/snippets/auth-next/index/auth_make_email_credential.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_make_email_credential_modular] import { EmailAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/index/auth_make_facebook_credential.js b/snippets/auth-next/index/auth_make_facebook_credential.js index 7a68e3b7..91f5ae63 100644 --- a/snippets/auth-next/index/auth_make_facebook_credential.js +++ b/snippets/auth-next/index/auth_make_facebook_credential.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_make_facebook_credential_modular] import { FacebookAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/index/auth_make_google_credential.js b/snippets/auth-next/index/auth_make_google_credential.js index 007bb7eb..2640d101 100644 --- a/snippets/auth-next/index/auth_make_google_credential.js +++ b/snippets/auth-next/index/auth_make_google_credential.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_make_google_credential_modular] import { GoogleAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/index/auth_set_language_code.js b/snippets/auth-next/index/auth_set_language_code.js index de11d4ce..fe9a2025 100644 --- a/snippets/auth-next/index/auth_set_language_code.js +++ b/snippets/auth-next/index/auth_set_language_code.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_set_language_code_modular] import { getAuth } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); auth.languageCode = 'it'; // To apply the default browser preference instead of explicitly setting it. -// firebase.auth().useDeviceLanguage(); +// auth.useDeviceLanguage(); // [END auth_set_language_code_modular] \ No newline at end of file diff --git a/snippets/auth-next/index/auth_sign_out.js b/snippets/auth-next/index/auth_sign_out.js index 9387b791..4cef4757 100644 --- a/snippets/auth-next/index/auth_sign_out.js +++ b/snippets/auth-next/index/auth_sign_out.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_sign_out_modular] import { getAuth, signOut } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signOut(auth).then(() => { // Sign-out successful. }).catch((error) => { diff --git a/snippets/auth-next/index/auth_signin_credential.js b/snippets/auth-next/index/auth_signin_credential.js index 6885e033..c2b027a3 100644 --- a/snippets/auth-next/index/auth_signin_credential.js +++ b/snippets/auth-next/index/auth_signin_credential.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_signin_credential_modular] import { getAuth, signInWithCredential } from "firebase/auth"; // Sign in with the credential from the user. -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithCredential(auth, credential) .then((result) => { // Signed in @@ -18,7 +19,7 @@ signInWithCredential(auth, credential) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // ... }); // [END auth_signin_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/index/auth_signin_redirect.js b/snippets/auth-next/index/auth_signin_redirect.js index 9062ac87..49c95513 100644 --- a/snippets/auth-next/index/auth_signin_redirect.js +++ b/snippets/auth-next/index/auth_signin_redirect.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./auth-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_signin_redirect_modular] import { getAuth, signInWithRedirect } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithRedirect(auth, provider); // [END auth_signin_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/index/auth_state_listener.js b/snippets/auth-next/index/auth_state_listener.js index 04f58e21..0f3e4e88 100644 --- a/snippets/auth-next/index/auth_state_listener.js +++ b/snippets/auth-next/index/auth_state_listener.js @@ -1,16 +1,17 @@ // This snippet file was generated by processing the source file: // ./auth-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_state_listener_modular] import { getAuth, onAuthStateChanged } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); onAuthStateChanged(auth, (user) => { if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/auth.user const uid = user.uid; // ... } else { diff --git a/snippets/auth-next/link-multiple-accounts/account_exists_popup.js b/snippets/auth-next/link-multiple-accounts/account_exists_popup.js new file mode 100644 index 00000000..2c667882 --- /dev/null +++ b/snippets/auth-next/link-multiple-accounts/account_exists_popup.js @@ -0,0 +1,61 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/link-multiple-accounts.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + + // [START account_exists_popup_modular] + import { signInWithPopup, signInWithEmailAndPassword, linkWithCredential } from "firebase/auth"; + + // User tries to sign in with Facebook. + signInWithPopup(auth, facebookProvider).catch((error) => { + // User's email already exists. + if (error.code === 'auth/account-exists-with-different-credential') { + // The pending Facebook credential. + const pendingCred = error.credential; + // The provider account's email address. + const email = error.customData.email; + + // Present the user with a list of providers they might have + // used to create the original account. + // Then, ask the user to sign in with the existing provider. + const method = promptUserForSignInMethod(); + + if (method === 'password') { + // TODO: Ask the user for their password. + // In real scenario, you should handle this asynchronously. + const password = promptUserForPassword(); + signInWithEmailAndPassword(auth, email, password).then((result) => { + return linkWithCredential(result.user, pendingCred); + }).then(() => { + // Facebook account successfully linked to the existing user. + goToApp(); + }); + return; + } + + // All other cases are external providers. + // Construct provider object for that provider. + // TODO: Implement getProviderForProviderId. + const provider = getProviderForProviderId(method); + // At this point, you should let the user know that they already have an + // account with a different provider, and validate they want to sign in + // with the new provider. + // Note: Browsers usually block popups triggered asynchronously, so in + // real app, you should ask the user to click on a "Continue" button + // that will trigger signInWithPopup(). + signInWithPopup(auth, provider).then((result) => { + // Note: Identity Platform doesn't control the provider's sign-in + // flow, so it's possible for the user to sign in with an account + // with a different email from the first one. + + // Link the Facebook credential. We have access to the pending + // credential, so we can directly call the link method. + linkWithCredential(result.user, pendingCred).then((userCred) => { + // Success. + goToApp(); + }); + }); + } +}); +// [END account_exists_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/link-multiple-accounts/auth_anonymous_link.js b/snippets/auth-next/link-multiple-accounts/auth_anonymous_link.js index fdffb99e..3bf9ab56 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_anonymous_link.js +++ b/snippets/auth-next/link-multiple-accounts/auth_anonymous_link.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_anonymous_link_modular] import { getAuth, linkWithCredential } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { const user = usercred.user; diff --git a/snippets/auth-next/link-multiple-accounts/auth_get_providers.js b/snippets/auth-next/link-multiple-accounts/auth_get_providers.js index 2550bdd7..0f1ebbc1 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_get_providers.js +++ b/snippets/auth-next/link-multiple-accounts/auth_get_providers.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_get_providers_modular] import { GoogleAuthProvider, FacebookAuthProvider, TwitterAuthProvider, GithubAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/link-multiple-accounts/auth_get_redirect_result.js b/snippets/auth-next/link-multiple-accounts/auth_get_redirect_result.js index 2118d9ba..1608a933 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_get_redirect_result.js +++ b/snippets/auth-next/link-multiple-accounts/auth_get_redirect_result.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_get_redirect_result_modular] import { getRedirectResult } from "firebase/auth"; diff --git a/snippets/auth-next/link-multiple-accounts/auth_link_with_popup.js b/snippets/auth-next/link-multiple-accounts/auth_link_with_popup.js index b7ff7374..b6619cad 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_link_with_popup.js +++ b/snippets/auth-next/link-multiple-accounts/auth_link_with_popup.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_link_with_popup_modular] import { getAuth, linkWithPopup, GoogleAuthProvider } from "firebase/auth"; const provider = new GoogleAuthProvider(); -const auth = getAuth(firebaseApp); +const auth = getAuth(); linkWithPopup(auth.currentUser, provider).then((result) => { // Accounts successfully linked. const credential = GoogleAuthProvider.credentialFromResult(result); diff --git a/snippets/auth-next/link-multiple-accounts/auth_link_with_redirect.js b/snippets/auth-next/link-multiple-accounts/auth_link_with_redirect.js index 4df66560..1e496f42 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_link_with_redirect.js +++ b/snippets/auth-next/link-multiple-accounts/auth_link_with_redirect.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_link_with_redirect_modular] import { getAuth, linkWithRedirect, GoogleAuthProvider } from "firebase/auth"; const provider = new GoogleAuthProvider(); -const auth = getAuth(firebaseApp); +const auth = getAuth(); linkWithRedirect(auth.currentUser, provider) .then(/* ... */) .catch(/* ... */); diff --git a/snippets/auth-next/link-multiple-accounts/auth_make_email_credential.js b/snippets/auth-next/link-multiple-accounts/auth_make_email_credential.js index e78c54e1..861d77e8 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_make_email_credential.js +++ b/snippets/auth-next/link-multiple-accounts/auth_make_email_credential.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_make_email_credential_modular] import { EmailAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/link-multiple-accounts/auth_merge_accounts.js b/snippets/auth-next/link-multiple-accounts/auth_merge_accounts.js index 1f7205f2..f7cc113c 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_merge_accounts.js +++ b/snippets/auth-next/link-multiple-accounts/auth_merge_accounts.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_merge_accounts_modular] import { getAuth, signInWithCredential, linkWithCredential, OAuthProvider } from "firebase/auth"; @@ -10,7 +11,7 @@ import { getAuth, signInWithCredential, linkWithCredential, OAuthProvider } from const repo = new MyUserDataRepo(); // Get reference to the currently signed-in user -const auth = getAuth(firebaseApp); +const auth = getAuth(); const prevUser = auth.currentUser; // Get the data which you will want to merge. This should be done now diff --git a/snippets/auth-next/link-multiple-accounts/auth_simple_link.js b/snippets/auth-next/link-multiple-accounts/auth_simple_link.js index 4aef5f6d..15c434a2 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_simple_link.js +++ b/snippets/auth-next/link-multiple-accounts/auth_simple_link.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_simple_link_modular] import { getAuth, linkWithCredential } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { const user = usercred.user; diff --git a/snippets/auth-next/link-multiple-accounts/auth_unlink_provider.js b/snippets/auth-next/link-multiple-accounts/auth_unlink_provider.js index 0140810a..46617b26 100644 --- a/snippets/auth-next/link-multiple-accounts/auth_unlink_provider.js +++ b/snippets/auth-next/link-multiple-accounts/auth_unlink_provider.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/link-multiple-accounts.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_unlink_provider_modular] import { getAuth, unlink } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); unlink(auth.currentUser, providerId).then(() => { // Auth provider unlinked from account // ... diff --git a/snippets/auth-next/manage/auth_delete_user.js b/snippets/auth-next/manage/auth_delete_user.js new file mode 100644 index 00000000..389a0852 --- /dev/null +++ b/snippets/auth-next/manage/auth_delete_user.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_delete_user_modular] +import { getAuth, deleteUser } from "firebase/auth"; + +const auth = getAuth(); +const user = auth.currentUser; + +deleteUser(user).then(() => { + // User deleted. +}).catch((error) => { + // An error ocurred + // ... +}); +// [END auth_delete_user_modular] \ No newline at end of file diff --git a/snippets/auth-next/manage/auth_get_user_profile.js b/snippets/auth-next/manage/auth_get_user_profile.js new file mode 100644 index 00000000..9dce7fdc --- /dev/null +++ b/snippets/auth-next/manage/auth_get_user_profile.js @@ -0,0 +1,24 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_get_user_profile_modular] +import { getAuth } from "firebase/auth"; + +const auth = getAuth(); +const user = auth.currentUser; +if (user !== null) { + // The user object has basic properties such as display name, email, etc. + const displayName = user.displayName; + const email = user.email; + const photoURL = user.photoURL; + const emailVerified = user.emailVerified; + + // The user's ID, unique to the Firebase project. Do NOT use + // this value to authenticate with your backend server, if + // you have one. Use User.getToken() instead. + const uid = user.uid; +} +// [END auth_get_user_profile_modular] \ No newline at end of file diff --git a/snippets/auth-next/manage/auth_get_user_profile_provider.js b/snippets/auth-next/manage/auth_get_user_profile_provider.js new file mode 100644 index 00000000..1d165d49 --- /dev/null +++ b/snippets/auth-next/manage/auth_get_user_profile_provider.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_get_user_profile_provider_modular] +import { getAuth } from "firebase/auth"; + +const auth = getAuth(); +const user = auth.currentUser; + +if (user !== null) { + user.providerData.forEach((profile) => { + console.log("Sign-in provider: " + profile.providerId); + console.log(" Provider-specific UID: " + profile.uid); + console.log(" Name: " + profile.displayName); + console.log(" Email: " + profile.email); + console.log(" Photo URL: " + profile.photoURL); + }); +} +// [END auth_get_user_profile_provider_modular] \ No newline at end of file diff --git a/snippets/auth-next/manage/auth_reauth_with_credential.js b/snippets/auth-next/manage/auth_reauth_with_credential.js new file mode 100644 index 00000000..74e84732 --- /dev/null +++ b/snippets/auth-next/manage/auth_reauth_with_credential.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_reauth_with_credential_modular] +import { getAuth, reauthenticateWithCredential } from "firebase/auth"; + +const auth = getAuth(); +const user = auth.currentUser; + +// TODO(you): prompt the user to re-provide their sign-in credentials +const credential = promptForCredentials(); + +reauthenticateWithCredential(user, credential).then(() => { + // User re-authenticated. +}).catch((error) => { + // An error ocurred + // ... +}); +// [END auth_reauth_with_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/manage/auth_send_password_reset.js b/snippets/auth-next/manage/auth_send_password_reset.js new file mode 100644 index 00000000..9e8f2c3c --- /dev/null +++ b/snippets/auth-next/manage/auth_send_password_reset.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_send_password_reset_modular] +import { getAuth, sendPasswordResetEmail } from "firebase/auth"; + +const auth = getAuth(); +const emailAddress = "user@example.com"; + +sendPasswordResetEmail(auth, emailAddress).then(() => { + // Email sent. +}).catch((error) => { + // An error ocurred + // ... +}); +// [END auth_send_password_reset_modular] \ No newline at end of file diff --git a/snippets/auth-next/manage/auth_update_password.js b/snippets/auth-next/manage/auth_update_password.js new file mode 100644 index 00000000..56e578b9 --- /dev/null +++ b/snippets/auth-next/manage/auth_update_password.js @@ -0,0 +1,21 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_update_password_modular] +import { getAuth, updatePassword } from "firebase/auth"; + +const auth = getAuth(); + +const user = auth.currentUser; +const newPassword = getASecureRandomPassword(); + +updatePassword(user, newPassword).then(() => { + // Update successful. +}).catch((error) => { + // An error ocurred + // ... +}); +// [END auth_update_password_modular] \ No newline at end of file diff --git a/snippets/auth-next/manage/auth_update_user_email.js b/snippets/auth-next/manage/auth_update_user_email.js new file mode 100644 index 00000000..d3607f75 --- /dev/null +++ b/snippets/auth-next/manage/auth_update_user_email.js @@ -0,0 +1,17 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_update_user_email_modular] +import { getAuth, updateEmail } from "firebase/auth"; +const auth = getAuth(); +updateEmail(auth.currentUser, "user@example.com").then(() => { + // Email updated! + // ... +}).catch((error) => { + // An error occurred + // ... +}); +// [END auth_update_user_email_modular] \ No newline at end of file diff --git a/snippets/auth-next/manage/auth_update_user_profile.js b/snippets/auth-next/manage/auth_update_user_profile.js new file mode 100644 index 00000000..2af9185a --- /dev/null +++ b/snippets/auth-next/manage/auth_update_user_profile.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_update_user_profile_modular] +import { getAuth, updateProfile } from "firebase/auth"; +const auth = getAuth(); +updateProfile(auth.currentUser, { + displayName: "Jane Q. User", photoURL: "https://example.com/jane-q-user/profile.jpg" +}).then(() => { + // Profile updated! + // ... +}).catch((error) => { + // An error occurred + // ... +}); +// [END auth_update_user_profile_modular] \ No newline at end of file diff --git a/snippets/auth-next/manage/send_email_verification.js b/snippets/auth-next/manage/send_email_verification.js new file mode 100644 index 00000000..34f06fdb --- /dev/null +++ b/snippets/auth-next/manage/send_email_verification.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/manage.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START send_email_verification_modular] +import { getAuth, sendEmailVerification } from "firebase/auth"; + +const auth = getAuth(); +const user = auth.currentUser; + +sendEmailVerification(user).then(() => { + // Email sent. +}).catch((error) => { + // An error ocurred + // ... +}); +// [END send_email_verification_modular] \ No newline at end of file diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_create_provider.js b/snippets/auth-next/microsoft-oauth/auth_msft_create_provider.js index bbde8267..c0a9039c 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_create_provider.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_create_provider.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_create_provider_modular] import { OAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_link_popup.js b/snippets/auth-next/microsoft-oauth/auth_msft_link_popup.js index 67a8ba9a..1a029c7e 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_link_popup.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_link_popup.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_link_popup_modular] import { getAuth, linkWithPopup, OAuthProvider } from "firebase/auth"; const provider = new OAuthProvider('microsoft.com'); -const auth = getAuth(firebaseApp); +const auth = getAuth(); linkWithPopup(auth.currentUser, provider) .then((result) => { diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_provider_params.js b/snippets/auth-next/microsoft-oauth/auth_msft_provider_params.js index dea75ee7..007ae646 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_provider_params.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_provider_params.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_provider_params_modular] provider.setCustomParameters({ diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_provider_params_tenant.js b/snippets/auth-next/microsoft-oauth/auth_msft_provider_params_tenant.js index 82abfe9b..341ff1f1 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_provider_params_tenant.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_provider_params_tenant.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_provider_params_tenant_modular] provider.setCustomParameters({ diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_provider_scopes.js b/snippets/auth-next/microsoft-oauth/auth_msft_provider_scopes.js index 6c4d2fed..ad86ac6e 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_provider_scopes.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_provider_scopes.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_provider_scopes_modular] provider.addScope('mail.read'); diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_reauth_popup.js b/snippets/auth-next/microsoft-oauth/auth_msft_reauth_popup.js index a15c3759..1d222fba 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_reauth_popup.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_reauth_popup.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_reauth_popup_modular] import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth"; const provider = new OAuthProvider('microsoft.com'); -const auth = getAuth(firebaseApp); +const auth = getAuth(); reauthenticateWithPopup(auth.currentUser, provider) .then((result) => { // User is re-authenticated with fresh tokens minted and diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_signin_popup.js b/snippets/auth-next/microsoft-oauth/auth_msft_signin_popup.js index 93c34d0a..a19e598d 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_signin_popup.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_signin_popup.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_signin_popup_modular] import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // User is signed in. diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_signin_redirect.js b/snippets/auth-next/microsoft-oauth/auth_msft_signin_redirect.js index 7edec614..c020dcf5 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_signin_redirect.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_signin_redirect.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_signin_redirect_modular] import { getAuth, signInWithRedirect } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithRedirect(auth, provider); // [END auth_msft_signin_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/microsoft-oauth/auth_msft_signin_redirect_result.js b/snippets/auth-next/microsoft-oauth/auth_msft_signin_redirect_result.js index 2d624588..e1249de1 100644 --- a/snippets/auth-next/microsoft-oauth/auth_msft_signin_redirect_result.js +++ b/snippets/auth-next/microsoft-oauth/auth_msft_signin_redirect_result.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/microsoft-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_msft_signin_redirect_result_modular] import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); getRedirectResult(auth) .then((result) => { // User is signed in. diff --git a/snippets/auth-next/multi-tenancy/multitenant_account_exists_popup.js b/snippets/auth-next/multi-tenancy/multitenant_account_exists_popup.js new file mode 100644 index 00000000..7bf33262 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_account_exists_popup.js @@ -0,0 +1,44 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_account_exists_popup_modular] +import { signInWithPopup, fetchSignInMethodsForEmail, linkWithCredential } from "firebase/auth"; +// Step 1. +// User tries to sign in to the SAML provider in that tenant. +auth.tenantId = 'TENANT_ID'; +signInWithPopup(auth, samlProvider) + .catch((error) => { + // An error happened. + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + // The pending SAML credential. + const pendingCred = error.credential; + // The credential's tenantId if needed: error.tenantId + // The provider account's email address. + const email = error.customData.email; + // Get sign-in methods for this email. + fetchSignInMethodsForEmail(email, auth) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + signInWithPopup(auth, googleProvider) + .then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + linkWithCredential(result.user, pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + } + }); + } + }); +// [END multitenant_account_exists_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_account_exists_redirect.js b/snippets/auth-next/multi-tenancy/multitenant_account_exists_redirect.js new file mode 100644 index 00000000..a81617dd --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_account_exists_redirect.js @@ -0,0 +1,51 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_account_exists_redirect_modular] +import { signInWithRedirect, getRedirectResult, fetchSignInMethodsForEmail, linkWithCredential } from "firebase/auth"; +// Step 1. +// User tries to sign in to SAML provider. +auth.tenantId = 'TENANT_ID'; +signInWithRedirect(auth, samlProvider); +var pendingCred; +// Redirect back from SAML IDP. auth.tenantId is null after redirecting. +getRedirectResult(auth).catch((error) => { + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + const tenantId = error.tenantId; + // The pending SAML credential. + pendingCred = error.credential; + // The provider account's email address. + const email = error.customData.email; + // Need to set the tenant ID again as the page was reloaded and the + // previous setting was reset. + auth.tenantId = tenantId; + // Get sign-in methods for this email. + fetchSignInMethodsForEmail(auth, email) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + signInWithRedirect(auth, googleProvider); + } + }); + } +}); + +// Redirect back from Google. auth.tenantId is null after redirecting. +getRedirectResult(auth).then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + // result.user.tenantId is 'TENANT_ID'. + linkWithCredential(result.user, pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); +}); +// [END multitenant_account_exists_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_account_linking.js b/snippets/auth-next/multi-tenancy/multitenant_account_linking.js new file mode 100644 index 00000000..c43ff90d --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_account_linking.js @@ -0,0 +1,34 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_account_linking_modular] +import { signInWithPopup, EmailAuthProvider, linkWithCredential, SAMLAuthProvider, signInWithCredential } from "firebase/auth"; +// Switch to TENANT_ID1 +auth.tenantId = 'TENANT_ID1'; + +// Sign-in with popup +signInWithPopup(auth, provider) + .then((userCredential) => { + // Existing user with e.g. SAML provider. + const prevUser = userCredential.user; + const emailCredential = + EmailAuthProvider.credential(email, password); + return linkWithCredential(prevUser, emailCredential) + .then((linkResult) => { + // Sign in with the newly linked credential + const linkCredential = SAMLAuthProvider.credentialFromResult(linkResult); + return signInWithCredential(auth, linkCredential); + }) + .then((signInResult) => { + // Handle sign in of merged user + // ... + }); + }) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_account_linking_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_create_custom_token.js b/snippets/auth-next/multi-tenancy/multitenant_create_custom_token.js new file mode 100644 index 00000000..1426cf8a --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_create_custom_token.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_create_custom_token_modular] +// Ensure you're using a tenant-aware auth instance +const tenantManager = admin.auth().tenantManager(); +const tenantAuth = tenantManager.authForTenant('TENANT_ID1'); + +// Create a custom token in the usual manner +tenantAuth.createCustomToken(uid) + .then((customToken) => { + // Send token back to client + }) + .catch((error) => { + console.log('Error creating custom token:', error); + }); +// [END multitenant_create_custom_token_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_send_emaillink.js b/snippets/auth-next/multi-tenancy/multitenant_send_emaillink.js new file mode 100644 index 00000000..4c4d95c5 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_send_emaillink.js @@ -0,0 +1,23 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_send_emaillink_modular] +import { sendSignInLinkToEmail } from "firebase/auth"; +// Switch to TENANT_ID1 +auth.tenantId = 'TENANT_ID1'; + +sendSignInLinkToEmail(auth, email, actionCodeSettings) + .then(() => { + // The link was successfully sent. Inform the user. + // Save the email locally so you don't need to ask the user for it again + // if they open the link on the same device. + window.localStorage.setItem('emailForSignIn', email); + }) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_send_emaillink_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_set_tenant.js b/snippets/auth-next/multi-tenancy/multitenant_set_tenant.js new file mode 100644 index 00000000..9510bc5e --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_set_tenant.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_set_tenant_modular] +import { getAuth } from "firebase/auth"; +const auth = getAuth(); +const tenantId = "TENANT_ID1"; +auth.tenantId = tenantId; +// [END multitenant_set_tenant_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_custom_token.js b/snippets/auth-next/multi-tenancy/multitenant_signin_custom_token.js new file mode 100644 index 00000000..b9fa9c58 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_custom_token.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_custom_token_modular] +import { signInWithCustomToken } from "firebase/auth"; +auth.tenantId = 'TENANT_ID1'; + +signInWithCustomToken(auth, token) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signin_custom_token_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_emaillink.js b/snippets/auth-next/multi-tenancy/multitenant_signin_emaillink.js new file mode 100644 index 00000000..0032af1c --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_emaillink.js @@ -0,0 +1,29 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_emaillink_modular] +import { isSignInWithEmailLink, parseActionCodeURL, signInWithEmailLink } from "firebase/auth"; +if (isSignInWithEmailLink(auth, window.location.href)) { + const actionCodeUrl = parseActionCodeURL(window.location.href); + if (actionCodeUrl.tenantId) { + auth.tenantId = actionCodeUrl.tenantId; + } + let email = window.localStorage.getItem('emailForSignIn'); + if (!email) { + // User opened the link on a different device. To prevent session fixation + // attacks, ask the user to provide the associated email again. For example: + email = window.prompt('Please provide your email for confirmation'); + } + // The client SDK will parse the code from the link for you. + signInWithEmailLink(auth, email, window.location.href) + .then((result) => { + // User is signed in. + // tenant ID available in result.user.tenantId. + // Clear email from storage. + window.localStorage.removeItem('emailForSignIn'); + }); +} +// [END multitenant_signin_emaillink_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_password.js b/snippets/auth-next/multi-tenancy/multitenant_signin_password.js new file mode 100644 index 00000000..73642a8d --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_password.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_password_modular] +import { signInWithEmailAndPassword } from "firebase/auth"; +auth.tenantId = 'TENANT_ID'; + +signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + // userCredential.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signin_password_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_password_demo.js b/snippets/auth-next/multi-tenancy/multitenant_signin_password_demo.js new file mode 100644 index 00000000..87882773 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_password_demo.js @@ -0,0 +1,33 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_password_demo_modular] +import { signInWithEmailAndPassword, onAuthStateChanged } from "firebase/auth"; +// Switch to TENANT_ID1 +auth.tenantId = 'TENANT_ID1'; + +// Sign in with tenant +signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + const user = userCredential.user; + // user.tenantId is set to 'TENANT_ID1'. + // Switch to 'TENANT_ID2'. + auth.tenantId = 'TENANT_ID2'; + // auth.currentUser still points to the user. + // auth.currentUser.tenantId is 'TENANT_ID1'. + }); + +// You could also get the current user from Auth state observer. +onAuthStateChanged(auth, (user) => { + if (user) { + // User is signed in. + // user.tenantId is set to 'TENANT_ID1'. + } else { + // No user is signed in. + } +}); +// [END multitenant_signin_password_demo_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_saml_popup.js b/snippets/auth-next/multi-tenancy/multitenant_signin_saml_popup.js new file mode 100644 index 00000000..6aa90550 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_saml_popup.js @@ -0,0 +1,25 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_saml_popup_modular] +import { signInWithPopup } from "firebase/auth"; +// Switch to TENANT_ID1. +auth.tenantId = 'TENANT_ID1'; + +// Sign-in with popup. +signInWithPopup(auth, provider) + .then((userCredential) => { + // User is signed in. + const user = userCredential.user; + // user.tenantId is set to 'TENANT_ID1'. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signin_saml_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_saml_redirect.js b/snippets/auth-next/multi-tenancy/multitenant_signin_saml_redirect.js new file mode 100644 index 00000000..d3552a56 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_saml_redirect.js @@ -0,0 +1,29 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_saml_redirect_modular] +import { signInWithRedirect, getRedirectResult } from "firebase/auth"; +// Switch to TENANT_ID1. +auth.tenantId = 'TENANT_ID1'; + +// Sign-in with redirect. +signInWithRedirect(auth, provider); + +// After the user completes sign-in and returns to the app, you can get +// the sign-in result by calling getRedirectResult. However, if they sign out +// and sign in again with an IdP, no tenant is used. +getRedirectResult(auth) + .then((result) => { + // User is signed in. + // The tenant ID available in result.user.tenantId. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signin_saml_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signup_password.js b/snippets/auth-next/multi-tenancy/multitenant_signup_password.js new file mode 100644 index 00000000..d89d5edf --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signup_password.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signup_password_modular] +import { createUserWithEmailAndPassword } from "firebase/auth"; +auth.tenantId = 'TENANT_ID'; + +createUserWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + // userCredential.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signup_password_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_switch_tenant.js b/snippets/auth-next/multi-tenancy/multitenant_switch_tenant.js new file mode 100644 index 00000000..455e4e3b --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_switch_tenant.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_switch_tenant_modular] +// One Auth instance +// Switch to tenant1 +auth.tenantId = "TENANT_ID1"; +// Switch to tenant2 +auth.tenantId = "TENANT_ID2"; +// Switch back to project level IdPs +auth.tenantId = null; +// [END multitenant_switch_tenant_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_switch_tenant_multiinstance.js b/snippets/auth-next/multi-tenancy/multitenant_switch_tenant_multiinstance.js new file mode 100644 index 00000000..72550493 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_switch_tenant_multiinstance.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_switch_tenant_multiinstance_modular] +// Multiple Auth instances +import { initializeApp } from "firebase/app"; +import { getAuth } from "firebase/auth"; +const firebaseApp1 = initializeApp(firebaseConfig1, 'app1_for_tenantId1'); +const firebaseApp2 = initializeApp(firebaseConfig2, 'app2_for_tenantId2'); + +const auth1 = getAuth(firebaseApp1); +const auth2 = getAuth(firebaseApp2); + +auth1.tenantId = "TENANT_ID1"; +auth2.tenantId = "TENANT_ID2"; +// [END multitenant_switch_tenant_multiinstance_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_direct_sign_in.js b/snippets/auth-next/oidc/auth_oidc_direct_sign_in.js new file mode 100644 index 00000000..558fd915 --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_direct_sign_in.js @@ -0,0 +1,31 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_direct_sign_in_modular] +import { getAuth, OAuthProvider, signInWithCredential } from "firebase/auth"; + +const auth = getAuth(); +const credential = provider.credential({ + idToken: oidcIdToken, +}); +signInWithCredential(auth, credential) + .then((result) => { + // User is signed in. + const newCredential = OAuthProvider.credentialFromResult(result); + // This gives you a new access token for the OIDC provider. You can use it to directly interact with that provider. + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_oidc_direct_sign_in_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_provider_create.js b/snippets/auth-next/oidc/auth_oidc_provider_create.js new file mode 100644 index 00000000..ce1846b9 --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_provider_create.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_provider_create_modular] +import { OAuthProvider } from "firebase/auth"; + +const provider = new OAuthProvider("oidc.myProvider"); +// [END auth_oidc_provider_create_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_signin_popup.js b/snippets/auth-next/oidc/auth_oidc_signin_popup.js new file mode 100644 index 00000000..130d617e --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_signin_popup.js @@ -0,0 +1,27 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_signin_popup_modular] +import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +signInWithPopup(auth, provider) + .then((result) => { + // User is signed in. + const credential = OAuthProvider.credentialFromResult(result); + // This gives you an access token for the OIDC provider. You can use it to directly interact with that provider + }).catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_oidc_signin_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_signin_redirect.js b/snippets/auth-next/oidc/auth_oidc_signin_redirect.js new file mode 100644 index 00000000..2038d116 --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_signin_redirect.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_signin_redirect_modular] +import { getAuth, signInWithRedirect } from "firebase/auth"; + +const auth = getAuth(); +signInWithRedirect(auth, provider); +// [END auth_oidc_signin_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_signin_redirect_result.js b/snippets/auth-next/oidc/auth_oidc_signin_redirect_result.js new file mode 100644 index 00000000..bc76a620 --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_signin_redirect_result.js @@ -0,0 +1,28 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_signin_redirect_result_modular] +import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +getRedirectResult(auth) + .then((result) => { + // User is signed in. + const credential = OAuthProvider.credentialFromResult(result); + // This gives you an access token for the OIDC provider. You can use it to directly interact with that provider + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_oidc_signin_redirect_result_modular] \ No newline at end of file diff --git a/snippets/auth-next/phone-auth/auth_get_recaptcha_response.js b/snippets/auth-next/phone-auth/auth_get_recaptcha_response.js index 83a31ed1..f19a93e6 100644 --- a/snippets/auth-next/phone-auth/auth_get_recaptcha_response.js +++ b/snippets/auth-next/phone-auth/auth_get_recaptcha_response.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/phone-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_get_recaptcha_response_modular] const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId); diff --git a/snippets/auth-next/phone-auth/auth_phone_recaptcha_render.js b/snippets/auth-next/phone-auth/auth_phone_recaptcha_render.js index 0bbceb0d..27e9d8c9 100644 --- a/snippets/auth-next/phone-auth/auth_phone_recaptcha_render.js +++ b/snippets/auth-next/phone-auth/auth_phone_recaptcha_render.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/phone-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_phone_recaptcha_render_modular] recaptchaVerifier.render().then((widgetId) => { diff --git a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_invisible.js b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_invisible.js index 2be4c94b..7fd16eea 100644 --- a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_invisible.js +++ b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_invisible.js @@ -1,17 +1,18 @@ // This snippet file was generated by processing the source file: // ./auth-next/phone-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_phone_recaptcha_verifier_invisible_modular] import { getAuth, RecaptchaVerifier } from "firebase/auth"; -const auth = getAuth(firebaseApp); -window.recaptchaVerifier = new RecaptchaVerifier('sign-in-button', { +const auth = getAuth(); +window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', { 'size': 'invisible', 'callback': (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. onSignInSubmit(); } -}, auth); +}); // [END auth_phone_recaptcha_verifier_invisible_modular] \ No newline at end of file diff --git a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_simple.js b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_simple.js index e36af4f5..b57eb37b 100644 --- a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_simple.js +++ b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_simple.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./auth-next/phone-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_phone_recaptcha_verifier_simple_modular] import { getAuth, RecaptchaVerifier } from "firebase/auth"; -const auth = getAuth(firebaseApp); -window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {}, auth); +const auth = getAuth(); +window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {}); // [END auth_phone_recaptcha_verifier_simple_modular] \ No newline at end of file diff --git a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_visible.js b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_visible.js index a3f4e28c..42ebbe69 100644 --- a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_visible.js +++ b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_visible.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/phone-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_phone_recaptcha_verifier_visible_modular] import { getAuth, RecaptchaVerifier } from "firebase/auth"; -const auth = getAuth(firebaseApp); -window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', { +const auth = getAuth(); +window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', { 'size': 'normal', 'callback': (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. @@ -17,5 +18,5 @@ window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', { // Response expired. Ask user to solve reCAPTCHA again. // ... } -}, auth); +}); // [END auth_phone_recaptcha_verifier_visible_modular] \ No newline at end of file diff --git a/snippets/auth-next/phone-auth/auth_phone_signin.js b/snippets/auth-next/phone-auth/auth_phone_signin.js index 1c9ecb69..31c3d248 100644 --- a/snippets/auth-next/phone-auth/auth_phone_signin.js +++ b/snippets/auth-next/phone-auth/auth_phone_signin.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/phone-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_phone_signin_modular] import { getAuth, signInWithPhoneNumber } from "firebase/auth"; @@ -9,7 +10,7 @@ import { getAuth, signInWithPhoneNumber } from "firebase/auth"; const phoneNumber = getPhoneNumberFromUserInput(); const appVerifier = window.recaptchaVerifier; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithPhoneNumber(auth, phoneNumber, appVerifier) .then((confirmationResult) => { // SMS sent. Prompt user to type the code from the message, then sign the diff --git a/snippets/auth-next/phone-auth/auth_phone_verify_code.js b/snippets/auth-next/phone-auth/auth_phone_verify_code.js index 51265141..299f8cf3 100644 --- a/snippets/auth-next/phone-auth/auth_phone_verify_code.js +++ b/snippets/auth-next/phone-auth/auth_phone_verify_code.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/phone-auth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_phone_verify_code_modular] const code = getCodeFromUserInput(); diff --git a/snippets/auth-next/saml/auth_saml_provider_create.js b/snippets/auth-next/saml/auth_saml_provider_create.js new file mode 100644 index 00000000..e492d490 --- /dev/null +++ b/snippets/auth-next/saml/auth_saml_provider_create.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/saml.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_saml_provider_create_modular] +import { SAMLAuthProvider } from "firebase/auth"; + +const provider = new SAMLAuthProvider("saml.myProvider"); +// [END auth_saml_provider_create_modular] \ No newline at end of file diff --git a/snippets/auth-next/saml/auth_saml_signin_popup.js b/snippets/auth-next/saml/auth_saml_signin_popup.js new file mode 100644 index 00000000..3a922a9a --- /dev/null +++ b/snippets/auth-next/saml/auth_saml_signin_popup.js @@ -0,0 +1,27 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/saml.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_saml_signin_popup_modular] +import { getAuth, signInWithPopup, SAMLAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +signInWithPopup(auth, provider) + .then((result) => { + // User is signed in. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }).catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = SAMLAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_saml_signin_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/saml/auth_saml_signin_redirect.js b/snippets/auth-next/saml/auth_saml_signin_redirect.js new file mode 100644 index 00000000..619af67f --- /dev/null +++ b/snippets/auth-next/saml/auth_saml_signin_redirect.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/saml.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_saml_signin_redirect_modular] +import { getAuth, signInWithRedirect } from "firebase/auth"; + +const auth = getAuth(); +signInWithRedirect(auth, provider); +// [END auth_saml_signin_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/saml/auth_saml_signin_redirect_result.js b/snippets/auth-next/saml/auth_saml_signin_redirect_result.js new file mode 100644 index 00000000..e4bf73de --- /dev/null +++ b/snippets/auth-next/saml/auth_saml_signin_redirect_result.js @@ -0,0 +1,28 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/saml.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_saml_signin_redirect_result_modular] +import { getAuth, getRedirectResult, SAMLAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +getRedirectResult(auth) + .then((result) => { + // User is signed in. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = SAMLAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_saml_signin_redirect_result_modular] \ No newline at end of file diff --git a/snippets/auth-next/service-worker-sessions/auth_svc_get_idtoken.js b/snippets/auth-next/service-worker-sessions/auth_svc_get_idtoken.js index fbed7d6b..dd78ada8 100644 --- a/snippets/auth-next/service-worker-sessions/auth_svc_get_idtoken.js +++ b/snippets/auth-next/service-worker-sessions/auth_svc_get_idtoken.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/service-worker-sessions.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_svc_get_idtoken_modular] import { getAuth, getIdToken } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); getIdToken(auth.currentUser) .then((idToken) => { // idToken can be passed back to server. diff --git a/snippets/auth-next/service-worker-sessions/auth_svc_intercept.js b/snippets/auth-next/service-worker-sessions/auth_svc_intercept.js index b14ccbed..419614ff 100644 --- a/snippets/auth-next/service-worker-sessions/auth_svc_intercept.js +++ b/snippets/auth-next/service-worker-sessions/auth_svc_intercept.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/service-worker-sessions.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_svc_intercept_modular] const getOriginFromUrl = (url) => { diff --git a/snippets/auth-next/service-worker-sessions/auth_svc_listen_activate.js b/snippets/auth-next/service-worker-sessions/auth_svc_listen_activate.js index a51cfedb..0337fc83 100644 --- a/snippets/auth-next/service-worker-sessions/auth_svc_listen_activate.js +++ b/snippets/auth-next/service-worker-sessions/auth_svc_listen_activate.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/service-worker-sessions.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_svc_listen_activate_modular] self.addEventListener('activate', (event) => { diff --git a/snippets/auth-next/service-worker-sessions/auth_svc_register.js b/snippets/auth-next/service-worker-sessions/auth_svc_register.js index 1b0b19c1..0cb36be3 100644 --- a/snippets/auth-next/service-worker-sessions/auth_svc_register.js +++ b/snippets/auth-next/service-worker-sessions/auth_svc_register.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/service-worker-sessions.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_svc_register_modular] // Install servicerWorker if supported on sign-in/sign-up page. diff --git a/snippets/auth-next/service-worker-sessions/auth_svc_sign_in_email.js b/snippets/auth-next/service-worker-sessions/auth_svc_sign_in_email.js index 14db554d..02e3a62a 100644 --- a/snippets/auth-next/service-worker-sessions/auth_svc_sign_in_email.js +++ b/snippets/auth-next/service-worker-sessions/auth_svc_sign_in_email.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/service-worker-sessions.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_svc_sign_in_email_modular] import { getAuth, signInWithEmailAndPassword } from "firebase/auth"; // Sign in screen. -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithEmailAndPassword(auth, email, password) .then((result) => { // Redirect to profile page after sign-in. The service worker will detect diff --git a/snippets/auth-next/service-worker-sessions/auth_svc_subscribe.js b/snippets/auth-next/service-worker-sessions/auth_svc_subscribe.js index c927fc4f..76448570 100644 --- a/snippets/auth-next/service-worker-sessions/auth_svc_subscribe.js +++ b/snippets/auth-next/service-worker-sessions/auth_svc_subscribe.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/service-worker-sessions.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_svc_subscribe_modular] import { initializeApp } from "firebase/app"; @@ -15,7 +16,7 @@ initializeApp(config); * @return {!Promise} The promise that resolves with an ID token if * available. Otherwise, the promise resolves with null. */ -const auth = getAuth(firebaseApp); +const auth = getAuth(); const getIdTokenPromise = () => { return new Promise((resolve, reject) => { const unsubscribe = onAuthStateChanged(auth, (user) => { diff --git a/snippets/auth-next/twitter/auth_twitter_provider_create.js b/snippets/auth-next/twitter/auth_twitter_provider_create.js index 496ae5f5..7fb82507 100644 --- a/snippets/auth-next/twitter/auth_twitter_provider_create.js +++ b/snippets/auth-next/twitter/auth_twitter_provider_create.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/twitter.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_twitter_provider_create_modular] import { TwitterAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/twitter/auth_twitter_provider_credential.js b/snippets/auth-next/twitter/auth_twitter_provider_credential.js new file mode 100644 index 00000000..e25b369c --- /dev/null +++ b/snippets/auth-next/twitter/auth_twitter_provider_credential.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/twitter.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_twitter_provider_credential_modular] +import { TwitterAuthProvider } from "firebase/auth"; + +const credential = TwitterAuthProvider.credential(accessToken, secret); +// [END auth_twitter_provider_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/twitter/auth_twitter_provider_params.js b/snippets/auth-next/twitter/auth_twitter_provider_params.js index cb7c7a39..14d457f0 100644 --- a/snippets/auth-next/twitter/auth_twitter_provider_params.js +++ b/snippets/auth-next/twitter/auth_twitter_provider_params.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/twitter.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_twitter_provider_params_modular] provider.setCustomParameters({ diff --git a/snippets/auth-next/twitter/auth_twitter_signin_popup.js b/snippets/auth-next/twitter/auth_twitter_signin_popup.js index d500a504..adb7322e 100644 --- a/snippets/auth-next/twitter/auth_twitter_signin_popup.js +++ b/snippets/auth-next/twitter/auth_twitter_signin_popup.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/twitter.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_twitter_signin_popup_modular] import { getAuth, signInWithPopup, TwitterAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // This gives you a the Twitter OAuth 1.0 Access Token and Secret. @@ -17,13 +18,14 @@ signInWithPopup(auth, provider) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = TwitterAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/twitter/auth_twitter_signin_redirect_result.js b/snippets/auth-next/twitter/auth_twitter_signin_redirect_result.js index 5d781644..357faa4e 100644 --- a/snippets/auth-next/twitter/auth_twitter_signin_redirect_result.js +++ b/snippets/auth-next/twitter/auth_twitter_signin_redirect_result.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/twitter.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_twitter_signin_redirect_result_modular] import { getAuth, getRedirectResult, TwitterAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); getRedirectResult(auth) .then((result) => { // This gives you a the Twitter OAuth 1.0 Access Token and Secret. @@ -18,12 +19,14 @@ getRedirectResult(auth) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = TwitterAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/yahoo-oauth/auth_yahoo_link_popup.js b/snippets/auth-next/yahoo-oauth/auth_yahoo_link_popup.js index fbdaaeb1..1a921bce 100644 --- a/snippets/auth-next/yahoo-oauth/auth_yahoo_link_popup.js +++ b/snippets/auth-next/yahoo-oauth/auth_yahoo_link_popup.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/yahoo-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_yahoo_link_popup_modular] import { getAuth, linkWithPopup, OAuthProvider } from "firebase/auth"; const provider = new OAuthProvider('yahoo.com'); -const auth = getAuth(firebaseApp); +const auth = getAuth(); linkWithPopup(auth.currentUser, provider) .then((result) => { // Yahoo credential is linked to the current user. diff --git a/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_create.js b/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_create.js index c30a64f0..c26cd5fd 100644 --- a/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_create.js +++ b/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_create.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/yahoo-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_yahoo_provider_create_modular] import { OAuthProvider } from "firebase/auth"; diff --git a/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_params.js b/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_params.js index 7bd28592..f8d918f9 100644 --- a/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_params.js +++ b/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_params.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/yahoo-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_yahoo_provider_params_modular] provider.setCustomParameters({ diff --git a/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_scopes.js b/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_scopes.js index 24e059c8..8a02ff7b 100644 --- a/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_scopes.js +++ b/snippets/auth-next/yahoo-oauth/auth_yahoo_provider_scopes.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./auth-next/yahoo-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_yahoo_provider_scopes_modular] // Request access to Yahoo Mail API. diff --git a/snippets/auth-next/yahoo-oauth/auth_yahoo_reauth_popup.js b/snippets/auth-next/yahoo-oauth/auth_yahoo_reauth_popup.js index d14b58e3..57243f05 100644 --- a/snippets/auth-next/yahoo-oauth/auth_yahoo_reauth_popup.js +++ b/snippets/auth-next/yahoo-oauth/auth_yahoo_reauth_popup.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./auth-next/yahoo-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_yahoo_reauth_popup_modular] import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth"; const provider = new OAuthProvider('yahoo.com'); -const auth = getAuth(firebaseApp); +const auth = getAuth(); reauthenticateWithPopup(auth.currentUser, provider) .then((result) => { // User is re-authenticated with fresh tokens minted and diff --git a/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_popup.js b/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_popup.js index cad34a24..91c04abc 100644 --- a/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_popup.js +++ b/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_popup.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/yahoo-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_yahoo_signin_popup_modular] import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithPopup(auth, provider) .then((result) => { // IdP data available in result.additionalUserInfo.profile diff --git a/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_redirect.js b/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_redirect.js index 98ae3029..f16cac73 100644 --- a/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_redirect.js +++ b/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_redirect.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./auth-next/yahoo-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_yahoo_signin_redirect_modular] import { getAuth, signInWithRedirect } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); signInWithRedirect(auth, provider); // [END auth_yahoo_signin_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_redirect_result.js b/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_redirect_result.js index 11be5523..61709b2c 100644 --- a/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_redirect_result.js +++ b/snippets/auth-next/yahoo-oauth/auth_yahoo_signin_redirect_result.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./auth-next/yahoo-oauth.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START auth_yahoo_signin_redirect_result_modular] import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth"; -const auth = getAuth(firebaseApp); +const auth = getAuth(); getRedirectResult(auth) .then((result) => { // IdP data available in result.additionalUserInfo.profile diff --git a/snippets/database-next/emulator-suite/rtdb_emulator_connect.js b/snippets/database-next/emulator-suite/rtdb_emulator_connect.js new file mode 100644 index 00000000..0bd145f6 --- /dev/null +++ b/snippets/database-next/emulator-suite/rtdb_emulator_connect.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./database-next/emulator-suite.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_emulator_connect_modular] +import { getDatabase, connectDatabaseEmulator } from "firebase/database"; + +const db = getDatabase(); +if (location.hostname === "localhost") { + // Point to the RTDB emulator running on localhost. + connectDatabaseEmulator(db, "127.0.0.1", 9000); +} +// [END rtdb_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/database-next/emulator-suite/rtdb_emulator_flush.js b/snippets/database-next/emulator-suite/rtdb_emulator_flush.js new file mode 100644 index 00000000..3e17ef9a --- /dev/null +++ b/snippets/database-next/emulator-suite/rtdb_emulator_flush.js @@ -0,0 +1,13 @@ +// This snippet file was generated by processing the source file: +// ./database-next/emulator-suite.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_emulator_flush_modular] +import { getDatabase, ref, set } from "firebase/database"; + +// With a database Reference, write null to clear the database. +const db = getDatabase(); +set(ref(db), null); +// [END rtdb_emulator_flush_modular] \ No newline at end of file diff --git a/snippets/database-next/index/rtdb_get_reference.js b/snippets/database-next/index/rtdb_get_reference.js new file mode 100644 index 00000000..ee87937e --- /dev/null +++ b/snippets/database-next/index/rtdb_get_reference.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./database-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_get_reference_modular] +import { getDatabase } from "firebase/database"; + +const database = getDatabase(); +// [END rtdb_get_reference_modular] \ No newline at end of file diff --git a/snippets/database-next/lists-of-data/rtdb_social_listen_children.js b/snippets/database-next/lists-of-data/rtdb_social_listen_children.js new file mode 100644 index 00000000..78f90ff2 --- /dev/null +++ b/snippets/database-next/lists-of-data/rtdb_social_listen_children.js @@ -0,0 +1,23 @@ +// This snippet file was generated by processing the source file: +// ./database-next/lists-of-data.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_listen_children_modular] +import { getDatabase, ref, onChildAdded, onChildChanged, onChildRemoved } from "firebase/database"; + +const db = getDatabase(); +const commentsRef = ref(db, 'post-comments/' + postId); +onChildAdded(commentsRef, (data) => { + addCommentElement(postElement, data.key, data.val().text, data.val().author); +}); + +onChildChanged(commentsRef, (data) => { + setCommentValues(postElement, data.key, data.val().text, data.val().author); +}); + +onChildRemoved(commentsRef, (data) => { + deleteComment(postElement, data.key); +}); +// [END rtdb_social_listen_children_modular] \ No newline at end of file diff --git a/snippets/database-next/lists-of-data/rtdb_social_listen_value.js b/snippets/database-next/lists-of-data/rtdb_social_listen_value.js new file mode 100644 index 00000000..d234eeea --- /dev/null +++ b/snippets/database-next/lists-of-data/rtdb_social_listen_value.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./database-next/lists-of-data.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_listen_value_modular] +import { getDatabase, ref, onValue } from "firebase/database"; + +const db = getDatabase(); +const dbRef = ref(db, '/a/b/c'); + +onValue(dbRef, (snapshot) => { + snapshot.forEach((childSnapshot) => { + const childKey = childSnapshot.key; + const childData = childSnapshot.val(); + // ... + }); +}, { + onlyOnce: true +}); +// [END rtdb_social_listen_value_modular] \ No newline at end of file diff --git a/snippets/database-next/lists-of-data/rtdb_social_most_starred.js b/snippets/database-next/lists-of-data/rtdb_social_most_starred.js new file mode 100644 index 00000000..63237fdf --- /dev/null +++ b/snippets/database-next/lists-of-data/rtdb_social_most_starred.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./database-next/lists-of-data.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_most_starred_modular] +import { getDatabase, ref, query, orderByChild } from "firebase/database"; +import { getAuth } from "firebase/auth"; + +const db = getDatabase(); +const auth = getAuth(); + +const myUserId = auth.currentUser.uid; +const topUserPostsRef = query(ref(db, 'user-posts/' + myUserId), orderByChild('starCount')); +// [END rtdb_social_most_starred_modular] \ No newline at end of file diff --git a/snippets/database-next/lists-of-data/rtdb_social_most_viewed.js b/snippets/database-next/lists-of-data/rtdb_social_most_viewed.js new file mode 100644 index 00000000..1ebe7edc --- /dev/null +++ b/snippets/database-next/lists-of-data/rtdb_social_most_viewed.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./database-next/lists-of-data.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_most_viewed_modular] +import { getDatabase, ref, query, orderByChild } from "firebase/database"; + +const db = getDatabase(); +const mostViewedPosts = query(ref(db, 'posts'), orderByChild('metrics/views')); +// [END rtdb_social_most_viewed_modular] \ No newline at end of file diff --git a/snippets/database-next/lists-of-data/rtdb_social_push.js b/snippets/database-next/lists-of-data/rtdb_social_push.js new file mode 100644 index 00000000..ec366352 --- /dev/null +++ b/snippets/database-next/lists-of-data/rtdb_social_push.js @@ -0,0 +1,17 @@ +// This snippet file was generated by processing the source file: +// ./database-next/lists-of-data.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_push_modular] +import { getDatabase, ref, push, set } from "firebase/database"; + +// Create a new post reference with an auto-generated id +const db = getDatabase(); +const postListRef = ref(db, 'posts'); +const newPostRef = push(postListRef); +set(newPostRef, { + // ... +}); +// [END rtdb_social_push_modular] \ No newline at end of file diff --git a/snippets/database-next/lists-of-data/rtdb_social_recent.js b/snippets/database-next/lists-of-data/rtdb_social_recent.js new file mode 100644 index 00000000..8b35d6e6 --- /dev/null +++ b/snippets/database-next/lists-of-data/rtdb_social_recent.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./database-next/lists-of-data.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_recent_modular] +import { getDatabase, ref, query, limitToLast } from "firebase/database"; + +const db = getDatabase(); +const recentPostsRef = query(ref(db, 'posts'), limitToLast(100)); +// [END rtdb_social_recent_modular] \ No newline at end of file diff --git a/snippets/database-next/offline/rtdb_detect_connection_state.js b/snippets/database-next/offline/rtdb_detect_connection_state.js new file mode 100644 index 00000000..313af6ee --- /dev/null +++ b/snippets/database-next/offline/rtdb_detect_connection_state.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./database-next/offline.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_detect_connection_state_modular] +import { getDatabase, ref, onValue } from "firebase/database"; + +const db = getDatabase(); +const connectedRef = ref(db, ".info/connected"); +onValue(connectedRef, (snap) => { + if (snap.val() === true) { + console.log("connected"); + } else { + console.log("not connected"); + } +}); +// [END rtdb_detect_connection_state_modular] \ No newline at end of file diff --git a/snippets/database-next/offline/rtdb_estimate_clock_skew.js b/snippets/database-next/offline/rtdb_estimate_clock_skew.js new file mode 100644 index 00000000..e1a92581 --- /dev/null +++ b/snippets/database-next/offline/rtdb_estimate_clock_skew.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./database-next/offline.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_estimate_clock_skew_modular] +import { getDatabase, ref, onValue } from "firebase/database"; + +const db = getDatabase(); +const offsetRef = ref(db, ".info/serverTimeOffset"); +onValue(offsetRef, (snap) => { + const offset = snap.val(); + const estimatedServerTimeMs = new Date().getTime() + offset; +}); +// [END rtdb_estimate_clock_skew_modular] \ No newline at end of file diff --git a/snippets/database-next/offline/rtdb_ondisconnect_callback.js b/snippets/database-next/offline/rtdb_ondisconnect_callback.js new file mode 100644 index 00000000..16071828 --- /dev/null +++ b/snippets/database-next/offline/rtdb_ondisconnect_callback.js @@ -0,0 +1,13 @@ +// This snippet file was generated by processing the source file: +// ./database-next/offline.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_ondisconnect_callback_modular] +onDisconnect(presenceRef).remove().catch((err) => { + if (err) { + console.error("could not establish onDisconnect event", err); + } +}); +// [END rtdb_ondisconnect_callback_modular] \ No newline at end of file diff --git a/snippets/database-next/offline/rtdb_ondisconnect_cancel.js b/snippets/database-next/offline/rtdb_ondisconnect_cancel.js new file mode 100644 index 00000000..f18cab8e --- /dev/null +++ b/snippets/database-next/offline/rtdb_ondisconnect_cancel.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./database-next/offline.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_ondisconnect_cancel_modular] +const onDisconnectRef = onDisconnect(presenceRef); +onDisconnectRef.set("I disconnected"); +// some time later when we change our minds +onDisconnectRef.cancel(); +// [END rtdb_ondisconnect_cancel_modular] \ No newline at end of file diff --git a/snippets/database-next/offline/rtdb_ondisconnect_simple.js b/snippets/database-next/offline/rtdb_ondisconnect_simple.js new file mode 100644 index 00000000..340e3fe5 --- /dev/null +++ b/snippets/database-next/offline/rtdb_ondisconnect_simple.js @@ -0,0 +1,14 @@ +// This snippet file was generated by processing the source file: +// ./database-next/offline.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_ondisconnect_simple_modular] +import { getDatabase, ref, onDisconnect } from "firebase/database"; + +const db = getDatabase(); +const presenceRef = ref(db, "disconnectmessage"); +// Write a string when this client loses connection +onDisconnect(presenceRef).set("I disconnected!"); +// [END rtdb_ondisconnect_simple_modular] \ No newline at end of file diff --git a/snippets/database-next/offline/rtdb_sample_presence_app.js b/snippets/database-next/offline/rtdb_sample_presence_app.js new file mode 100644 index 00000000..394e64e6 --- /dev/null +++ b/snippets/database-next/offline/rtdb_sample_presence_app.js @@ -0,0 +1,35 @@ +// This snippet file was generated by processing the source file: +// ./database-next/offline.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_sample_presence_app_modular] +import { getDatabase, ref, onValue, push, onDisconnect, set, serverTimestamp } from "firebase/database"; + +// Since I can connect from multiple devices or browser tabs, we store each connection instance separately +// any time that connectionsRef's value is null (i.e. has no children) I am offline +const db = getDatabase(); +const myConnectionsRef = ref(db, 'users/joe/connections'); + +// stores the timestamp of my last disconnect (the last time I was seen online) +const lastOnlineRef = ref(db, 'users/joe/lastOnline'); + +const connectedRef = ref(db, '.info/connected'); +onValue(connectedRef, (snap) => { + if (snap.val() === true) { + // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) + const con = push(myConnectionsRef); + + // When I disconnect, remove this device + onDisconnect(con).remove(); + + // Add this device to my connections list + // this value could contain info about the device or a timestamp too + set(con, true); + + // When I disconnect, update the last time I was seen online + onDisconnect(lastOnlineRef).set(serverTimestamp()); + } +}); +// [END rtdb_sample_presence_app_modular] \ No newline at end of file diff --git a/snippets/database-next/offline/rtdb_set_server_timestamp.js b/snippets/database-next/offline/rtdb_set_server_timestamp.js new file mode 100644 index 00000000..8a9d2e8a --- /dev/null +++ b/snippets/database-next/offline/rtdb_set_server_timestamp.js @@ -0,0 +1,13 @@ +// This snippet file was generated by processing the source file: +// ./database-next/offline.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_set_server_timestamp_modular] +import { getDatabase, ref, onDisconnect, serverTimestamp } from "firebase/database"; + +const db = getDatabase(); +const userLastOnlineRef = ref(db, "users/joe/lastOnline"); +onDisconnect(userLastOnlineRef).set(serverTimestamp()); +// [END rtdb_set_server_timestamp_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_read_once_get.js b/snippets/database-next/read-and-write/rtdb_read_once_get.js new file mode 100644 index 00000000..a0cf77a5 --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_read_once_get.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_read_once_get_modular] +import { getDatabase, ref, child, get } from "firebase/database"; + +const dbRef = ref(getDatabase()); +get(child(dbRef, `users/${userId}`)).then((snapshot) => { + if (snapshot.exists()) { + console.log(snapshot.val()); + } else { + console.log("No data available"); + } +}).catch((error) => { + console.error(error); +}); +// [END rtdb_read_once_get_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_social_completion_callback.js b/snippets/database-next/read-and-write/rtdb_social_completion_callback.js new file mode 100644 index 00000000..b1ab42a1 --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_social_completion_callback.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_completion_callback_modular] +import { getDatabase, ref, set } from "firebase/database"; + +const db = getDatabase(); +set(ref(db, 'users/' + userId), { + username: name, + email: email, + profile_picture : imageUrl +}) +.then(() => { + // Data saved successfully! +}) +.catch((error) => { + // The write failed... +}); +// [END rtdb_social_completion_callback_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_social_listen_star_count.js b/snippets/database-next/read-and-write/rtdb_social_listen_star_count.js new file mode 100644 index 00000000..eb782894 --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_social_listen_star_count.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_listen_star_count_modular] +import { getDatabase, ref, onValue } from "firebase/database"; + +const db = getDatabase(); +const starCountRef = ref(db, 'posts/' + postId + '/starCount'); +onValue(starCountRef, (snapshot) => { + const data = snapshot.val(); + updateStarCount(postElement, data); +}); +// [END rtdb_social_listen_star_count_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_social_single_value_read.js b/snippets/database-next/read-and-write/rtdb_social_single_value_read.js new file mode 100644 index 00000000..3debb5e5 --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_social_single_value_read.js @@ -0,0 +1,21 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_single_value_read_modular] +import { getDatabase, ref, onValue } from "firebase/database"; +import { getAuth } from "firebase/auth"; + +const db = getDatabase(); +const auth = getAuth(); + +const userId = auth.currentUser.uid; +return onValue(ref(db, '/users/' + userId), (snapshot) => { + const username = (snapshot.val() && snapshot.val().username) || 'Anonymous'; + // ... +}, { + onlyOnce: true +}); +// [END rtdb_social_single_value_read_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_social_star_increment.js b/snippets/database-next/read-and-write/rtdb_social_star_increment.js new file mode 100644 index 00000000..dce5e8a9 --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_social_star_increment.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_star_increment_modular] +function addStar(uid, key) { + import { getDatabase, increment, ref, update } from "firebase/database"; + const dbRef = ref(getDatabase()); + + const updates = {}; + updates[`posts/${key}/stars/${uid}`] = true; + updates[`posts/${key}/starCount`] = increment(1); + updates[`user-posts/${key}/stars/${uid}`] = true; + updates[`user-posts/${key}/starCount`] = increment(1); + update(dbRef, updates); +} +// [END rtdb_social_star_increment_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_social_star_transaction.js b/snippets/database-next/read-and-write/rtdb_social_star_transaction.js new file mode 100644 index 00000000..bf837c92 --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_social_star_transaction.js @@ -0,0 +1,30 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_star_transaction_modular] +import { getDatabase, ref, runTransaction } from "firebase/database"; + +function toggleStar(uid) { + const db = getDatabase(); + const postRef = ref(db, '/posts/foo-bar-123'); + + runTransaction(postRef, (post) => { + if (post) { + if (post.stars && post.stars[uid]) { + post.starCount--; + post.stars[uid] = null; + } else { + post.starCount++; + if (!post.stars) { + post.stars = {}; + } + post.stars[uid] = true; + } + } + return post; + }); +} +// [END rtdb_social_star_transaction_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_social_write_fan_out.js b/snippets/database-next/read-and-write/rtdb_social_write_fan_out.js new file mode 100644 index 00000000..783eca2b --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_social_write_fan_out.js @@ -0,0 +1,33 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_social_write_fan_out_modular] +import { getDatabase, ref, child, push, update } from "firebase/database"; + +function writeNewPost(uid, username, picture, title, body) { + const db = getDatabase(); + + // A post entry. + const postData = { + author: username, + uid: uid, + body: body, + title: title, + starCount: 0, + authorPic: picture + }; + + // Get a key for a new Post. + const newPostKey = push(child(ref(db), 'posts')).key; + + // Write the new post's data simultaneously in the posts list and the user's post list. + const updates = {}; + updates['/posts/' + newPostKey] = postData; + updates['/user-posts/' + uid + '/' + newPostKey] = postData; + + return update(ref(db), updates); +} +// [END rtdb_social_write_fan_out_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_write_new_user.js b/snippets/database-next/read-and-write/rtdb_write_new_user.js new file mode 100644 index 00000000..eef24086 --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_write_new_user.js @@ -0,0 +1,18 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_write_new_user_modular] +import { getDatabase, ref, set } from "firebase/database"; + +function writeUserData(userId, name, email, imageUrl) { + const db = getDatabase(); + set(ref(db, 'users/' + userId), { + username: name, + email: email, + profile_picture : imageUrl + }); +} +// [END rtdb_write_new_user_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_write_new_user_completion.js b/snippets/database-next/read-and-write/rtdb_write_new_user_completion.js new file mode 100644 index 00000000..8bb5878e --- /dev/null +++ b/snippets/database-next/read-and-write/rtdb_write_new_user_completion.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./database-next/read-and-write.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_write_new_user_completion_modular] +import { getDatabase, ref, set } from "firebase/database"; + +const db = getDatabase(); +set(ref(db, 'users/' + userId), { + username: name, + email: email, + profile_picture : imageUrl +}) +.then(() => { + // Data saved successfully! +}) +.catch((error) => { + // The write failed... +}); +// [END rtdb_write_new_user_completion_modular] \ No newline at end of file diff --git a/snippets/database-next/sharding/rtdb_multiple_instances.js b/snippets/database-next/sharding/rtdb_multiple_instances.js new file mode 100644 index 00000000..fe66cbc8 --- /dev/null +++ b/snippets/database-next/sharding/rtdb_multiple_instances.js @@ -0,0 +1,24 @@ +// This snippet file was generated by processing the source file: +// ./database-next/sharding.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START rtdb_multiple_instances_modular] +import { initializeApp } from "firebase/app"; +import { getDatabase } from "firebase/database"; + +const app1 = initializeApp({ + databaseURL: "https://testapp-1234-1.firebaseio.com" +}); + +const app2 = initializeApp({ + databaseURL: "https://testapp-1234-2.firebaseio.com" +}, 'app2'); + +// Get the default database instance for an app1 +const database1 = getDatabase(app1); + +// Get a database instance for app2 +const database2 = getDatabase(app2); +// [END rtdb_multiple_instances_modular] \ No newline at end of file diff --git a/snippets/firebaseapp-next/firebaseapp/app_default_init_options.js b/snippets/firebaseapp-next/firebaseapp/app_default_init_options.js new file mode 100644 index 00000000..7cebaaf3 --- /dev/null +++ b/snippets/firebaseapp-next/firebaseapp/app_default_init_options.js @@ -0,0 +1,24 @@ +// This snippet file was generated by processing the source file: +// ./firebaseapp-next/firebaseapp.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START app_default_init_options_modular] +import { initializeApp } from "firebase/app"; +import { getStorage } from "firebase/storage"; +import { getFirestore } from "firebase/firestore"; + +// Initialize Firebase with a "default" Firebase project +const defaultProject = initializeApp(firebaseConfig); + +console.log(defaultProject.name); // "[DEFAULT]" + +// Option 1: Access Firebase services via the defaultProject variable +let defaultStorage = getStorage(defaultProject); +let defaultFirestore = getFirestore(defaultProject); + +// Option 2: Access Firebase services using shorthand notation +defaultStorage = getStorage(); +defaultFirestore = getFirestore(); +// [END app_default_init_options_modular] \ No newline at end of file diff --git a/snippets/firebaseapp-next/firebaseapp/app_multi_project_init_options.js b/snippets/firebaseapp-next/firebaseapp/app_multi_project_init_options.js new file mode 100644 index 00000000..415f8813 --- /dev/null +++ b/snippets/firebaseapp-next/firebaseapp/app_multi_project_init_options.js @@ -0,0 +1,28 @@ +// This snippet file was generated by processing the source file: +// ./firebaseapp-next/firebaseapp.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START app_multi_project_init_options_modular] +import { initializeApp, getApp } from "firebase/app"; +import { getStorage } from "firebase/storage"; +import { getFirestore } from "firebase/firestore"; + +// Initialize Firebase with a default Firebase project +initializeApp(firebaseConfig); + +// Initialize Firebase with a second Firebase project +const otherProject = initializeApp(otherProjectFirebaseConfig, "other"); + +console.log(getApp().name); // "[DEFAULT]" +console.log(otherProject.name); // "otherProject" + +// Use the shorthand notation to access the default project's Firebase services +const defaultStorage = getStorage(); +const defaultFirestore = getFirestore(); + +// Use the otherProject variable to access the second project's Firebase services +const otherStorage = getStorage(otherProject); +const otherFirestore = getFirestore(otherProject); +// [END app_multi_project_init_options_modular] \ No newline at end of file diff --git a/snippets/firebaseapp-next/firebaseapp/firebase_options.js b/snippets/firebaseapp-next/firebaseapp/firebase_options.js new file mode 100644 index 00000000..f951d4d7 --- /dev/null +++ b/snippets/firebaseapp-next/firebaseapp/firebase_options.js @@ -0,0 +1,21 @@ +// This snippet file was generated by processing the source file: +// ./firebaseapp-next/firebaseapp.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START firebase_options_modular] +import { initializeApp } from "firebase/app"; + +// The following fields are REQUIRED: +// - Project ID +// - App ID +// - API Key +const secondaryAppConfig = { + projectId: "", + appId: "", + apiKey: "", + // databaseURL: "...", + // storageBucket: "...", +}; +// [END firebase_options_modular] \ No newline at end of file diff --git a/snippets/firebaseapp-next/firebaseapp/firebase_secondary.js b/snippets/firebaseapp-next/firebaseapp/firebase_secondary.js new file mode 100644 index 00000000..2dd04f0f --- /dev/null +++ b/snippets/firebaseapp-next/firebaseapp/firebase_secondary.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./firebaseapp-next/firebaseapp.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START firebase_secondary_modular] +// Initialize another app with a different config +const secondaryApp = initializeApp(secondaryAppConfig, "secondary"); +// Access services, such as the Realtime Database +// getDatabase(secondaryApp) +// [END firebase_secondary_modular] \ No newline at end of file diff --git a/snippets/firestore-next/emulator-suite/fs_emulator_connect.js b/snippets/firestore-next/emulator-suite/fs_emulator_connect.js index 9824a297..d70fbb68 100644 --- a/snippets/firestore-next/emulator-suite/fs_emulator_connect.js +++ b/snippets/firestore-next/emulator-suite/fs_emulator_connect.js @@ -1,19 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/emulator-suite.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START fs_emulator_connect_modular] -import { initializeFirestore } from "firebase/firestore"; - -let settings = {}; -if (location.hostname === "localhost") { - settings = { - host: "localhost:8080", - ssl: false - }; -} +import { getFirestore, connectFirestoreEmulator } from "firebase/firestore"; // firebaseApps previously initialized using initializeApp() -const db = initializeFirestore(firebaseApp, settings); +const db = getFirestore(); +connectFirestoreEmulator(db, '127.0.0.1', 8080); // [END fs_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/add_ada_lovelace.js b/snippets/firestore-next/test-firestore/add_ada_lovelace.js index 7e9a0516..ae9e168a 100644 --- a/snippets/firestore-next/test-firestore/add_ada_lovelace.js +++ b/snippets/firestore-next/test-firestore/add_ada_lovelace.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START add_ada_lovelace_modular] import { collection, addDoc } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/add_alan_turing.js b/snippets/firestore-next/test-firestore/add_alan_turing.js index 6ea96265..0c7abaaf 100644 --- a/snippets/firestore-next/test-firestore/add_alan_turing.js +++ b/snippets/firestore-next/test-firestore/add_alan_turing.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START add_alan_turing_modular] // Add a second document with a generated ID. diff --git a/snippets/firestore-next/test-firestore/add_document.js b/snippets/firestore-next/test-firestore/add_document.js index 2ecb5c36..ddfea007 100644 --- a/snippets/firestore-next/test-firestore/add_document.js +++ b/snippets/firestore-next/test-firestore/add_document.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START add_document_modular] import { collection, addDoc } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/add_rating_transaction.js b/snippets/firestore-next/test-firestore/add_rating_transaction.js index 248f5e54..7d698806 100644 --- a/snippets/firestore-next/test-firestore/add_rating_transaction.js +++ b/snippets/firestore-next/test-firestore/add_rating_transaction.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START add_rating_transaction_modular] -import { collection, doc, runTransaction} from "firebase/firestore"; +import { collection, doc, runTransaction } from "firebase/firestore"; async function addRating(restaurantRef, rating) { // Create a reference for a new rating, for use inside the transaction diff --git a/snippets/firestore-next/test-firestore/array_contains_any_filter.js b/snippets/firestore-next/test-firestore/array_contains_any_filter.js index 72c550f8..3ee6e4d9 100644 --- a/snippets/firestore-next/test-firestore/array_contains_any_filter.js +++ b/snippets/firestore-next/test-firestore/array_contains_any_filter.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START array_contains_any_filter_modular] import { query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/array_contains_filter.js b/snippets/firestore-next/test-firestore/array_contains_filter.js index 9a9fcdb3..4576a193 100644 --- a/snippets/firestore-next/test-firestore/array_contains_filter.js +++ b/snippets/firestore-next/test-firestore/array_contains_filter.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START array_contains_filter_modular] import { query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/chain_filters.js b/snippets/firestore-next/test-firestore/chain_filters.js index b13640b4..cbf3322f 100644 --- a/snippets/firestore-next/test-firestore/chain_filters.js +++ b/snippets/firestore-next/test-firestore/chain_filters.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START chain_filters_modular] import { query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/cities_document_set.js b/snippets/firestore-next/test-firestore/cities_document_set.js index edebdc0c..4b85b25d 100644 --- a/snippets/firestore-next/test-firestore/cities_document_set.js +++ b/snippets/firestore-next/test-firestore/cities_document_set.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START cities_document_set_modular] -import { collection, doc, setDoc } from "firebase/firestore"; +import { doc, setDoc } from "firebase/firestore"; -await setDoc(doc(collection(db, "cities"), "new-city-id"), data); +await setDoc(doc(db, "cities", "new-city-id"), data); // [END cities_document_set_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/city_custom_object.js b/snippets/firestore-next/test-firestore/city_custom_object.js index 4335d06e..c8e4b80c 100644 --- a/snippets/firestore-next/test-firestore/city_custom_object.js +++ b/snippets/firestore-next/test-firestore/city_custom_object.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START city_custom_object_modular] class City { @@ -16,15 +17,15 @@ class City { } // Firestore data converter -var cityConverter = { - toFirestore: function(city) { +const cityConverter = { + toFirestore: (city) => { return { name: city.name, state: city.state, country: city.country }; }, - fromFirestore: function(snapshot, options){ + fromFirestore: (snapshot, options) => { const data = snapshot.data(options); return new City(data.name, data.state, data.country); } diff --git a/snippets/firestore-next/test-firestore/collection_reference.js b/snippets/firestore-next/test-firestore/collection_reference.js index 2b43362d..d69f17e4 100644 --- a/snippets/firestore-next/test-firestore/collection_reference.js +++ b/snippets/firestore-next/test-firestore/collection_reference.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START collection_reference_modular] import { collection } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/count_aggregate_collection.js b/snippets/firestore-next/test-firestore/count_aggregate_collection.js new file mode 100644 index 00000000..7dca7e37 --- /dev/null +++ b/snippets/firestore-next/test-firestore/count_aggregate_collection.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./firestore-next/test.firestore.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START count_aggregate_collection_modular] +const coll = collection(db, "cities"); +const snapshot = await getCountFromServer(coll); +console.log('count: ', snapshot.data().count); +// [END count_aggregate_collection_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/count_aggregate_query.js b/snippets/firestore-next/test-firestore/count_aggregate_query.js new file mode 100644 index 00000000..37a27458 --- /dev/null +++ b/snippets/firestore-next/test-firestore/count_aggregate_query.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./firestore-next/test.firestore.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START count_aggregate_query_modular] +const coll = collection(db, "cities"); +const q = query(coll, where("state", "==", "CA")); +const snapshot = await getCountFromServer(q); +console.log('count: ', snapshot.data().count); +// [END count_aggregate_query_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/data_types.js b/snippets/firestore-next/test-firestore/data_types.js index faace529..9218ae6b 100644 --- a/snippets/firestore-next/test-firestore/data_types.js +++ b/snippets/firestore-next/test-firestore/data_types.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START data_types_modular] -import { doc, collection, setDoc, Timestamp } from "firebase/firestore"; +import { doc, setDoc, Timestamp } from "firebase/firestore"; const docData = { stringExample: "Hello world!", @@ -20,5 +21,5 @@ const docData = { } } }; -await setDoc(doc(collection(db, "data"), "one"), docData); +await setDoc(doc(db, "data", "one"), docData); // [END data_types_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/delete_collection.js b/snippets/firestore-next/test-firestore/delete_collection.js index d9d6c70a..4adef6f8 100644 --- a/snippets/firestore-next/test-firestore/delete_collection.js +++ b/snippets/firestore-next/test-firestore/delete_collection.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START delete_collection_modular] /** @@ -13,7 +14,7 @@ import { collection, query, orderBy, limit, getDocs, writeBatch } from "firebase function deleteCollection(db, collectionRef, batchSize) { const q = query(collectionRef, orderBy('__name__'), limit(batchSize)); - return new Promise(function(resolve) { + return new Promise((resolve) => { deleteQueryBatch(db, q, batchSize, resolve); }); } diff --git a/snippets/firestore-next/test-firestore/delete_document.js b/snippets/firestore-next/test-firestore/delete_document.js index 27c0bec9..b00ae490 100644 --- a/snippets/firestore-next/test-firestore/delete_document.js +++ b/snippets/firestore-next/test-firestore/delete_document.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START delete_document_modular] -import { collection, doc, deleteDoc } from "firebase/firestore"; +import { doc, deleteDoc } from "firebase/firestore"; -await deleteDoc(doc(collection(db, "cities"), "DC")); +await deleteDoc(doc(db, "cities", "DC")); // [END delete_document_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/detach_listener.js b/snippets/firestore-next/test-firestore/detach_listener.js index 24848db2..cd921018 100644 --- a/snippets/firestore-next/test-firestore/detach_listener.js +++ b/snippets/firestore-next/test-firestore/detach_listener.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START detach_listener_modular] import { collection, onSnapshot } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/disable_network.js b/snippets/firestore-next/test-firestore/disable_network.js index 095e6090..efa1fc27 100644 --- a/snippets/firestore-next/test-firestore/disable_network.js +++ b/snippets/firestore-next/test-firestore/disable_network.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START disable_network_modular] import { disableNetwork } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/doc_reference.js b/snippets/firestore-next/test-firestore/doc_reference.js index 4f3fc134..c5380539 100644 --- a/snippets/firestore-next/test-firestore/doc_reference.js +++ b/snippets/firestore-next/test-firestore/doc_reference.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START doc_reference_modular] -import { collection, doc } from "firebase/firestore"; +import { doc } from "firebase/firestore"; -const alovelaceDocumentRef = doc(collection(db, 'users'), 'alovelace'); +const alovelaceDocumentRef = doc(db, 'users', 'alovelace'); // [END doc_reference_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/doc_reference_alternative.js b/snippets/firestore-next/test-firestore/doc_reference_alternative.js index 8b60f4de..c88294a9 100644 --- a/snippets/firestore-next/test-firestore/doc_reference_alternative.js +++ b/snippets/firestore-next/test-firestore/doc_reference_alternative.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START doc_reference_alternative_modular] import { doc } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/enable_network.js b/snippets/firestore-next/test-firestore/enable_network.js index e6d59889..2df9171b 100644 --- a/snippets/firestore-next/test-firestore/enable_network.js +++ b/snippets/firestore-next/test-firestore/enable_network.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START enable_network_modular] import { enableNetwork } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/example_data.js b/snippets/firestore-next/test-firestore/example_data.js index 52204078..cb7e92aa 100644 --- a/snippets/firestore-next/test-firestore/example_data.js +++ b/snippets/firestore-next/test-firestore/example_data.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START example_data_modular] import { collection, doc, setDoc } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/example_filters.js b/snippets/firestore-next/test-firestore/example_filters.js index ccadb811..b481e5a8 100644 --- a/snippets/firestore-next/test-firestore/example_filters.js +++ b/snippets/firestore-next/test-firestore/example_filters.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START example_filters_modular] -const q1 = query(citiesRef, where("state", "==", "CA")); -const q2 = query(citiesRef, where("population", "<", 100000)); -const q3 = query(citiesRef, where("name", ">=", "San Francisco")); +const stateQuery = query(citiesRef, where("state", "==", "CA")); +const populationQuery = query(citiesRef, where("population", "<", 100000)); +const nameQuery = query(citiesRef, where("name", ">=", "San Francisco")); // [END example_filters_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/filter_and_order.js b/snippets/firestore-next/test-firestore/filter_and_order.js index 13e31c0a..b8c03705 100644 --- a/snippets/firestore-next/test-firestore/filter_and_order.js +++ b/snippets/firestore-next/test-firestore/filter_and_order.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START filter_and_order_modular] import { query, where, orderBy, limit } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/firestore_query_subcollection.js b/snippets/firestore-next/test-firestore/firestore_query_subcollection.js new file mode 100644 index 00000000..76a1b847 --- /dev/null +++ b/snippets/firestore-next/test-firestore/firestore_query_subcollection.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./firestore-next/test.firestore.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START firestore_query_subcollection_modular] +import { collection, getDocs } from "firebase/firestore"; +// Query a reference to a subcollection +const querySnapshot = await getDocs(collection(db, "cities", "SF", "landmarks")); +querySnapshot.forEach((doc) => { + // doc.data() is never undefined for query doc snapshots + console.log(doc.id, " => ", doc.data()); +}); +// [END firestore_query_subcollection_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/fs_collection_group_query.js b/snippets/firestore-next/test-firestore/fs_collection_group_query.js index 96a2d735..3468017b 100644 --- a/snippets/firestore-next/test-firestore/fs_collection_group_query.js +++ b/snippets/firestore-next/test-firestore/fs_collection_group_query.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START fs_collection_group_query_modular] import { collectionGroup, query, where, getDocs } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/fs_collection_group_query_data_setup.js b/snippets/firestore-next/test-firestore/fs_collection_group_query_data_setup.js index ab8964f1..f06ea0f8 100644 --- a/snippets/firestore-next/test-firestore/fs_collection_group_query_data_setup.js +++ b/snippets/firestore-next/test-firestore/fs_collection_group_query_data_setup.js @@ -1,51 +1,52 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START fs_collection_group_query_data_setup_modular] -import { collection, doc, setDoc } from "firebase/firestore"; +import { collection, addDoc } from "firebase/firestore"; const citiesRef = collection(db, 'cities'); await Promise.all([ - setDoc(doc(collection(doc(citiesRef, 'SF'), 'landmarks')), { + addDoc(collection(citiesRef, 'SF', 'landmarks'), { name: 'Golden Gate Bridge', type: 'bridge' }), - setDoc(doc(collection(doc(citiesRef, 'SF'), 'landmarks')), { + addDoc(collection(citiesRef, 'SF', 'landmarks'), { name: 'Legion of Honor', type: 'museum' }), - setDoc(doc(collection(doc(citiesRef, 'LA'), 'landmarks')), { + addDoc(collection(citiesRef, 'LA', 'landmarks'), { name: 'Griffith Park', type: 'park' }), - setDoc(doc(collection(doc(citiesRef, 'LA'), 'landmarks')), { + addDoc(collection(citiesRef, 'LA', 'landmarks'), { name: 'The Getty', type: 'museum' }), - setDoc(doc(collection(doc(citiesRef, 'DC'), 'landmarks')), { + addDoc(collection(citiesRef, 'DC', 'landmarks'), { name: 'Lincoln Memorial', type: 'memorial' }), - setDoc(doc(collection(doc(citiesRef, 'DC'), 'landmarks')), { + addDoc(collection(citiesRef, 'DC', 'landmarks'), { name: 'National Air and Space Museum', type: 'museum' }), - setDoc(doc(collection(doc(citiesRef, 'TOK'), 'landmarks')), { + addDoc(collection(citiesRef, 'TOK', 'landmarks'), { name: 'Ueno Park', type: 'park' }), - setDoc(doc(collection(doc(citiesRef, 'TOK'), 'landmarks')), { + addDoc(collection(citiesRef, 'TOK', 'landmarks'), { name: 'National Museum of Nature and Science', type: 'museum' }), - setDoc(doc(collection(doc(citiesRef, 'BJ'), 'landmarks')), { + addDoc(collection(citiesRef, 'BJ', 'landmarks'), { name: 'Jingshan Park', type: 'park' }), - setDoc(doc(collection(doc(citiesRef, 'BJ'), 'landmarks')), { + addDoc(collection(citiesRef, 'BJ', 'landmarks'), { name: 'Beijing Ancient Observatory', type: 'museum' }) diff --git a/snippets/firestore-next/test-firestore/fs_setup_cache.js b/snippets/firestore-next/test-firestore/fs_setup_cache.js index 3085eb65..8429da4c 100644 --- a/snippets/firestore-next/test-firestore/fs_setup_cache.js +++ b/snippets/firestore-next/test-firestore/fs_setup_cache.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START fs_setup_cache_modular] import { initializeFirestore, CACHE_SIZE_UNLIMITED } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/get_all_users.js b/snippets/firestore-next/test-firestore/get_all_users.js index c8c86b5d..59dd760a 100644 --- a/snippets/firestore-next/test-firestore/get_all_users.js +++ b/snippets/firestore-next/test-firestore/get_all_users.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START get_all_users_modular] import { collection, getDocs } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/get_custom_object.js b/snippets/firestore-next/test-firestore/get_custom_object.js index 92b27330..e20a6839 100644 --- a/snippets/firestore-next/test-firestore/get_custom_object.js +++ b/snippets/firestore-next/test-firestore/get_custom_object.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START get_custom_object_modular] -import { doc, collection, getDoc} from "firebase/firestore"; +import { doc, getDoc} from "firebase/firestore"; -const ref = doc(collection(db, "cities"), "LA").withConverter(cityConverter); +const ref = doc(db, "cities", "LA").withConverter(cityConverter); const docSnap = await getDoc(ref); if (docSnap.exists()) { // Convert to City object diff --git a/snippets/firestore-next/test-firestore/get_document.js b/snippets/firestore-next/test-firestore/get_document.js index 79886025..1653b61a 100644 --- a/snippets/firestore-next/test-firestore/get_document.js +++ b/snippets/firestore-next/test-firestore/get_document.js @@ -1,18 +1,19 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START get_document_modular] -import { collection, doc, getDoc } from "firebase/firestore"; +import { doc, getDoc } from "firebase/firestore"; -const docRef = doc(collection(db, "cities"), "SF"); +const docRef = doc(db, "cities", "SF"); const docSnap = await getDoc(docRef); if (docSnap.exists()) { console.log("Document data:", docSnap.data()); } else { - // doc.data() will be undefined in this case + // docSnap.data() will be undefined in this case console.log("No such document!"); } // [END get_document_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/get_document_options.js b/snippets/firestore-next/test-firestore/get_document_options.js index ecaf4b55..3a708a0d 100644 --- a/snippets/firestore-next/test-firestore/get_document_options.js +++ b/snippets/firestore-next/test-firestore/get_document_options.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START get_document_options_modular] -import { collection, doc, getDocFromCache } from "firebase/firestore"; +import { doc, getDocFromCache } from "firebase/firestore"; -const docRef = doc(collection(db, "cities"), "SF"); +const docRef = doc(db, "cities", "SF"); // Get a document, forcing the SDK to fetch from the offline cache. try { diff --git a/snippets/firestore-next/test-firestore/get_multiple.js b/snippets/firestore-next/test-firestore/get_multiple.js index 9b1616c2..59f8f9c3 100644 --- a/snippets/firestore-next/test-firestore/get_multiple.js +++ b/snippets/firestore-next/test-firestore/get_multiple.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START get_multiple_modular] import { collection, query, where, getDocs } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/get_multiple_all.js b/snippets/firestore-next/test-firestore/get_multiple_all.js index c61ec1ad..721f222e 100644 --- a/snippets/firestore-next/test-firestore/get_multiple_all.js +++ b/snippets/firestore-next/test-firestore/get_multiple_all.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START get_multiple_all_modular] import { collection, getDocs } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/handle_listen_errors.js b/snippets/firestore-next/test-firestore/handle_listen_errors.js index bb59c7d5..c330b67b 100644 --- a/snippets/firestore-next/test-firestore/handle_listen_errors.js +++ b/snippets/firestore-next/test-firestore/handle_listen_errors.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START handle_listen_errors_modular] import { collection, onSnapshot } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/in_filter.js b/snippets/firestore-next/test-firestore/in_filter.js index 55f0a0a7..4a041397 100644 --- a/snippets/firestore-next/test-firestore/in_filter.js +++ b/snippets/firestore-next/test-firestore/in_filter.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START in_filter_modular] import { query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/in_filter_with_array.js b/snippets/firestore-next/test-firestore/in_filter_with_array.js index 722b11aa..190e9dfe 100644 --- a/snippets/firestore-next/test-firestore/in_filter_with_array.js +++ b/snippets/firestore-next/test-firestore/in_filter_with_array.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START in_filter_with_array_modular] import { query, where } from "firebase/firestore"; -const q = query(citiesRef, where('regions', 'in', [['west_coast', 'east_coast']])); +const q = query(citiesRef, where('regions', 'in', [['west_coast'], ['east_coast']])); // [END in_filter_with_array_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/initialize_persistence.js b/snippets/firestore-next/test-firestore/initialize_persistence.js index 97936466..acd5e988 100644 --- a/snippets/firestore-next/test-firestore/initialize_persistence.js +++ b/snippets/firestore-next/test-firestore/initialize_persistence.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START initialize_persistence_modular] import { enableIndexedDbPersistence } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/invalid_filter_and_order.js b/snippets/firestore-next/test-firestore/invalid_filter_and_order.js index 5d8e73e6..708c9cd1 100644 --- a/snippets/firestore-next/test-firestore/invalid_filter_and_order.js +++ b/snippets/firestore-next/test-firestore/invalid_filter_and_order.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START invalid_filter_and_order_modular] import { query, where, orderBy } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/invalid_range_filters.js b/snippets/firestore-next/test-firestore/invalid_range_filters.js index 9ebde4ef..b6236824 100644 --- a/snippets/firestore-next/test-firestore/invalid_range_filters.js +++ b/snippets/firestore-next/test-firestore/invalid_range_filters.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START invalid_range_filters_modular] import { query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/listen_diffs.js b/snippets/firestore-next/test-firestore/listen_diffs.js index 0ef32dff..531c6f1e 100644 --- a/snippets/firestore-next/test-firestore/listen_diffs.js +++ b/snippets/firestore-next/test-firestore/listen_diffs.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START listen_diffs_modular] import { collection, query, where, onSnapshot } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/listen_document.js b/snippets/firestore-next/test-firestore/listen_document.js index 54affb09..47b65229 100644 --- a/snippets/firestore-next/test-firestore/listen_document.js +++ b/snippets/firestore-next/test-firestore/listen_document.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START listen_document_modular] -import { collection, doc, onSnapshot } from "firebase/firestore"; +import { doc, onSnapshot } from "firebase/firestore"; -const unsub = onSnapshot(doc(collection(db, "cities"), "SF"), (doc) => { +const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => { console.log("Current data: ", doc.data()); }); // [END listen_document_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/listen_document_local.js b/snippets/firestore-next/test-firestore/listen_document_local.js index 63a70475..cdb4e63b 100644 --- a/snippets/firestore-next/test-firestore/listen_document_local.js +++ b/snippets/firestore-next/test-firestore/listen_document_local.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START listen_document_local_modular] -import { collection, doc, onSnapshot } from "firebase/firestore"; +import { doc, onSnapshot } from "firebase/firestore"; -const unsub = onSnapshot(doc(collection(db, "cities"), "SF"), (doc) => { +const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => { const source = doc.metadata.hasPendingWrites ? "Local" : "Server"; console.log(source, " data: ", doc.data()); }); diff --git a/snippets/firestore-next/test-firestore/listen_for_users.js b/snippets/firestore-next/test-firestore/listen_for_users.js index 4a8de4a9..5a519349 100644 --- a/snippets/firestore-next/test-firestore/listen_for_users.js +++ b/snippets/firestore-next/test-firestore/listen_for_users.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START listen_for_users_modular] import { collection, where, query, onSnapshot } from "firebase/firestore"; @@ -9,7 +10,7 @@ import { collection, where, query, onSnapshot } from "firebase/firestore"; const q = query(collection(db, "users"), where("born", "<", 1900)); const unsubscribe = onSnapshot(q, (snapshot) => { console.log("Current users born before 1900:"); - snapshot.forEach(function (userSnapshot) { + snapshot.forEach((userSnapshot) => { console.log(userSnapshot.data()); }); }); diff --git a/snippets/firestore-next/test-firestore/listen_multiple.js b/snippets/firestore-next/test-firestore/listen_multiple.js index 0c7f9d46..cf30c178 100644 --- a/snippets/firestore-next/test-firestore/listen_multiple.js +++ b/snippets/firestore-next/test-firestore/listen_multiple.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START listen_multiple_modular] import { collection, query, where, onSnapshot } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/listen_with_metadata.js b/snippets/firestore-next/test-firestore/listen_with_metadata.js index c40746b9..693c1dc1 100644 --- a/snippets/firestore-next/test-firestore/listen_with_metadata.js +++ b/snippets/firestore-next/test-firestore/listen_with_metadata.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START listen_with_metadata_modular] -import { collection, doc, onSnapshot } from "firebase/firestore"; +import { doc, onSnapshot } from "firebase/firestore"; const unsub = onSnapshot( - doc(collection(db, "cities"), "SF"), + doc(db, "cities", "SF"), { includeMetadataChanges: true }, (doc) => { // ... diff --git a/snippets/firestore-next/test-firestore/new_document.js b/snippets/firestore-next/test-firestore/new_document.js index c83e4aa6..219efce7 100644 --- a/snippets/firestore-next/test-firestore/new_document.js +++ b/snippets/firestore-next/test-firestore/new_document.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START new_document_modular] import { collection, doc, setDoc } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/not_in_filter.js b/snippets/firestore-next/test-firestore/not_in_filter.js index c880cb02..70e82480 100644 --- a/snippets/firestore-next/test-firestore/not_in_filter.js +++ b/snippets/firestore-next/test-firestore/not_in_filter.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START not_in_filter_modular] import { query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/order_and_end.js b/snippets/firestore-next/test-firestore/order_and_end.js index d543ea06..7c68047f 100644 --- a/snippets/firestore-next/test-firestore/order_and_end.js +++ b/snippets/firestore-next/test-firestore/order_and_end.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START order_and_end_modular] import { query, orderBy, endAt } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/order_and_limit.js b/snippets/firestore-next/test-firestore/order_and_limit.js index 6979b518..6ff03737 100644 --- a/snippets/firestore-next/test-firestore/order_and_limit.js +++ b/snippets/firestore-next/test-firestore/order_and_limit.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START order_and_limit_modular] import { query, orderBy, limit } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/order_and_limit_desc.js b/snippets/firestore-next/test-firestore/order_and_limit_desc.js index ed61d2ab..725983de 100644 --- a/snippets/firestore-next/test-firestore/order_and_limit_desc.js +++ b/snippets/firestore-next/test-firestore/order_and_limit_desc.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START order_and_limit_desc_modular] import { query, orderBy, limit } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/order_and_start.js b/snippets/firestore-next/test-firestore/order_and_start.js index 20587a90..35cccc84 100644 --- a/snippets/firestore-next/test-firestore/order_and_start.js +++ b/snippets/firestore-next/test-firestore/order_and_start.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START order_and_start_modular] import { query, orderBy, startAt } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/order_multiple.js b/snippets/firestore-next/test-firestore/order_multiple.js index c0991c8c..7e6e5ad6 100644 --- a/snippets/firestore-next/test-firestore/order_multiple.js +++ b/snippets/firestore-next/test-firestore/order_multiple.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START order_multiple_modular] import { query, orderBy } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/paginate.js b/snippets/firestore-next/test-firestore/paginate.js index 26a7325b..cdc146ca 100644 --- a/snippets/firestore-next/test-firestore/paginate.js +++ b/snippets/firestore-next/test-firestore/paginate.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START paginate_modular] import { collection, query, orderBy, startAfter, limit, getDocs } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/server_timestamp_resolution_options.js b/snippets/firestore-next/test-firestore/server_timestamp_resolution_options.js index f59048e2..ac0ce5cb 100644 --- a/snippets/firestore-next/test-firestore/server_timestamp_resolution_options.js +++ b/snippets/firestore-next/test-firestore/server_timestamp_resolution_options.js @@ -1,15 +1,16 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START server_timestamp_resolution_options_modular] -import { collection, doc, updateDoc, serverTimestamp, onSnapshot } from "firebase/firestore"; +import { doc, updateDoc, serverTimestamp, onSnapshot } from "firebase/firestore"; // Perform an update followed by an immediate read without // waiting for the update to complete. Due to the snapshot // options we will get two results: one with an estimate // timestamp and one with the resolved server timestamp. -const docRef = doc(collection(db, 'objects'), 'some-id'); +const docRef = doc(db, 'objects', 'some-id'); updateDoc(docRef, { timestamp: serverTimestamp() }); diff --git a/snippets/firestore-next/test-firestore/set_custom_object.js b/snippets/firestore-next/test-firestore/set_custom_object.js index a71d06ef..e27d3dd4 100644 --- a/snippets/firestore-next/test-firestore/set_custom_object.js +++ b/snippets/firestore-next/test-firestore/set_custom_object.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START set_custom_object_modular] -import { doc, collection, setDoc } from "firebase/firestore"; +import { doc, setDoc } from "firebase/firestore"; // Set with cityConverter -const ref = doc(collection(db, "cities"), "LA").withConverter(cityConverter); +const ref = doc(db, "cities", "LA").withConverter(cityConverter); await setDoc(ref, new City("Los Angeles", "CA", "USA")); // [END set_custom_object_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/set_document.js b/snippets/firestore-next/test-firestore/set_document.js index d3c246ad..a4c9bdb4 100644 --- a/snippets/firestore-next/test-firestore/set_document.js +++ b/snippets/firestore-next/test-firestore/set_document.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START set_document_modular] -import { doc, collection, setDoc } from "firebase/firestore"; +import { doc, setDoc } from "firebase/firestore"; // Add a new document in collection "cities" -await setDoc(doc(collection(db, "cities"), "LA"), { +await setDoc(doc(db, "cities", "LA"), { name: "Los Angeles", state: "CA", country: "USA" diff --git a/snippets/firestore-next/test-firestore/set_with_merge.js b/snippets/firestore-next/test-firestore/set_with_merge.js index e3981920..f33def30 100644 --- a/snippets/firestore-next/test-firestore/set_with_merge.js +++ b/snippets/firestore-next/test-firestore/set_with_merge.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START set_with_merge_modular] -import { doc, collection, setDoc } from "firebase/firestore"; +import { doc, setDoc } from "firebase/firestore"; -const cityRef = doc(collection(db, 'cities'), 'BJ'); +const cityRef = doc(db, 'cities', 'BJ'); setDoc(cityRef, { capital: true }, { merge: true }); // [END set_with_merge_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/simple_queries.js b/snippets/firestore-next/test-firestore/simple_queries.js index 348cd4e6..9eede831 100644 --- a/snippets/firestore-next/test-firestore/simple_queries.js +++ b/snippets/firestore-next/test-firestore/simple_queries.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START simple_queries_modular] // Create a reference to the cities collection diff --git a/snippets/firestore-next/test-firestore/simple_queries_again.js b/snippets/firestore-next/test-firestore/simple_queries_again.js index f6256baf..bb2ebc83 100644 --- a/snippets/firestore-next/test-firestore/simple_queries_again.js +++ b/snippets/firestore-next/test-firestore/simple_queries_again.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START simple_queries_again_modular] import { collection, query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/simple_query_not_equal.js b/snippets/firestore-next/test-firestore/simple_query_not_equal.js index 0ddb5643..d2bef734 100644 --- a/snippets/firestore-next/test-firestore/simple_query_not_equal.js +++ b/snippets/firestore-next/test-firestore/simple_query_not_equal.js @@ -1,8 +1,9 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START simple_query_not_equal_modular] -const q4 = query(citiesRef, where("capital", "!=", false)); +const notCapitalQuery = query(citiesRef, where("capital", "!=", false)); // [END simple_query_not_equal_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/start_doc.js b/snippets/firestore-next/test-firestore/start_doc.js index 23f38e63..88448fcd 100644 --- a/snippets/firestore-next/test-firestore/start_doc.js +++ b/snippets/firestore-next/test-firestore/start_doc.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START start_doc_modular] import { collection, doc, getDoc, query, orderBy, startAt } from "firebase/firestore"; @@ -10,6 +11,6 @@ const citiesRef = collection(db, "cities"); const docSnap = await getDoc(doc(citiesRef, "SF")); // Get all cities with a population bigger than San Francisco -const biggerThanSf = query(citiesRef, orderBy("popuation"), startAt(docSnap)); +const biggerThanSf = query(citiesRef, orderBy("population"), startAt(docSnap)); // ... // [END start_doc_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/start_multiple_orderby.js b/snippets/firestore-next/test-firestore/start_multiple_orderby.js index f0faaec0..88133d16 100644 --- a/snippets/firestore-next/test-firestore/start_multiple_orderby.js +++ b/snippets/firestore-next/test-firestore/start_multiple_orderby.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START start_multiple_orderby_modular] // Will return all Springfields diff --git a/snippets/firestore-next/test-firestore/subcollection_reference.js b/snippets/firestore-next/test-firestore/subcollection_reference.js index 56019331..997714f1 100644 --- a/snippets/firestore-next/test-firestore/subcollection_reference.js +++ b/snippets/firestore-next/test-firestore/subcollection_reference.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START subcollection_reference_modular] -import { doc, collection } from "firebase/firestore"; +import { doc } from "firebase/firestore"; -const messageRef = doc(collection(doc(collection(db, "rooms"), "roomA"), "messages"), "message1"); +const messageRef = doc(db, "rooms", "roomA", "messages", "message1"); // [END subcollection_reference_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/transaction.js b/snippets/firestore-next/test-firestore/transaction.js index 27b84264..727c5f41 100644 --- a/snippets/firestore-next/test-firestore/transaction.js +++ b/snippets/firestore-next/test-firestore/transaction.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START transaction_modular] import { runTransaction } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/transaction_promise.js b/snippets/firestore-next/test-firestore/transaction_promise.js index ef5ca4c7..94792933 100644 --- a/snippets/firestore-next/test-firestore/transaction_promise.js +++ b/snippets/firestore-next/test-firestore/transaction_promise.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START transaction_promise_modular] -import { collection, doc, runTransaction } from "firebase/firestore"; +import { doc, runTransaction } from "firebase/firestore"; // Create a reference to the SF doc. -const sfDocRef = doc(collection(db, "cities"), "SF"); +const sfDocRef = doc(db, "cities", "SF"); try { const newPopulation = await runTransaction(db, async (transaction) => { @@ -19,6 +20,7 @@ try { const newPop = sfDoc.data().population + 1; if (newPop <= 1000000) { transaction.update(sfDocRef, { population: newPop }); + return newPop; } else { return Promise.reject("Sorry! Population is too big"); } diff --git a/snippets/firestore-next/test-firestore/update_delete_field.js b/snippets/firestore-next/test-firestore/update_delete_field.js index b5477302..fc6f1f94 100644 --- a/snippets/firestore-next/test-firestore/update_delete_field.js +++ b/snippets/firestore-next/test-firestore/update_delete_field.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START update_delete_field_modular] -import { doc, collection, updateDoc, deleteField } from "firebase/firestore"; +import { doc, updateDoc, deleteField } from "firebase/firestore"; -const cityRef = doc(collection(db, 'cities'), 'BJ'); +const cityRef = doc(db, 'cities', 'BJ'); // Remove the 'capital' field from the document await updateDoc(cityRef, { diff --git a/snippets/firestore-next/test-firestore/update_document.js b/snippets/firestore-next/test-firestore/update_document.js index 02c21f35..1073482a 100644 --- a/snippets/firestore-next/test-firestore/update_document.js +++ b/snippets/firestore-next/test-firestore/update_document.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START update_document_modular] -import { collection, doc, updateDoc } from "firebase/firestore"; +import { doc, updateDoc } from "firebase/firestore"; -const washingtonRef = doc(collection(db, "cities"), "DC"); +const washingtonRef = doc(db, "cities", "DC"); // Set the "capital" field of the city 'DC' await updateDoc(washingtonRef, { diff --git a/snippets/firestore-next/test-firestore/update_document_array.js b/snippets/firestore-next/test-firestore/update_document_array.js index e2c07145..29a5c04e 100644 --- a/snippets/firestore-next/test-firestore/update_document_array.js +++ b/snippets/firestore-next/test-firestore/update_document_array.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START update_document_array_modular] -import { collection, doc, updateDoc, arrayUnion, arrayRemove } from "firebase/firestore"; +import { doc, updateDoc, arrayUnion, arrayRemove } from "firebase/firestore"; -const washingtonRef = doc(collection(db, "cities"), "DC"); +const washingtonRef = doc(db, "cities", "DC"); // Atomically add a new region to the "regions" array field. await updateDoc(washingtonRef, { diff --git a/snippets/firestore-next/test-firestore/update_document_increment.js b/snippets/firestore-next/test-firestore/update_document_increment.js index 5ad2bb6a..b8555bcf 100644 --- a/snippets/firestore-next/test-firestore/update_document_increment.js +++ b/snippets/firestore-next/test-firestore/update_document_increment.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START update_document_increment_modular] -import { collection, doc, updateDoc, increment } from "firebase/firestore"; +import { doc, updateDoc, increment } from "firebase/firestore"; -const washingtonRef = doc(collection(db, "cities"), "DC"); +const washingtonRef = doc(db, "cities", "DC"); // Atomically increment the population of the city by 50. await updateDoc(washingtonRef, { diff --git a/snippets/firestore-next/test-firestore/update_document_nested.js b/snippets/firestore-next/test-firestore/update_document_nested.js index a1412018..be66b031 100644 --- a/snippets/firestore-next/test-firestore/update_document_nested.js +++ b/snippets/firestore-next/test-firestore/update_document_nested.js @@ -1,13 +1,14 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START update_document_nested_modular] -import { doc, collection, setDoc, updateDoc } from "firebase/firestore"; +import { doc, setDoc, updateDoc } from "firebase/firestore"; // Create an initial document to update. -const frankDocRef = doc(collection(db, "users"), "frank"); +const frankDocRef = doc(db, "users", "frank"); await setDoc(frankDocRef, { name: "Frank", favorites: { food: "Pizza", color: "Blue", subject: "recess" }, diff --git a/snippets/firestore-next/test-firestore/update_with_server_timestamp.js b/snippets/firestore-next/test-firestore/update_with_server_timestamp.js index 39cb4c94..e761f11f 100644 --- a/snippets/firestore-next/test-firestore/update_with_server_timestamp.js +++ b/snippets/firestore-next/test-firestore/update_with_server_timestamp.js @@ -1,12 +1,13 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START update_with_server_timestamp_modular] -import { collection, updateDoc, serverTimestamp } from "firebase/firestore"; +import { updateDoc, serverTimestamp } from "firebase/firestore"; -const docRef = doc(collection(db, 'objects'), 'some-id'); +const docRef = doc(db, 'objects', 'some-id'); // Update the timestamp field with the value from the server const updateTimestamp = await updateDoc(docRef, { diff --git a/snippets/firestore-next/test-firestore/use_from_cache.js b/snippets/firestore-next/test-firestore/use_from_cache.js index 9f125e6c..e9f257da 100644 --- a/snippets/firestore-next/test-firestore/use_from_cache.js +++ b/snippets/firestore-next/test-firestore/use_from_cache.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START use_from_cache_modular] import { collection, onSnapshot, where, query } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/valid_filter_and_order.js b/snippets/firestore-next/test-firestore/valid_filter_and_order.js index ae2519d0..d75524e9 100644 --- a/snippets/firestore-next/test-firestore/valid_filter_and_order.js +++ b/snippets/firestore-next/test-firestore/valid_filter_and_order.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START valid_filter_and_order_modular] import { query, where, orderBy } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/valid_range_filters.js b/snippets/firestore-next/test-firestore/valid_range_filters.js index cd559456..9a7f5350 100644 --- a/snippets/firestore-next/test-firestore/valid_range_filters.js +++ b/snippets/firestore-next/test-firestore/valid_range_filters.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START valid_range_filters_modular] import { query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-firestore/write_batch.js b/snippets/firestore-next/test-firestore/write_batch.js index 157d1bcf..38f41f47 100644 --- a/snippets/firestore-next/test-firestore/write_batch.js +++ b/snippets/firestore-next/test-firestore/write_batch.js @@ -1,24 +1,25 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.firestore.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START write_batch_modular] -import { writeBatch, doc, collection } from "firebase/firestore"; +import { writeBatch, doc } from "firebase/firestore"; // Get a new write batch const batch = writeBatch(db); // Set the value of 'NYC' -const nycRef = doc(collection(db, "cities"), "NYC"); +const nycRef = doc(db, "cities", "NYC"); batch.set(nycRef, {name: "New York City"}); // Update the population of 'SF' -const sfRef = doc(collection(db, "cities"), "SF"); +const sfRef = doc(db, "cities", "SF"); batch.update(sfRef, {"population": 1000000}); // Delete the city 'LA' -const laRef = doc(collection(db, "cities"), "LA"); +const laRef = doc(db, "cities", "LA"); batch.delete(laRef); // Commit the batch diff --git a/snippets/firestore-next/test-solution-aggregation/get_collection_ratings.js b/snippets/firestore-next/test-solution-aggregation/get_collection_ratings.js index 7f820455..bc83cf8b 100644 --- a/snippets/firestore-next/test-solution-aggregation/get_collection_ratings.js +++ b/snippets/firestore-next/test-solution-aggregation/get_collection_ratings.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-aggregation.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START get_collection_ratings_modular] -import { collection, doc, getDocs } from "firebase/firestore"; +import { collection, getDocs } from "firebase/firestore"; -const ratingsRef = collection(doc(collection(db, "restaurants"), "arinell-pizza"), "ratings"); +const ratingsRef = collection(db, "restaurants", "arinell-pizza", "ratings"); const ratingsDocs = await getDocs(ratingsRef); // [END get_collection_ratings_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-solution-aggregation/sample_doc.js b/snippets/firestore-next/test-solution-aggregation/sample_doc.js index 651b4d37..4cec6773 100644 --- a/snippets/firestore-next/test-solution-aggregation/sample_doc.js +++ b/snippets/firestore-next/test-solution-aggregation/sample_doc.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-aggregation.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START sample_doc_modular] const arinellDoc = { diff --git a/snippets/firestore-next/test-solution-arrays/post_with_array.js b/snippets/firestore-next/test-solution-arrays/post_with_array.js index da070d3d..eb336d14 100644 --- a/snippets/firestore-next/test-solution-arrays/post_with_array.js +++ b/snippets/firestore-next/test-solution-arrays/post_with_array.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-arrays.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START post_with_array_modular] // Sample document in the 'posts' collection. diff --git a/snippets/firestore-next/test-solution-arrays/post_with_map.js b/snippets/firestore-next/test-solution-arrays/post_with_map.js index 36ce26cc..16313ace 100644 --- a/snippets/firestore-next/test-solution-arrays/post_with_map.js +++ b/snippets/firestore-next/test-solution-arrays/post_with_map.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-arrays.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START post_with_map_modular] // Sample document in the 'posts' collection diff --git a/snippets/firestore-next/test-solution-arrays/post_with_map_advanced.js b/snippets/firestore-next/test-solution-arrays/post_with_map_advanced.js index b5b40eca..4cb176db 100644 --- a/snippets/firestore-next/test-solution-arrays/post_with_map_advanced.js +++ b/snippets/firestore-next/test-solution-arrays/post_with_map_advanced.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-arrays.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START post_with_map_advanced_modular] // The value of each entry in 'categories' is a unix timestamp diff --git a/snippets/firestore-next/test-solution-arrays/query_in_category.js b/snippets/firestore-next/test-solution-arrays/query_in_category.js index 212ef92b..3a13d2cf 100644 --- a/snippets/firestore-next/test-solution-arrays/query_in_category.js +++ b/snippets/firestore-next/test-solution-arrays/query_in_category.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-arrays.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START query_in_category_modular] import { collection, getDocs, query, where } from "firebase/firestore"; diff --git a/snippets/firestore-next/test-solution-arrays/query_in_category_timestamp.js b/snippets/firestore-next/test-solution-arrays/query_in_category_timestamp.js index 88477e12..87dd9c6f 100644 --- a/snippets/firestore-next/test-solution-arrays/query_in_category_timestamp.js +++ b/snippets/firestore-next/test-solution-arrays/query_in_category_timestamp.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-arrays.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START query_in_category_timestamp_modular] -import { collection, query, where, orderBy } from "@firebase/firestore"; +import { collection, query, where, orderBy } from "firebase/firestore"; const q = query(collection(db, "posts"), where("categories.cats", ">", 0), diff --git a/snippets/firestore-next/test-solution-arrays/query_in_category_timestamp_invalid.js b/snippets/firestore-next/test-solution-arrays/query_in_category_timestamp_invalid.js index 65a84c9f..f50dc17c 100644 --- a/snippets/firestore-next/test-solution-arrays/query_in_category_timestamp_invalid.js +++ b/snippets/firestore-next/test-solution-arrays/query_in_category_timestamp_invalid.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-arrays.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START query_in_category_timestamp_invalid_modular] -import { collection, query, where, orderBy, FirebaseFirestore } from "@firebase/firestore"; +import { collection, query, where, orderBy, Firestore } from "firebase/firestore"; const q = query(collection(db, "posts"), where("categories.cats", "==", true), diff --git a/snippets/firestore-next/test-solution-bundles/fs_bundle_load.js b/snippets/firestore-next/test-solution-bundles/fs_bundle_load.js new file mode 100644 index 00000000..e61315d2 --- /dev/null +++ b/snippets/firestore-next/test-solution-bundles/fs_bundle_load.js @@ -0,0 +1,25 @@ +// This snippet file was generated by processing the source file: +// ./firestore-next/test.solution-bundles.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START fs_bundle_load_modular] +import { loadBundle, namedQuery, getDocsFromCache } from "firebase/firestore"; + +async function fetchFromBundle() { + // Fetch the bundle from Firebase Hosting, if the CDN cache is hit the 'X-Cache' + // response header will be set to 'HIT' + const resp = await fetch('/createBundle'); + + // Load the bundle contents into the Firestore SDK + await loadBundle(db, resp.body); + + // Query the results from the cache + const query = await namedQuery(db, 'latest-stories-query'); + const storiesSnap = await getDocsFromCache(query); + + // Use the results + // ... +} +// [END fs_bundle_load_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-solution-counters/create_counter.js b/snippets/firestore-next/test-solution-counters/create_counter.js index d69b00e6..11dfb3d8 100644 --- a/snippets/firestore-next/test-solution-counters/create_counter.js +++ b/snippets/firestore-next/test-solution-counters/create_counter.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-counters.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START create_counter_modular] function createCounter(ref, num_shards) { - import { collection, doc, writeBatch } from "firebase/firestore"; + import { doc, writeBatch } from "firebase/firestore"; const batch = writeBatch(db); @@ -14,7 +15,7 @@ function createCounter(ref, num_shards) { // Initialize each shard with count=0 for (let i = 0; i < num_shards; i++) { - const shardRef = doc(collection(ref, 'shards'), i.toString()); + const shardRef = doc(ref, 'shards', i.toString()); batch.set(shardRef, { count: 0 }); } diff --git a/snippets/firestore-next/test-solution-counters/get_count.js b/snippets/firestore-next/test-solution-counters/get_count.js index 614173c9..7dec78f1 100644 --- a/snippets/firestore-next/test-solution-counters/get_count.js +++ b/snippets/firestore-next/test-solution-counters/get_count.js @@ -1,11 +1,12 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-counters.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START get_count_modular] async function getCount(ref) { - import { collection, getDocs } from "@firebase/firestore"; + import { collection, getDocs } from "firebase/firestore"; // Sum the count of each shard in the subcollection const snapshot = await getDocs(collection(ref, 'shards')); diff --git a/snippets/firestore-next/test-solution-counters/increment_counter.js b/snippets/firestore-next/test-solution-counters/increment_counter.js index 278fea5f..22defe9c 100644 --- a/snippets/firestore-next/test-solution-counters/increment_counter.js +++ b/snippets/firestore-next/test-solution-counters/increment_counter.js @@ -1,15 +1,16 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-counters.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START increment_counter_modular] function incrementCounter(db, ref, num_shards) { - import { collection, doc, updateDoc, increment, FirebaseFirestore } from "@firebase/firestore"; + import { doc, updateDoc, increment } from "firebase/firestore"; // Select a shard of the counter at random const shardId = Math.floor(Math.random() * num_shards).toString(); - const shardRef = doc(collection(ref, 'shards'), shardId); + const shardRef = doc(ref, 'shards', shardId); // Update count return updateDoc(shardRef, "count", increment(1)); diff --git a/snippets/firestore-next/test-solution-geoqueries/fs_geo_add_hash.js b/snippets/firestore-next/test-solution-geoqueries/fs_geo_add_hash.js index f50ab477..29caa3d5 100644 --- a/snippets/firestore-next/test-solution-geoqueries/fs_geo_add_hash.js +++ b/snippets/firestore-next/test-solution-geoqueries/fs_geo_add_hash.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-geoqueries.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START fs_geo_add_hash_modular] import { doc, updateDoc } from 'firebase/firestore'; diff --git a/snippets/firestore-next/test-solution-geoqueries/fs_geo_query_hashes.js b/snippets/firestore-next/test-solution-geoqueries/fs_geo_query_hashes.js index 1230a989..95a8863c 100644 --- a/snippets/firestore-next/test-solution-geoqueries/fs_geo_query_hashes.js +++ b/snippets/firestore-next/test-solution-geoqueries/fs_geo_query_hashes.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./firestore-next/test.solution-geoqueries.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START fs_geo_query_hashes_modular] import { collection, query, orderBy, startAt, endAt, getDocs } from 'firebase/firestore'; diff --git a/snippets/functions-next/callable/functions_call_add_message.js b/snippets/functions-next/callable/fb_functions_call_add_message.js similarity index 51% rename from snippets/functions-next/callable/functions_call_add_message.js rename to snippets/functions-next/callable/fb_functions_call_add_message.js index 7836b85c..67c01eff 100644 --- a/snippets/functions-next/callable/functions_call_add_message.js +++ b/snippets/functions-next/callable/fb_functions_call_add_message.js @@ -1,16 +1,19 @@ // This snippet file was generated by processing the source file: // ./functions-next/callable.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. -// [START functions_call_add_message_modular] +// [START fb_functions_call_add_message_modular] import { getFunctions, httpsCallable } from "firebase/functions"; -const functions = getFunctions(firebaseApp); +const functions = getFunctions(); const addMessage = httpsCallable(functions, 'addMessage'); addMessage({ text: messageText }) .then((result) => { // Read result of the Cloud Function. - const sanitizedMessage = result.data.text; + /** @type {any} */ + const data = result.data; + const sanitizedMessage = data.text; }); -// [END functions_call_add_message_modular] \ No newline at end of file +// [END fb_functions_call_add_message_modular] \ No newline at end of file diff --git a/snippets/functions-next/callable/functions_call_add_message_error.js b/snippets/functions-next/callable/fb_functions_call_add_message_error.js similarity index 60% rename from snippets/functions-next/callable/functions_call_add_message_error.js rename to snippets/functions-next/callable/fb_functions_call_add_message_error.js index 84d8a381..e87afbdd 100644 --- a/snippets/functions-next/callable/functions_call_add_message_error.js +++ b/snippets/functions-next/callable/fb_functions_call_add_message_error.js @@ -1,17 +1,20 @@ // This snippet file was generated by processing the source file: // ./functions-next/callable.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. -// [START functions_call_add_message_error_modular] +// [START fb_functions_call_add_message_error_modular] import { getFunctions, httpsCallable } from "firebase/functions"; -const functions = getFunctions(firebaseApp); +const functions = getFunctions(); const addMessage = httpsCallable(functions, 'addMessage'); addMessage({ text: messageText }) .then((result) => { // Read result of the Cloud Function. - const sanitizedMessage = result.data.text; + /** @type {any} */ + const data = result.data; + const sanitizedMessage = data.text; }) .catch((error) => { // Getting the Error details. @@ -20,4 +23,4 @@ addMessage({ text: messageText }) const details = error.details; // ... }); -// [END functions_call_add_message_error_modular] \ No newline at end of file +// [END fb_functions_call_add_message_error_modular] \ No newline at end of file diff --git a/snippets/functions-next/callable/fb_functions_initialize.js b/snippets/functions-next/callable/fb_functions_initialize.js new file mode 100644 index 00000000..d03268c8 --- /dev/null +++ b/snippets/functions-next/callable/fb_functions_initialize.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./functions-next/callable.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START fb_functions_initialize_modular] +import { initializeApp } from "firebase/app"; +import { getFunctions } from "firebase/functions"; + +initializeApp({ + // Your Firebase Web SDK configuration + // [START_EXCLUDE] + projectId: "", + apiKey: "", + // [END_EXCLUDE] +}); + +const functions = getFunctions(); +// [END fb_functions_initialize_modular] \ No newline at end of file diff --git a/snippets/functions-next/emulator-suite/functions_callable_call.js b/snippets/functions-next/emulator-suite/fb_functions_callable_call.js similarity index 59% rename from snippets/functions-next/emulator-suite/functions_callable_call.js rename to snippets/functions-next/emulator-suite/fb_functions_callable_call.js index 8ac5f8ed..e547c3d3 100644 --- a/snippets/functions-next/emulator-suite/functions_callable_call.js +++ b/snippets/functions-next/emulator-suite/fb_functions_callable_call.js @@ -1,9 +1,10 @@ // This snippet file was generated by processing the source file: // ./functions-next/emulator-suite.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. -// [START functions_callable_call_modular] +// [START fb_functions_callable_call_modular] import { getApp } from "firebase/app"; import { getFunctions, httpsCallable } from "firebase/functions"; @@ -11,6 +12,8 @@ const functions = getFunctions(getApp()); const addMessage = httpsCallable(functions, 'addMessage'); const result = await addMessage({ text: ''}); -const sanitizedMessage = result.data.text; +/** @type {any} */ +const data = result.data; +const sanitizedMessage = data.text; // ... -// [END functions_callable_call_modular] \ No newline at end of file +// [END fb_functions_callable_call_modular] \ No newline at end of file diff --git a/snippets/functions-next/emulator-suite/fb_functions_emulator_connect.js b/snippets/functions-next/emulator-suite/fb_functions_emulator_connect.js new file mode 100644 index 00000000..835a2c60 --- /dev/null +++ b/snippets/functions-next/emulator-suite/fb_functions_emulator_connect.js @@ -0,0 +1,13 @@ +// This snippet file was generated by processing the source file: +// ./functions-next/emulator-suite.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START fb_functions_emulator_connect_modular] +import { getApp } from "firebase/app"; +import { getFunctions, connectFunctionsEmulator } from "firebase/functions"; + +const functions = getFunctions(getApp()); +connectFunctionsEmulator(functions, "127.0.0.1", 5001); +// [END fb_functions_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/functions-next/emulator-suite/functions_emulator_connect.js b/snippets/functions-next/emulator-suite/functions_emulator_connect.js deleted file mode 100644 index e9d5fead..00000000 --- a/snippets/functions-next/emulator-suite/functions_emulator_connect.js +++ /dev/null @@ -1,12 +0,0 @@ -// This snippet file was generated by processing the source file: -// ./functions-next/emulator-suite.js -// -// To make edits to the snippets in this file, please edit the source - -// [START functions_emulator_connect_modular] -import { getApp } from "firebase/app"; -import { getFunctions, useFunctionsEmulator } from "firebase/functions"; - -const functions = getFunctions(getApp()); -useFunctionsEmulator(functions, "localhost", 5001); -// [END functions_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/messaging-next/index/messaging_delete_token.js b/snippets/messaging-next/index/messaging_delete_token.js new file mode 100644 index 00000000..2e27ab2a --- /dev/null +++ b/snippets/messaging-next/index/messaging_delete_token.js @@ -0,0 +1,17 @@ +// This snippet file was generated by processing the source file: +// ./messaging-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START messaging_delete_token_modular] +import { getMessaging, deleteToken } from "firebase/messaging"; + +const messaging = getMessaging(); +deleteToken(messaging).then(() => { + console.log('Token deleted.'); + // ... +}).catch((err) => { + console.log('Unable to delete token. ', err); +}); +// [END messaging_delete_token_modular] \ No newline at end of file diff --git a/snippets/messaging-next/index/messaging_get_messaging_object.js b/snippets/messaging-next/index/messaging_get_messaging_object.js new file mode 100644 index 00000000..1768bdd2 --- /dev/null +++ b/snippets/messaging-next/index/messaging_get_messaging_object.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./messaging-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START messaging_get_messaging_object_modular] +import { getMessaging } from "firebase/messaging"; + +const messaging = getMessaging(); +// [END messaging_get_messaging_object_modular] \ No newline at end of file diff --git a/snippets/messaging-next/index/messaging_get_token.js b/snippets/messaging-next/index/messaging_get_token.js new file mode 100644 index 00000000..fe571340 --- /dev/null +++ b/snippets/messaging-next/index/messaging_get_token.js @@ -0,0 +1,26 @@ +// This snippet file was generated by processing the source file: +// ./messaging-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START messaging_get_token_modular] +import { getMessaging, getToken } from "firebase/messaging"; + +// Get registration token. Initially this makes a network call, once retrieved +// subsequent calls to getToken will return from cache. +const messaging = getMessaging(); +getToken(messaging, { vapidKey: '' }).then((currentToken) => { + if (currentToken) { + // Send the token to your server and update the UI if necessary + // ... + } else { + // Show permission request UI + console.log('No registration token available. Request permission to generate one.'); + // ... + } +}).catch((err) => { + console.log('An error occurred while retrieving token. ', err); + // ... +}); +// [END messaging_get_token_modular] \ No newline at end of file diff --git a/snippets/messaging-next/index/messaging_receive_message.js b/snippets/messaging-next/index/messaging_receive_message.js new file mode 100644 index 00000000..63825c00 --- /dev/null +++ b/snippets/messaging-next/index/messaging_receive_message.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./messaging-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START messaging_receive_message_modular] +// Handle incoming messages. Called when: +// - a message is received while the app has focus +// - the user clicks on an app notification created by a service worker +// `messaging.onBackgroundMessage` handler. +import { getMessaging, onMessage } from "firebase/messaging"; + +const messaging = getMessaging(); +onMessage(messaging, (payload) => { + console.log('Message received. ', payload); + // ... +}); +// [END messaging_receive_message_modular] \ No newline at end of file diff --git a/snippets/messaging-next/index/messaging_request_permission.js b/snippets/messaging-next/index/messaging_request_permission.js new file mode 100644 index 00000000..c6653037 --- /dev/null +++ b/snippets/messaging-next/index/messaging_request_permission.js @@ -0,0 +1,17 @@ +// This snippet file was generated by processing the source file: +// ./messaging-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START messaging_request_permission_modular] +Notification.requestPermission().then((permission) => { + if (permission === 'granted') { + console.log('Notification permission granted.'); + // TODO(developer): Retrieve a registration token for use with FCM. + // ... + } else { + console.log('Unable to get permission to notify.'); + } +}); +// [END messaging_request_permission_modular] \ No newline at end of file diff --git a/snippets/messaging-next/service-worker/messaging_init_in_sw.js b/snippets/messaging-next/service-worker/messaging_init_in_sw.js new file mode 100644 index 00000000..42f0f526 --- /dev/null +++ b/snippets/messaging-next/service-worker/messaging_init_in_sw.js @@ -0,0 +1,28 @@ +// This snippet file was generated by processing the source file: +// ./messaging-next/service-worker.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START messaging_init_in_sw_modular] +import { initializeApp } from "firebase/app"; +import { getMessaging } from "firebase/messaging/sw"; + +// Initialize the Firebase app in the service worker by passing in +// your app's Firebase config object. +// https://firebase.google.com/docs/web/setup#config-object +const firebaseApp = initializeApp({ + apiKey: 'api-key', + authDomain: 'project-id.firebaseapp.com', + databaseURL: 'https://project-id.firebaseio.com', + projectId: 'project-id', + storageBucket: 'project-id.appspot.com', + messagingSenderId: 'sender-id', + appId: 'app-id', + measurementId: 'G-measurement-id', +}); + +// Retrieve an instance of Firebase Messaging so that it can handle background +// messages. +const messaging = getMessaging(firebaseApp); +// [END messaging_init_in_sw_modular] \ No newline at end of file diff --git a/snippets/messaging-next/service-worker/messaging_on_background_message.js b/snippets/messaging-next/service-worker/messaging_on_background_message.js new file mode 100644 index 00000000..79c17eea --- /dev/null +++ b/snippets/messaging-next/service-worker/messaging_on_background_message.js @@ -0,0 +1,24 @@ +// This snippet file was generated by processing the source file: +// ./messaging-next/service-worker.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START messaging_on_background_message_modular] +import { getMessaging } from "firebase/messaging/sw"; +import { onBackgroundMessage } from "firebase/messaging/sw"; + +const messaging = getMessaging(); +onBackgroundMessage(messaging, (payload) => { + console.log('[firebase-messaging-sw.js] Received background message ', payload); + // Customize notification here + const notificationTitle = 'Background Message Title'; + const notificationOptions = { + body: 'Background Message body.', + icon: '/firebase-logo.png' + }; + + self.registration.showNotification(notificationTitle, + notificationOptions); +}); +// [END messaging_on_background_message_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_add_custom_attributes.js b/snippets/perf-next/index/perf_add_custom_attributes.js index 42639c63..a1a7b13d 100644 --- a/snippets/perf-next/index/perf_add_custom_attributes.js +++ b/snippets/perf-next/index/perf_add_custom_attributes.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./perf-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START perf_add_custom_attributes_modular] import { trace } from "firebase/performance"; diff --git a/snippets/perf-next/index/perf_add_custom_metrics.js b/snippets/perf-next/index/perf_add_custom_metrics.js index ad8ef48c..86dd674b 100644 --- a/snippets/perf-next/index/perf_add_custom_metrics.js +++ b/snippets/perf-next/index/perf_add_custom_metrics.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./perf-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START perf_add_custom_metrics_modular] import { trace } from "firebase/performance"; diff --git a/snippets/perf-next/index/perf_add_custom_trace.js b/snippets/perf-next/index/perf_add_custom_trace.js index 004ecda2..6fd54e49 100644 --- a/snippets/perf-next/index/perf_add_custom_trace.js +++ b/snippets/perf-next/index/perf_add_custom_trace.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./perf-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START perf_add_custom_trace_modular] import { trace } from "firebase/performance"; diff --git a/snippets/perf-next/index/perf_get_instance.js b/snippets/perf-next/index/perf_get_instance.js index c17d5103..8b62eb72 100644 --- a/snippets/perf-next/index/perf_get_instance.js +++ b/snippets/perf-next/index/perf_get_instance.js @@ -1,9 +1,10 @@ // This snippet file was generated by processing the source file: // ./perf-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START perf_get_instance_modular] import { getPerformance } from "firebase/performance"; -const perf = getPerformance(firebaseApp); +const perf = getPerformance(); // [END perf_get_instance_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_import.js b/snippets/perf-next/index/perf_import.js new file mode 100644 index 00000000..326afe91 --- /dev/null +++ b/snippets/perf-next/index/perf_import.js @@ -0,0 +1,9 @@ +// This snippet file was generated by processing the source file: +// ./perf-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START perf_import_modular] +import { getPerformance } from "firebase/performance"; +// [END perf_import_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_import_app.js b/snippets/perf-next/index/perf_import_app.js new file mode 100644 index 00000000..c2b640b9 --- /dev/null +++ b/snippets/perf-next/index/perf_import_app.js @@ -0,0 +1,9 @@ +// This snippet file was generated by processing the source file: +// ./perf-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START perf_import_app_modular] +import { initializeApp } from "firebase/app"; +// [END perf_import_app_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_initialize_app.js b/snippets/perf-next/index/perf_initialize_app.js new file mode 100644 index 00000000..94e0c966 --- /dev/null +++ b/snippets/perf-next/index/perf_initialize_app.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./perf-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START perf_initialize_app_modular] +// TODO: Replace the following with your app's Firebase project configuration +// See: https://firebase.google.com/docs/web/learn-more#config-object +const firebaseConfig = { + // ... +}; + +// Initialize Firebase +const app = initializeApp(firebaseConfig); +// [END perf_initialize_app_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_singleton.js b/snippets/perf-next/index/perf_singleton.js new file mode 100644 index 00000000..e070b52b --- /dev/null +++ b/snippets/perf-next/index/perf_singleton.js @@ -0,0 +1,10 @@ +// This snippet file was generated by processing the source file: +// ./perf-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START perf_singleton_modular] +// Initialize Performance Monitoring and get a reference to the service +const perf = getPerformance(app); +// [END perf_singleton_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_user_timing_marks.js b/snippets/perf-next/index/perf_user_timing_marks.js index 5854f85c..8450370f 100644 --- a/snippets/perf-next/index/perf_user_timing_marks.js +++ b/snippets/perf-next/index/perf_user_timing_marks.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./perf-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START perf_user_timing_marks_modular] const performance = window.performance; diff --git a/snippets/placeholder/coming_soon.js b/snippets/placeholder/coming_soon.js index 715d6a3d..0477645f 100644 --- a/snippets/placeholder/coming_soon.js +++ b/snippets/placeholder/coming_soon.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./placeholder.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START coming_soon_modular] // TODO: Snippet coming soon! diff --git a/snippets/remoteconfig-next/index/rc_fetch_config_callback.js b/snippets/remoteconfig-next/index/rc_fetch_config_callback.js index 3975befd..3cb39de0 100644 --- a/snippets/remoteconfig-next/index/rc_fetch_config_callback.js +++ b/snippets/remoteconfig-next/index/rc_fetch_config_callback.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./remoteconfig-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START rc_fetch_config_callback_modular] import { fetchAndActivate } from "firebase/remote-config"; diff --git a/snippets/remoteconfig-next/index/rc_get_instance.js b/snippets/remoteconfig-next/index/rc_get_instance.js index e20bd5a9..0bf952b8 100644 --- a/snippets/remoteconfig-next/index/rc_get_instance.js +++ b/snippets/remoteconfig-next/index/rc_get_instance.js @@ -1,10 +1,11 @@ // This snippet file was generated by processing the source file: // ./remoteconfig-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START rc_get_instance_modular] import { getRemoteConfig } from "firebase/remote-config"; -const remoteConfig = getRemoteConfig(firebaseApp); +const remoteConfig = getRemoteConfig(); // [END rc_get_instance_modular] \ No newline at end of file diff --git a/snippets/remoteconfig-next/index/rc_get_values.js b/snippets/remoteconfig-next/index/rc_get_values.js index 1266cfe9..67018e3b 100644 --- a/snippets/remoteconfig-next/index/rc_get_values.js +++ b/snippets/remoteconfig-next/index/rc_get_values.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./remoteconfig-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START rc_get_values_modular] import { getValue } from "firebase/remote-config"; diff --git a/snippets/remoteconfig-next/index/rc_set_default_values.js b/snippets/remoteconfig-next/index/rc_set_default_values.js index 6db33c0d..80e0e8c2 100644 --- a/snippets/remoteconfig-next/index/rc_set_default_values.js +++ b/snippets/remoteconfig-next/index/rc_set_default_values.js @@ -1,7 +1,8 @@ // This snippet file was generated by processing the source file: // ./remoteconfig-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START rc_set_default_values_modular] remoteConfig.defaultConfig = { diff --git a/snippets/remoteconfig-next/index/rc_set_minimum_fetch_time.js b/snippets/remoteconfig-next/index/rc_set_minimum_fetch_time.js index 77a442f9..77aa9f45 100644 --- a/snippets/remoteconfig-next/index/rc_set_minimum_fetch_time.js +++ b/snippets/remoteconfig-next/index/rc_set_minimum_fetch_time.js @@ -1,8 +1,10 @@ // This snippet file was generated by processing the source file: // ./remoteconfig-next/index.js // -// To make edits to the snippets in this file, please edit the source +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. // [START rc_set_minimum_fetch_time_modular] +// The default and recommended production fetch interval for Remote Config is 12 hours remoteConfig.settings.minimumFetchIntervalMillis = 3600000; // [END rc_set_minimum_fetch_time_modular] \ No newline at end of file diff --git a/snippets/storage-next/create-reference/storage_create_ref.js b/snippets/storage-next/create-reference/storage_create_ref.js new file mode 100644 index 00000000..761a634a --- /dev/null +++ b/snippets/storage-next/create-reference/storage_create_ref.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/create-reference.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_create_ref_modular] +import { getStorage, ref } from "firebase/storage"; + +// Get a reference to the storage service, which is used to create references in your storage bucket +const storage = getStorage(); + +// Create a storage reference from our storage service +const storageRef = ref(storage); +// [END storage_create_ref_modular] \ No newline at end of file diff --git a/snippets/storage-next/create-reference/storage_create_ref_child.js b/snippets/storage-next/create-reference/storage_create_ref_child.js new file mode 100644 index 00000000..5e16407a --- /dev/null +++ b/snippets/storage-next/create-reference/storage_create_ref_child.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/create-reference.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_create_ref_child_modular] +import { getStorage, ref } from "firebase/storage"; + +const storage = getStorage(); + +// Create a child reference +const imagesRef = ref(storage, 'images'); +// imagesRef now points to 'images' + +// Child references can also take paths delimited by '/' +const spaceRef = ref(storage, 'images/space.jpg'); +// spaceRef now points to "images/space.jpg" +// imagesRef still points to "images" +// [END storage_create_ref_child_modular] \ No newline at end of file diff --git a/snippets/storage-next/create-reference/storage_navigate_ref.js b/snippets/storage-next/create-reference/storage_navigate_ref.js new file mode 100644 index 00000000..ee279c72 --- /dev/null +++ b/snippets/storage-next/create-reference/storage_navigate_ref.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/create-reference.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_navigate_ref_modular] +import { getStorage, ref } from "firebase/storage"; + +const storage = getStorage(); +const spaceRef = ref(storage, 'images/space.jpg'); + +// Parent allows us to move to the parent of a reference +const imagesRef = spaceRef.parent; +// imagesRef now points to 'images' + +// Root allows us to move all the way back to the top of our bucket +const rootRef = spaceRef.root; +// rootRef now points to the root +// [END storage_navigate_ref_modular] \ No newline at end of file diff --git a/snippets/storage-next/create-reference/storage_navigate_ref_chain.js b/snippets/storage-next/create-reference/storage_navigate_ref_chain.js new file mode 100644 index 00000000..d5e13752 --- /dev/null +++ b/snippets/storage-next/create-reference/storage_navigate_ref_chain.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/create-reference.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_navigate_ref_chain_modular] +import { getStorage, ref } from "firebase/storage"; + +const storage = getStorage(); +const spaceRef = ref(storage, 'images/space.jpg'); + +// References can be chained together multiple times +const earthRef = ref(spaceRef.parent, 'earth.jpg'); +// earthRef points to 'images/earth.jpg' + +// nullRef is null, since the parent of root is null +const nullRef = spaceRef.root.parent; +// [END storage_navigate_ref_chain_modular] \ No newline at end of file diff --git a/snippets/storage-next/create-reference/storage_ref_full_example.js b/snippets/storage-next/create-reference/storage_ref_full_example.js new file mode 100644 index 00000000..e61f4594 --- /dev/null +++ b/snippets/storage-next/create-reference/storage_ref_full_example.js @@ -0,0 +1,31 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/create-reference.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_ref_full_example_modular] +import { getStorage, ref } from "firebase/storage"; + +const storage = getStorage(); + +// Points to the root reference +const storageRef = ref(storage); + +// Points to 'images' +const imagesRef = ref(storageRef, 'images'); + +// Points to 'images/space.jpg' +// Note that you can use variables to create child values +const fileName = 'space.jpg'; +const spaceRef = ref(imagesRef, fileName); + +// File path is 'images/space.jpg' +const path = spaceRef.fullPath; + +// File name is 'space.jpg' +const name = spaceRef.name; + +// Points to 'images' +const imagesRefAgain = spaceRef.parent; +// [END storage_ref_full_example_modular] \ No newline at end of file diff --git a/snippets/storage-next/create-reference/storage_ref_properties.js b/snippets/storage-next/create-reference/storage_ref_properties.js new file mode 100644 index 00000000..c95a5b13 --- /dev/null +++ b/snippets/storage-next/create-reference/storage_ref_properties.js @@ -0,0 +1,23 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/create-reference.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_ref_properties_modular] +import { getStorage, ref } from "firebase/storage"; + +const storage = getStorage(); +const spaceRef = ref(storage, 'images/space.jpg'); + +// Reference's path is: 'images/space.jpg' +// This is analogous to a file path on disk +spaceRef.fullPath; + +// Reference's name is the last segment of the full path: 'space.jpg' +// This is analogous to the file name +spaceRef.name; + +// Reference's bucket is the name of the storage bucket where files are stored +spaceRef.bucket; +// [END storage_ref_properties_modular] \ No newline at end of file diff --git a/snippets/storage-next/delete-files/storage_delete_file.js b/snippets/storage-next/delete-files/storage_delete_file.js new file mode 100644 index 00000000..c851c447 --- /dev/null +++ b/snippets/storage-next/delete-files/storage_delete_file.js @@ -0,0 +1,21 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/delete-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_delete_file_modular] +import { getStorage, ref, deleteObject } from "firebase/storage"; + +const storage = getStorage(); + +// Create a reference to the file to delete +const desertRef = ref(storage, 'images/desert.jpg'); + +// Delete the file +deleteObject(desertRef).then(() => { + // File deleted successfully +}).catch((error) => { + // Uh-oh, an error occurred! +}); +// [END storage_delete_file_modular] \ No newline at end of file diff --git a/snippets/storage-next/download-files/storage_download_create_ref.js b/snippets/storage-next/download-files/storage_download_create_ref.js new file mode 100644 index 00000000..8b1345b7 --- /dev/null +++ b/snippets/storage-next/download-files/storage_download_create_ref.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/download-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_download_create_ref_modular] +import { getStorage, ref } from "firebase/storage"; + +// Create a reference with an initial file path and name +const storage = getStorage(); +const pathReference = ref(storage, 'images/stars.jpg'); + +// Create a reference from a Google Cloud Storage URI +const gsReference = ref(storage, 'gs://bucket/images/stars.jpg'); + +// Create a reference from an HTTPS URL +// Note that in the URL, characters are URL escaped! +const httpsReference = ref(storage, 'https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg'); +// [END storage_download_create_ref_modular] \ No newline at end of file diff --git a/snippets/storage-next/download-files/storage_download_full_example.js b/snippets/storage-next/download-files/storage_download_full_example.js new file mode 100644 index 00000000..cdd12166 --- /dev/null +++ b/snippets/storage-next/download-files/storage_download_full_example.js @@ -0,0 +1,40 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/download-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_download_full_example_modular] +import { getStorage, ref, getDownloadURL } from "firebase/storage"; + +// Create a reference to the file we want to download +const storage = getStorage(); +const starsRef = ref(storage, 'images/stars.jpg'); + +// Get the download URL +getDownloadURL(starsRef) + .then((url) => { + // Insert url into an tag to "download" + }) + .catch((error) => { + // A full list of error codes is available at + // https://firebase.google.com/docs/storage/web/handle-errors + switch (error.code) { + case 'storage/object-not-found': + // File doesn't exist + break; + case 'storage/unauthorized': + // User doesn't have permission to access the object + break; + case 'storage/canceled': + // User canceled the upload + break; + + // ... + + case 'storage/unknown': + // Unknown error occurred, inspect the server response + break; + } + }); +// [END storage_download_full_example_modular] \ No newline at end of file diff --git a/snippets/storage-next/download-files/storage_download_via_url.js b/snippets/storage-next/download-files/storage_download_via_url.js new file mode 100644 index 00000000..c90e235c --- /dev/null +++ b/snippets/storage-next/download-files/storage_download_via_url.js @@ -0,0 +1,31 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/download-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_download_via_url_modular] +import { getStorage, ref, getDownloadURL } from "firebase/storage"; + +const storage = getStorage(); +getDownloadURL(ref(storage, 'images/stars.jpg')) + .then((url) => { + // `url` is the download URL for 'images/stars.jpg' + + // This can be downloaded directly: + const xhr = new XMLHttpRequest(); + xhr.responseType = 'blob'; + xhr.onload = (event) => { + const blob = xhr.response; + }; + xhr.open('GET', url); + xhr.send(); + + // Or inserted into an element + const img = document.getElementById('myimg'); + img.setAttribute('src', url); + }) + .catch((error) => { + // Handle any errors + }); +// [END storage_download_via_url_modular] \ No newline at end of file diff --git a/snippets/storage-next/emulator-suite/storage_emulator_connect.js b/snippets/storage-next/emulator-suite/storage_emulator_connect.js new file mode 100644 index 00000000..4b247d17 --- /dev/null +++ b/snippets/storage-next/emulator-suite/storage_emulator_connect.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/emulator-suite.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_emulator_connect_modular] +import { getStorage, connectStorageEmulator } from "firebase/storage"; + +const storage = getStorage(); +if (location.hostname === "localhost") { + // Point to the Storage emulator running on localhost. + connectStorageEmulator(storage, "127.0.0.1", 9199); +} +// [END storage_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/storage-next/file-metadata/storage_custom_metadata.js b/snippets/storage-next/file-metadata/storage_custom_metadata.js new file mode 100644 index 00000000..d6fb5ab4 --- /dev/null +++ b/snippets/storage-next/file-metadata/storage_custom_metadata.js @@ -0,0 +1,14 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/file-metadata.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_custom_metadata_modular] +const metadata = { + customMetadata: { + 'location': 'Yosemite, CA, USA', + 'activity': 'Hiking' + } +}; +// [END storage_custom_metadata_modular] \ No newline at end of file diff --git a/snippets/storage-next/file-metadata/storage_delete_metadata.js b/snippets/storage-next/file-metadata/storage_delete_metadata.js new file mode 100644 index 00000000..71db946e --- /dev/null +++ b/snippets/storage-next/file-metadata/storage_delete_metadata.js @@ -0,0 +1,25 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/file-metadata.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_delete_metadata_modular] +import { getStorage, ref, updateMetadata } from "firebase/storage"; + +const storage = getStorage(); +const forestRef = ref(storage, 'images/forest.jpg'); + +// Create file metadata with property to delete +const deleteMetadata = { + contentType: null +}; + +// Delete the metadata property +updateMetadata(forestRef, deleteMetadata) + .then((metadata) => { + // metadata.contentType should be null + }).catch((error) => { + // Uh-oh, an error occurred! + }); +// [END storage_delete_metadata_modular] \ No newline at end of file diff --git a/snippets/storage-next/file-metadata/storage_get_metadata.js b/snippets/storage-next/file-metadata/storage_get_metadata.js new file mode 100644 index 00000000..b2c96f1a --- /dev/null +++ b/snippets/storage-next/file-metadata/storage_get_metadata.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/file-metadata.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_get_metadata_modular] +import { getStorage, ref, getMetadata } from "firebase/storage"; + +// Create a reference to the file whose metadata we want to retrieve +const storage = getStorage(); +const forestRef = ref(storage, 'images/forest.jpg'); + +// Get metadata properties +getMetadata(forestRef) + .then((metadata) => { + // Metadata now contains the metadata for 'images/forest.jpg' + }) + .catch((error) => { + // Uh-oh, an error occurred! + }); +// [END storage_get_metadata_modular] \ No newline at end of file diff --git a/snippets/storage-next/file-metadata/storage_update_metadata.js b/snippets/storage-next/file-metadata/storage_update_metadata.js new file mode 100644 index 00000000..2435983b --- /dev/null +++ b/snippets/storage-next/file-metadata/storage_update_metadata.js @@ -0,0 +1,27 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/file-metadata.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_update_metadata_modular] +import { getStorage, ref, updateMetadata } from "firebase/storage"; + +// Create a reference to the file whose metadata we want to change +const storage = getStorage(); +const forestRef = ref(storage, 'images/forest.jpg'); + +// Create file metadata to update +const newMetadata = { + cacheControl: 'public,max-age=300', + contentType: 'image/jpeg' +}; + +// Update metadata properties +updateMetadata(forestRef, newMetadata) + .then((metadata) => { + // Updated metadata for 'images/forest.jpg' is returned in the Promise + }).catch((error) => { + // Uh-oh, an error occurred! + }); +// [END storage_update_metadata_modular] \ No newline at end of file diff --git a/snippets/storage-next/index/storage_custom_app.js b/snippets/storage-next/index/storage_custom_app.js new file mode 100644 index 00000000..7196c252 --- /dev/null +++ b/snippets/storage-next/index/storage_custom_app.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_custom_app_modular] +import { getStorage } from "firebase/storage"; + +// Get the default bucket from a custom firebase.app.App +const storage1 = getStorage(customApp); + +// Get a non-default bucket from a custom firebase.app.App +const storage2 = getStorage(customApp, "gs://my-custom-bucket"); +// [END storage_custom_app_modular] \ No newline at end of file diff --git a/snippets/storage-next/index/storage_initialize.js b/snippets/storage-next/index/storage_initialize.js new file mode 100644 index 00000000..422df3dd --- /dev/null +++ b/snippets/storage-next/index/storage_initialize.js @@ -0,0 +1,23 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_initialize_modular] +import { initializeApp } from "firebase/app"; +import { getStorage } from "firebase/storage"; + +// Set the configuration for your app +// TODO: Replace with your app's config object +const firebaseConfig = { + apiKey: '', + authDomain: '', + databaseURL: '', + storageBucket: '' +}; +const firebaseApp = initializeApp(firebaseConfig); + +// Get a reference to the storage service, which is used to create references in your storage bucket +const storage = getStorage(firebaseApp); +// [END storage_initialize_modular] \ No newline at end of file diff --git a/snippets/storage-next/index/storage_multiple_buckets.js b/snippets/storage-next/index/storage_multiple_buckets.js new file mode 100644 index 00000000..426dd4f4 --- /dev/null +++ b/snippets/storage-next/index/storage_multiple_buckets.js @@ -0,0 +1,14 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_multiple_buckets_modular] +import { getApp } from "firebase/app"; +import { getStorage } from "firebase/storage"; + +// Get a non-default Storage bucket +const firebaseApp = getApp(); +const storage = getStorage(firebaseApp, "gs://my-custom-bucket"); +// [END storage_multiple_buckets_modular] \ No newline at end of file diff --git a/snippets/storage-next/index/storage_on_complete.js b/snippets/storage-next/index/storage_on_complete.js new file mode 100644 index 00000000..e5d792f3 --- /dev/null +++ b/snippets/storage-next/index/storage_on_complete.js @@ -0,0 +1,25 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_on_complete_modular] +import { getStorage, ref, uploadBytesResumable, getDownloadURL } from "firebase/storage"; + +const storage = getStorage(); +const imageRef = ref(storage, 'images/' + file.name); +uploadBytesResumable(imageRef, file, metadata) + .then((snapshot) => { + console.log('Uploaded', snapshot.totalBytes, 'bytes.'); + console.log('File metadata:', snapshot.metadata); + // Let's get a download URL for the file. + getDownloadURL(snapshot.ref).then((url) => { + console.log('File available at', url); + // ... + }); + }).catch((error) => { + console.error('Upload failed', error); + // ... + }); +// [END storage_on_complete_modular] \ No newline at end of file diff --git a/snippets/storage-next/list-files/storage_list_all.js b/snippets/storage-next/list-files/storage_list_all.js new file mode 100644 index 00000000..11e72e9e --- /dev/null +++ b/snippets/storage-next/list-files/storage_list_all.js @@ -0,0 +1,28 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/list-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_list_all_modular] +import { getStorage, ref, listAll } from "firebase/storage"; + +const storage = getStorage(); + +// Create a reference under which you want to list +const listRef = ref(storage, 'files/uid'); + +// Find all the prefixes and items. +listAll(listRef) + .then((res) => { + res.prefixes.forEach((folderRef) => { + // All the prefixes under listRef. + // You may call listAll() recursively on them. + }); + res.items.forEach((itemRef) => { + // All the items under listRef. + }); + }).catch((error) => { + // Uh-oh, an error occurred! + }); +// [END storage_list_all_modular] \ No newline at end of file diff --git a/snippets/storage-next/list-files/storage_list_paginate.js b/snippets/storage-next/list-files/storage_list_paginate.js new file mode 100644 index 00000000..c7dd314e --- /dev/null +++ b/snippets/storage-next/list-files/storage_list_paginate.js @@ -0,0 +1,32 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/list-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_list_paginate_modular] +import { getStorage, ref, list } from "firebase/storage"; + +async function pageTokenExample(){ + // Create a reference under which you want to list + const storage = getStorage(); + const listRef = ref(storage, 'files/uid'); + + // Fetch the first page of 100. + const firstPage = await list(listRef, { maxResults: 100 }); + + // Use the result. + // processItems(firstPage.items) + // processPrefixes(firstPage.prefixes) + + // Fetch the second page if there are more elements. + if (firstPage.nextPageToken) { + const secondPage = await list(listRef, { + maxResults: 100, + pageToken: firstPage.nextPageToken, + }); + // processItems(secondPage.items) + // processPrefixes(secondPage.prefixes) + } +} +// [END storage_list_paginate_modular] \ No newline at end of file diff --git a/snippets/storage-next/upload-files/storage_manage_uploads.js b/snippets/storage-next/upload-files/storage_manage_uploads.js new file mode 100644 index 00000000..0eaf008a --- /dev/null +++ b/snippets/storage-next/upload-files/storage_manage_uploads.js @@ -0,0 +1,24 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/upload-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_manage_uploads_modular] +import { getStorage, ref, uploadBytesResumable } from "firebase/storage"; + +const storage = getStorage(); +const storageRef = ref(storage, 'images/mountains.jpg'); + +// Upload the file and metadata +const uploadTask = uploadBytesResumable(storageRef, file); + +// Pause the upload +uploadTask.pause(); + +// Resume the upload +uploadTask.resume(); + +// Cancel the upload +uploadTask.cancel(); +// [END storage_manage_uploads_modular] \ No newline at end of file diff --git a/snippets/storage-next/upload-files/storage_monitor_upload.js b/snippets/storage-next/upload-files/storage_monitor_upload.js new file mode 100644 index 00000000..cf035832 --- /dev/null +++ b/snippets/storage-next/upload-files/storage_monitor_upload.js @@ -0,0 +1,45 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/upload-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_monitor_upload_modular] +import { getStorage, ref, uploadBytesResumable, getDownloadURL } from "firebase/storage"; + +const storage = getStorage(); +const storageRef = ref(storage, 'images/rivers.jpg'); + +const uploadTask = uploadBytesResumable(storageRef, file); + +// Register three observers: +// 1. 'state_changed' observer, called any time the state changes +// 2. Error observer, called on failure +// 3. Completion observer, called on successful completion +uploadTask.on('state_changed', + (snapshot) => { + // Observe state change events such as progress, pause, and resume + // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded + const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + console.log('Upload is ' + progress + '% done'); + switch (snapshot.state) { + case 'paused': + console.log('Upload is paused'); + break; + case 'running': + console.log('Upload is running'); + break; + } + }, + (error) => { + // Handle unsuccessful uploads + }, + () => { + // Handle successful uploads on complete + // For instance, get the download URL: https://firebasestorage.googleapis.com/... + getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { + console.log('File available at', downloadURL); + }); + } +); +// [END storage_monitor_upload_modular] \ No newline at end of file diff --git a/snippets/storage-next/upload-files/storage_upload_blob.js b/snippets/storage-next/upload-files/storage_upload_blob.js new file mode 100644 index 00000000..5ad22f8e --- /dev/null +++ b/snippets/storage-next/upload-files/storage_upload_blob.js @@ -0,0 +1,17 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/upload-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_upload_blob_modular] +import { getStorage, ref, uploadBytes } from "firebase/storage"; + +const storage = getStorage(); +const storageRef = ref(storage, 'some-child'); + +// 'file' comes from the Blob or File API +uploadBytes(storageRef, file).then((snapshot) => { + console.log('Uploaded a blob or file!'); +}); +// [END storage_upload_blob_modular] \ No newline at end of file diff --git a/snippets/storage-next/upload-files/storage_upload_bytes.js b/snippets/storage-next/upload-files/storage_upload_bytes.js new file mode 100644 index 00000000..82acac25 --- /dev/null +++ b/snippets/storage-next/upload-files/storage_upload_bytes.js @@ -0,0 +1,17 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/upload-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_upload_bytes_modular] +import { getStorage, ref, uploadBytes } from "firebase/storage"; + +const storage = getStorage(); +const storageRef = ref(storage, 'some-child'); + +const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21]); +uploadBytes(storageRef, bytes).then((snapshot) => { + console.log('Uploaded an array!'); +}); +// [END storage_upload_bytes_modular] \ No newline at end of file diff --git a/snippets/storage-next/upload-files/storage_upload_handle_error.js b/snippets/storage-next/upload-files/storage_upload_handle_error.js new file mode 100644 index 00000000..bf50c6b5 --- /dev/null +++ b/snippets/storage-next/upload-files/storage_upload_handle_error.js @@ -0,0 +1,62 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/upload-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_upload_handle_error_modular] +import { getStorage, ref, uploadBytesResumable, getDownloadURL } from "firebase/storage"; + +const storage = getStorage(); + +// Create the file metadata +/** @type {any} */ +const metadata = { + contentType: 'image/jpeg' +}; + +// Upload file and metadata to the object 'images/mountains.jpg' +const storageRef = ref(storage, 'images/' + file.name); +const uploadTask = uploadBytesResumable(storageRef, file, metadata); + +// Listen for state changes, errors, and completion of the upload. +uploadTask.on('state_changed', + (snapshot) => { + // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded + const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + console.log('Upload is ' + progress + '% done'); + switch (snapshot.state) { + case 'paused': + console.log('Upload is paused'); + break; + case 'running': + console.log('Upload is running'); + break; + } + }, + (error) => { + // A full list of error codes is available at + // https://firebase.google.com/docs/storage/web/handle-errors + switch (error.code) { + case 'storage/unauthorized': + // User doesn't have permission to access the object + break; + case 'storage/canceled': + // User canceled the upload + break; + + // ... + + case 'storage/unknown': + // Unknown error occurred, inspect error.serverResponse + break; + } + }, + () => { + // Upload completed successfully, now we can get the download URL + getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { + console.log('File available at', downloadURL); + }); + } +); +// [END storage_upload_handle_error_modular] \ No newline at end of file diff --git a/snippets/storage-next/upload-files/storage_upload_metadata.js b/snippets/storage-next/upload-files/storage_upload_metadata.js new file mode 100644 index 00000000..3dd304b4 --- /dev/null +++ b/snippets/storage-next/upload-files/storage_upload_metadata.js @@ -0,0 +1,21 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/upload-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_upload_metadata_modular] +import { getStorage, ref, uploadBytes } from "firebase/storage"; + +const storage = getStorage(); +const storageRef = ref(storage, 'images/mountains.jpg'); + +// Create file metadata including the content type +/** @type {any} */ +const metadata = { + contentType: 'image/jpeg', +}; + +// Upload the file and metadata +const uploadTask = uploadBytes(storageRef, file, metadata); +// [END storage_upload_metadata_modular] \ No newline at end of file diff --git a/snippets/storage-next/upload-files/storage_upload_ref.js b/snippets/storage-next/upload-files/storage_upload_ref.js new file mode 100644 index 00000000..ef565bf2 --- /dev/null +++ b/snippets/storage-next/upload-files/storage_upload_ref.js @@ -0,0 +1,22 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/upload-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_upload_ref_modular] +import { getStorage, ref } from "firebase/storage"; + +// Create a root reference +const storage = getStorage(); + +// Create a reference to 'mountains.jpg' +const mountainsRef = ref(storage, 'mountains.jpg'); + +// Create a reference to 'images/mountains.jpg' +const mountainImagesRef = ref(storage, 'images/mountains.jpg'); + +// While the file names are the same, the references point to different files +mountainsRef.name === mountainImagesRef.name; // true +mountainsRef.fullPath === mountainImagesRef.fullPath; // false +// [END storage_upload_ref_modular] \ No newline at end of file diff --git a/snippets/storage-next/upload-files/storage_upload_string.js b/snippets/storage-next/upload-files/storage_upload_string.js new file mode 100644 index 00000000..6450a566 --- /dev/null +++ b/snippets/storage-next/upload-files/storage_upload_string.js @@ -0,0 +1,36 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/upload-files.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_upload_string_modular] +import { getStorage, ref, uploadString } from "firebase/storage"; + +const storage = getStorage(); +const storageRef = ref(storage, 'some-child'); + +// Raw string is the default if no format is provided +const message = 'This is my message.'; +uploadString(storageRef, message).then((snapshot) => { + console.log('Uploaded a raw string!'); +}); + +// Base64 formatted string +const message2 = '5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; +uploadString(storageRef, message2, 'base64').then((snapshot) => { + console.log('Uploaded a base64 string!'); +}); + +// Base64url formatted string +const message3 = '5b6p5Y-344GX44G-44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; +uploadString(storageRef, message3, 'base64url').then((snapshot) => { + console.log('Uploaded a base64url string!'); +}); + +// Data URL string +const message4 = 'data:text/plain;base64,5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; +uploadString(storageRef, message4, 'data_url').then((snapshot) => { + console.log('Uploaded a data_url string!'); +}); +// [END storage_upload_string_modular] \ No newline at end of file diff --git a/storage-next/create-reference.js b/storage-next/create-reference.js new file mode 100644 index 00000000..47a6e227 --- /dev/null +++ b/storage-next/create-reference.js @@ -0,0 +1,112 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function createRef() { + // [START storage_create_ref] + const { getStorage, ref } = require("firebase/storage"); + + // Get a reference to the storage service, which is used to create references in your storage bucket + const storage = getStorage(); + + // Create a storage reference from our storage service + const storageRef = ref(storage); + // [END storage_create_ref] +} + +function createRefChild() { + // [START storage_create_ref_child] + const { getStorage, ref } = require("firebase/storage"); + + const storage = getStorage(); + + // Create a child reference + const imagesRef = ref(storage, 'images'); + // imagesRef now points to 'images' + + // Child references can also take paths delimited by '/' + const spaceRef = ref(storage, 'images/space.jpg'); + // spaceRef now points to "images/space.jpg" + // imagesRef still points to "images" + // [END storage_create_ref_child] +} + +function navigateRef() { + // [START storage_navigate_ref] + const { getStorage, ref } = require("firebase/storage"); + + const storage = getStorage(); + const spaceRef = ref(storage, 'images/space.jpg'); + + // Parent allows us to move to the parent of a reference + const imagesRef = spaceRef.parent; + // imagesRef now points to 'images' + + // Root allows us to move all the way back to the top of our bucket + const rootRef = spaceRef.root; + // rootRef now points to the root + // [END storage_navigate_ref] +} + +function navigateRefChain() { + // [START storage_navigate_ref_chain] + const { getStorage, ref } = require("firebase/storage"); + + const storage = getStorage(); + const spaceRef = ref(storage, 'images/space.jpg'); + + // References can be chained together multiple times + const earthRef = ref(spaceRef.parent, 'earth.jpg'); + // earthRef points to 'images/earth.jpg' + + // nullRef is null, since the parent of root is null + const nullRef = spaceRef.root.parent; + // [END storage_navigate_ref_chain] +} + +function refProperties() { + // [START storage_ref_properties] + const { getStorage, ref } = require("firebase/storage"); + + const storage = getStorage(); + const spaceRef = ref(storage, 'images/space.jpg'); + + // Reference's path is: 'images/space.jpg' + // This is analogous to a file path on disk + spaceRef.fullPath; + + // Reference's name is the last segment of the full path: 'space.jpg' + // This is analogous to the file name + spaceRef.name; + + // Reference's bucket is the name of the storage bucket where files are stored + spaceRef.bucket; + // [END storage_ref_properties] +} + +function refFullExample() { + // [START storage_ref_full_example] + const { getStorage, ref } = require("firebase/storage"); + + const storage = getStorage(); + + // Points to the root reference + const storageRef = ref(storage); + + // Points to 'images' + const imagesRef = ref(storageRef, 'images'); + + // Points to 'images/space.jpg' + // Note that you can use variables to create child values + const fileName = 'space.jpg'; + const spaceRef = ref(imagesRef, fileName); + + // File path is 'images/space.jpg' + const path = spaceRef.fullPath; + + // File name is 'space.jpg' + const name = spaceRef.name; + + // Points to 'images' + const imagesRefAgain = spaceRef.parent; + // [END storage_ref_full_example] +} diff --git a/storage-next/delete-files.js b/storage-next/delete-files.js new file mode 100644 index 00000000..767a26f2 --- /dev/null +++ b/storage-next/delete-files.js @@ -0,0 +1,20 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function deleteFile() { + // [START storage_delete_file] + const { getStorage, ref, deleteObject } = require("firebase/storage"); + + const storage = getStorage(); + + // Create a reference to the file to delete + const desertRef = ref(storage, 'images/desert.jpg'); + + // Delete the file + deleteObject(desertRef).then(() => { + // File deleted successfully + }).catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_delete_file] +} diff --git a/storage-next/download-files.js b/storage-next/download-files.js new file mode 100644 index 00000000..6e94e63a --- /dev/null +++ b/storage-next/download-files.js @@ -0,0 +1,84 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function downloadCreateRef() { + // [START storage_download_create_ref] + const { getStorage, ref } = require("firebase/storage"); + + // Create a reference with an initial file path and name + const storage = getStorage(); + const pathReference = ref(storage, 'images/stars.jpg'); + + // Create a reference from a Google Cloud Storage URI + const gsReference = ref(storage, 'gs://bucket/images/stars.jpg'); + + // Create a reference from an HTTPS URL + // Note that in the URL, characters are URL escaped! + const httpsReference = ref(storage, 'https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg'); + // [END storage_download_create_ref] +} + +function downloadViaUrl() { + // [START storage_download_via_url] + const { getStorage, ref, getDownloadURL } = require("firebase/storage"); + + const storage = getStorage(); + getDownloadURL(ref(storage, 'images/stars.jpg')) + .then((url) => { + // `url` is the download URL for 'images/stars.jpg' + + // This can be downloaded directly: + const xhr = new XMLHttpRequest(); + xhr.responseType = 'blob'; + xhr.onload = (event) => { + const blob = xhr.response; + }; + xhr.open('GET', url); + xhr.send(); + + // Or inserted into an element + const img = document.getElementById('myimg'); + img.setAttribute('src', url); + }) + .catch((error) => { + // Handle any errors + }); + // [END storage_download_via_url] +} + +function downloadFullExample() { + // [START storage_download_full_example] + const { getStorage, ref, getDownloadURL } = require("firebase/storage"); + + // Create a reference to the file we want to download + const storage = getStorage(); + const starsRef = ref(storage, 'images/stars.jpg'); + + // Get the download URL + getDownloadURL(starsRef) + .then((url) => { + // Insert url into an tag to "download" + }) + .catch((error) => { + // A full list of error codes is available at + // https://firebase.google.com/docs/storage/web/handle-errors + switch (error.code) { + case 'storage/object-not-found': + // File doesn't exist + break; + case 'storage/unauthorized': + // User doesn't have permission to access the object + break; + case 'storage/canceled': + // User canceled the upload + break; + + // ... + + case 'storage/unknown': + // Unknown error occurred, inspect the server response + break; + } + }); + // [END storage_download_full_example] +} diff --git a/storage-next/emulator-suite.js b/storage-next/emulator-suite.js new file mode 100644 index 00000000..78891a4f --- /dev/null +++ b/storage-next/emulator-suite.js @@ -0,0 +1,14 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function onDocumentReady() { + // [START storage_emulator_connect] + const { getStorage, connectStorageEmulator } = require("firebase/storage"); + + const storage = getStorage(); + if (location.hostname === "localhost") { + // Point to the Storage emulator running on localhost. + connectStorageEmulator(storage, "127.0.0.1", 9199); + } + // [END storage_emulator_connect] +} diff --git a/storage-next/file-metadata.js b/storage-next/file-metadata.js new file mode 100644 index 00000000..c45827cd --- /dev/null +++ b/storage-next/file-metadata.js @@ -0,0 +1,78 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function getMetadata() { + // [START storage_get_metadata] + const { getStorage, ref, getMetadata } = require("firebase/storage"); + + // Create a reference to the file whose metadata we want to retrieve + const storage = getStorage(); + const forestRef = ref(storage, 'images/forest.jpg'); + + // Get metadata properties + getMetadata(forestRef) + .then((metadata) => { + // Metadata now contains the metadata for 'images/forest.jpg' + }) + .catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_get_metadata] +} + +function updateMetadata() { + // [START storage_update_metadata] + const { getStorage, ref, updateMetadata } = require("firebase/storage"); + + // Create a reference to the file whose metadata we want to change + const storage = getStorage(); + const forestRef = ref(storage, 'images/forest.jpg'); + + // Create file metadata to update + const newMetadata = { + cacheControl: 'public,max-age=300', + contentType: 'image/jpeg' + }; + + // Update metadata properties + updateMetadata(forestRef, newMetadata) + .then((metadata) => { + // Updated metadata for 'images/forest.jpg' is returned in the Promise + }).catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_update_metadata] +} + +function deleteMetadata() { + // [START storage_delete_metadata] + const { getStorage, ref, updateMetadata } = require("firebase/storage"); + + const storage = getStorage(); + const forestRef = ref(storage, 'images/forest.jpg'); + + // Create file metadata with property to delete + const deleteMetadata = { + contentType: null + }; + + // Delete the metadata property + updateMetadata(forestRef, deleteMetadata) + .then((metadata) => { + // metadata.contentType should be null + }).catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_delete_metadata] +} + +function customMetadata() { + // [START storage_custom_metadata] + const metadata = { + customMetadata: { + 'location': 'Yosemite, CA, USA', + 'activity': 'Hiking' + } + }; + // [END storage_custom_metadata] +} diff --git a/storage-next/index.js b/storage-next/index.js new file mode 100644 index 00000000..15b07e5f --- /dev/null +++ b/storage-next/index.js @@ -0,0 +1,86 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function initialize() { + // [START storage_initialize] + const { initializeApp } = require("firebase/app"); + const { getStorage } = require("firebase/storage"); + + // Set the configuration for your app + // TODO: Replace with your app's config object + const firebaseConfig = { + apiKey: '', + authDomain: '', + databaseURL: '', + storageBucket: '' + }; + const firebaseApp = initializeApp(firebaseConfig); + + // Get a reference to the storage service, which is used to create references in your storage bucket + const storage = getStorage(firebaseApp); + // [END storage_initialize] +} + +function multipleBuckets() { + // [START storage_multiple_buckets] + const { getApp } = require("firebase/app"); + const { getStorage } = require("firebase/storage"); + + // Get a non-default Storage bucket + const firebaseApp = getApp(); + const storage = getStorage(firebaseApp, "gs://my-custom-bucket"); + // [END storage_multiple_buckets] +} + +function storageCustomApp() { + const { initializeApp } = require("firebase/app"); + + const customApp = initializeApp({ + // ... custom stuff + }); + + // [START storage_custom_app] + const { getStorage } = require("firebase/storage"); + + // Get the default bucket from a custom firebase.app.App + const storage1 = getStorage(customApp); + + // Get a non-default bucket from a custom firebase.app.App + const storage2 = getStorage(customApp, "gs://my-custom-bucket"); + // [END storage_custom_app] +} + +/** + * @param {File} file + */ +function storageOnComplete(file) { + // The file param would be a File object from a file selection event in the browser. + // See: + // - https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications + // - https://developer.mozilla.org/en-US/docs/Web/API/File + + /** @type {any} */ + const metadata = { + 'contentType': file.type + }; + + // [START storage_on_complete] + const { getStorage, ref, uploadBytesResumable, getDownloadURL } = require("firebase/storage"); + + const storage = getStorage(); + const imageRef = ref(storage, 'images/' + file.name); + uploadBytesResumable(imageRef, file, metadata) + .then((snapshot) => { + console.log('Uploaded', snapshot.totalBytes, 'bytes.'); + console.log('File metadata:', snapshot.metadata); + // Let's get a download URL for the file. + getDownloadURL(snapshot.ref).then((url) => { + console.log('File available at', url); + // ... + }); + }).catch((error) => { + console.error('Upload failed', error); + // ... + }); + // [END storage_on_complete] +} diff --git a/storage-next/list-files.js b/storage-next/list-files.js new file mode 100644 index 00000000..493972d2 --- /dev/null +++ b/storage-next/list-files.js @@ -0,0 +1,56 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function listAll() { + // [START storage_list_all] + const { getStorage, ref, listAll } = require("firebase/storage"); + + const storage = getStorage(); + + // Create a reference under which you want to list + const listRef = ref(storage, 'files/uid'); + + // Find all the prefixes and items. + listAll(listRef) + .then((res) => { + res.prefixes.forEach((folderRef) => { + // All the prefixes under listRef. + // You may call listAll() recursively on them. + }); + res.items.forEach((itemRef) => { + // All the items under listRef. + }); + }).catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_list_all] +} + +function listPaginate() { + // [START storage_list_paginate] + const { getStorage, ref, list } = require("firebase/storage"); + + async function pageTokenExample(){ + // Create a reference under which you want to list + const storage = getStorage(); + const listRef = ref(storage, 'files/uid'); + + // Fetch the first page of 100. + const firstPage = await list(listRef, { maxResults: 100 }); + + // Use the result. + // processItems(firstPage.items) + // processPrefixes(firstPage.prefixes) + + // Fetch the second page if there are more elements. + if (firstPage.nextPageToken) { + const secondPage = await list(listRef, { + maxResults: 100, + pageToken: firstPage.nextPageToken, + }); + // processItems(secondPage.items) + // processPrefixes(secondPage.prefixes) + } + } + // [END storage_list_paginate] +} diff --git a/storage-next/package.json b/storage-next/package.json new file mode 100644 index 00000000..b1c449ab --- /dev/null +++ b/storage-next/package.json @@ -0,0 +1,11 @@ +{ + "name": "storage-next", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^10.0.0" + } +} diff --git a/storage-next/upload-files.js b/storage-next/upload-files.js new file mode 100644 index 00000000..98b93225 --- /dev/null +++ b/storage-next/upload-files.js @@ -0,0 +1,237 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function uploadRef() { + // [START storage_upload_ref] + const { getStorage, ref } = require("firebase/storage"); + + // Create a root reference + const storage = getStorage(); + + // Create a reference to 'mountains.jpg' + const mountainsRef = ref(storage, 'mountains.jpg'); + + // Create a reference to 'images/mountains.jpg' + const mountainImagesRef = ref(storage, 'images/mountains.jpg'); + + // While the file names are the same, the references point to different files + mountainsRef.name === mountainImagesRef.name; // true + mountainsRef.fullPath === mountainImagesRef.fullPath; // false + // [END storage_upload_ref] +} + +/** + * @param {File} file + */ +function uploadBlob(file) { + // [START storage_upload_blob] + const { getStorage, ref, uploadBytes } = require("firebase/storage"); + + const storage = getStorage(); + const storageRef = ref(storage, 'some-child'); + + // 'file' comes from the Blob or File API + uploadBytes(storageRef, file).then((snapshot) => { + console.log('Uploaded a blob or file!'); + }); + // [END storage_upload_blob] +} + +function uploadBytes() { + // [START storage_upload_bytes] + const { getStorage, ref, uploadBytes } = require("firebase/storage"); + + const storage = getStorage(); + const storageRef = ref(storage, 'some-child'); + + const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21]); + uploadBytes(storageRef, bytes).then((snapshot) => { + console.log('Uploaded an array!'); + }); + // [END storage_upload_bytes] +} + +function uploadString() { + // [START storage_upload_string] + const { getStorage, ref, uploadString } = require("firebase/storage"); + + const storage = getStorage(); + const storageRef = ref(storage, 'some-child'); + + // Raw string is the default if no format is provided + const message = 'This is my message.'; + uploadString(storageRef, message).then((snapshot) => { + console.log('Uploaded a raw string!'); + }); + + // Base64 formatted string + const message2 = '5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; + uploadString(storageRef, message2, 'base64').then((snapshot) => { + console.log('Uploaded a base64 string!'); + }); + + // Base64url formatted string + const message3 = '5b6p5Y-344GX44G-44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; + uploadString(storageRef, message3, 'base64url').then((snapshot) => { + console.log('Uploaded a base64url string!'); + }); + + // Data URL string + const message4 = 'data:text/plain;base64,5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; + uploadString(storageRef, message4, 'data_url').then((snapshot) => { + console.log('Uploaded a data_url string!'); + }); + // [END storage_upload_string] +} + +/** + * @param {File} file + */ +function uploadMetadata(file) { + // [START storage_upload_metadata] + const { getStorage, ref, uploadBytes } = require("firebase/storage"); + + const storage = getStorage(); + const storageRef = ref(storage, 'images/mountains.jpg'); + + // Create file metadata including the content type + /** @type {any} */ + const metadata = { + contentType: 'image/jpeg', + }; + + // Upload the file and metadata + const uploadTask = uploadBytes(storageRef, file, metadata); + // [END storage_upload_metadata] +} + +/** + * @param {File} file + */ +function manageUploads(file) { + // [START storage_manage_uploads] + const { getStorage, ref, uploadBytesResumable } = require("firebase/storage"); + + const storage = getStorage(); + const storageRef = ref(storage, 'images/mountains.jpg'); + + // Upload the file and metadata + const uploadTask = uploadBytesResumable(storageRef, file); + + // Pause the upload + uploadTask.pause(); + + // Resume the upload + uploadTask.resume(); + + // Cancel the upload + uploadTask.cancel(); + // [END storage_manage_uploads] +} + +/** + * @param {File} file + */ +function monitorUpload(file) { + // [START storage_monitor_upload] + const { getStorage, ref, uploadBytesResumable, getDownloadURL } = require("firebase/storage"); + + const storage = getStorage(); + const storageRef = ref(storage, 'images/rivers.jpg'); + + const uploadTask = uploadBytesResumable(storageRef, file); + + // Register three observers: + // 1. 'state_changed' observer, called any time the state changes + // 2. Error observer, called on failure + // 3. Completion observer, called on successful completion + uploadTask.on('state_changed', + (snapshot) => { + // Observe state change events such as progress, pause, and resume + // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded + const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + console.log('Upload is ' + progress + '% done'); + switch (snapshot.state) { + case 'paused': + console.log('Upload is paused'); + break; + case 'running': + console.log('Upload is running'); + break; + } + }, + (error) => { + // Handle unsuccessful uploads + }, + () => { + // Handle successful uploads on complete + // For instance, get the download URL: https://firebasestorage.googleapis.com/... + getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { + console.log('File available at', downloadURL); + }); + } + ); + // [END storage_monitor_upload] +} + +/** + * @param {File} file + */ +function uploadHandleError(file) { + // [START storage_upload_handle_error] + const { getStorage, ref, uploadBytesResumable, getDownloadURL } = require("firebase/storage"); + + const storage = getStorage(); + + // Create the file metadata + /** @type {any} */ + const metadata = { + contentType: 'image/jpeg' + }; + + // Upload file and metadata to the object 'images/mountains.jpg' + const storageRef = ref(storage, 'images/' + file.name); + const uploadTask = uploadBytesResumable(storageRef, file, metadata); + + // Listen for state changes, errors, and completion of the upload. + uploadTask.on('state_changed', + (snapshot) => { + // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded + const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + console.log('Upload is ' + progress + '% done'); + switch (snapshot.state) { + case 'paused': + console.log('Upload is paused'); + break; + case 'running': + console.log('Upload is running'); + break; + } + }, + (error) => { + // A full list of error codes is available at + // https://firebase.google.com/docs/storage/web/handle-errors + switch (error.code) { + case 'storage/unauthorized': + // User doesn't have permission to access the object + break; + case 'storage/canceled': + // User canceled the upload + break; + + // ... + + case 'storage/unknown': + // Unknown error occurred, inspect error.serverResponse + break; + } + }, + () => { + // Upload completed successfully, now we can get the download URL + getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { + console.log('File available at', downloadURL); + }); + } + ); + // [END storage_upload_handle_error] +} diff --git a/storage/create-reference.js b/storage/create-reference.js new file mode 100644 index 00000000..09794832 --- /dev/null +++ b/storage/create-reference.js @@ -0,0 +1,95 @@ +import firebase from "firebase/app"; +import "firebase/storage"; + +function createRef() { + // [START storage_create_ref] + // Get a reference to the storage service, which is used to create references in your storage bucket + var storage = firebase.storage(); + + // Create a storage reference from our storage service + var storageRef = storage.ref(); + // [END storage_create_ref] +} + +function createRefChild() { + const storageRef = firebase.storage().ref(); + + // [START storage_create_ref_child] + // Create a child reference + var imagesRef = storageRef.child('images'); + // imagesRef now points to 'images' + + // Child references can also take paths delimited by '/' + var spaceRef = storageRef.child('images/space.jpg'); + // spaceRef now points to "images/space.jpg" + // imagesRef still points to "images" + // [END storage_create_ref_child] +} + +function navigateRef() { + const spaceRef = firebase.storage().ref().child('images/space.jpg'); + + // [START storage_navigate_ref] + // Parent allows us to move to the parent of a reference + var imagesRef = spaceRef.parent; + // imagesRef now points to 'images' + + // Root allows us to move all the way back to the top of our bucket + var rootRef = spaceRef.root; + // rootRef now points to the root + // [END storage_navigate_ref] +} + +function navigateRefChain() { + const spaceRef = firebase.storage().ref().child('images/space.jpg'); + + // [START storage_navigate_ref_chain] + // References can be chained together multiple times + var earthRef = spaceRef.parent.child('earth.jpg'); + // earthRef points to 'images/earth.jpg' + + // nullRef is null, since the parent of root is null + var nullRef = spaceRef.root.parent; + // [END storage_navigate_ref_chain] +} + +function refProperties() { + const spaceRef = firebase.storage().ref().child('images/space.jpg'); + + // [START storage_ref_properties] + // Reference's path is: 'images/space.jpg' + // This is analogous to a file path on disk + spaceRef.fullPath; + + // Reference's name is the last segment of the full path: 'space.jpg' + // This is analogous to the file name + spaceRef.name; + + // Reference's bucket is the name of the storage bucket where files are stored + spaceRef.bucket; + // [END storage_ref_properties] +} + +function refFullExample() { + // [START storage_ref_full_example] + // Points to the root reference + var storageRef = firebase.storage().ref(); + + // Points to 'images' + var imagesRef = storageRef.child('images'); + + // Points to 'images/space.jpg' + // Note that you can use variables to create child values + var fileName = 'space.jpg'; + var spaceRef = imagesRef.child(fileName); + + // File path is 'images/space.jpg' + var path = spaceRef.fullPath; + + // File name is 'space.jpg' + var name = spaceRef.name; + + // Points to 'images' + var imagesRef = spaceRef.parent; + // [END storage_ref_full_example] +} diff --git a/storage/delete-files.js b/storage/delete-files.js new file mode 100644 index 00000000..73b84904 --- /dev/null +++ b/storage/delete-files.js @@ -0,0 +1,18 @@ +import firebase from "firebase/app"; +import "firebase/storage"; + +function deleteFile() { + const storageRef = firebase.storage().ref(); + + // [START storage_delete_file] + // Create a reference to the file to delete + var desertRef = storageRef.child('images/desert.jpg'); + + // Delete the file + desertRef.delete().then(() => { + // File deleted successfully + }).catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_delete_file] +} diff --git a/storage/download-files.js b/storage/download-files.js new file mode 100644 index 00000000..cb2af375 --- /dev/null +++ b/storage/download-files.js @@ -0,0 +1,80 @@ +import firebase from "firebase/app"; +import "firebase/storage"; + +function downloadCreateRef() { + // [START storage_download_create_ref] + // Create a reference with an initial file path and name + var storage = firebase.storage(); + var pathReference = storage.ref('images/stars.jpg'); + + // Create a reference from a Google Cloud Storage URI + var gsReference = storage.refFromURL('gs://bucket/images/stars.jpg'); + + // Create a reference from an HTTPS URL + // Note that in the URL, characters are URL escaped! + var httpsReference = storage.refFromURL('https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg'); + // [END storage_download_create_ref] +} + +function downloadViaUrl() { + const storageRef = firebase.storage().ref(); + + // [START storage_download_via_url] + storageRef.child('images/stars.jpg').getDownloadURL() + .then((url) => { + // `url` is the download URL for 'images/stars.jpg' + + // This can be downloaded directly: + var xhr = new XMLHttpRequest(); + xhr.responseType = 'blob'; + xhr.onload = (event) => { + var blob = xhr.response; + }; + xhr.open('GET', url); + xhr.send(); + + // Or inserted into an element + var img = document.getElementById('myimg'); + img.setAttribute('src', url); + }) + .catch((error) => { + // Handle any errors + }); + // [END storage_download_via_url] +} + +function downloadFullExample() { + const storageRef = firebase.storage().ref(); + + // [START storage_download_full_example] + // Create a reference to the file we want to download + var starsRef = storageRef.child('images/stars.jpg'); + + // Get the download URL + starsRef.getDownloadURL() + .then((url) => { + // Insert url into an tag to "download" + }) + .catch((error) => { + // A full list of error codes is available at + // https://firebase.google.com/docs/storage/web/handle-errors + switch (error.code) { + case 'storage/object-not-found': + // File doesn't exist + break; + case 'storage/unauthorized': + // User doesn't have permission to access the object + break; + case 'storage/canceled': + // User canceled the upload + break; + + // ... + + case 'storage/unknown': + // Unknown error occurred, inspect the server response + break; + } + }); + // [END storage_download_full_example] +} diff --git a/storage/emulator-suite.js b/storage/emulator-suite.js new file mode 100644 index 00000000..be1f2dd4 --- /dev/null +++ b/storage/emulator-suite.js @@ -0,0 +1,16 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/storage"; + +function onDocumentReady() { + // [START storage_emulator_connect] + var storage = firebase.storage(); + if (location.hostname === "localhost") { + // Point to the Storage emulator running on localhost. + storage.useEmulator("127.0.0.1", 9199); + } + // [END storage_emulator_connect] +} + diff --git a/storage/file-metadata.js b/storage/file-metadata.js new file mode 100644 index 00000000..cef42364 --- /dev/null +++ b/storage/file-metadata.js @@ -0,0 +1,75 @@ +import firebase from "firebase/app"; +import "firebase/storage"; + +function getMetadata() { + const storageRef = firebase.storage().ref(); + + // [START storage_get_metadata] + // Create a reference to the file whose metadata we want to retrieve + var forestRef = storageRef.child('images/forest.jpg'); + + // Get metadata properties + forestRef.getMetadata() + .then((metadata) => { + // Metadata now contains the metadata for 'images/forest.jpg' + }) + .catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_get_metadata] +} + +function updateMetadata() { + const storageRef = firebase.storage().ref(); + + // [START storage_update_metadata] + // Create a reference to the file whose metadata we want to change + var forestRef = storageRef.child('images/forest.jpg'); + + // Create file metadata to update + var newMetadata = { + cacheControl: 'public,max-age=300', + contentType: 'image/jpeg' + }; + + // Update metadata properties + forestRef.updateMetadata(newMetadata) + .then((metadata) => { + // Updated metadata for 'images/forest.jpg' is returned in the Promise + }).catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_update_metadata] +} + +function deleteMetadata() { + const storageRef = firebase.storage().ref(); + const forestRef = storageRef.child('images/forest.jpg'); + + // [START storage_delete_metadata] + + // Create file metadata with property to delete + var deleteMetadata = { + contentType: null + }; + + // Delete the metadata property + forestRef.updateMetadata(deleteMetadata) + .then((metadata) => { + // metadata.contentType should be null + }).catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_delete_metadata] +} + +function customMetadata() { + // [START storage_custom_metadata] + var metadata = { + customMetadata: { + 'location': 'Yosemite, CA, USA', + 'activity': 'Hiking' + } + }; + // [END storage_custom_metadata] +} diff --git a/storage/index.js b/storage/index.js new file mode 100644 index 00000000..7a7db0df --- /dev/null +++ b/storage/index.js @@ -0,0 +1,71 @@ +import firebase from "firebase/app"; +import "firebase/storage"; + +function initialize() { + // [START storage_initialize] + // Set the configuration for your app + // TODO: Replace with your app's config object + var firebaseConfig = { + apiKey: '', + authDomain: '', + databaseURL: '', + storageBucket: '' + }; + firebase.initializeApp(firebaseConfig); + + // Get a reference to the storage service, which is used to create references in your storage bucket + var storage = firebase.storage(); + // [END storage_initialize] +} + +function multipleBuckets() { + // [START storage_multiple_buckets] + // Get a non-default Storage bucket + var storage = firebase.app().storage("gs://my-custom-bucket"); + // [END storage_multiple_buckets] +} + +function storageCustomApp() { + const customApp = firebase.initializeApp({ + // ... custom stuff + }); + + // [START storage_custom_app] + // Get the default bucket from a custom firebase.app.App + var storage = customApp.storage(); + + // Get a non-default bucket from a custom firebase.app.App + var storage = customApp.storage("gs://my-custom-bucket"); + // [END storage_custom_app] +} + +/** + * @param {File} file + */ +function storageOnComplete(file) { + // The file param would be a File object from a file selection event in the browser. + // See: + // - https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications + // - https://developer.mozilla.org/en-US/docs/Web/API/File + + const metadata = { + 'contentType': file.type + }; + + // [START storage_on_complete] + const storageRef = firebase.storage().ref(); + storageRef.child('images/' + file.name).put(file, metadata) + .then((snapshot) => { + console.log('Uploaded', snapshot.totalBytes, 'bytes.'); + console.log('File metadata:', snapshot.metadata); + // Let's get a download URL for the file. + snapshot.ref.getDownloadURL().then((url) => { + console.log('File available at', url); + // ... + }); + }).catch((error) => { + console.error('Upload failed', error); + // ... + }); + // [END storage_on_complete] +} diff --git a/storage/list-files.js b/storage/list-files.js new file mode 100644 index 00000000..ef248da7 --- /dev/null +++ b/storage/list-files.js @@ -0,0 +1,53 @@ +import firebase from "firebase/app"; +import "firebase/storage"; + +function listAll() { + const storageRef = firebase.storage().ref(); + + // [START storage_list_all] + // Create a reference under which you want to list + var listRef = storageRef.child('files/uid'); + + // Find all the prefixes and items. + listRef.listAll() + .then((res) => { + res.prefixes.forEach((folderRef) => { + // All the prefixes under listRef. + // You may call listAll() recursively on them. + }); + res.items.forEach((itemRef) => { + // All the items under listRef. + }); + }).catch((error) => { + // Uh-oh, an error occurred! + }); + // [END storage_list_all] +} + +function listPaginate() { + const storageRef = firebase.storage().ref(); + + // [START storage_list_paginate] + async function pageTokenExample(){ + // Create a reference under which you want to list + var listRef = storageRef.child('files/uid'); + + // Fetch the first page of 100. + var firstPage = await listRef.list({ maxResults: 100}); + + // Use the result. + // processItems(firstPage.items) + // processPrefixes(firstPage.prefixes) + + // Fetch the second page if there are more elements. + if (firstPage.nextPageToken) { + var secondPage = await listRef.list({ + maxResults: 100, + pageToken: firstPage.nextPageToken, + }); + // processItems(secondPage.items) + // processPrefixes(secondPage.prefixes) + } + } + // [END storage_list_paginate] +} diff --git a/storage/package.json b/storage/package.json new file mode 100644 index 00000000..e27166e7 --- /dev/null +++ b/storage/package.json @@ -0,0 +1,11 @@ +{ + "name": "storage", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^8.10.0" + } +} diff --git a/storage/upload-files.js b/storage/upload-files.js new file mode 100644 index 00000000..2f889019 --- /dev/null +++ b/storage/upload-files.js @@ -0,0 +1,212 @@ +import firebase from "firebase/app"; +import "firebase/storage"; + +function uploadRef() { + // [START storage_upload_ref] + // Create a root reference + var storageRef = firebase.storage().ref(); + + // Create a reference to 'mountains.jpg' + var mountainsRef = storageRef.child('mountains.jpg'); + + // Create a reference to 'images/mountains.jpg' + var mountainImagesRef = storageRef.child('images/mountains.jpg'); + + // While the file names are the same, the references point to different files + mountainsRef.name === mountainImagesRef.name; // true + mountainsRef.fullPath === mountainImagesRef.fullPath; // false + // [END storage_upload_ref] +} + +/** + * @param {File} file + */ +function uploadBlob(file) { + const ref = firebase.storage().ref().child('some-child'); + + // [START storage_upload_blob] + // 'file' comes from the Blob or File API + ref.put(file).then((snapshot) => { + console.log('Uploaded a blob or file!'); + }); + // [END storage_upload_blob] +} + +function uploadBytes() { + const ref = firebase.storage().ref().child('some-child'); + + // [START storage_upload_bytes] + var bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21]); + ref.put(bytes).then((snapshot) => { + console.log('Uploaded an array!'); + }); + // [END storage_upload_bytes] +} + +function uploadString() { + const ref = firebase.storage().ref().child('some-child'); + + // [START storage_upload_string] + // Raw string is the default if no format is provided + var message = 'This is my message.'; + ref.putString(message).then((snapshot) => { + console.log('Uploaded a raw string!'); + }); + + // Base64 formatted string + var message = '5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; + ref.putString(message, 'base64').then((snapshot) => { + console.log('Uploaded a base64 string!'); + }); + + // Base64url formatted string + var message = '5b6p5Y-344GX44G-44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; + ref.putString(message, 'base64url').then((snapshot) => { + console.log('Uploaded a base64url string!'); + }); + + // Data URL string + var message = 'data:text/plain;base64,5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB'; + ref.putString(message, 'data_url').then((snapshot) => { + console.log('Uploaded a data_url string!'); + }); + // [END storage_upload_string] +} + +/** + * @param {File} file + */ +function uploadMetadata(file) { + const storageRef = firebase.storage().ref(); + + // [START storage_upload_metadata] + // Create file metadata including the content type + var metadata = { + contentType: 'image/jpeg', + }; + + // Upload the file and metadata + var uploadTask = storageRef.child('images/mountains.jpg').put(file, metadata); + // [END storage_upload_metadata] +} + +/** + * @param {File} file + */ +function manageUploads(file) { + const storageRef = firebase.storage().ref(); + + // [START storage_manage_uploads] + // Upload the file and metadata + var uploadTask = storageRef.child('images/mountains.jpg').put(file); + + // Pause the upload + uploadTask.pause(); + + // Resume the upload + uploadTask.resume(); + + // Cancel the upload + uploadTask.cancel(); + // [END storage_manage_uploads] +} + +/** + * @param {File} file + */ +function monitorUpload(file) { + const storageRef = firebase.storage().ref(); + + // [START storage_monitor_upload] + var uploadTask = storageRef.child('images/rivers.jpg').put(file); + + // Register three observers: + // 1. 'state_changed' observer, called any time the state changes + // 2. Error observer, called on failure + // 3. Completion observer, called on successful completion + uploadTask.on('state_changed', + (snapshot) => { + // Observe state change events such as progress, pause, and resume + // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded + var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + console.log('Upload is ' + progress + '% done'); + switch (snapshot.state) { + case firebase.storage.TaskState.PAUSED: // or 'paused' + console.log('Upload is paused'); + break; + case firebase.storage.TaskState.RUNNING: // or 'running' + console.log('Upload is running'); + break; + } + }, + (error) => { + // Handle unsuccessful uploads + }, + () => { + // Handle successful uploads on complete + // For instance, get the download URL: https://firebasestorage.googleapis.com/... + uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => { + console.log('File available at', downloadURL); + }); + } + ); + // [END storage_monitor_upload] +} + +/** + * @param {File} file + */ +function uploadHandleError(file) { + const storageRef = firebase.storage().ref(); + + // [START storage_upload_handle_error] + // Create the file metadata + var metadata = { + contentType: 'image/jpeg' + }; + + // Upload file and metadata to the object 'images/mountains.jpg' + var uploadTask = storageRef.child('images/' + file.name).put(file, metadata); + + // Listen for state changes, errors, and completion of the upload. + uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed' + (snapshot) => { + // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded + var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + console.log('Upload is ' + progress + '% done'); + switch (snapshot.state) { + case firebase.storage.TaskState.PAUSED: // or 'paused' + console.log('Upload is paused'); + break; + case firebase.storage.TaskState.RUNNING: // or 'running' + console.log('Upload is running'); + break; + } + }, + (error) => { + // A full list of error codes is available at + // https://firebase.google.com/docs/storage/web/handle-errors + switch (error.code) { + case 'storage/unauthorized': + // User doesn't have permission to access the object + break; + case 'storage/canceled': + // User canceled the upload + break; + + // ... + + case 'storage/unknown': + // Unknown error occurred, inspect error.serverResponse + break; + } + }, + () => { + // Upload completed successfully, now we can get the download URL + uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => { + console.log('File available at', downloadURL); + }); + } + ); + // [END storage_upload_handle_error] +}