Skip to content

Commit 5c9b649

Browse files
erikeldridgetrekforeverjenh
authored
Add public SSRC methods (#2458)
Add public SSRC methods --------- Co-authored-by: Xin Wei <[email protected]> Co-authored-by: jen_h <[email protected]>
1 parent aed5646 commit 5c9b649

File tree

5 files changed

+688
-0
lines changed

5 files changed

+688
-0
lines changed

etc/firebase-admin.remote-config.api.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ export class RemoteConfig {
4646
// (undocumented)
4747
readonly app: App;
4848
createTemplateFromJSON(json: string): RemoteConfigTemplate;
49+
getServerTemplate(options?: RemoteConfigServerTemplateOptions): Promise<RemoteConfigServerTemplate>;
4950
getTemplate(): Promise<RemoteConfigTemplate>;
5051
getTemplateAtVersion(versionNumber: number | string): Promise<RemoteConfigTemplate>;
52+
initServerTemplate(options?: RemoteConfigServerTemplateOptions): RemoteConfigServerTemplate;
5153
listVersions(options?: ListVersionsOptions): Promise<ListVersionsResult>;
5254
publishTemplate(template: RemoteConfigTemplate, options?: {
5355
force: boolean;
@@ -84,6 +86,41 @@ export interface RemoteConfigParameterGroup {
8486
// @public
8587
export type RemoteConfigParameterValue = ExplicitParameterValue | InAppDefaultValue;
8688

89+
// @public
90+
export interface RemoteConfigServerCondition {
91+
expression: string;
92+
name: string;
93+
}
94+
95+
// @public
96+
export type RemoteConfigServerConfig = {
97+
[key: string]: string | boolean | number;
98+
};
99+
100+
// @public
101+
export interface RemoteConfigServerTemplate {
102+
cache: RemoteConfigServerTemplateData;
103+
defaultConfig: RemoteConfigServerConfig;
104+
evaluate(): RemoteConfigServerConfig;
105+
load(): Promise<void>;
106+
}
107+
108+
// @public
109+
export interface RemoteConfigServerTemplateData {
110+
conditions: RemoteConfigServerCondition[];
111+
readonly etag: string;
112+
parameters: {
113+
[key: string]: RemoteConfigParameter;
114+
};
115+
version?: Version;
116+
}
117+
118+
// @public
119+
export interface RemoteConfigServerTemplateOptions {
120+
defaultConfig?: RemoteConfigServerConfig;
121+
template?: RemoteConfigServerTemplateData;
122+
}
123+
87124
// @public
88125
export interface RemoteConfigTemplate {
89126
conditions: RemoteConfigCondition[];

src/remote-config/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ export {
3535
RemoteConfigParameterGroup,
3636
RemoteConfigParameterValue,
3737
RemoteConfigTemplate,
38+
RemoteConfigServerCondition,
39+
RemoteConfigServerConfig,
40+
RemoteConfigServerTemplate,
41+
RemoteConfigServerTemplateData,
42+
RemoteConfigServerTemplateOptions,
3843
RemoteConfigUser,
3944
TagColor,
4045
Version,

src/remote-config/remote-config-api.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,27 @@ export interface RemoteConfigServerTemplateData {
213213
version?: Version;
214214
}
215215

216+
/**
217+
* Represents optional arguments that can be used when instantiating {@link RemoteConfigServerTemplate}.
218+
*/
219+
export interface RemoteConfigServerTemplateOptions {
220+
221+
/**
222+
* Defines in-app default parameter values, so that your app behaves as
223+
* intended before it connects to the Remote Config backend, and so that
224+
* default values are available if none are set on the backend.
225+
*/
226+
defaultConfig?: RemoteConfigServerConfig,
227+
228+
/**
229+
* Enables integrations to use template data loaded independently. For
230+
* example, customers can reduce initialization latency by pre-fetching and
231+
* caching template data and then using this option to initialize the SDK with
232+
* that data.
233+
*/
234+
template?: RemoteConfigServerTemplateData,
235+
}
236+
216237
/**
217238
* Represents a stateful abstraction for a Remote Config server template.
218239
*/

src/remote-config/remote-config.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,16 @@ import {
2323
RemoteConfigCondition,
2424
RemoteConfigParameter,
2525
RemoteConfigParameterGroup,
26+
RemoteConfigServerTemplate,
2627
RemoteConfigTemplate,
2728
RemoteConfigUser,
2829
Version,
30+
ExplicitParameterValue,
31+
InAppDefaultValue,
32+
ParameterValueType,
33+
RemoteConfigServerConfig,
34+
RemoteConfigServerTemplateData,
35+
RemoteConfigServerTemplateOptions,
2936
} from './remote-config-api';
3037

3138
/**
@@ -168,6 +175,27 @@ export class RemoteConfig {
168175

169176
return new RemoteConfigTemplateImpl(template);
170177
}
178+
179+
/**
180+
* Instantiates {@link RemoteConfigServerTemplate} and then fetches and caches the latest
181+
* template version of the project.
182+
*/
183+
public async getServerTemplate(options?: RemoteConfigServerTemplateOptions): Promise<RemoteConfigServerTemplate> {
184+
const template = this.initServerTemplate(options);
185+
await template.load();
186+
return template;
187+
}
188+
189+
/**
190+
* Synchronously instantiates {@link RemoteConfigServerTemplate}.
191+
*/
192+
public initServerTemplate(options?: RemoteConfigServerTemplateOptions): RemoteConfigServerTemplate {
193+
const template = new RemoteConfigServerTemplateImpl(this.client, options?.defaultConfig);
194+
if (options?.template) {
195+
template.cache = options?.template;
196+
}
197+
return template;
198+
}
171199
}
172200

173201
/**
@@ -254,6 +282,143 @@ class RemoteConfigTemplateImpl implements RemoteConfigTemplate {
254282
}
255283
}
256284

285+
/**
286+
* Remote Config dataplane template data implementation.
287+
*/
288+
class RemoteConfigServerTemplateImpl implements RemoteConfigServerTemplate {
289+
public cache: RemoteConfigServerTemplateData;
290+
291+
constructor(
292+
private readonly apiClient: RemoteConfigApiClient,
293+
public readonly defaultConfig: RemoteConfigServerConfig = {}
294+
) { }
295+
296+
/**
297+
* Fetches and caches the current active version of the project's {@link RemoteConfigServerTemplate}.
298+
*/
299+
public load(): Promise<void> {
300+
return this.apiClient.getServerTemplate()
301+
.then((template) => {
302+
this.cache = new RemoteConfigServerTemplateDataImpl(template);
303+
});
304+
}
305+
306+
/**
307+
* Evaluates the current template in cache to produce a {@link RemoteConfigServerConfig}.
308+
*/
309+
public evaluate(): RemoteConfigServerConfig {
310+
if (!this.cache) {
311+
throw new FirebaseRemoteConfigError(
312+
'failed-precondition',
313+
'No Remote Config Server template in cache. Call load() before calling evaluate().');
314+
}
315+
316+
const evaluatedConfig: RemoteConfigServerConfig = {};
317+
318+
for (const [key, parameter] of Object.entries(this.cache.parameters)) {
319+
const { defaultValue, valueType } = parameter;
320+
321+
if (!defaultValue) {
322+
// TODO: add logging once we have a wrapped logger.
323+
continue;
324+
}
325+
326+
if ((defaultValue as InAppDefaultValue).useInAppDefault) {
327+
// TODO: add logging once we have a wrapped logger.
328+
continue;
329+
}
330+
331+
const parameterDefaultValue = (defaultValue as ExplicitParameterValue).value;
332+
333+
evaluatedConfig[key] = this.parseRemoteConfigParameterValue(valueType, parameterDefaultValue);
334+
}
335+
336+
// Merges rendered config over default config.
337+
const mergedConfig = Object.assign(this.defaultConfig, evaluatedConfig);
338+
339+
// Enables config to be a convenient object, but with the ability to perform additional
340+
// functionality when a value is retrieved.
341+
const proxyHandler = {
342+
get(target: RemoteConfigServerConfig, prop: string) {
343+
return target[prop];
344+
}
345+
};
346+
347+
return new Proxy(mergedConfig, proxyHandler);
348+
}
349+
350+
/**
351+
* Private helper method that processes and parses a parameter value based on {@link ParameterValueType}.
352+
*/
353+
private parseRemoteConfigParameterValue(parameterType: ParameterValueType | undefined,
354+
parameterDefaultValue: string): string | number | boolean {
355+
const BOOLEAN_TRUTHY_VALUES = ['1', 'true', 't', 'yes', 'y', 'on'];
356+
const DEFAULT_VALUE_FOR_NUMBER = 0;
357+
const DEFAULT_VALUE_FOR_STRING = '';
358+
359+
if (parameterType === 'BOOLEAN') {
360+
return BOOLEAN_TRUTHY_VALUES.indexOf(parameterDefaultValue) >= 0;
361+
} else if (parameterType === 'NUMBER') {
362+
const num = Number(parameterDefaultValue);
363+
if (isNaN(num)) {
364+
return DEFAULT_VALUE_FOR_NUMBER;
365+
}
366+
return num;
367+
} else {
368+
// Treat everything else as string
369+
return parameterDefaultValue || DEFAULT_VALUE_FOR_STRING;
370+
}
371+
}
372+
}
373+
374+
/**
375+
* Remote Config dataplane template data implementation.
376+
*/
377+
class RemoteConfigServerTemplateDataImpl implements RemoteConfigServerTemplateData {
378+
public parameters: { [key: string]: RemoteConfigParameter };
379+
public parameterGroups: { [key: string]: RemoteConfigParameterGroup };
380+
public conditions: RemoteConfigCondition[];
381+
public readonly etag: string;
382+
public version?: Version;
383+
384+
constructor(template: RemoteConfigServerTemplateData) {
385+
if (!validator.isNonNullObject(template) ||
386+
!validator.isNonEmptyString(template.etag)) {
387+
throw new FirebaseRemoteConfigError(
388+
'invalid-argument',
389+
`Invalid Remote Config template: ${JSON.stringify(template)}`);
390+
}
391+
392+
this.etag = template.etag;
393+
394+
if (typeof template.parameters !== 'undefined') {
395+
if (!validator.isNonNullObject(template.parameters)) {
396+
throw new FirebaseRemoteConfigError(
397+
'invalid-argument',
398+
'Remote Config parameters must be a non-null object');
399+
}
400+
this.parameters = template.parameters;
401+
} else {
402+
this.parameters = {};
403+
}
404+
405+
if (typeof template.conditions !== 'undefined') {
406+
if (!validator.isArray(template.conditions)) {
407+
throw new FirebaseRemoteConfigError(
408+
'invalid-argument',
409+
'Remote Config conditions must be an array');
410+
}
411+
this.conditions = template.conditions;
412+
} else {
413+
this.conditions = [];
414+
}
415+
416+
if (typeof template.version !== 'undefined') {
417+
this.version = new VersionImpl(template.version);
418+
}
419+
}
420+
}
421+
257422
/**
258423
* Remote Config Version internal implementation.
259424
*/

0 commit comments

Comments
 (0)