@firebase/remote-config
Advanced tools
Comparing version 0.5.0-canary.b3e68ca41 to 0.5.0-canary.b92592d98
import { _getProvider, getApp, _registerComponent, registerVersion, SDK_VERSION } from '@firebase/app'; | ||
import { ErrorFactory, FirebaseError, getModularInstance, calculateBackoffMillis, isIndexedDBAvailable, validateIndexedDBOpenable } from '@firebase/util'; | ||
import { ErrorFactory, FirebaseError, getModularInstance, deepEqual, calculateBackoffMillis, isIndexedDBAvailable, validateIndexedDBOpenable } from '@firebase/util'; | ||
import { Component } from '@firebase/component'; | ||
@@ -8,3 +8,3 @@ import { LogLevel, Logger } from '@firebase/logger'; | ||
const name = "@firebase/remote-config"; | ||
const version = "0.5.0-canary.b3e68ca41"; | ||
const version = "0.5.0-canary.b92592d98"; | ||
@@ -85,2 +85,3 @@ /** | ||
const ERROR_DESCRIPTION_MAP = { | ||
["already-initialized" /* ErrorCode.ALREADY_INITIALIZED */]: 'Remote Config already initialized', | ||
["registration-window" /* ErrorCode.REGISTRATION_WINDOW */]: 'Undefined window object. This SDK only supports usage in a browser environment.', | ||
@@ -181,2 +182,4 @@ ["registration-project-id" /* ErrorCode.REGISTRATION_PROJECT_ID */]: 'Undefined project identifier. Check Firebase app initialization.', | ||
* @param app - The {@link @firebase/app#FirebaseApp} instance. | ||
* @param options - Optional. The {@link RemoteConfigOptions} with which to instantiate the | ||
* Remote Config instance. | ||
* @returns A {@link RemoteConfig} instance. | ||
@@ -186,6 +189,30 @@ * | ||
*/ | ||
function getRemoteConfig(app = getApp()) { | ||
function getRemoteConfig(app = getApp(), options = {}) { | ||
var _a, _b; | ||
app = getModularInstance(app); | ||
const rcProvider = _getProvider(app, RC_COMPONENT_NAME); | ||
return rcProvider.getImmediate(); | ||
if (rcProvider.isInitialized()) { | ||
const initialOptions = rcProvider.getOptions(); | ||
if (deepEqual(initialOptions, options)) { | ||
return rcProvider.getImmediate(); | ||
} | ||
throw ERROR_FACTORY.create("already-initialized" /* ErrorCode.ALREADY_INITIALIZED */); | ||
} | ||
rcProvider.initialize({ options }); | ||
const rc = rcProvider.getImmediate(); | ||
if (options.initialFetchResponse) { | ||
// We use these initial writes as the initialization promise since they will hydrate the same | ||
// fields that `storageCache.loadFromStorage` would set. | ||
rc._initializePromise = Promise.all([ | ||
rc._storage.setLastSuccessfulFetchResponse(options.initialFetchResponse), | ||
rc._storage.setActiveConfigEtag(((_a = options.initialFetchResponse) === null || _a === void 0 ? void 0 : _a.eTag) || ''), | ||
rc._storageCache.setLastSuccessfulFetchTimestampMillis(Date.now()), | ||
rc._storageCache.setLastFetchStatus('success'), | ||
rc._storageCache.setActiveConfig(((_b = options.initialFetchResponse) === null || _b === void 0 ? void 0 : _b.config) || {}) | ||
]).then(); | ||
// The `storageCache` methods above set their in-memory fields synchronously, so it's | ||
// safe to declare our initialization complete at this point. | ||
rc._isInitializationComplete = true; | ||
} | ||
return rc; | ||
} | ||
@@ -936,13 +963,2 @@ /** | ||
class Storage { | ||
/** | ||
* @param appId enables storage segmentation by app (ID + name). | ||
* @param appName enables storage segmentation by app (ID + name). | ||
* @param namespace enables storage segmentation by namespace. | ||
*/ | ||
constructor(appId, appName, namespace, openDbPromise = openDatabase()) { | ||
this.appId = appId; | ||
this.appName = appName; | ||
this.namespace = namespace; | ||
this.openDbPromise = openDbPromise; | ||
} | ||
getLastFetchStatus() { | ||
@@ -992,2 +1008,16 @@ return this.get('last_fetch_status'); | ||
} | ||
} | ||
class IndexedDbStorage extends Storage { | ||
/** | ||
* @param appId enables storage segmentation by app (ID + name). | ||
* @param appName enables storage segmentation by app (ID + name). | ||
* @param namespace enables storage segmentation by namespace. | ||
*/ | ||
constructor(appId, appName, namespace, openDbPromise = openDatabase()) { | ||
super(); | ||
this.appId = appId; | ||
this.appName = appName; | ||
this.namespace = namespace; | ||
this.openDbPromise = openDbPromise; | ||
} | ||
async setCustomSignals(customSignals) { | ||
@@ -997,20 +1027,3 @@ const db = await this.openDbPromise; | ||
const storedSignals = await this.getWithTransaction('custom_signals', transaction); | ||
const combinedSignals = Object.assign(Object.assign({}, storedSignals), customSignals); | ||
// Filter out key-value assignments with null values since they are signals being unset | ||
const updatedSignals = Object.fromEntries(Object.entries(combinedSignals) | ||
.filter(([_, v]) => v !== null) | ||
.map(([k, v]) => { | ||
// Stringify numbers to store a map of string keys and values which can be sent | ||
// as-is in a fetch call. | ||
if (typeof v === 'number') { | ||
return [k, v.toString()]; | ||
} | ||
return [k, v]; | ||
})); | ||
// Throw an error if the number of custom signals to be stored exceeds the limit | ||
if (Object.keys(updatedSignals).length > RC_CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS) { | ||
throw ERROR_FACTORY.create("custom-signal-max-allowed-signals" /* ErrorCode.CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS */, { | ||
maxSignals: RC_CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS | ||
}); | ||
} | ||
const updatedSignals = mergeCustomSignals(customSignals, storedSignals || {}); | ||
await this.setWithTransaction('custom_signals', updatedSignals, transaction); | ||
@@ -1120,2 +1133,46 @@ return updatedSignals; | ||
} | ||
class InMemoryStorage extends Storage { | ||
constructor() { | ||
super(...arguments); | ||
this.storage = {}; | ||
} | ||
async get(key) { | ||
return Promise.resolve(this.storage[key]); | ||
} | ||
async set(key, value) { | ||
this.storage[key] = value; | ||
return Promise.resolve(undefined); | ||
} | ||
async delete(key) { | ||
this.storage[key] = undefined; | ||
return Promise.resolve(); | ||
} | ||
async setCustomSignals(customSignals) { | ||
const storedSignals = (this.storage['custom_signals'] || | ||
{}); | ||
this.storage['custom_signals'] = mergeCustomSignals(customSignals, storedSignals); | ||
return Promise.resolve(this.storage['custom_signals']); | ||
} | ||
} | ||
function mergeCustomSignals(customSignals, storedSignals) { | ||
const combinedSignals = Object.assign(Object.assign({}, storedSignals), customSignals); | ||
// Filter out key-value assignments with null values since they are signals being unset | ||
const updatedSignals = Object.fromEntries(Object.entries(combinedSignals) | ||
.filter(([_, v]) => v !== null) | ||
.map(([k, v]) => { | ||
// Stringify numbers to store a map of string keys and values which can be sent | ||
// as-is in a fetch call. | ||
if (typeof v === 'number') { | ||
return [k, v.toString()]; | ||
} | ||
return [k, v]; | ||
})); | ||
// Throw an error if the number of custom signals to be stored exceeds the limit | ||
if (Object.keys(updatedSignals).length > RC_CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS) { | ||
throw ERROR_FACTORY.create("custom-signal-max-allowed-signals" /* ErrorCode.CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS */, { | ||
maxSignals: RC_CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS | ||
}); | ||
} | ||
return updatedSignals; | ||
} | ||
@@ -1232,3 +1289,3 @@ /** | ||
registerVersion(name, version, 'esm2017'); | ||
function remoteConfigFactory(container, { instanceIdentifier: namespace }) { | ||
function remoteConfigFactory(container, { options }) { | ||
/* Dependencies */ | ||
@@ -1241,10 +1298,2 @@ // getImmediate for FirebaseApp will always succeed | ||
.getImmediate(); | ||
// Guards against the SDK being used in non-browser environments. | ||
if (typeof window === 'undefined') { | ||
throw ERROR_FACTORY.create("registration-window" /* ErrorCode.REGISTRATION_WINDOW */); | ||
} | ||
// Guards against the SDK being used when indexedDB is not available. | ||
if (!isIndexedDBAvailable()) { | ||
throw ERROR_FACTORY.create("indexed-db-unavailable" /* ErrorCode.INDEXED_DB_UNAVAILABLE */); | ||
} | ||
// Normalizes optional inputs. | ||
@@ -1261,4 +1310,6 @@ const { projectId, apiKey, appId } = app.options; | ||
} | ||
namespace = namespace || 'firebase'; | ||
const storage = new Storage(appId, app.name, namespace); | ||
const namespace = (options === null || options === void 0 ? void 0 : options.templateId) || 'firebase'; | ||
const storage = isIndexedDBAvailable() | ||
? new IndexedDbStorage(appId, app.name, namespace) | ||
: new InMemoryStorage(); | ||
const storageCache = new StorageCache(storage); | ||
@@ -1265,0 +1316,0 @@ const logger = new Logger(name); |
@@ -18,6 +18,8 @@ /** | ||
import { FirebaseApp } from '@firebase/app'; | ||
import { CustomSignals, LogLevel as RemoteConfigLogLevel, RemoteConfig, Value } from './public_types'; | ||
import { CustomSignals, LogLevel as RemoteConfigLogLevel, RemoteConfig, Value, RemoteConfigOptions } from './public_types'; | ||
/** | ||
* | ||
* @param app - The {@link @firebase/app#FirebaseApp} instance. | ||
* @param options - Optional. The {@link RemoteConfigOptions} with which to instantiate the | ||
* Remote Config instance. | ||
* @returns A {@link RemoteConfig} instance. | ||
@@ -27,3 +29,3 @@ * | ||
*/ | ||
export declare function getRemoteConfig(app?: FirebaseApp): RemoteConfig; | ||
export declare function getRemoteConfig(app?: FirebaseApp, options?: RemoteConfigOptions): RemoteConfig; | ||
/** | ||
@@ -30,0 +32,0 @@ * Makes the last fetched config available to the getters. |
@@ -18,3 +18,4 @@ /** | ||
import { StorageCache } from '../storage/storage_cache'; | ||
import { FetchResponse, RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { FetchResponse } from '../public_types'; | ||
import { RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { Storage } from '../storage/storage'; | ||
@@ -21,0 +22,0 @@ import { Logger } from '@firebase/logger'; |
@@ -17,3 +17,3 @@ /** | ||
*/ | ||
import { CustomSignals } from '../public_types'; | ||
import { CustomSignals, FetchResponse } from '../public_types'; | ||
/** | ||
@@ -38,8 +38,2 @@ * Defines a client, as in https://en.wikipedia.org/wiki/Client%E2%80%93server_model, for the | ||
/** | ||
* Defines a self-descriptive reference for config key-value pairs. | ||
*/ | ||
export interface FirebaseRemoteConfigObject { | ||
[key: string]: string; | ||
} | ||
/** | ||
* Shims a minimal AbortSignal. | ||
@@ -101,32 +95,1 @@ * | ||
} | ||
/** | ||
* Defines a successful response (200 or 304). | ||
* | ||
* <p>Modeled after the native {@link Response} interface, but simplified for Remote Config's | ||
* use case. | ||
*/ | ||
export interface FetchResponse { | ||
/** | ||
* The HTTP status, which is useful for differentiating success responses with data from | ||
* those without. | ||
* | ||
* <p>{@link RemoteConfigClient} is modeled after the native {@link GlobalFetch} 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. | ||
*/ | ||
status: number; | ||
/** | ||
* Defines the ETag response header value. | ||
* | ||
* <p>Only defined for 200 and 304 responses. | ||
*/ | ||
eTag?: string; | ||
/** | ||
* Defines the map of parameters returned as "entries" in the fetch response body. | ||
* | ||
* <p>Only defined for 200 responses. | ||
*/ | ||
config?: FirebaseRemoteConfigObject; | ||
} |
@@ -17,3 +17,4 @@ /** | ||
*/ | ||
import { FetchResponse, RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { FetchResponse } from '../public_types'; | ||
import { RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { _FirebaseInstallationsInternal } from '@firebase/installations'; | ||
@@ -20,0 +21,0 @@ /** |
@@ -17,3 +17,4 @@ /** | ||
*/ | ||
import { RemoteConfigAbortSignal, RemoteConfigFetchClient, FetchResponse, FetchRequest } from './remote_config_fetch_client'; | ||
import { FetchResponse } from '../public_types'; | ||
import { RemoteConfigAbortSignal, RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { ThrottleMetadata, Storage } from '../storage/storage'; | ||
@@ -20,0 +21,0 @@ /** |
@@ -19,2 +19,3 @@ /** | ||
export declare const enum ErrorCode { | ||
ALREADY_INITIALIZED = "already-initialized", | ||
REGISTRATION_WINDOW = "registration-window", | ||
@@ -21,0 +22,0 @@ REGISTRATION_PROJECT_ID = "registration-project-id", |
@@ -50,2 +50,54 @@ /** | ||
/** | ||
* Defines a self-descriptive reference for config key-value pairs. | ||
*/ | ||
export interface FirebaseRemoteConfigObject { | ||
[key: string]: string; | ||
} | ||
/** | ||
* Defines a successful response (200 or 304). | ||
* | ||
* <p>Modeled after the native `Response` interface, but simplified for Remote Config's | ||
* use case. | ||
*/ | ||
export interface FetchResponse { | ||
/** | ||
* 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 `Fetch` 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. | ||
*/ | ||
status: number; | ||
/** | ||
* Defines the ETag response header value. | ||
* | ||
* <p>Only defined for 200 and 304 responses. | ||
*/ | ||
eTag?: string; | ||
/** | ||
* Defines the map of parameters returned as "entries" in the fetch response body. | ||
* | ||
* <p>Only defined for 200 responses. | ||
*/ | ||
config?: FirebaseRemoteConfigObject; | ||
} | ||
/** | ||
* Options for Remote Config initialization. | ||
* | ||
* @public | ||
*/ | ||
export interface RemoteConfigOptions { | ||
/** | ||
* The ID of the template to use. If not provided, defaults to "firebase". | ||
*/ | ||
templateId?: string; | ||
/** | ||
* Hydrates the state with an initial fetch response. | ||
*/ | ||
initialFetchResponse?: FetchResponse; | ||
} | ||
/** | ||
* Indicates the source of a value. | ||
@@ -52,0 +104,0 @@ * |
@@ -18,3 +18,3 @@ /** | ||
import { FetchStatus, CustomSignals } from '@firebase/remote-config-types'; | ||
import { FirebaseRemoteConfigObject } from '../client/remote_config_fetch_client'; | ||
import { FirebaseRemoteConfigObject } from '../public_types'; | ||
import { Storage } from './storage'; | ||
@@ -21,0 +21,0 @@ /** |
@@ -18,3 +18,3 @@ /** | ||
import { FetchStatus, CustomSignals } from '@firebase/remote-config-types'; | ||
import { FetchResponse, FirebaseRemoteConfigObject } from '../client/remote_config_fetch_client'; | ||
import { FetchResponse, FirebaseRemoteConfigObject } from '../public_types'; | ||
/** | ||
@@ -48,13 +48,3 @@ * A general-purpose store keyed by app + namespace + {@link | ||
*/ | ||
export declare class Storage { | ||
private readonly appId; | ||
private readonly appName; | ||
private readonly namespace; | ||
private readonly openDbPromise; | ||
/** | ||
* @param appId enables storage segmentation by app (ID + name). | ||
* @param appName enables storage segmentation by app (ID + name). | ||
* @param namespace enables storage segmentation by namespace. | ||
*/ | ||
constructor(appId: string, appName: string, namespace: string, openDbPromise?: Promise<IDBDatabase>); | ||
export declare abstract class Storage { | ||
getLastFetchStatus(): Promise<FetchStatus | undefined>; | ||
@@ -74,2 +64,18 @@ setLastFetchStatus(status: FetchStatus): Promise<void>; | ||
getCustomSignals(): Promise<CustomSignals | undefined>; | ||
abstract setCustomSignals(customSignals: CustomSignals): Promise<CustomSignals>; | ||
abstract get<T>(key: ProjectNamespaceKeyFieldValue): Promise<T | undefined>; | ||
abstract set<T>(key: ProjectNamespaceKeyFieldValue, value: T): Promise<void>; | ||
abstract delete(key: ProjectNamespaceKeyFieldValue): Promise<void>; | ||
} | ||
export declare class IndexedDbStorage extends Storage { | ||
private readonly appId; | ||
private readonly appName; | ||
private readonly namespace; | ||
private readonly openDbPromise; | ||
/** | ||
* @param appId enables storage segmentation by app (ID + name). | ||
* @param appName enables storage segmentation by app (ID + name). | ||
* @param namespace enables storage segmentation by namespace. | ||
*/ | ||
constructor(appId: string, appName: string, namespace: string, openDbPromise?: Promise<IDBDatabase>); | ||
setCustomSignals(customSignals: CustomSignals): Promise<CustomSignals>; | ||
@@ -98,2 +104,9 @@ /** | ||
} | ||
export declare class InMemoryStorage extends Storage { | ||
private storage; | ||
get<T>(key: ProjectNamespaceKeyFieldValue): Promise<T>; | ||
set<T>(key: ProjectNamespaceKeyFieldValue, value: T): Promise<void>; | ||
delete(key: ProjectNamespaceKeyFieldValue): Promise<void>; | ||
setCustomSignals(customSignals: CustomSignals): Promise<CustomSignals>; | ||
} | ||
export {}; |
@@ -12,3 +12,3 @@ 'use strict'; | ||
const name = "@firebase/remote-config"; | ||
const version = "0.5.0-canary.b3e68ca41"; | ||
const version = "0.5.0-canary.b92592d98"; | ||
@@ -89,2 +89,3 @@ /** | ||
const ERROR_DESCRIPTION_MAP = { | ||
["already-initialized" /* ErrorCode.ALREADY_INITIALIZED */]: 'Remote Config already initialized', | ||
["registration-window" /* ErrorCode.REGISTRATION_WINDOW */]: 'Undefined window object. This SDK only supports usage in a browser environment.', | ||
@@ -185,2 +186,4 @@ ["registration-project-id" /* ErrorCode.REGISTRATION_PROJECT_ID */]: 'Undefined project identifier. Check Firebase app initialization.', | ||
* @param app - The {@link @firebase/app#FirebaseApp} instance. | ||
* @param options - Optional. The {@link RemoteConfigOptions} with which to instantiate the | ||
* Remote Config instance. | ||
* @returns A {@link RemoteConfig} instance. | ||
@@ -190,6 +193,30 @@ * | ||
*/ | ||
function getRemoteConfig(app$1 = app.getApp()) { | ||
function getRemoteConfig(app$1 = app.getApp(), options = {}) { | ||
var _a, _b; | ||
app$1 = util.getModularInstance(app$1); | ||
const rcProvider = app._getProvider(app$1, RC_COMPONENT_NAME); | ||
return rcProvider.getImmediate(); | ||
if (rcProvider.isInitialized()) { | ||
const initialOptions = rcProvider.getOptions(); | ||
if (util.deepEqual(initialOptions, options)) { | ||
return rcProvider.getImmediate(); | ||
} | ||
throw ERROR_FACTORY.create("already-initialized" /* ErrorCode.ALREADY_INITIALIZED */); | ||
} | ||
rcProvider.initialize({ options }); | ||
const rc = rcProvider.getImmediate(); | ||
if (options.initialFetchResponse) { | ||
// We use these initial writes as the initialization promise since they will hydrate the same | ||
// fields that `storageCache.loadFromStorage` would set. | ||
rc._initializePromise = Promise.all([ | ||
rc._storage.setLastSuccessfulFetchResponse(options.initialFetchResponse), | ||
rc._storage.setActiveConfigEtag(((_a = options.initialFetchResponse) === null || _a === void 0 ? void 0 : _a.eTag) || ''), | ||
rc._storageCache.setLastSuccessfulFetchTimestampMillis(Date.now()), | ||
rc._storageCache.setLastFetchStatus('success'), | ||
rc._storageCache.setActiveConfig(((_b = options.initialFetchResponse) === null || _b === void 0 ? void 0 : _b.config) || {}) | ||
]).then(); | ||
// The `storageCache` methods above set their in-memory fields synchronously, so it's | ||
// safe to declare our initialization complete at this point. | ||
rc._isInitializationComplete = true; | ||
} | ||
return rc; | ||
} | ||
@@ -940,13 +967,2 @@ /** | ||
class Storage { | ||
/** | ||
* @param appId enables storage segmentation by app (ID + name). | ||
* @param appName enables storage segmentation by app (ID + name). | ||
* @param namespace enables storage segmentation by namespace. | ||
*/ | ||
constructor(appId, appName, namespace, openDbPromise = openDatabase()) { | ||
this.appId = appId; | ||
this.appName = appName; | ||
this.namespace = namespace; | ||
this.openDbPromise = openDbPromise; | ||
} | ||
getLastFetchStatus() { | ||
@@ -996,2 +1012,16 @@ return this.get('last_fetch_status'); | ||
} | ||
} | ||
class IndexedDbStorage extends Storage { | ||
/** | ||
* @param appId enables storage segmentation by app (ID + name). | ||
* @param appName enables storage segmentation by app (ID + name). | ||
* @param namespace enables storage segmentation by namespace. | ||
*/ | ||
constructor(appId, appName, namespace, openDbPromise = openDatabase()) { | ||
super(); | ||
this.appId = appId; | ||
this.appName = appName; | ||
this.namespace = namespace; | ||
this.openDbPromise = openDbPromise; | ||
} | ||
async setCustomSignals(customSignals) { | ||
@@ -1001,20 +1031,3 @@ const db = await this.openDbPromise; | ||
const storedSignals = await this.getWithTransaction('custom_signals', transaction); | ||
const combinedSignals = Object.assign(Object.assign({}, storedSignals), customSignals); | ||
// Filter out key-value assignments with null values since they are signals being unset | ||
const updatedSignals = Object.fromEntries(Object.entries(combinedSignals) | ||
.filter(([_, v]) => v !== null) | ||
.map(([k, v]) => { | ||
// Stringify numbers to store a map of string keys and values which can be sent | ||
// as-is in a fetch call. | ||
if (typeof v === 'number') { | ||
return [k, v.toString()]; | ||
} | ||
return [k, v]; | ||
})); | ||
// Throw an error if the number of custom signals to be stored exceeds the limit | ||
if (Object.keys(updatedSignals).length > RC_CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS) { | ||
throw ERROR_FACTORY.create("custom-signal-max-allowed-signals" /* ErrorCode.CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS */, { | ||
maxSignals: RC_CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS | ||
}); | ||
} | ||
const updatedSignals = mergeCustomSignals(customSignals, storedSignals || {}); | ||
await this.setWithTransaction('custom_signals', updatedSignals, transaction); | ||
@@ -1124,2 +1137,46 @@ return updatedSignals; | ||
} | ||
class InMemoryStorage extends Storage { | ||
constructor() { | ||
super(...arguments); | ||
this.storage = {}; | ||
} | ||
async get(key) { | ||
return Promise.resolve(this.storage[key]); | ||
} | ||
async set(key, value) { | ||
this.storage[key] = value; | ||
return Promise.resolve(undefined); | ||
} | ||
async delete(key) { | ||
this.storage[key] = undefined; | ||
return Promise.resolve(); | ||
} | ||
async setCustomSignals(customSignals) { | ||
const storedSignals = (this.storage['custom_signals'] || | ||
{}); | ||
this.storage['custom_signals'] = mergeCustomSignals(customSignals, storedSignals); | ||
return Promise.resolve(this.storage['custom_signals']); | ||
} | ||
} | ||
function mergeCustomSignals(customSignals, storedSignals) { | ||
const combinedSignals = Object.assign(Object.assign({}, storedSignals), customSignals); | ||
// Filter out key-value assignments with null values since they are signals being unset | ||
const updatedSignals = Object.fromEntries(Object.entries(combinedSignals) | ||
.filter(([_, v]) => v !== null) | ||
.map(([k, v]) => { | ||
// Stringify numbers to store a map of string keys and values which can be sent | ||
// as-is in a fetch call. | ||
if (typeof v === 'number') { | ||
return [k, v.toString()]; | ||
} | ||
return [k, v]; | ||
})); | ||
// Throw an error if the number of custom signals to be stored exceeds the limit | ||
if (Object.keys(updatedSignals).length > RC_CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS) { | ||
throw ERROR_FACTORY.create("custom-signal-max-allowed-signals" /* ErrorCode.CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS */, { | ||
maxSignals: RC_CUSTOM_SIGNAL_MAX_ALLOWED_SIGNALS | ||
}); | ||
} | ||
return updatedSignals; | ||
} | ||
@@ -1236,3 +1293,3 @@ /** | ||
app.registerVersion(name, version, 'cjs2017'); | ||
function remoteConfigFactory(container, { instanceIdentifier: namespace }) { | ||
function remoteConfigFactory(container, { options }) { | ||
/* Dependencies */ | ||
@@ -1245,10 +1302,2 @@ // getImmediate for FirebaseApp will always succeed | ||
.getImmediate(); | ||
// Guards against the SDK being used in non-browser environments. | ||
if (typeof window === 'undefined') { | ||
throw ERROR_FACTORY.create("registration-window" /* ErrorCode.REGISTRATION_WINDOW */); | ||
} | ||
// Guards against the SDK being used when indexedDB is not available. | ||
if (!util.isIndexedDBAvailable()) { | ||
throw ERROR_FACTORY.create("indexed-db-unavailable" /* ErrorCode.INDEXED_DB_UNAVAILABLE */); | ||
} | ||
// Normalizes optional inputs. | ||
@@ -1265,4 +1314,6 @@ const { projectId, apiKey, appId } = app$1.options; | ||
} | ||
namespace = namespace || 'firebase'; | ||
const storage = new Storage(appId, app$1.name, namespace); | ||
const namespace = (options === null || options === void 0 ? void 0 : options.templateId) || 'firebase'; | ||
const storage = util.isIndexedDBAvailable() | ||
? new IndexedDbStorage(appId, app$1.name, namespace) | ||
: new InMemoryStorage(); | ||
const storageCache = new StorageCache(storage); | ||
@@ -1269,0 +1320,0 @@ const logger$1 = new logger.Logger(name); |
@@ -67,2 +67,34 @@ /** | ||
/** | ||
* Defines a successful response (200 or 304). | ||
* | ||
* <p>Modeled after the native `Response` interface, but simplified for Remote Config's | ||
* use case. | ||
*/ | ||
export declare interface FetchResponse { | ||
/** | ||
* 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 `Fetch` 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. | ||
*/ | ||
status: number; | ||
/** | ||
* Defines the ETag response header value. | ||
* | ||
* <p>Only defined for 200 and 304 responses. | ||
*/ | ||
eTag?: string; | ||
/** | ||
* Defines the map of parameters returned as "entries" in the fetch response body. | ||
* | ||
* <p>Only defined for 200 responses. | ||
*/ | ||
config?: FirebaseRemoteConfigObject; | ||
} | ||
/** | ||
* Summarizes the outcome of the last attempt to fetch config from the Firebase Remote Config server. | ||
@@ -83,2 +115,9 @@ * | ||
/** | ||
* Defines a self-descriptive reference for config key-value pairs. | ||
*/ | ||
export declare interface FirebaseRemoteConfigObject { | ||
[key: string]: string; | ||
} | ||
/** | ||
* Gets all config. | ||
@@ -123,2 +162,4 @@ * | ||
* @param app - The {@link @firebase/app#FirebaseApp} instance. | ||
* @param options - Optional. The {@link RemoteConfigOptions} with which to instantiate the | ||
* Remote Config instance. | ||
* @returns A {@link RemoteConfig} instance. | ||
@@ -128,3 +169,3 @@ * | ||
*/ | ||
export declare function getRemoteConfig(app?: FirebaseApp): RemoteConfig; | ||
export declare function getRemoteConfig(app?: FirebaseApp, options?: RemoteConfigOptions): RemoteConfig; | ||
@@ -208,2 +249,18 @@ /** | ||
/** | ||
* Options for Remote Config initialization. | ||
* | ||
* @public | ||
*/ | ||
export declare interface RemoteConfigOptions { | ||
/** | ||
* The ID of the template to use. If not provided, defaults to "firebase". | ||
*/ | ||
templateId?: string; | ||
/** | ||
* Hydrates the state with an initial fetch response. | ||
*/ | ||
initialFetchResponse?: FetchResponse; | ||
} | ||
/** | ||
* Defines configuration options for the Remote Config SDK. | ||
@@ -210,0 +267,0 @@ * |
@@ -67,2 +67,34 @@ /** | ||
/** | ||
* Defines a successful response (200 or 304). | ||
* | ||
* <p>Modeled after the native `Response` interface, but simplified for Remote Config's | ||
* use case. | ||
*/ | ||
export declare interface FetchResponse { | ||
/** | ||
* 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 `Fetch` 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. | ||
*/ | ||
status: number; | ||
/** | ||
* Defines the ETag response header value. | ||
* | ||
* <p>Only defined for 200 and 304 responses. | ||
*/ | ||
eTag?: string; | ||
/** | ||
* Defines the map of parameters returned as "entries" in the fetch response body. | ||
* | ||
* <p>Only defined for 200 responses. | ||
*/ | ||
config?: FirebaseRemoteConfigObject; | ||
} | ||
/** | ||
* Summarizes the outcome of the last attempt to fetch config from the Firebase Remote Config server. | ||
@@ -83,2 +115,9 @@ * | ||
/** | ||
* Defines a self-descriptive reference for config key-value pairs. | ||
*/ | ||
export declare interface FirebaseRemoteConfigObject { | ||
[key: string]: string; | ||
} | ||
/** | ||
* Gets all config. | ||
@@ -123,2 +162,4 @@ * | ||
* @param app - The {@link @firebase/app#FirebaseApp} instance. | ||
* @param options - Optional. The {@link RemoteConfigOptions} with which to instantiate the | ||
* Remote Config instance. | ||
* @returns A {@link RemoteConfig} instance. | ||
@@ -128,3 +169,3 @@ * | ||
*/ | ||
export declare function getRemoteConfig(app?: FirebaseApp): RemoteConfig; | ||
export declare function getRemoteConfig(app?: FirebaseApp, options?: RemoteConfigOptions): RemoteConfig; | ||
@@ -208,2 +249,18 @@ /** | ||
/** | ||
* Options for Remote Config initialization. | ||
* | ||
* @public | ||
*/ | ||
export declare interface RemoteConfigOptions { | ||
/** | ||
* The ID of the template to use. If not provided, defaults to "firebase". | ||
*/ | ||
templateId?: string; | ||
/** | ||
* Hydrates the state with an initial fetch response. | ||
*/ | ||
initialFetchResponse?: FetchResponse; | ||
} | ||
/** | ||
* Defines configuration options for the Remote Config SDK. | ||
@@ -210,0 +267,0 @@ * |
@@ -18,6 +18,8 @@ /** | ||
import { FirebaseApp } from '@firebase/app'; | ||
import { CustomSignals, LogLevel as RemoteConfigLogLevel, RemoteConfig, Value } from './public_types'; | ||
import { CustomSignals, LogLevel as RemoteConfigLogLevel, RemoteConfig, Value, RemoteConfigOptions } from './public_types'; | ||
/** | ||
* | ||
* @param app - The {@link @firebase/app#FirebaseApp} instance. | ||
* @param options - Optional. The {@link RemoteConfigOptions} with which to instantiate the | ||
* Remote Config instance. | ||
* @returns A {@link RemoteConfig} instance. | ||
@@ -27,3 +29,3 @@ * | ||
*/ | ||
export declare function getRemoteConfig(app?: FirebaseApp): RemoteConfig; | ||
export declare function getRemoteConfig(app?: FirebaseApp, options?: RemoteConfigOptions): RemoteConfig; | ||
/** | ||
@@ -30,0 +32,0 @@ * Makes the last fetched config available to the getters. |
@@ -18,3 +18,4 @@ /** | ||
import { StorageCache } from '../storage/storage_cache'; | ||
import { FetchResponse, RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { FetchResponse } from '../public_types'; | ||
import { RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { Storage } from '../storage/storage'; | ||
@@ -21,0 +22,0 @@ import { Logger } from '@firebase/logger'; |
@@ -17,3 +17,3 @@ /** | ||
*/ | ||
import { CustomSignals } from '../public_types'; | ||
import { CustomSignals, FetchResponse } from '../public_types'; | ||
/** | ||
@@ -38,8 +38,2 @@ * Defines a client, as in https://en.wikipedia.org/wiki/Client%E2%80%93server_model, for the | ||
/** | ||
* Defines a self-descriptive reference for config key-value pairs. | ||
*/ | ||
export interface FirebaseRemoteConfigObject { | ||
[key: string]: string; | ||
} | ||
/** | ||
* Shims a minimal AbortSignal. | ||
@@ -101,32 +95,1 @@ * | ||
} | ||
/** | ||
* Defines a successful response (200 or 304). | ||
* | ||
* <p>Modeled after the native {@link Response} interface, but simplified for Remote Config's | ||
* use case. | ||
*/ | ||
export interface FetchResponse { | ||
/** | ||
* The HTTP status, which is useful for differentiating success responses with data from | ||
* those without. | ||
* | ||
* <p>{@link RemoteConfigClient} is modeled after the native {@link GlobalFetch} 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. | ||
*/ | ||
status: number; | ||
/** | ||
* Defines the ETag response header value. | ||
* | ||
* <p>Only defined for 200 and 304 responses. | ||
*/ | ||
eTag?: string; | ||
/** | ||
* Defines the map of parameters returned as "entries" in the fetch response body. | ||
* | ||
* <p>Only defined for 200 responses. | ||
*/ | ||
config?: FirebaseRemoteConfigObject; | ||
} |
@@ -17,3 +17,4 @@ /** | ||
*/ | ||
import { FetchResponse, RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { FetchResponse } from '../public_types'; | ||
import { RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { _FirebaseInstallationsInternal } from '@firebase/installations'; | ||
@@ -20,0 +21,0 @@ /** |
@@ -17,3 +17,4 @@ /** | ||
*/ | ||
import { RemoteConfigAbortSignal, RemoteConfigFetchClient, FetchResponse, FetchRequest } from './remote_config_fetch_client'; | ||
import { FetchResponse } from '../public_types'; | ||
import { RemoteConfigAbortSignal, RemoteConfigFetchClient, FetchRequest } from './remote_config_fetch_client'; | ||
import { ThrottleMetadata, Storage } from '../storage/storage'; | ||
@@ -20,0 +21,0 @@ /** |
@@ -19,2 +19,3 @@ /** | ||
export declare const enum ErrorCode { | ||
ALREADY_INITIALIZED = "already-initialized", | ||
REGISTRATION_WINDOW = "registration-window", | ||
@@ -21,0 +22,0 @@ REGISTRATION_PROJECT_ID = "registration-project-id", |
@@ -50,2 +50,54 @@ /** | ||
/** | ||
* Defines a self-descriptive reference for config key-value pairs. | ||
*/ | ||
export interface FirebaseRemoteConfigObject { | ||
[key: string]: string; | ||
} | ||
/** | ||
* Defines a successful response (200 or 304). | ||
* | ||
* <p>Modeled after the native `Response` interface, but simplified for Remote Config's | ||
* use case. | ||
*/ | ||
export interface FetchResponse { | ||
/** | ||
* 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 `Fetch` 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. | ||
*/ | ||
status: number; | ||
/** | ||
* Defines the ETag response header value. | ||
* | ||
* <p>Only defined for 200 and 304 responses. | ||
*/ | ||
eTag?: string; | ||
/** | ||
* Defines the map of parameters returned as "entries" in the fetch response body. | ||
* | ||
* <p>Only defined for 200 responses. | ||
*/ | ||
config?: FirebaseRemoteConfigObject; | ||
} | ||
/** | ||
* Options for Remote Config initialization. | ||
* | ||
* @public | ||
*/ | ||
export interface RemoteConfigOptions { | ||
/** | ||
* The ID of the template to use. If not provided, defaults to "firebase". | ||
*/ | ||
templateId?: string; | ||
/** | ||
* Hydrates the state with an initial fetch response. | ||
*/ | ||
initialFetchResponse?: FetchResponse; | ||
} | ||
/** | ||
* Indicates the source of a value. | ||
@@ -52,0 +104,0 @@ * |
@@ -18,3 +18,3 @@ /** | ||
import { FetchStatus, CustomSignals } from '@firebase/remote-config-types'; | ||
import { FirebaseRemoteConfigObject } from '../client/remote_config_fetch_client'; | ||
import { FirebaseRemoteConfigObject } from '../public_types'; | ||
import { Storage } from './storage'; | ||
@@ -21,0 +21,0 @@ /** |
@@ -18,3 +18,3 @@ /** | ||
import { FetchStatus, CustomSignals } from '@firebase/remote-config-types'; | ||
import { FetchResponse, FirebaseRemoteConfigObject } from '../client/remote_config_fetch_client'; | ||
import { FetchResponse, FirebaseRemoteConfigObject } from '../public_types'; | ||
/** | ||
@@ -48,13 +48,3 @@ * A general-purpose store keyed by app + namespace + {@link | ||
*/ | ||
export declare class Storage { | ||
private readonly appId; | ||
private readonly appName; | ||
private readonly namespace; | ||
private readonly openDbPromise; | ||
/** | ||
* @param appId enables storage segmentation by app (ID + name). | ||
* @param appName enables storage segmentation by app (ID + name). | ||
* @param namespace enables storage segmentation by namespace. | ||
*/ | ||
constructor(appId: string, appName: string, namespace: string, openDbPromise?: Promise<IDBDatabase>); | ||
export declare abstract class Storage { | ||
getLastFetchStatus(): Promise<FetchStatus | undefined>; | ||
@@ -74,2 +64,18 @@ setLastFetchStatus(status: FetchStatus): Promise<void>; | ||
getCustomSignals(): Promise<CustomSignals | undefined>; | ||
abstract setCustomSignals(customSignals: CustomSignals): Promise<CustomSignals>; | ||
abstract get<T>(key: ProjectNamespaceKeyFieldValue): Promise<T | undefined>; | ||
abstract set<T>(key: ProjectNamespaceKeyFieldValue, value: T): Promise<void>; | ||
abstract delete(key: ProjectNamespaceKeyFieldValue): Promise<void>; | ||
} | ||
export declare class IndexedDbStorage extends Storage { | ||
private readonly appId; | ||
private readonly appName; | ||
private readonly namespace; | ||
private readonly openDbPromise; | ||
/** | ||
* @param appId enables storage segmentation by app (ID + name). | ||
* @param appName enables storage segmentation by app (ID + name). | ||
* @param namespace enables storage segmentation by namespace. | ||
*/ | ||
constructor(appId: string, appName: string, namespace: string, openDbPromise?: Promise<IDBDatabase>); | ||
setCustomSignals(customSignals: CustomSignals): Promise<CustomSignals>; | ||
@@ -98,2 +104,9 @@ /** | ||
} | ||
export declare class InMemoryStorage extends Storage { | ||
private storage; | ||
get<T>(key: ProjectNamespaceKeyFieldValue): Promise<T>; | ||
set<T>(key: ProjectNamespaceKeyFieldValue, value: T): Promise<void>; | ||
delete(key: ProjectNamespaceKeyFieldValue): Promise<void>; | ||
setCustomSignals(customSignals: CustomSignals): Promise<CustomSignals>; | ||
} | ||
export {}; |
{ | ||
"name": "@firebase/remote-config", | ||
"version": "0.5.0-canary.b3e68ca41", | ||
"version": "0.5.0-canary.b92592d98", | ||
"description": "The Remote Config package of the Firebase JS SDK", | ||
@@ -40,9 +40,9 @@ "author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)", | ||
"peerDependencies": { | ||
"@firebase/app": "0.11.0-canary.b3e68ca41" | ||
"@firebase/app": "0.11.0-canary.b92592d98" | ||
}, | ||
"dependencies": { | ||
"@firebase/installations": "0.6.12-canary.b3e68ca41", | ||
"@firebase/logger": "0.4.4-canary.b3e68ca41", | ||
"@firebase/util": "1.10.3-canary.b3e68ca41", | ||
"@firebase/component": "0.6.12-canary.b3e68ca41", | ||
"@firebase/installations": "0.6.12-canary.b92592d98", | ||
"@firebase/logger": "0.4.4-canary.b92592d98", | ||
"@firebase/util": "1.10.3-canary.b92592d98", | ||
"@firebase/component": "0.6.12-canary.b92592d98", | ||
"tslib": "^2.1.0" | ||
@@ -52,3 +52,3 @@ }, | ||
"devDependencies": { | ||
"@firebase/app": "0.11.0-canary.b3e68ca41", | ||
"@firebase/app": "0.11.0-canary.b92592d98", | ||
"rollup": "2.79.2", | ||
@@ -55,0 +55,0 @@ "rollup-plugin-typescript2": "0.36.0", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
401997
5405
+ Added@firebase/app@0.11.0-canary.b92592d98(transitive)
+ Added@firebase/component@0.6.12-canary.b92592d98(transitive)
+ Added@firebase/installations@0.6.12-canary.b92592d98(transitive)
+ Added@firebase/logger@0.4.4-canary.b92592d98(transitive)
+ Added@firebase/util@1.10.3-canary.b92592d98(transitive)
- Removed@firebase/app@0.11.0-canary.b3e68ca41(transitive)
- Removed@firebase/component@0.6.12-canary.b3e68ca41(transitive)
- Removed@firebase/installations@0.6.12-canary.b3e68ca41(transitive)
- Removed@firebase/logger@0.4.4-canary.b3e68ca41(transitive)
- Removed@firebase/util@1.10.3-canary.b3e68ca41(transitive)