Skip to content

Commit fc71031

Browse files
committed
Merge latest SDK
1 parent 62ce8c3 commit fc71031

File tree

3 files changed

+62
-8
lines changed

3 files changed

+62
-8
lines changed

flagsmith-core.ts

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,23 @@ const FLAGSMITH_CONFIG_ANALYTICS_KEY = "flagsmith_value_";
5656
const FLAGSMITH_FLAG_ANALYTICS_KEY = "flagsmith_enabled_";
5757
const FLAGSMITH_TRAIT_ANALYTICS_KEY = "flagsmith_trait_";
5858

59+
60+
/*API configuration includes the /v1/
61+
This function replaces that version with another.
62+
In future, we may exclude /v1/ from api configuration however this would be a breaking change*/
63+
function apiVersion(api:string, version:number) {
64+
return api.replace("/v1/",`/v${version}/`)
65+
}
66+
5967
const Flagsmith = class {
6068
_trigger?:(()=>void)|null= null
6169
_triggerLoadingState?:(()=>void)|null= null
6270
timestamp: number|null = null
6371
isLoading = false
6472
eventSource:EventSource|null = null
73+
events: string[] = []
74+
splitTestingAnalytics=false;
75+
6576
constructor(props: Config) {
6677
if (props.fetch) {
6778
_fetch = props.fetch as LikeFetch;
@@ -225,11 +236,11 @@ const Flagsmith = class {
225236
const { api } = this;
226237

227238
if (!this.evaluationEvent || !this.evaluationContext.environment || !this.evaluationEvent[this.evaluationContext.environment.apiKey]) {
228-
return
239+
return Promise.resolve()
229240
}
230241

231242
if (this.evaluationEvent && Object.getOwnPropertyNames(this.evaluationEvent).length !== 0 && Object.getOwnPropertyNames(this.evaluationEvent[this.evaluationContext.environment.apiKey]).length !== 0) {
232-
return this.getJSON(api + 'analytics/flags/', 'POST', JSON.stringify(this.evaluationEvent[this.evaluationContext.environment.apiKey]))
243+
return this.getJSON(apiVersion(`${api}`, this.splitTestingAnalytics?2:1) + 'analytics/flags/', 'POST', JSON.stringify(this.toAnalyticsPayload(this.evaluationEvent[this.evaluationContext.environment.apiKey])))
233244
.then((res) => {
234245
if (!this.evaluationContext.environment) {
235246
return;
@@ -248,6 +259,7 @@ const Flagsmith = class {
248259
this.log("Exception fetching evaluationEvent", err);
249260
});
250261
}
262+
return Promise.resolve()
251263
};
252264

253265
datadogRum: IDatadogRum | null = null;
@@ -298,9 +310,11 @@ const Flagsmith = class {
298310
state,
299311
cacheOptions,
300312
angularHttpClient,
313+
splitTestingAnalytics,
301314
_trigger,
302315
_triggerLoadingState,
303316
} = config;
317+
this.splitTestingAnalytics = !!splitTestingAnalytics;
304318
evaluationContext.environment = environmentID ? {apiKey: environmentID} : evaluationContext.environment;
305319
if (!evaluationContext.environment || !evaluationContext.environment.apiKey) {
306320
throw new Error('Please provide `evaluationContext.environment` with non-empty `apiKey`');
@@ -553,6 +567,7 @@ const Flagsmith = class {
553567
// clear out old traits when switching identity
554568
traits: this.evaluationContext.identity && this.evaluationContext.identity.identifier == userId ? this.evaluationContext.identity.traits : {}
555569
}
570+
this.events.map(this.trackEvent)
556571
this.evaluationContext.identity.identifier = userId;
557572
this.log("Identify: " + this.evaluationContext.identity.identifier)
558573

@@ -723,6 +738,25 @@ const Flagsmith = class {
723738
});
724739
};
725740

741+
trackEvent = (event: string) => {
742+
if (!this.splitTestingAnalytics) {
743+
const error = new Error("This feature is only enabled for self-hosted customers using split testing.");
744+
console.error(error.message);
745+
return Promise.reject(error);
746+
} else if (!this.evaluationContext.identity?.identifier) {
747+
this.events.push(event);
748+
this.log("Waiting for user to be identified before tracking event", event);
749+
return Promise.resolve();
750+
} else {
751+
return this.analyticsFlags().then(() => {
752+
return this.getJSON(this.api + 'split-testing/conversion-events/', "POST", JSON.stringify({
753+
'identity_identifier': this.evaluationContext.identity?.identifier,
754+
'type': event
755+
}));
756+
});
757+
}
758+
};
759+
726760
hasFeature = (key: string, options?: HasFeatureOptions) => {
727761
// Support legacy skipAnalytics boolean parameter
728762
const usingNewOptions = typeof options === 'object'
@@ -759,6 +793,26 @@ const Flagsmith = class {
759793
}
760794
}
761795

796+
797+
798+
private toAnalyticsPayload = (evaluations: Record<string, number>|null)=> {
799+
if(!this.splitTestingAnalytics) {
800+
return evaluations || {}
801+
}
802+
if(!evaluations) return {evaluations: []}
803+
return {
804+
evaluations: Object.keys(evaluations).map((feature_name)=>(
805+
{
806+
feature_name,
807+
"identity_identifier": this.evaluationContext?.identity?.identifier||null,
808+
"count": evaluations[feature_name],
809+
"enabled_when_evaluated": this.hasFeature(feature_name),
810+
}
811+
))
812+
}
813+
};
814+
815+
762816
private updateStorage() {
763817
if (this.cacheFlags) {
764818
this.ts = new Date().valueOf();

test/analytics.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('Analytics', () => {
4646
}),
4747
cache: 'no-cache',
4848
headers: {
49-
'x-environment-key': flagsmith.environmentID,
49+
'X-Environment-Key': flagsmith.getContext().environment?.apiKey,
5050
'Content-Type': 'application/json; charset=utf-8',
5151
},
5252
},
@@ -80,7 +80,7 @@ describe('Analytics', () => {
8080
}),
8181
cache: 'no-cache',
8282
headers: {
83-
'x-environment-key': flagsmith.environmentID,
83+
'X-Environment-Key': flagsmith.getContext().environment?.apiKey,
8484
'Content-Type': 'application/json; charset=utf-8',
8585
},
8686
},
@@ -107,7 +107,7 @@ describe('Analytics', () => {
107107
}),
108108
cache: 'no-cache',
109109
headers: {
110-
'x-environment-key': flagsmith.environmentID,
110+
'X-Environment-Key': flagsmith.getContext().environment?.apiKey,
111111
'Content-Type': 'application/json; charset=utf-8',
112112
},
113113
},

test/test-constants.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ export function getStateToCheck(_state: IState) {
6868
return state;
6969
}
7070

71-
export function getFlagsmith(config: Partial<IInitConfig> = {}, mockFetch?:any) {
71+
export function getFlagsmith(config: Partial<IInitConfig> = {}, _mockFetch?:any) {
7272
const flagsmith = createFlagsmithInstance();
7373
const AsyncStorage = new MockAsyncStorage();
74-
const _mockFetch = mockFetch || jest.fn(async (url, options) => {
74+
const mockFetch = _mockFetch||jest.fn(async (url, options) => {
7575
switch (url) {
7676
case 'https://edge.api.flagsmith.com/api/v1/flags/':
7777
return {status: 200, text: () => fs.readFile('./test/data/flags.json', 'utf8')}
@@ -86,7 +86,7 @@ export function getFlagsmith(config: Partial<IInitConfig> = {}, mockFetch?:any)
8686
flagsmith.canUseStorage = true;
8787
const initConfig: IInitConfig = {
8888
AsyncStorage,
89-
fetch: _mockFetch,
89+
fetch: mockFetch,
9090
...config,
9191
};
9292
initConfig.evaluationContext = {

0 commit comments

Comments
 (0)