Skip to content

Commit 621ffd6

Browse files
committed
feat: no-op event methods when events are disabled instead of throwing
1 parent 4551809 commit 621ffd6

3 files changed

Lines changed: 26 additions & 23 deletions

File tree

flagsmith-core.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -947,24 +947,18 @@ const Flagsmith = class {
947947
this.updateEventStorage();
948948
};
949949

950-
private requireEventProcessor(): EventProcessor {
951-
if (!this.eventProcessor) {
952-
throw new Error('Flagsmith: events must be enabled (enableEvents: true) to use this method.');
953-
}
954-
return this.eventProcessor;
955-
}
956-
957950
trackEvent = (event: string, opts?: {
958951
identifier?: string | null;
959952
value?: IFlagsmithValue;
960953
traits?: ITraits;
961954
metadata?: Record<string, unknown>;
962955
}) => {
963-
const processor = this.requireEventProcessor();
956+
// No-op when events are disabled, mirroring enableAnalytics: false.
957+
if (!this.eventProcessor) return;
964958
if (event.startsWith('$')) {
965959
throw new Error(`Flagsmith: event names starting with "$" are reserved; use trackExposureEvent to record "${FLAG_EXPOSURE_EVENT}".`);
966960
}
967-
processor.trackEvent({
961+
this.eventProcessor.trackEvent({
968962
event,
969963
identifier: opts?.identifier ?? this.evaluationContext.identity?.identifier ?? null,
970964
value: opts?.value ?? null,
@@ -979,8 +973,9 @@ const Flagsmith = class {
979973
traits?: ITraits;
980974
metadata?: Record<string, unknown>;
981975
}) => {
982-
const processor = this.requireEventProcessor();
983-
processor.trackExposureEvent({
976+
// No-op when events are disabled, mirroring enableAnalytics: false.
977+
if (!this.eventProcessor) return;
978+
this.eventProcessor.trackExposureEvent({
984979
featureName,
985980
identifier: opts?.identifier ?? this.evaluationContext.identity?.identifier ?? null,
986981
value: opts?.value ?? null,
@@ -992,9 +987,10 @@ const Flagsmith = class {
992987
flushEvents = (): Promise<void> => this.eventProcessor ? this.eventProcessor.flush() : Promise.resolve();
993988

994989
getExperimentFlag = (featureName: string): IFlagsmithFeature | null => {
995-
this.requireEventProcessor();
996990
const key = featureName.toLowerCase().replace(/ /g, '_');
997991
const flag = (this.flags && this.flags[key]) || null;
992+
// When events are disabled this degrades to a plain flag read.
993+
if (!this.eventProcessor) return flag;
998994
const identifier = this.evaluationContext.identity?.identifier;
999995
if (!identifier) {
1000996
this.log('Flagsmith: getExperimentFlag called without an identity; call identify() (optionally with transient: true) before using experiments to record an exposure. Returning environment flags; no exposure recorded.');

test/events.test.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,22 @@ function eventCalls(mockFetch: jest.Mock) {
1616
}
1717

1818
describe('events gate', () => {
19-
test('trackEvent throws when events are not enabled', async () => {
20-
const { flagsmith, initConfig } = getFlagsmith();
19+
test('trackEvent is a no-op when events are not enabled', async () => {
20+
const { flagsmith, initConfig, mockFetch } = getFlagsmith();
2121
await flagsmith.init(initConfig);
22-
expect(() => flagsmith.trackEvent('purchase')).toThrow(/events must be enabled/i);
22+
expect(() => flagsmith.trackEvent('purchase')).not.toThrow();
23+
await flagsmith.flushEvents();
24+
expect(eventCalls(mockFetch)).toHaveLength(0);
2325
});
2426

25-
test('trackExposureEvent and getExperimentFlag throw when not enabled', async () => {
26-
const { flagsmith, initConfig } = getFlagsmith();
27+
test('trackExposureEvent and getExperimentFlag are no-ops when not enabled', async () => {
28+
const { flagsmith, initConfig, mockFetch } = getFlagsmith({ identity: testIdentity });
2729
await flagsmith.init(initConfig);
28-
expect(() => flagsmith.trackExposureEvent('f')).toThrow(/events must be enabled/i);
29-
expect(() => flagsmith.getExperimentFlag('f')).toThrow(/events must be enabled/i);
30+
expect(() => flagsmith.trackExposureEvent('font_size')).not.toThrow();
31+
// getExperimentFlag still returns the flag, just records no exposure.
32+
expect(flagsmith.getExperimentFlag('font_size')).toEqual(expect.objectContaining({ value: 16 }));
33+
await flagsmith.flushEvents();
34+
expect(eventCalls(mockFetch)).toHaveLength(0);
3035
});
3136

3237
test('eventProcessorConfig without enableEvents throws at init', async () => {

types.d.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,8 @@ T extends string = string
291291
*/
292292
setTraits: (traits: ITraits) => Promise<void>;
293293
/**
294-
* Record an arbitrary product event (e.g. "purchase"). Requires
295-
* enableEvents: true (throws otherwise). identifier/traits default to the
294+
* Record an arbitrary product event (e.g. "purchase"). No-op when events
295+
* are disabled (enableEvents is not set). identifier/traits default to the
296296
* current identified context when omitted.
297297
* @experimental @internal
298298
*/
@@ -304,7 +304,8 @@ T extends string = string
304304
}) => void;
305305
/**
306306
* Record that an identity was exposed to a flag/variant (emits the reserved
307-
* "$flag_exposure" event). Requires enableEvents: true (throws otherwise).
307+
* "$flag_exposure" event). No-op when events are disabled (enableEvents is
308+
* not set).
308309
* @experimental @internal
309310
*/
310311
trackExposureEvent: (featureName: string, opts?: {
@@ -316,7 +317,8 @@ T extends string = string
316317
/**
317318
* Resolve a flag for the currently identified user and fire one
318319
* "$flag_exposure" event (skipped unless flags were loaded from the server
319-
* and the feature exists). Requires enableEvents: true (throws otherwise).
320+
* and the feature exists). When events are disabled (enableEvents is not
321+
* set) this degrades to a plain flag read.
320322
* @experimental @internal
321323
*/
322324
getExperimentFlag: (featureName: string) => IFlagsmithFeature | null;

0 commit comments

Comments
 (0)