Skip to content
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

feat(rc): Add custom signals support #8602

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
8 changes: 8 additions & 0 deletions .changeset/hip-apricots-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@firebase/remote-config-compat': minor
'@firebase/remote-config-types': minor
'@firebase/remote-config': minor
'firebase': minor
---

Add custom signals support to RC in client environments
9 changes: 9 additions & 0 deletions common/api-review/remote-config.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import { FirebaseApp } from '@firebase/app';
// @public
export function activate(remoteConfig: RemoteConfig): Promise<boolean>;

// @public
export interface CustomSignals {
// (undocumented)

Choose a reason for hiding this comment

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

Hmm. This would appear to indicate we've missed documentation on a public API, but I see a comment on CustomSignals in public_types.ts, so it's unclear what more we should be doing. This would be a question for the core JS team. I see getRemoteConfig is also flagged as undocumented, so this may be a non-issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

This indicates there's no documentation comment for the key/value pair here which it looks like probably isn't needed here given the thorough documentation on the parent interface.

[key: string]: string | number;
}

// @public
export function ensureInitialized(remoteConfig: RemoteConfig): Promise<void>;

Expand Down Expand Up @@ -62,6 +68,9 @@ export interface RemoteConfigSettings {
minimumFetchIntervalMillis: number;
}

// @public
export function setCustomSignals(remoteConfig: RemoteConfig, customSignals: CustomSignals): Promise<void>;

// @public
export function setLogLevel(remoteConfig: RemoteConfig, logLevel: LogLevel): void;

Expand Down
2 changes: 2 additions & 0 deletions docs-devsite/_toc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,8 @@ toc:
- title: remote-config
path: /docs/reference/js/remote-config.md
section:
- title: CustomSignals
path: /docs/reference/js/remote-config.customsignals.md
- title: RemoteConfig
path: /docs/reference/js/remote-config.remoteconfig.md
- title: RemoteConfigSettings
Expand Down
23 changes: 23 additions & 0 deletions docs-devsite/remote-config.customsignals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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 %}

# 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> </ul>

<b>Signature:</b>

```typescript
export interface CustomSignals
```
23 changes: 23 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. |
| [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> |
| [isSupported()](./remote-config.md#issupported) | This method provides two different checks:<!-- -->1. Check if IndexedDB exists in the browser environment. 2. Check if the current browser context allows IndexedDB <code>open()</code> calls. |
Expand All @@ -36,6 +37,7 @@ The Firebase Remote Config Web SDK. This SDK does not work in a Node.js environm

| Interface | Description |
| --- | --- |
| [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> </ul> |
| [RemoteConfig](./remote-config.remoteconfig.md#remoteconfig_interface) | The Firebase Remote Config service interface. |
| [RemoteConfigSettings](./remote-config.remoteconfigsettings.md#remoteconfigsettings_interface) | Defines configuration options for the Remote Config SDK. |
| [Value](./remote-config.value.md#value_interface) | Wraps a value with metadata and type-safe getters. |
Expand Down Expand Up @@ -276,6 +278,27 @@ export declare function getValue(remoteConfig: RemoteConfig, key: string): Value

The value for the given key.

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

Sets the custom signals for the app instance.

<b>Signature:</b>

```typescript
export declare function setCustomSignals(remoteConfig: RemoteConfig, customSignals: CustomSignals): Promise<void>;
```

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| remoteConfig | [RemoteConfig](./remote-config.remoteconfig.md#remoteconfig_interface) | The [RemoteConfig](./remote-config.remoteconfig.md#remoteconfig_interface) instance. |
| customSignals | [CustomSignals](./remote-config.customsignals.md#customsignals_interface) | Map (key, value) of the custom signals to be set for the app instance. |

<b>Returns:</b>

Promise&lt;void&gt;

### setLogLevel(remoteConfig, logLevel) {:#setloglevel_039a45b}

Defines the log level to use.
Expand Down
18 changes: 18 additions & 0 deletions packages/firebase/compat/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1971,6 +1971,11 @@ declare namespace firebase.remoteConfig {
* Defines the log level to use.
*/
setLogLevel(logLevel: LogLevel): void;

/**
* Sets custom signals for the Remote Config instance.
ashish-kothari marked this conversation as resolved.
Show resolved Hide resolved
*/
setCustomSignals(customSignals: CustomSignals): Promise<void>;
}

/**
Expand Down Expand Up @@ -2046,6 +2051,19 @@ declare namespace firebase.remoteConfig {
* Defines levels of Remote Config logging.
*/
export type LogLevel = 'debug' | 'error' | 'silent';

/**
* 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>
* </ul>
*/
export type CustomSignals = { [key: string]: string | number };

/**
* This method provides two different checks:
*
Expand Down
13 changes: 13 additions & 0 deletions packages/remote-config-compat/src/remoteConfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,17 @@ describe('Remote Config Compat', () => {
'debug'
);
});

it('setCustomSignals() calls modular setCustomSignals()', async () => {
const modularSetCustomSignalsStub = stub(
modularApi,
'setCustomSignals'
).callsFake(() => Promise.resolve());
await remoteConfig.setCustomSignals({ 'customSignal': 'value' });

expect(modularSetCustomSignalsStub).to.have.been.calledWithExactly(
fakeModularRemoteConfig,
{ 'customSignal': 'value' }
);
});
});
10 changes: 8 additions & 2 deletions packages/remote-config-compat/src/remoteConfig.ts
ashish-kothari marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {
FetchStatus as FetchSTatusCompat,
Settings as SettingsCompat,
LogLevel as RemoteConfigLogLevel,
RemoteConfig as RemoteConfigCompat
RemoteConfig as RemoteConfigCompat,
CustomSignals as RemoteConfigCustomSignals
} from '@firebase/remote-config-types';
import {
RemoteConfig,
Expand All @@ -35,7 +36,8 @@ import {
getNumber,
getString,
getValue,
isSupported
isSupported,
setCustomSignals
} from '@firebase/remote-config';

export { isSupported };
Expand Down Expand Up @@ -115,4 +117,8 @@ export class RemoteConfigCompatImpl
setLogLevel(logLevel: RemoteConfigLogLevel): void {
setLogLevel(this._delegate, logLevel);
}

setCustomSignals(customSignals: RemoteConfigCustomSignals): Promise<void> {
return setCustomSignals(this._delegate, customSignals);
}
}
17 changes: 17 additions & 0 deletions packages/remote-config-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ export interface RemoteConfig {
* Defines the log level to use.
*/
setLogLevel(logLevel: LogLevel): void;

/**
* Sets custom signals for the Remote Config instance.
*/
setCustomSignals(customSignals: CustomSignals): Promise<void>;
}

/**
Expand Down Expand Up @@ -173,6 +178,18 @@ export type FetchStatus = 'no-fetch-yet' | 'success' | 'failure' | 'throttle';
*/
export type LogLevel = 'debug' | 'error' | 'silent';

/**
* 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>
* </ul>
*/
export type CustomSignals = { [key: string]: string | number };

declare module '@firebase/component' {
interface NameServiceMapping {
'remoteConfig-compat': RemoteConfig;
Expand Down
20 changes: 19 additions & 1 deletion packages/remote-config/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import { _getProvider, FirebaseApp, getApp } from '@firebase/app';
import {
CustomSignals,
LogLevel as RemoteConfigLogLevel,
RemoteConfig,
Value
Expand Down Expand Up @@ -118,7 +119,8 @@ export async function fetchConfig(remoteConfig: RemoteConfig): Promise<void> {
try {
await rc._client.fetch({
cacheMaxAgeMillis: rc.settings.minimumFetchIntervalMillis,
signal: abortSignal
signal: abortSignal,
customSignals: rc._storageCache.getCustomSignals()
});

await rc._storageCache.setLastFetchStatus('success');
Expand Down Expand Up @@ -258,3 +260,19 @@ export function setLogLevel(
function getAllKeys(obj1: {} = {}, obj2: {} = {}): string[] {
return Object.keys({ ...obj1, ...obj2 });
}

/**
* Sets the custom signals for the app instance.
*
* @param remoteConfig - The {@link RemoteConfig} instance.
* @param customSignals - Map (key, value) of the custom signals to be set for the app instance.
*
* @public
*/
export async function setCustomSignals(
remoteConfig: RemoteConfig,
customSignals: CustomSignals
): Promise<void> {
const rc = getModularInstance(remoteConfig) as RemoteConfigImpl;
return rc._storageCache.setCustomSignals(customSignals);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* limitations under the License.
*/

import { CustomSignals } from '../public_types';

/**
* Defines a client, as in https://en.wikipedia.org/wiki/Client%E2%80%93server_model, for the
* Remote Config server (https://firebase.google.com/docs/reference/remote-config/rest).
Expand Down Expand Up @@ -99,6 +101,12 @@ export interface FetchRequest {
* <p>Comparable to passing `headers = { 'If-None-Match': <eTag> }` to the native Fetch API.
*/
eTag?: string;

/** The custom signals stored for the app instance.
*
* <p>Optional in case no custom signals are set for the instance.
*/
customSignals?: CustomSignals;
}

/**
Expand Down
5 changes: 4 additions & 1 deletion packages/remote-config/src/client/rest_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/

import { CustomSignals } from '../public_types';
import {
FetchResponse,
RemoteConfigFetchClient,
Expand All @@ -41,6 +42,7 @@ interface FetchRequestBody {
app_instance_id_token: string;
app_id: string;
language_code: string;
custom_signals?: CustomSignals;
/* eslint-enable camelcase */
}

Expand Down Expand Up @@ -92,7 +94,8 @@ export class RestClient implements RemoteConfigFetchClient {
app_instance_id: installationId,
app_instance_id_token: installationToken,
app_id: this.appId,
language_code: getUserLanguage()
language_code: getUserLanguage(),
custom_signals: request.customSignals
/* eslint-enable camelcase */
};

Expand Down
16 changes: 16 additions & 0 deletions packages/remote-config/src/public_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,22 @@ export type FetchStatus = 'no-fetch-yet' | 'success' | 'failure' | 'throttle';
*/
export type LogLevel = 'debug' | 'error' | 'silent';

/**
* 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>
* </ul>
*
* @public
*/
export interface CustomSignals {
[key: string]: string | number;
}

declare module '@firebase/component' {
interface NameServiceMapping {
'remote-config': RemoteConfig;
Expand Down
Loading
Loading