Skip to content

Commit

Permalink
Merge pull request #258 from Flagsmith/revert-252-feat/support-multip…
Browse files Browse the repository at this point in the history
…le-environment-caching

Revert "feat: support multiple environment caching"
  • Loading branch information
rolodato authored Oct 10, 2024
2 parents b81e1de + c772f71 commit e2cfafd
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 104 deletions.
56 changes: 24 additions & 32 deletions flagsmith-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ type RequestOptions = {
}

let AsyncStorage: AsyncStorageType = null;
const DEFAULT_FLAGSMITH_KEY = "FLAGSMITH_DB";
const DEFAULT_FLAGSMITH_EVENT = "FLAGSMITH_EVENT";
let FlagsmithEvent = DEFAULT_FLAGSMITH_EVENT;
const FLAGSMITH_KEY = "BULLET_TRAIN_DB";
const FLAGSMITH_EVENT = "BULLET_TRAIN_EVENT";
const defaultAPI = 'https://edge.api.flagsmith.com/api/v1/';
let eventSource: typeof EventSource;
const initError = function(caller: string) {
Expand Down Expand Up @@ -81,7 +80,7 @@ const Flagsmith = class {
}

getFlags = () => {
const { api, evaluationContext } = this;
let { api, evaluationContext } = this;
this.log("Get Flags")
this.isLoading = true;

Expand Down Expand Up @@ -272,7 +271,7 @@ const Flagsmith = class {
timer: number|null= null
dtrum= null
withTraits?: ITraits|null= null
cacheOptions = {ttl:0, skipAPI: false, loadStale: false, storageKey: undefined as string|undefined}
cacheOptions = {ttl:0, skipAPI: false, loadStale: false}
async init(config: IInitConfig) {
const evaluationContext = toEvaluationContext(config.evaluationContext || {});
try {
Expand All @@ -291,7 +290,7 @@ const Flagsmith = class {
enableDynatrace,
enableAnalytics,
realtime,
eventSourceUrl= "https://realtime.flagsmith.com/",
eventSourceUrl= "https://realtime.flagsmith.com/",
AsyncStorage: _AsyncStorage,
identity,
traits,
Expand Down Expand Up @@ -332,7 +331,7 @@ const Flagsmith = class {
onError?.(message);
};
this.enableLogs = enableLogs || false;
this.cacheOptions = cacheOptions ? { skipAPI: !!cacheOptions.skipAPI, ttl: cacheOptions.ttl || 0, storageKey:cacheOptions.storageKey, loadStale: !!cacheOptions.loadStale } : this.cacheOptions;
this.cacheOptions = cacheOptions ? { skipAPI: !!cacheOptions.skipAPI, ttl: cacheOptions.ttl || 0, loadStale: !!cacheOptions.loadStale } : this.cacheOptions;
if (!this.cacheOptions.ttl && this.cacheOptions.skipAPI) {
console.warn("Flagsmith: you have set a cache ttl of 0 and are skipping API calls, this means the API will not be hit unless you clear local storage.")
}
Expand All @@ -346,9 +345,6 @@ const Flagsmith = class {
this.ticks = 10000;
this.timer = this.enableLogs ? new Date().valueOf() : null;
this.cacheFlags = typeof AsyncStorage !== 'undefined' && !!cacheFlags;

FlagsmithEvent = DEFAULT_FLAGSMITH_EVENT + "_" + evaluationContext.environment.apiKey;

if (_AsyncStorage) {
AsyncStorage = _AsyncStorage;
}
Expand Down Expand Up @@ -385,7 +381,7 @@ const Flagsmith = class {
}

if (AsyncStorage && this.canUseStorage) {
AsyncStorage.getItem(FlagsmithEvent)
AsyncStorage.getItem(FLAGSMITH_EVENT)
.then((res)=>{
try {
this.evaluationEvent = JSON.parse(res!) || {}
Expand All @@ -402,12 +398,12 @@ const Flagsmith = class {
}

if (AsyncStorage && this.canUseStorage) {
AsyncStorage.getItem(FlagsmithEvent, (err, res) => {
AsyncStorage.getItem(FLAGSMITH_EVENT, (err, res) => {
if (res && this.evaluationContext.environment) {
const json = JSON.parse(res);
if (json[this.evaluationContext.environment.apiKey]) {
const state = this.getState();
this.log("Retrieved events from cache", res);
const state = this.getState();
this.log("Retrieved events from cache", res);
this.setState({
...state,
evaluationEvent: json[this.evaluationContext.environment.apiKey],
Expand Down Expand Up @@ -457,7 +453,7 @@ const Flagsmith = class {
...json,
evaluationContext: toEvaluationContext({
...json.evaluationContext,
identity: json.evaluationContext?.identity ? {
identity: !!json.evaluationContext?.identity ? {
...json.evaluationContext?.identity,
traits: {
...json.evaluationContext?.identity?.traits || {},
Expand Down Expand Up @@ -514,7 +510,7 @@ const Flagsmith = class {
}
};
try {
const res = AsyncStorage.getItemSync? AsyncStorage.getItemSync(this.getStorageKey()) : await AsyncStorage.getItem(this.getStorageKey());
const res = AsyncStorage.getItemSync? AsyncStorage.getItemSync(FLAGSMITH_KEY) : await AsyncStorage.getItem(FLAGSMITH_KEY);
await onRetrievedStorage(null, res)
} catch (e) {}
}
Expand Down Expand Up @@ -542,6 +538,15 @@ const Flagsmith = class {
}
}

private _loadedState(error: any = null, source: FlagSource, isFetching = false) {
return {
error,
isFetching,
isLoading: false,
source
}
}

getAllFlags() {
return this.flags;
}
Expand Down Expand Up @@ -655,7 +660,7 @@ const Flagsmith = class {
}

setContext = (clientEvaluationContext: ClientEvaluationContext) => {
const evaluationContext = toEvaluationContext(clientEvaluationContext);
let evaluationContext = toEvaluationContext(clientEvaluationContext);
this.evaluationContext = {
...evaluationContext,
environment: evaluationContext.environment || this.evaluationContext.environment,
Expand Down Expand Up @@ -740,19 +745,6 @@ const Flagsmith = class {
return res;
};

private _loadedState(error: any = null, source: FlagSource, isFetching = false) {
return {
error,
isFetching,
isLoading: false,
source
}
}

private getStorageKey = ()=> {
return this.cacheOptions?.storageKey || DEFAULT_FLAGSMITH_KEY + "_" + this.evaluationContext.environment?.apiKey
}

private log(...args: (unknown)[]) {
if (this.enableLogs) {
console.log.apply(this, ['FLAGSMITH:', new Date().valueOf() - (this.timer || 0), 'ms', ...args]);
Expand All @@ -764,7 +756,7 @@ const Flagsmith = class {
this.ts = new Date().valueOf();
const state = JSON.stringify(this.getState());
this.log('Setting storage', state);
AsyncStorage!.setItem(this.getStorageKey(), state);
AsyncStorage!.setItem(FLAGSMITH_KEY, state);
}
}

Expand Down Expand Up @@ -828,7 +820,7 @@ const Flagsmith = class {
private updateEventStorage() {
if (this.enableAnalytics) {
const events = JSON.stringify(this.getState().evaluationEvent);
AsyncStorage!.setItem(FlagsmithEvent, events);
AsyncStorage!.setItem(FLAGSMITH_EVENT, events);
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/flagsmith-es/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "flagsmith-es",
"version": "6.0.0",
"version": "7.0.0",
"description": "Feature flagging to support continuous development. This is an esm equivalent of the standard flagsmith npm module.",
"main": "./index.js",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion lib/flagsmith/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "flagsmith",
"version": "6.0.0",
"version": "7.0.0",
"description": "Feature flagging to support continuous development",
"main": "./index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion lib/react-native-flagsmith/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-flagsmith",
"version": "6.0.0",
"version": "7.0.0",
"description": "Feature flagging to support continuous development",
"main": "./index.js",
"repository": {
Expand Down
67 changes: 35 additions & 32 deletions test/cache.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Sample test
import {
defaultState,
defaultStateAlt,
FLAGSMITH_KEY,
getFlagsmith,
getStateToCheck,
identityState,
Expand Down Expand Up @@ -33,21 +33,7 @@ describe('Cache', () => {
onChange,
});
await flagsmith.init(initConfig);
const cache = await AsyncStorage.getItem(FLAGSMITH_KEY);
expect(getStateToCheck(JSON.parse(`${cache}`))).toEqual(defaultState);
});
test('should set cache after init with custom key', async () => {
const onChange = jest.fn();
const customKey = 'custom_key';
const { flagsmith, initConfig, AsyncStorage, mockFetch } = getFlagsmith({
cacheFlags: true,
cacheOptions: {
storageKey: customKey,
},
onChange,
});
await flagsmith.init(initConfig);
const cache = await AsyncStorage.getItem(customKey);
const cache = await AsyncStorage.getItem('BULLET_TRAIN_DB');
expect(getStateToCheck(JSON.parse(`${cache}`))).toEqual(defaultState);
});
test('should call onChange with cache then eventually with an API response', async () => {
Expand All @@ -67,7 +53,7 @@ describe('Cache', () => {
cacheFlags: true,
onChange,
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify(defaultStateAlt));
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify(defaultStateAlt));
await flagsmith.init(initConfig);

// Flags retrieved from cache
Expand Down Expand Up @@ -100,7 +86,7 @@ describe('Cache', () => {
identity: testIdentity,
onChange,
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultStateAlt,
identity: 'bad_identity',
}));
Expand All @@ -116,7 +102,7 @@ describe('Cache', () => {
onChange,
cacheOptions: { ttl: 1 },
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultStateAlt,
ts: new Date().valueOf() - 100,
}));
Expand All @@ -134,7 +120,7 @@ describe('Cache', () => {
onChange,
cacheOptions: { ttl: 1, loadStale: true },
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultStateAlt,
ts: new Date().valueOf() - 100,
}));
Expand All @@ -152,7 +138,7 @@ describe('Cache', () => {
onChange,
cacheOptions: { ttl: 1000 },
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultStateAlt,
ts: new Date().valueOf(),
}));
Expand All @@ -169,7 +155,7 @@ describe('Cache', () => {
cacheFlags: false,
onChange,
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultStateAlt,
ts: new Date().valueOf(),
}));
Expand All @@ -187,7 +173,25 @@ describe('Cache', () => {
onChange,
cacheOptions: { ttl: 1000, skipAPI: true },
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultStateAlt,
ts: new Date().valueOf(),
}));
await flagsmith.init(initConfig);
expect(onChange).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledTimes(0);
expect(getStateToCheck(flagsmith.getState())).toEqual({
...defaultStateAlt,
});
});
test('should not get flags from API when skipAPI is set', async () => {
const onChange = jest.fn();
const { flagsmith, initConfig, AsyncStorage, mockFetch } = getFlagsmith({
cacheFlags: true,
onChange,
cacheOptions: { ttl: 1000, skipAPI: true },
});
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultStateAlt,
ts: new Date().valueOf(),
}));
Expand All @@ -205,7 +209,7 @@ describe('Cache', () => {
onChange,
cacheOptions: { ttl: 1, skipAPI: true, loadStale: true },
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultStateAlt,
ts: new Date().valueOf() - 100,
}));
Expand All @@ -216,15 +220,14 @@ describe('Cache', () => {
...defaultStateAlt,
});
});

test('should validate flags are unchanged when fetched', async () => {
const onChange = jest.fn();
const { flagsmith, initConfig, AsyncStorage, mockFetch } = getFlagsmith({
onChange,
cacheFlags: true,
preventFetch: true,
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultState,
}));
await flagsmith.init(initConfig);
Expand Down Expand Up @@ -270,7 +273,7 @@ describe('Cache', () => {
preventFetch: true,
defaultFlags: defaultState.flags,
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultState,
}));
await flagsmith.init(initConfig);
Expand Down Expand Up @@ -316,7 +319,7 @@ describe('Cache', () => {
preventFetch: true,
});
const storage = new SyncStorageMock();
await storage.setItem(FLAGSMITH_KEY, JSON.stringify({
await storage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultState,
}));
flagsmith.init({
Expand All @@ -342,7 +345,7 @@ describe('Cache', () => {
preventFetch: true,
});
const storage = new SyncStorageMock();
await storage.setItem(FLAGSMITH_KEY, JSON.stringify({
await storage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...identityState,
}));
const ts = Date.now();
Expand All @@ -353,8 +356,8 @@ describe('Cache', () => {
});
expect(flagsmith.getAllTraits()).toEqual({
...identityState.traits,
ts,
});
ts
})
});
test('should cache transient traits correctly', async () => {
const onChange = jest.fn();
Expand Down Expand Up @@ -392,4 +395,4 @@ describe('Cache', () => {
},
})
});
});
});
4 changes: 2 additions & 2 deletions test/default-flags.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Sample test
import { defaultState, defaultStateAlt, FLAGSMITH_KEY, getFlagsmith, getStateToCheck } from './test-constants';
import { defaultState, defaultStateAlt, getFlagsmith, getStateToCheck } from './test-constants';
import { IFlags } from '../types';

describe('Default Flags', () => {
Expand Down Expand Up @@ -51,7 +51,7 @@ describe('Default Flags', () => {
cacheFlags: true,
defaultFlags: {...defaultFlags, ...itemsToRemove},
});
await AsyncStorage.setItem(FLAGSMITH_KEY, JSON.stringify({
await AsyncStorage.setItem('BULLET_TRAIN_DB', JSON.stringify({
...defaultState,
flags: {
...defaultFlags,
Expand Down
Loading

0 comments on commit e2cfafd

Please sign in to comment.