Skip to content

Commit 246c2ae

Browse files
authored
fix: Update configuration stores in ConfigurationRequestor when they are changed on the client (#257)
* reset config stores in the config requestor when set on the client * tests * v4.14.4
1 parent f5080f6 commit 246c2ae

File tree

4 files changed

+110
-8
lines changed

4 files changed

+110
-8
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eppo/js-client-sdk-common",
3-
"version": "4.14.3",
3+
"version": "4.14.4",
44
"description": "Common library for Eppo JavaScript SDKs (web, react native, and node)",
55
"main": "dist/index.js",
66
"files": [

src/client/eppo-client.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,17 @@ export default class EppoClient {
209209
// noinspection JSUnusedGlobalSymbols
210210
setFlagConfigurationStore(flagConfigurationStore: IConfigurationStore<Flag | ObfuscatedFlag>) {
211211
this.flagConfigurationStore = flagConfigurationStore;
212+
213+
this.updateConfigRequestorIfExists();
212214
}
213215

214216
// noinspection JSUnusedGlobalSymbols
215217
setBanditVariationConfigurationStore(
216218
banditVariationConfigurationStore: IConfigurationStore<BanditVariation[]>,
217219
) {
218220
this.banditVariationConfigurationStore = banditVariationConfigurationStore;
221+
222+
this.updateConfigRequestorIfExists();
219223
}
220224

221225
/** Sets the EventDispatcher instance to use when tracking events with {@link track}. */
@@ -244,6 +248,19 @@ export default class EppoClient {
244248
banditModelConfigurationStore: IConfigurationStore<BanditParameters>,
245249
) {
246250
this.banditModelConfigurationStore = banditModelConfigurationStore;
251+
252+
this.updateConfigRequestorIfExists();
253+
}
254+
255+
private updateConfigRequestorIfExists() {
256+
// Update the ConfigurationRequestor if it exists
257+
if (this.configurationRequestor) {
258+
this.configurationRequestor.setConfigurationStores(
259+
this.flagConfigurationStore,
260+
this.banditVariationConfigurationStore || null,
261+
this.banditModelConfigurationStore || null,
262+
);
263+
}
247264
}
248265

249266
// noinspection JSUnusedGlobalSymbols

src/configuration-requestor.spec.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import FetchHttpClient, {
1515
IUniversalFlagConfigResponse,
1616
} from './http-client';
1717
import { StoreBackedConfiguration } from './i-configuration';
18-
import { BanditParameters, BanditVariation, Flag } from './interfaces';
18+
import { BanditParameters, BanditVariation, Flag, VariationType } from './interfaces';
1919

2020
describe('ConfigurationRequestor', () => {
2121
let flagStore: IConfigurationStore<Flag>;
@@ -641,5 +641,72 @@ describe('ConfigurationRequestor', () => {
641641
// expect(fetchSpy.mock.calls.length).toBe(initialFetchCount + 1);
642642
});
643643
});
644+
645+
describe('IConfigurationStore updates', () => {
646+
it('should update configuration when stores are changed', async () => {
647+
// Create new stores
648+
const newFlagStore = new MemoryOnlyConfigurationStore<Flag>();
649+
const newBanditVariationStore = new MemoryOnlyConfigurationStore<BanditVariation[]>();
650+
const newBanditModelStore = new MemoryOnlyConfigurationStore<BanditParameters>();
651+
652+
// Add a test flag to the new flag store
653+
await newFlagStore.setEntries({
654+
'test-flag': {
655+
key: 'test-flag',
656+
enabled: true,
657+
variationType: VariationType.STRING,
658+
variations: {
659+
control: { key: 'control', value: 'control-value' },
660+
treatment: { key: 'treatment', value: 'treatment-value' },
661+
},
662+
allocations: [
663+
{
664+
key: 'allocation-1',
665+
rules: [],
666+
splits: [
667+
{
668+
shards: [{ salt: '', ranges: [{ start: 0, end: 10000 }] }],
669+
variationKey: 'treatment',
670+
},
671+
],
672+
doLog: true,
673+
},
674+
],
675+
totalShards: 10000,
676+
},
677+
});
678+
679+
await newBanditModelStore.setEntries({
680+
'test-bandit': {
681+
banditKey: 'test-bandt',
682+
modelVersion: 'v123',
683+
modelName: 'falcon',
684+
modelData: {
685+
coefficients: {},
686+
gamma: 0,
687+
defaultActionScore: 0,
688+
actionProbabilityFloor: 0,
689+
},
690+
},
691+
});
692+
693+
// Get the configuration and verify it has the test flag
694+
const initialConfig = configurationRequestor.getConfiguration();
695+
expect(initialConfig.getFlagKeys()).toEqual([]);
696+
expect(Object.keys(initialConfig.getBandits())).toEqual([]);
697+
698+
// Update the stores
699+
configurationRequestor.setConfigurationStores(
700+
newFlagStore,
701+
newBanditVariationStore,
702+
newBanditModelStore,
703+
);
704+
705+
// Get the configuration and verify it has the test flag
706+
const config = configurationRequestor.getConfiguration();
707+
expect(config.getFlagKeys()).toEqual(['test-flag']);
708+
expect(Object.keys(config.getBandits())).toEqual(['test-bandit']);
709+
});
710+
});
644711
});
645712
});

src/configuration-requestor.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@ import { BanditVariation, BanditParameters, Flag, BanditReference } from './inte
1010
// Requests AND stores flag configurations
1111
export default class ConfigurationRequestor {
1212
private banditModelVersions: string[] = [];
13-
private readonly configuration: StoreBackedConfiguration;
13+
private configuration: StoreBackedConfiguration;
1414

1515
constructor(
1616
private readonly httpClient: IHttpClient,
17-
private readonly flagConfigurationStore: IConfigurationStore<Flag>,
18-
private readonly banditVariationConfigurationStore: IConfigurationStore<
19-
BanditVariation[]
20-
> | null,
21-
private readonly banditModelConfigurationStore: IConfigurationStore<BanditParameters> | null,
17+
private flagConfigurationStore: IConfigurationStore<Flag>,
18+
private banditVariationConfigurationStore: IConfigurationStore<BanditVariation[]> | null,
19+
private banditModelConfigurationStore: IConfigurationStore<BanditParameters> | null,
2220
) {
2321
this.configuration = new StoreBackedConfiguration(
2422
this.flagConfigurationStore,
@@ -27,6 +25,26 @@ export default class ConfigurationRequestor {
2725
);
2826
}
2927

28+
/**
29+
* Updates the configuration stores and recreates the StoreBackedConfiguration
30+
*/
31+
public setConfigurationStores(
32+
flagConfigurationStore: IConfigurationStore<Flag>,
33+
banditVariationConfigurationStore: IConfigurationStore<BanditVariation[]> | null,
34+
banditModelConfigurationStore: IConfigurationStore<BanditParameters> | null,
35+
): void {
36+
this.flagConfigurationStore = flagConfigurationStore;
37+
this.banditVariationConfigurationStore = banditVariationConfigurationStore;
38+
this.banditModelConfigurationStore = banditModelConfigurationStore;
39+
40+
// Recreate the configuration with the new stores
41+
this.configuration = new StoreBackedConfiguration(
42+
this.flagConfigurationStore,
43+
this.banditVariationConfigurationStore,
44+
this.banditModelConfigurationStore,
45+
);
46+
}
47+
3048
public isFlagConfigExpired(): Promise<boolean> {
3149
return this.flagConfigurationStore.isExpired();
3250
}

0 commit comments

Comments
 (0)