Skip to content

Commit

Permalink
Merge pull request #3 from nosnibor89/feat/svelte-sdk-refactor-is-on
Browse files Browse the repository at this point in the history
[refactor] Update SvelteLDClient to use proxy for flag variations. Allows to track flag evaluations
  • Loading branch information
nosnibor89 authored Nov 29, 2024
2 parents 3bf80cb + 3690339 commit 00380bb
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const mockLDClient = {
on: (e: string, cb: () => void) => mockLDEventEmitter.on(e, cb),
off: vi.fn(),
allFlags: vi.fn().mockReturnValue(rawFlags),
variation: vi.fn(),
variation: vi.fn((_, defaultValue) => defaultValue),
identify: vi.fn(),
};

Expand Down Expand Up @@ -130,6 +130,9 @@ describe('launchDarkly', () => {
const flagStore = ld.watch(booleanFlagKey);
const flagStore2 = ld.watch(stringFlagKey);

// emit ready event to set initial flag values
mockLDEventEmitter.emit('ready');

// 'test-flag' initial value is true according to `rawFlags`
expect(get(flagStore)).toBe(true);
// 'another-test-flag' intial value is 'flag-value' according to `rawFlags`
Expand Down
2 changes: 0 additions & 2 deletions packages/sdk/svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,11 @@
},
"peerDependencies": {
"@launchdarkly/js-client-sdk": "workspace:^",
"@launchdarkly/js-client-sdk-common": "^1.10.0",
"@launchdarkly/node-server-sdk": "^9.4.6",
"svelte": "^4.0.0"
},
"dependencies": {
"@launchdarkly/js-client-sdk": "workspace:^",
"@launchdarkly/js-client-sdk-common": "1.10.0",
"esm-env": "^1.0.0"
},
"devDependencies": {
Expand Down
51 changes: 42 additions & 9 deletions packages/sdk/svelte/src/lib/client/SvelteLDClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,43 @@ function isClientInitialized(client: LDClient | undefined): asserts client is LD
}
}

/**
* Creates a proxy for the given flags object that intercepts access to flag values.
* When a flag value is accessed, it checks if the flag key exists in the target object.
* If the flag key exists, it returns the variation of the flag from the client.
* Otherwise, it returns the current value of the flag.
*
* @param client - The LaunchDarkly client instance used to get flag variations.
* @param flags - The initial flags object to be proxied.
* @returns A proxy object that intercepts access to flag values and returns the appropriate variation.
*/
function toFlagsProxy(client: LDClient, flags: LDFlags): LDFlags {
return new Proxy(flags, {
get(target, prop, receiver) {
const currentValue = Reflect.get(target, prop, receiver);
// only process flag keys and ignore symbols and native Object functions
if (typeof prop === 'symbol') {
return currentValue;
}

// check if flag key exists
const validFlagKey = Object.hasOwn(target, prop);

if (!validFlagKey) {
return currentValue;
}

return client.variation(prop, currentValue);
},
});
}

/**
* Creates a LaunchDarkly instance.
* @returns {Object} The LaunchDarkly instance object.
*/
function createLD() {
let jsSdk: LDClient | undefined;
let coreLdClient: LDClient | undefined;
const loading = writable(true);
const flagsWritable = writable<LDFlags>({});

Expand All @@ -43,15 +74,17 @@ function createLD() {
*/

function LDInitialize(clientId: LDClientID) {
jsSdk = initialize(clientId);
jsSdk!.on('ready', () => {
coreLdClient = initialize(clientId);
coreLdClient!.on('ready', () => {
loading.set(false);
const allFlags = jsSdk!.allFlags();
const rawFlags = coreLdClient!.allFlags();
const allFlags = toFlagsProxy(coreLdClient, rawFlags);
flagsWritable.set(allFlags);
});

jsSdk!.on('change', () => {
const allFlags = jsSdk!.allFlags();
coreLdClient!.on('change', () => {
const rawFlags = coreLdClient!.allFlags();
const allFlags = toFlagsProxy(coreLdClient, rawFlags);
flagsWritable.set(allFlags);
});

Expand All @@ -66,8 +99,8 @@ function createLD() {
* @returns {Promise} A promise that resolves when the user is identified.
*/
async function identify(context: LDContext) {
isClientInitialized(jsSdk);
return jsSdk.identify(context);
isClientInitialized(coreLdClient);
return coreLdClient.identify(context);
}

/**
Expand All @@ -84,7 +117,7 @@ function createLD() {
* @returns {boolean} True if the flag is on, false otherwise.
*/
const isOn = (flagKey: string): boolean => {
isClientInitialized(jsSdk);
isClientInitialized(coreLdClient);
const currentFlags = get(flagsWritable);
return !!currentFlags[flagKey];
};
Expand Down

0 comments on commit 00380bb

Please sign in to comment.