diff --git a/packages/sdk/browser/src/BrowserClient.ts b/packages/sdk/browser/src/BrowserClient.ts index abb9ceb4c2..3c8e0ea911 100644 --- a/packages/sdk/browser/src/BrowserClient.ts +++ b/packages/sdk/browser/src/BrowserClient.ts @@ -18,6 +18,7 @@ import { Platform, } from '@launchdarkly/js-client-sdk-common'; +import { readFlagsFromBootstrap } from './bootstrap'; import { getHref } from './BrowserApi'; import BrowserDataManager from './BrowserDataManager'; import { BrowserIdentifyOptions as LDIdentifyOptions } from './BrowserIdentifyOptions'; @@ -32,6 +33,7 @@ import BrowserPlatform from './platform/BrowserPlatform'; class BrowserClientImpl extends LDClientImpl { private readonly _goalManager?: GoalManager; private readonly _plugins?: LDPlugin[]; + private _bootstrapAttempted = false; constructor( clientSideId: string, @@ -197,6 +199,12 @@ class BrowserClientImpl extends LDClientImpl { ); } + /** + * @ignore + * NOTE: this identify is not doing anything as the `makeClient` function maps the + * identify function to identifyResults. We will need to consolidate this function + * in the js-client-sdk-common package. + */ override async identify(context: LDContext, identifyOptions?: LDIdentifyOptions): Promise { return super.identify(context, identifyOptions); } @@ -211,6 +219,21 @@ class BrowserClientImpl extends LDClientImpl { if (identifyOptions?.sheddable === undefined) { identifyOptionsWithUpdatedDefaults.sheddable = true; } + + if (!this._bootstrapAttempted && identifyOptionsWithUpdatedDefaults.bootstrap) { + try { + const bootstrapData = readFlagsFromBootstrap( + this.logger, + identifyOptionsWithUpdatedDefaults.bootstrap, + ); + this.setBootstrap(context, bootstrapData); + } catch (e) { + this.logger.error('failed to bootstrap data'); + } finally { + this._bootstrapAttempted = true; + } + } + const res = await super.identifyResult(context, identifyOptionsWithUpdatedDefaults); this._goalManager?.startTracking(); return res; diff --git a/packages/shared/sdk-client/src/LDClientImpl.ts b/packages/shared/sdk-client/src/LDClientImpl.ts index 5253275b2e..ad43f86d67 100644 --- a/packages/shared/sdk-client/src/LDClientImpl.ts +++ b/packages/shared/sdk-client/src/LDClientImpl.ts @@ -43,6 +43,7 @@ import createEventProcessor from './events/createEventProcessor'; import EventFactory from './events/EventFactory'; import DefaultFlagManager, { FlagManager } from './flag-manager/FlagManager'; import { FlagChangeType } from './flag-manager/FlagUpdater'; +import { ItemDescriptor } from './flag-manager/ItemDescriptor'; import HookRunner from './HookRunner'; import { getInspectorHook } from './inspection/getInspectorHook'; import InspectorManager from './inspection/InspectorManager'; @@ -360,6 +361,19 @@ export default class LDClientImpl implements LDClient, LDClientIdentifyResult { return Promise.race([callSitePromise, timeoutPromise]); } + /** + * Exposes the bootstrap functionality to the derived classes. This function is mainly used to help set + * flag values for bootstrapped clients before the initialization is complete. + * + * @param pristineContext The LDContext object to be identified. + * @param newFlags The new flags to set. + */ + protected setBootstrap(pristineContext: LDContext, newFlags: { [key: string]: ItemDescriptor }) { + this._uncheckedContext = pristineContext; + this._checkedContext = Context.fromLDContext(this._uncheckedContext); + this._flagManager.setBootstrap(this._checkedContext, newFlags); + } + on(eventName: EventName, listener: Function): void { this.emitter.on(eventName, listener); }