- 
                Notifications
    You must be signed in to change notification settings 
- Fork 983
App Hosting JS SDK autoinit #8483
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 21 commits
6470299
              cd6d61a
              1381961
              6b0c6b1
              1fb66a5
              c8ffa75
              525a4e2
              d0ce18e
              861e5b0
              63b449e
              85b8992
              9a38e30
              f247bea
              f52116a
              f83c02b
              a4a09cf
              2c6344c
              641203d
              df72b14
              10f959b
              7955cc8
              939af36
              15a35e9
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@firebase/util': minor | ||
| 'firebase': minor | ||
| --- | ||
|  | ||
| Add support for the `FIREBASE_WEBAPP_CONFIG` environment variable at install time. | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| /** | ||
| * @license | ||
| * Copyright 2025 Google LLC | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|  | ||
| const { writeFile, readFile } = require('node:fs/promises'); | ||
| const { pathToFileURL } = require('node:url'); | ||
| const { isAbsolute, join } = require('node:path'); | ||
|  | ||
| async function getPartialConfig() { | ||
| if (!process.env.FIREBASE_WEBAPP_CONFIG) { | ||
| return undefined; | ||
| } | ||
|  | ||
| // Like FIREBASE_CONFIG (admin autoinit) FIREBASE_WEBAPP_CONFIG can be | ||
| // either a JSON representation of FirebaseOptions or the path to a filename | ||
| if (process.env.FIREBASE_WEBAPP_CONFIG.startsWith('{"')) { | ||
| try { | ||
| return JSON.parse(process.env.FIREBASE_WEBAPP_CONFIG); | ||
| } catch (e) { | ||
| console.warn( | ||
| 'FIREBASE_WEBAPP_CONFIG could not be parsed, ignoring.\n', | ||
| e | ||
| ); | ||
| return undefined; | ||
| } | ||
| } | ||
|  | ||
| const fileName = process.env.FIREBASE_WEBAPP_CONFIG; | ||
| const fileURL = pathToFileURL( | ||
| isAbsolute(fileName) ? fileName : join(process.cwd(), fileName) | ||
| ); | ||
|  | ||
| try { | ||
| const fileContents = await readFile(fileURL, 'utf-8'); | ||
| return JSON.parse(fileContents); | ||
| } catch (e) { | ||
| console.warn( | ||
| `Contents of "${fileName}" could not be parsed, ignoring FIREBASE_WEBAPP_CONFIG.\n`, | ||
| e | ||
| ); | ||
| return undefined; | ||
| } | ||
| } | ||
|  | ||
| async function getFullConfig(partialConfig) { | ||
| if (!partialConfig) { | ||
| return undefined; | ||
| } | ||
| // In Firebase App Hosting the config provided to the environment variable is up-to-date and | ||
| // "complete" we should not reach out to the webConfig endpoint to freshen it | ||
| if (process.env.X_GOOGLE_TARGET_PLATFORM === 'fah') { | ||
| return partialConfig; | ||
| } | ||
| const projectId = partialConfig.projectId || '-'; | ||
| // If the projectId starts with demo- this is an demo project from the firebase emulators | ||
| // treat the config as whole | ||
| if (projectId.startsWith('demo-')) { | ||
| return partialConfig; | ||
| } | ||
| const appId = partialConfig.appId; | ||
| const apiKey = partialConfig.apiKey; | ||
| if (!appId || !apiKey) { | ||
| console.warn( | ||
| `Unable to fetch Firebase config, appId and apiKey are required, ignoring FIREBASE_WEBAPP_CONFIG.` | ||
| ); | ||
| return undefined; | ||
| } | ||
|  | ||
| const url = `https://firebase.googleapis.com/v1alpha/projects/${projectId}/apps/${appId}/webConfig`; | ||
|  | ||
| try { | ||
| const response = await fetch(url, { | ||
| headers: { 'x-goog-api-key': apiKey } | ||
| }); | ||
| if (!response.ok) { | ||
| console.warn( | ||
| `Unable to fetch Firebase config, ignoring FIREBASE_WEBAPP_CONFIG.` | ||
| ); | ||
| console.warn( | ||
| `${url} returned ${response.statusText} (${response.status})` | ||
| ); | ||
| try { | ||
| console.warn((await response.json()).error.message); | ||
| } catch (e) {} | ||
| return undefined; | ||
| } | ||
| const json = await response.json(); | ||
| return { ...json, apiKey }; | ||
| } catch (e) { | ||
| console.warn( | ||
| `Unable to fetch Firebase config, ignoring FIREBASE_WEBAPP_CONFIG.\n`, | ||
| e | ||
| ); | ||
| return undefined; | ||
| } | ||
| } | ||
|  | ||
| function handleUnexpectedError(e) { | ||
| console.warn( | ||
| 'Unexpected error encountered in @firebase/util postinstall script, ignoring FIREBASE_WEBAPP_CONFIG.' | ||
| ); | ||
| console.warn(e); | ||
| process.exit(0); | ||
| } | ||
|  | ||
| getPartialConfig() | ||
| .catch(handleUnexpectedError) | ||
| .then(getFullConfig) | ||
| .catch(handleUnexpectedError) | ||
| .then(async config => { | ||
|         
                  jamesdaniels marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| const emulatorHosts = { | ||
|          | ||
| firestore: process.env.FIRESTORE_EMULATOR_HOST, | ||
| database: process.env.FIREBASE_DATABASE_EMULATOR_HOST, | ||
| storage: process.env.FIREBASE_STORAGE_EMULATOR_HOST, | ||
| auth: process.env.FIREBASE_AUTH_EMULATOR_HOST | ||
| }; | ||
|  | ||
| const defaults = config && { config, emulatorHosts }; | ||
|  | ||
| await Promise.all([ | ||
| writeFile( | ||
| join(__dirname, 'dist', 'postinstall.js'), | ||
| `'use strict'; | ||
| Object.defineProperty(exports, '__esModule', { value: true }); | ||
| exports.getDefaultsFromPostinstall = () => (${JSON.stringify(defaults)});` | ||
| ), | ||
| writeFile( | ||
| join(__dirname, 'dist', 'postinstall.mjs'), | ||
| `const getDefaultsFromPostinstall = () => (${JSON.stringify(defaults)}); | ||
|          | ||
| export { getDefaultsFromPostinstall };` | ||
| ) | ||
| ]); | ||
|  | ||
| process.exit(0); | ||
| }) | ||
| .catch(handleUnexpectedError); | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /** | ||
| * @license | ||
| * Copyright 2025 Google LLC | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|  | ||
| import type { FirebaseDefaults } from './defaults'; | ||
|  | ||
| // This value is retrieved and hardcoded by the NPM postinstall script | ||
| export const getDefaultsFromPostinstall: () => FirebaseDefaults | undefined = () => undefined; | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -2633,6 +2633,14 @@ | |
| is-module "^1.0.0" | ||
| resolve "^1.22.1" | ||
|  | ||
| "@rollup/[email protected]": | ||
| version "6.0.2" | ||
| resolved "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz#2f565d312d681e4570ff376c55c5c08eb6f1908d" | ||
| integrity sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ== | ||
| dependencies: | ||
| "@rollup/pluginutils" "^5.0.1" | ||
| magic-string "^0.30.3" | ||
|  | ||
| "@rollup/[email protected]": | ||
| version "2.1.0" | ||
| resolved "https://registry.npmjs.org/@rollup/plugin-strip/-/plugin-strip-2.1.0.tgz#04c2d2ccfb2c6b192bb70447fbf26e336379a333" | ||
|  | @@ -11233,7 +11241,7 @@ magic-string@^0.25.2, magic-string@^0.25.7: | |
| dependencies: | ||
| sourcemap-codec "^1.4.8" | ||
|  | ||
| magic-string@^0.30.2, magic-string@~0.30.0: | ||
| magic-string@^0.30.2, magic-string@^0.30.3, magic-string@~0.30.0: | ||
| version "0.30.17" | ||
| resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" | ||
| integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== | ||
|  | ||
Uh oh!
There was an error while loading. Please reload this page.