Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
22ba366
added the api-definition, interfaces, realtime connection and backoff…
Samruddhi90 Aug 8, 2025
77bc5ef
Added TODO and comments
Samruddhi90 Aug 8, 2025
c16eadd
Added the visibilityMonitor
Samruddhi90 Aug 9, 2025
c5d7dfb
resolved the comment about the spacing problem
Samruddhi90 Aug 11, 2025
77a6aca
Fix check failures
Samruddhi90 Aug 11, 2025
4002ed9
minor changes
Samruddhi90 Aug 11, 2025
0ff4893
Fix yarn failures
Samruddhi90 Aug 12, 2025
52686fc
Merge branch 'realtime-backoff' into realtime-visibility-api
Samruddhi90 Aug 12, 2025
6105412
resolving the spacing problem
Samruddhi90 Aug 12, 2025
61ba815
Convert backoff time from seconds to minutes
Samruddhi90 Aug 12, 2025
a98f140
Merge branch 'realtime-backoff' into realtime-visibility-api
Samruddhi90 Aug 12, 2025
c4a8b72
fixed the minor errors
Samruddhi90 Aug 13, 2025
5b23deb
Minor refactoring
Samruddhi90 Aug 13, 2025
960b88e
fixing yarn lint errors
Samruddhi90 Aug 13, 2025
2653ebb
Adding synchronous delay
Samruddhi90 Aug 13, 2025
b8b2751
updating the fetch call
Samruddhi90 Aug 14, 2025
024e042
Closing the connection in a proper way
Samruddhi90 Aug 14, 2025
f882ad4
close connection async
Samruddhi90 Aug 14, 2025
a7d271b
Added the comments
Samruddhi90 Aug 14, 2025
ac82ed7
minor fixes
Samruddhi90 Aug 14, 2025
006127b
Modifying the name of the method `beginRealtimeHttpStream` to `prepar…
Samruddhi90 Aug 18, 2025
874299e
Updating the onConfigUpdate method definition.
Samruddhi90 Aug 18, 2025
412b664
Merge branch 'realtime-for-web' into realtime-handle-notifications
Samruddhi90 Aug 18, 2025
649a2ac
Delete realtime_handler.test.ts
Samruddhi90 Aug 18, 2025
11077d8
fixing the comments.
Samruddhi90 Aug 18, 2025
494af7d
Adding a TODO for X-`Firebase-RC-Fetch-Type` header
Samruddhi90 Aug 20, 2025
385d8bd
Update the errorcodes
Samruddhi90 Aug 20, 2025
f583f8e
minor fix
Samruddhi90 Aug 20, 2025
17b9eb5
Resolving the comment
Samruddhi90 Aug 20, 2025
3eee5f8
Adding changeset
Samruddhi90 Aug 21, 2025
5d43520
Realtime RC test cases (#9210)
Samruddhi90 Aug 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions common/api-review/remote-config.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@
```ts

import { FirebaseApp } from '@firebase/app';
import { FirebaseError } from '@firebase/app';

// @public
export function activate(remoteConfig: RemoteConfig): Promise<boolean>;

// @public
export interface ConfigUpdate {
getUpdatedKeys(): Set<string>;
}

// @public
export interface ConfigUpdateObserver {
complete: () => void;
error: (error: FirebaseError) => void;
next: (configUpdate: ConfigUpdate) => void;
}

// @public
export interface CustomSignals {
// (undocumented)
Expand All @@ -29,11 +42,15 @@ export interface FetchResponse {
config?: FirebaseRemoteConfigObject;
eTag?: string;
status: number;
templateVersion?: number;
}

// @public
export type FetchStatus = 'no-fetch-yet' | 'success' | 'failure' | 'throttle';

// @public
export type FetchType = 'BASE' | 'REALTIME';

// @public
export interface FirebaseRemoteConfigObject {
// (undocumented)
Expand Down Expand Up @@ -64,6 +81,9 @@ export function isSupported(): Promise<boolean>;
// @public
export type LogLevel = 'debug' | 'error' | 'silent';

// @public
export function onConfigUpdate(remoteConfig: RemoteConfig, observer: ConfigUpdateObserver): Unsubscribe;

// @public
export interface RemoteConfig {
app: FirebaseApp;
Expand Down Expand Up @@ -93,6 +113,9 @@ export function setCustomSignals(remoteConfig: RemoteConfig, customSignals: Cust
// @public
export function setLogLevel(remoteConfig: RemoteConfig, logLevel: LogLevel): void;

// @public
export type Unsubscribe = () => void;

// @public
export interface Value {
asBoolean(): boolean;
Expand Down
4 changes: 4 additions & 0 deletions docs-devsite/_toc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,10 @@ toc:
- title: remote-config
path: /docs/reference/js/remote-config.md
section:
- title: ConfigUpdate
path: /docs/reference/js/remote-config.configupdate.md
- title: ConfigUpdateObserver
path: /docs/reference/js/remote-config.configupdateobserver.md
- title: CustomSignals
path: /docs/reference/js/remote-config.customsignals.md
- title: FetchResponse
Expand Down
39 changes: 39 additions & 0 deletions docs-devsite/remote-config.configupdate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Project: /docs/reference/js/_project.yaml
Book: /docs/reference/_book.yaml
page_type: reference

{% comment %}
DO NOT EDIT THIS FILE!
This is generated by the JS SDK team, and any local changes will be
overwritten. Changes should be made in the source code at
https://github.com/firebase/firebase-js-sdk
{% endcomment %}

# ConfigUpdate interface
Contains information about which keys have been updated.

<b>Signature:</b>

```typescript
export interface ConfigUpdate
```

## Methods

| Method | Description |
| --- | --- |
| [getUpdatedKeys()](./remote-config.configupdate.md#configupdategetupdatedkeys) | Parameter keys whose values have been updated from the currently activated values. Includes keys that are added, deleted, or whose value, value source, or metadata has changed. |

## ConfigUpdate.getUpdatedKeys()

Parameter keys whose values have been updated from the currently activated values. Includes keys that are added, deleted, or whose value, value source, or metadata has changed.

<b>Signature:</b>

```typescript
getUpdatedKeys(): Set<string>;
```
<b>Returns:</b>

Set&lt;string&gt;

59 changes: 59 additions & 0 deletions docs-devsite/remote-config.configupdateobserver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Project: /docs/reference/js/_project.yaml
Book: /docs/reference/_book.yaml
page_type: reference

{% comment %}
DO NOT EDIT THIS FILE!
This is generated by the JS SDK team, and any local changes will be
overwritten. Changes should be made in the source code at
https://github.com/firebase/firebase-js-sdk
{% endcomment %}

# ConfigUpdateObserver interface
Observer interface for receiving real-time Remote Config update notifications.

NOTE: Although an `complete` callback can be provided, it will never be called because the ConfigUpdate stream is never-ending.

<b>Signature:</b>

```typescript
export interface ConfigUpdateObserver
```

## Properties

| Property | Type | Description |
| --- | --- | --- |
| [complete](./remote-config.configupdateobserver.md#configupdateobservercomplete) | () =&gt; void | Called when the stream is gracefully terminated. |
| [error](./remote-config.configupdateobserver.md#configupdateobservererror) | (error: [FirebaseError](./util.firebaseerror.md#firebaseerror_class)<!-- -->) =&gt; void | Called if an error occurs during the stream. |
| [next](./remote-config.configupdateobserver.md#configupdateobservernext) | (configUpdate: [ConfigUpdate](./remote-config.configupdate.md#configupdate_interface)<!-- -->) =&gt; void | Called when a new ConfigUpdate is available. |

## ConfigUpdateObserver.complete

Called when the stream is gracefully terminated.

<b>Signature:</b>

```typescript
complete: () => void;
```

## ConfigUpdateObserver.error

Called if an error occurs during the stream.

<b>Signature:</b>

```typescript
error: (error: FirebaseError) => void;
```

## ConfigUpdateObserver.next

Called when a new ConfigUpdate is available.

<b>Signature:</b>

```typescript
next: (configUpdate: ConfigUpdate) => void;
```
11 changes: 11 additions & 0 deletions docs-devsite/remote-config.fetchresponse.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface FetchResponse
| [config](./remote-config.fetchresponse.md#fetchresponseconfig) | [FirebaseRemoteConfigObject](./remote-config.firebaseremoteconfigobject.md#firebaseremoteconfigobject_interface) | Defines the map of parameters returned as "entries" in the fetch response body.<p>Only defined for 200 responses. |
| [eTag](./remote-config.fetchresponse.md#fetchresponseetag) | string | Defines the ETag response header value.<p>Only defined for 200 and 304 responses. |
| [status](./remote-config.fetchresponse.md#fetchresponsestatus) | number | The HTTP status, which is useful for differentiating success responses with data from those without.<p>The Remote Config client is modeled after the native <code>Fetch</code> interface, so HTTP status is first-class.<p>Disambiguation: the fetch response returns a legacy "state" value that is redundant with the HTTP status code. The former is normalized into the latter. |
| [templateVersion](./remote-config.fetchresponse.md#fetchresponsetemplateversion) | number | The version number of the config template fetched from the server. |

## FetchResponse.config

Expand Down Expand Up @@ -65,3 +66,13 @@ The HTTP status, which is useful for differentiating success responses with data
```typescript
status: number;
```

## FetchResponse.templateVersion

The version number of the config template fetched from the server.

<b>Signature:</b>

```typescript
templateVersion?: number;
```
52 changes: 52 additions & 0 deletions docs-devsite/remote-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ The Firebase Remote Config Web SDK. This SDK does not work in a Node.js environm
| [getNumber(remoteConfig, key)](./remote-config.md#getnumber_476c09f) | Gets the value for the given key as a number.<!-- -->Convenience method for calling <code>remoteConfig.getValue(key).asNumber()</code>. |
| [getString(remoteConfig, key)](./remote-config.md#getstring_476c09f) | Gets the value for the given key as a string. Convenience method for calling <code>remoteConfig.getValue(key).asString()</code>. |
| [getValue(remoteConfig, key)](./remote-config.md#getvalue_476c09f) | Gets the [Value](./remote-config.value.md#value_interface) for the given key. |
| [onConfigUpdate(remoteConfig, observer)](./remote-config.md#onconfigupdate_8b13b26) | Starts listening for real-time config updates from the Remote Config backend and automatically fetches updates from the RC backend when they are available.<p>If a connection to the Remote Config backend is not already open, calling this method will open it. Multiple listeners can be added by calling this method again, but subsequent calls re-use the same connection to the backend. |
| [setCustomSignals(remoteConfig, customSignals)](./remote-config.md#setcustomsignals_aeeb95e) | Sets the custom signals for the app instance. |
| [setLogLevel(remoteConfig, logLevel)](./remote-config.md#setloglevel_039a45b) | Defines the log level to use. |
| <b>function()</b> |
Expand All @@ -37,6 +38,8 @@ The Firebase Remote Config Web SDK. This SDK does not work in a Node.js environm

| Interface | Description |
| --- | --- |
| [ConfigUpdate](./remote-config.configupdate.md#configupdate_interface) | Contains information about which keys have been updated. |
| [ConfigUpdateObserver](./remote-config.configupdateobserver.md#configupdateobserver_interface) | Observer interface for receiving real-time Remote Config update notifications.<!-- -->NOTE: Although an <code>complete</code> callback can be provided, it will never be called because the ConfigUpdate stream is never-ending. |
| [CustomSignals](./remote-config.customsignals.md#customsignals_interface) | Defines the type for representing custom signals and their values.<p>The values in CustomSignals must be one of the following types:<ul> <li><code>string</code> <li><code>number</code> <li><code>null</code> </ul> |
| [FetchResponse](./remote-config.fetchresponse.md#fetchresponse_interface) | Defines a successful response (200 or 304).<p>Modeled after the native <code>Response</code> interface, but simplified for Remote Config's use case. |
| [FirebaseRemoteConfigObject](./remote-config.firebaseremoteconfigobject.md#firebaseremoteconfigobject_interface) | Defines a self-descriptive reference for config key-value pairs. |
Expand All @@ -50,7 +53,9 @@ The Firebase Remote Config Web SDK. This SDK does not work in a Node.js environm
| Type Alias | Description |
| --- | --- |
| [FetchStatus](./remote-config.md#fetchstatus) | Summarizes the outcome of the last attempt to fetch config from the Firebase Remote Config server.<ul> <li>"no-fetch-yet" indicates the [RemoteConfig](./remote-config.remoteconfig.md#remoteconfig_interface) instance has not yet attempted to fetch config, or that SDK initialization is incomplete.</li> <li>"success" indicates the last attempt succeeded.</li> <li>"failure" indicates the last attempt failed.</li> <li>"throttle" indicates the last attempt was rate-limited.</li> </ul> |
| [FetchType](./remote-config.md#fetchtype) | Indicates the type of fetch request.<ul> <li>"BASE" indicates a standard fetch request.</li> <li>"REALTIME" indicates a fetch request triggered by a real-time update.</li> </ul> |
| [LogLevel](./remote-config.md#loglevel) | Defines levels of Remote Config logging. |
| [Unsubscribe](./remote-config.md#unsubscribe) | A function that unsubscribes from a real-time event stream. |
| [ValueSource](./remote-config.md#valuesource) | Indicates the source of a value.<ul> <li>"static" indicates the value was defined by a static constant.</li> <li>"default" indicates the value was defined by default config.</li> <li>"remote" indicates the value was defined by fetched config.</li> </ul> |

## function(app, ...)
Expand Down Expand Up @@ -282,6 +287,31 @@ export declare function getValue(remoteConfig: RemoteConfig, key: string): Value

The value for the given key.

### onConfigUpdate(remoteConfig, observer) {:#onconfigupdate_8b13b26}

Starts listening for real-time config updates from the Remote Config backend and automatically fetches updates from the RC backend when they are available.

<p>If a connection to the Remote Config backend is not already open, calling this method will open it. Multiple listeners can be added by calling this method again, but subsequent calls re-use the same connection to the backend.

<b>Signature:</b>

```typescript
export declare function onConfigUpdate(remoteConfig: RemoteConfig, observer: ConfigUpdateObserver): Unsubscribe;
```

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| remoteConfig | [RemoteConfig](./remote-config.remoteconfig.md#remoteconfig_interface) | The [RemoteConfig](./remote-config.remoteconfig.md#remoteconfig_interface) instance. |
| observer | [ConfigUpdateObserver](./remote-config.configupdateobserver.md#configupdateobserver_interface) | The [ConfigUpdateObserver](./remote-config.configupdateobserver.md#configupdateobserver_interface) to be notified of config updates. |

<b>Returns:</b>

[Unsubscribe](./remote-config.md#unsubscribe)

An [Unsubscribe](./remote-config.md#unsubscribe) function to remove the listener.

### setCustomSignals(remoteConfig, customSignals) {:#setcustomsignals_aeeb95e}

Sets the custom signals for the app instance.
Expand Down Expand Up @@ -355,6 +385,18 @@ Summarizes the outcome of the last attempt to fetch config from the Firebase Rem
export type FetchStatus = 'no-fetch-yet' | 'success' | 'failure' | 'throttle';
```

## FetchType

Indicates the type of fetch request.

<ul> <li>"BASE" indicates a standard fetch request.</li> <li>"REALTIME" indicates a fetch request triggered by a real-time update.</li> </ul>

<b>Signature:</b>

```typescript
export type FetchType = 'BASE' | 'REALTIME';
```

## LogLevel

Defines levels of Remote Config logging.
Expand All @@ -365,6 +407,16 @@ Defines levels of Remote Config logging.
export type LogLevel = 'debug' | 'error' | 'silent';
```

## Unsubscribe

A function that unsubscribes from a real-time event stream.

<b>Signature:</b>

```typescript
export type Unsubscribe = () => void;
```

## ValueSource

Indicates the source of a value.
Expand Down
39 changes: 37 additions & 2 deletions packages/remote-config/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import {
LogLevel as RemoteConfigLogLevel,
RemoteConfig,
Value,
RemoteConfigOptions
RemoteConfigOptions,
ConfigUpdateObserver,
Unsubscribe
} from './public_types';
import { RemoteConfigAbortSignal } from './client/remote_config_fetch_client';
import {
Expand Down Expand Up @@ -66,6 +68,9 @@ export function getRemoteConfig(
rc._initializePromise = Promise.all([
rc._storage.setLastSuccessfulFetchResponse(options.initialFetchResponse),
rc._storage.setActiveConfigEtag(options.initialFetchResponse?.eTag || ''),
rc._storage.setActiveConfigTemplateVersion(
options.initialFetchResponse.templateVersion || 0
),
rc._storageCache.setLastSuccessfulFetchTimestampMillis(Date.now()),
rc._storageCache.setLastFetchStatus('success'),
rc._storageCache.setActiveConfig(
Expand Down Expand Up @@ -98,6 +103,7 @@ export async function activate(remoteConfig: RemoteConfig): Promise<boolean> {
!lastSuccessfulFetchResponse ||
!lastSuccessfulFetchResponse.config ||
!lastSuccessfulFetchResponse.eTag ||
!lastSuccessfulFetchResponse.templateVersion ||
lastSuccessfulFetchResponse.eTag === activeConfigEtag
) {
// Either there is no successful fetched config, or is the same as current active
Expand All @@ -106,7 +112,10 @@ export async function activate(remoteConfig: RemoteConfig): Promise<boolean> {
}
await Promise.all([
rc._storageCache.setActiveConfig(lastSuccessfulFetchResponse.config),
rc._storage.setActiveConfigEtag(lastSuccessfulFetchResponse.eTag)
rc._storage.setActiveConfigEtag(lastSuccessfulFetchResponse.eTag),
rc._storage.setActiveConfigTemplateVersion(
lastSuccessfulFetchResponse.templateVersion
)
]);
return true;
}
Expand Down Expand Up @@ -351,3 +360,29 @@ export async function setCustomSignals(
);
}
}

// TODO: Add public document for the Remote Config Realtime API guide on the Web Platform.
/**
* Starts listening for real-time config updates from the Remote Config backend and automatically
* fetches updates from the RC backend when they are available.
*
* <p>If a connection to the Remote Config backend is not already open, calling this method will
* open it. Multiple listeners can be added by calling this method again, but subsequent calls
* re-use the same connection to the backend.
*
* @param remoteConfig - The {@link RemoteConfig} instance.
* @param observer - The {@link ConfigUpdateObserver} to be notified of config updates.
* @returns An {@link Unsubscribe} function to remove the listener.
*
* @public
*/
export function onConfigUpdate(
remoteConfig: RemoteConfig,
observer: ConfigUpdateObserver
): Unsubscribe {
const rc = getModularInstance(remoteConfig) as RemoteConfigImpl;
rc._realtimeHandler.addObserver(observer);
return () => {
rc._realtimeHandler.removeObserver(observer);
};
}
Loading