Skip to content

(feat) initializeServerApp support for App Hosting auto init #9151

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

Merged
merged 12 commits into from
Jul 12, 2025
6 changes: 6 additions & 0 deletions .changeset/thin-bikes-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@firebase/app': minor
'firebase': minor
---

initializeServerApp now supports auto-initialization for Firebase App Hosting.
10 changes: 8 additions & 2 deletions common/api-review/app.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,20 @@ export function initializeApp(options: FirebaseOptions, config?: FirebaseAppSett
export function initializeApp(): FirebaseApp;

// @public
export function initializeServerApp(options: FirebaseOptions | FirebaseApp, config: FirebaseServerAppSettings): FirebaseServerApp;
export function initializeServerApp(options: FirebaseOptions | FirebaseApp, config?: FirebaseServerAppSettings): FirebaseServerApp;

// @public
export function initializeServerApp(config?: FirebaseServerAppSettings): FirebaseServerApp;

// @internal (undocumented)
export function _isFirebaseApp(obj: FirebaseApp | FirebaseOptions): obj is FirebaseApp;
export function _isFirebaseApp(obj: FirebaseApp | FirebaseOptions | FirebaseAppSettings): obj is FirebaseApp;

// @internal (undocumented)
export function _isFirebaseServerApp(obj: FirebaseApp | FirebaseServerApp | null | undefined): obj is FirebaseServerApp;

// @internal (undocumented)
export function _isFirebaseServerAppSettings(obj: FirebaseApp | FirebaseOptions | FirebaseAppSettings): obj is FirebaseServerAppSettings;

// @public
export function onLog(logCallback: LogCallback | null, options?: LogOptions): void;

Expand Down
56 changes: 54 additions & 2 deletions docs-devsite/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ This package coordinates the communication between the different Firebase compon
| <b>function()</b> |
| [getApps()](./app.md#getapps) | A (read-only) array of all initialized apps. |
| [initializeApp()](./app.md#initializeapp) | Creates and initializes a FirebaseApp instance. |
| <b>function(config, ...)</b> |
| [initializeServerApp(config)](./app.md#initializeserverapp_e7d0728) | Creates and initializes a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface) instance. |
| <b>function(libraryKeyOrName, ...)</b> |
| [registerVersion(libraryKeyOrName, version, variant)](./app.md#registerversion_f673248) | Registers a library's name and version for platform logging purposes. |
| <b>function(logCallback, ...)</b> |
Expand Down Expand Up @@ -116,6 +118,38 @@ export declare function initializeApp(): FirebaseApp;

[FirebaseApp](./app.firebaseapp.md#firebaseapp_interface)

## function(config, ...)

### initializeServerApp(config) {:#initializeserverapp_e7d0728}

Creates and initializes a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface) instance.

<b>Signature:</b>

```typescript
export declare function initializeServerApp(config?: FirebaseServerAppSettings): FirebaseServerApp;
```

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| config | [FirebaseServerAppSettings](./app.firebaseserverappsettings.md#firebaseserverappsettings_interface) | Optional <code>FirebaseServerApp</code> settings. |

<b>Returns:</b>

[FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)

The initialized `FirebaseServerApp`<!-- -->.

#### Exceptions

If invoked in an unsupported non-server environment such as a browser.

If [FirebaseServerAppSettings.releaseOnDeref](./app.firebaseserverappsettings.md#firebaseserverappsettingsreleaseonderef) is defined but the runtime doesn't provide Finalization Registry support.

If the `FIREBASE_OPTIONS` enviornment variable does not contain a valid project configuration required for auto-initialization.

## function(libraryKeyOrName, ...)

### registerVersion(libraryKeyOrName, version, variant) {:#registerversion_f673248}
Expand Down Expand Up @@ -260,6 +294,12 @@ export declare function initializeApp(options: FirebaseOptions, name?: string):

The initialized app.

#### Exceptions

If the optional `name` parameter is malformed or empty.

If a `FirebaseApp` already exists with the same name but with a different configuration.

### Example 1


Expand Down Expand Up @@ -312,6 +352,12 @@ export declare function initializeApp(options: FirebaseOptions, config?: Firebas

[FirebaseApp](./app.firebaseapp.md#firebaseapp_interface)

#### Exceptions

If [FirebaseAppSettings.name](./app.firebaseappsettings.md#firebaseappsettingsname) is defined but the value is malformed or empty.

If a `FirebaseApp` already exists with the same name but with a different configuration.

### initializeServerApp(options, config) {:#initializeserverapp_30ab697}

Creates and initializes a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface) instance.
Expand All @@ -323,22 +369,28 @@ See [Add Firebase to your app](https://firebase.google.com/docs/web/setup#add_fi
<b>Signature:</b>

```typescript
export declare function initializeServerApp(options: FirebaseOptions | FirebaseApp, config: FirebaseServerAppSettings): FirebaseServerApp;
export declare function initializeServerApp(options: FirebaseOptions | FirebaseApp, config?: FirebaseServerAppSettings): FirebaseServerApp;
```

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| options | [FirebaseOptions](./app.firebaseoptions.md#firebaseoptions_interface) \| [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface) | <code>Firebase.AppOptions</code> to configure the app's services, or a a <code>FirebaseApp</code> instance which contains the <code>AppOptions</code> within. |
| config | [FirebaseServerAppSettings](./app.firebaseserverappsettings.md#firebaseserverappsettings_interface) | <code>FirebaseServerApp</code> configuration. |
| config | [FirebaseServerAppSettings](./app.firebaseserverappsettings.md#firebaseserverappsettings_interface) | Optional <code>FirebaseServerApp</code> settings. |

<b>Returns:</b>

[FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)

The initialized `FirebaseServerApp`<!-- -->.

#### Exceptions

If invoked in an unsupported non-server environment such as a browser.

If [FirebaseServerAppSettings.releaseOnDeref](./app.firebaseserverappsettings.md#firebaseserverappsettingsreleaseonderef) is defined but the runtime doesn't provide Finalization Registry support.

### Example


Expand Down
76 changes: 59 additions & 17 deletions packages/app/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
_apps,
_components,
_isFirebaseApp,
_isFirebaseServerAppSettings,
_registerComponent,
_serverApps
} from './internal';
Expand Down Expand Up @@ -106,6 +107,10 @@ export const SDK_VERSION = version;
*
* @returns The initialized app.
*
* @throws If the optional `name` parameter is malformed or empty.
*
* @throws If a `FirebaseApp` already exists with the same name but with a different configuration.
*
* @public
*/
export function initializeApp(
Expand All @@ -118,6 +123,9 @@ export function initializeApp(
* @param options - Options to configure the app's services.
* @param config - FirebaseApp Configuration
*
* @throws If {@link FirebaseAppSettings.name} is defined but the value is malformed or empty.
*
* @throws If a `FirebaseApp` already exists with the same name but with a different configuration.
* @public
*/
export function initializeApp(
Expand Down Expand Up @@ -220,41 +228,75 @@ export function initializeApp(
*
* @param options - `Firebase.AppOptions` to configure the app's services, or a
* a `FirebaseApp` instance which contains the `AppOptions` within.
* @param config - `FirebaseServerApp` configuration.
* @param config - Optional `FirebaseServerApp` settings.
*
* @returns The initialized `FirebaseServerApp`.
*
* @throws If invoked in an unsupported non-server environment such as a browser.
*
* @throws If {@link FirebaseServerAppSettings.releaseOnDeref} is defined but the runtime doesn't
* provide Finalization Registry support.
*
* @public
*/
export function initializeServerApp(
options: FirebaseOptions | FirebaseApp,
config: FirebaseServerAppSettings
config?: FirebaseServerAppSettings
): FirebaseServerApp;

/**
* Creates and initializes a {@link @firebase/app#FirebaseServerApp} instance.
*
* @param config - Optional `FirebaseServerApp` settings.
*
* @returns The initialized `FirebaseServerApp`.
*
* @throws If invoked in an unsupported non-server environment such as a browser.
* @throws If {@link FirebaseServerAppSettings.releaseOnDeref} is defined but the runtime doesn't
* provide Finalization Registry support.
* @throws If the `FIREBASE_OPTIONS` enviornment variable does not contain a valid project
* configuration required for auto-initialization.
*
* @public
*/
export function initializeServerApp(
_options: FirebaseOptions | FirebaseApp,
_serverAppConfig: FirebaseServerAppSettings
config?: FirebaseServerAppSettings
): FirebaseServerApp;
export function initializeServerApp(
_options?: FirebaseApp | FirebaseServerAppSettings | FirebaseOptions,
_serverAppConfig: FirebaseServerAppSettings = {}
): FirebaseServerApp {
if (isBrowser() && !isWebWorker()) {
// FirebaseServerApp isn't designed to be run in browsers.
throw ERROR_FACTORY.create(AppError.INVALID_SERVER_APP_ENVIRONMENT);
}

if (_serverAppConfig.automaticDataCollectionEnabled === undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we getting rid of this? Should this go in the second branch of the if/else? Maybe also the third?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thank you, nice catch!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

_serverAppConfig.automaticDataCollectionEnabled = true;
let firebaseOptions: FirebaseOptions | undefined;
let serverAppSettings: FirebaseServerAppSettings = _serverAppConfig || {};

if (_options) {
if (_isFirebaseApp(_options)) {
firebaseOptions = _options.options;
} else if (_isFirebaseServerAppSettings(_options)) {
serverAppSettings = _options;
} else {
firebaseOptions = _options;
}
}

let appOptions: FirebaseOptions;
if (_isFirebaseApp(_options)) {
appOptions = _options.options;
} else {
appOptions = _options;
if (serverAppSettings.automaticDataCollectionEnabled === undefined) {
serverAppSettings.automaticDataCollectionEnabled = true;
}

firebaseOptions ||= getDefaultAppConfig();
if (!firebaseOptions) {
throw ERROR_FACTORY.create(AppError.NO_OPTIONS);
}

// Build an app name based on a hash of the configuration options.
const nameObj = {
..._serverAppConfig,
...appOptions
...serverAppSettings,
...firebaseOptions
};

// However, Do not mangle the name based on releaseOnDeref, since it will vary between the
Expand All @@ -270,7 +312,7 @@ export function initializeServerApp(
);
};

if (_serverAppConfig.releaseOnDeref !== undefined) {
if (serverAppSettings.releaseOnDeref !== undefined) {
if (typeof FinalizationRegistry === 'undefined') {
throw ERROR_FACTORY.create(
AppError.FINALIZATION_REGISTRY_NOT_SUPPORTED,
Expand All @@ -283,7 +325,7 @@ export function initializeServerApp(
const existingApp = _serverApps.get(nameString) as FirebaseServerApp;
if (existingApp) {
(existingApp as FirebaseServerAppImpl).incRefCount(
_serverAppConfig.releaseOnDeref
serverAppSettings.releaseOnDeref
);
return existingApp;
}
Expand All @@ -294,8 +336,8 @@ export function initializeServerApp(
}

const newApp = new FirebaseServerAppImpl(
appOptions,
_serverAppConfig,
firebaseOptions,
serverAppSettings,
nameString,
container
);
Expand Down
28 changes: 26 additions & 2 deletions packages/app/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import {
FirebaseApp,
FirebaseAppSettings,
FirebaseServerAppSettings,
FirebaseOptions,
FirebaseServerApp
} from './public-types';
Expand Down Expand Up @@ -147,18 +149,40 @@ export function _removeServiceInstance<T extends Name>(

/**
*
* @param obj - an object of type FirebaseApp or FirebaseOptions.
* @param obj - an object of type FirebaseApp, FirebaseOptions or FirebaseAppSettings.
*
* @returns true if the provide object is of type FirebaseApp.
*
* @internal
*/
export function _isFirebaseApp(
obj: FirebaseApp | FirebaseOptions
obj: FirebaseApp | FirebaseOptions | FirebaseAppSettings
): obj is FirebaseApp {
return (obj as FirebaseApp).options !== undefined;
}

/**
*
* @param obj - an object of type FirebaseApp, FirebaseOptions or FirebaseAppSettings.
*
* @returns true if the provided object is of type FirebaseServerAppImpl.
*
* @internal
*/
export function _isFirebaseServerAppSettings(
obj: FirebaseApp | FirebaseOptions | FirebaseAppSettings
): obj is FirebaseServerAppSettings {
if (_isFirebaseApp(obj)) {
return false;
}
return (
'authIdToken' in obj ||
'appCheckToken' in obj ||
'releaseOnDeref' in obj ||
'automaticDataCollectionEnabled' in obj
);
}

/**
*
* @param obj - an object of type FirebaseApp.
Expand Down
Loading