From 81eefdf38fff4ab8d820ae109b403d8299c1686c Mon Sep 17 00:00:00 2001 From: Erik Hughes Date: Tue, 9 Sep 2025 14:13:22 +0200 Subject: [PATCH 1/2] refactor: remove "evaluate" and "evaluate-config" events. - Eliminated the emitEvaluationEvents configuration option and related logic. - Cleaned up tests to reflect the removal of evaluation event handling. --- packages/node-sdk/src/client.ts | 67 +------------- packages/node-sdk/src/types.ts | 4 +- packages/node-sdk/test/client.test.ts | 128 -------------------------- 3 files changed, 5 insertions(+), 194 deletions(-) diff --git a/packages/node-sdk/src/client.ts b/packages/node-sdk/src/client.ts index b524d726..859a3e0f 100644 --- a/packages/node-sdk/src/client.ts +++ b/packages/node-sdk/src/client.ts @@ -78,7 +78,7 @@ type BulkEvent = } | { type: "feature-flag-event"; - action: "check" | "evaluate" | "check-config" | "evaluate-config"; + action: "check" | "check-config"; key: string; targetingVersion?: number; evalResult: @@ -126,7 +126,6 @@ export class ReflagClient { fallbackFlags?: Record; flagOverrides: FlagOverridesFn; offline: boolean; - emitEvaluationEvents: boolean; configFile?: string; flagsFetchRetries: number; fetchTimeoutMs: number; @@ -302,7 +301,6 @@ export class ReflagClient { this._config = { offline, - emitEvaluationEvents: config.emitEvaluationEvents ?? true, apiBaseUrl: (config.apiBaseUrl ?? config.host) || API_BASE_URL, headers: { "Content-Type": "application/json", @@ -841,10 +839,7 @@ export class ReflagClient { ok(typeof event === "object", "event must be an object"); ok( typeof event.action === "string" && - (event.action === "evaluate" || - event.action === "evaluate-config" || - event.action === "check" || - event.action === "check-config"), + (event.action === "check" || event.action === "check-config"), "event must have an action", ); ok( @@ -883,13 +878,6 @@ export class ReflagClient { return; } - if ( - !this._config.emitEvaluationEvents && - (event.action === "evaluate" || event.action === "evaluate-config") - ) { - return; - } - if ( !this.rateLimiter.isAllowed( hashObject({ @@ -1056,7 +1044,7 @@ export class ReflagClient { flagDefinitions = flagDefs; } - const { enableTracking = true, meta: _, ...context } = options; + const { enableTracking: _, meta: __, ...context } = options; const evaluated = flagDefinitions .filter(({ key: flagKey }) => (key ? key === flagKey : true)) @@ -1076,55 +1064,6 @@ export class ReflagClient { } satisfies EvaluationResult), })); - if (enableTracking) { - const promises = evaluated - .map((res) => { - const outPromises: Promise[] = []; - outPromises.push( - this.sendFlagEvent({ - action: "evaluate", - key: res.flagKey, - targetingVersion: res.targetingVersion, - evalResult: res.enabledResult.value ?? false, - evalContext: res.enabledResult.context, - evalRuleResults: res.enabledResult.ruleEvaluationResults, - evalMissingFields: res.enabledResult.missingContextFields, - }), - ); - - const config = res.configResult; - if (config.value) { - outPromises.push( - this.sendFlagEvent({ - action: "evaluate-config", - key: res.flagKey, - targetingVersion: res.configVersion, - evalResult: config.value, - evalContext: config.context, - evalRuleResults: config.ruleEvaluationResults, - evalMissingFields: config.missingContextFields, - }), - ); - } - - return outPromises; - }) - .flat(); - - void Promise.allSettled(promises).then((results) => { - const failed = results - .map((result) => - result.status === "rejected" ? result.reason : undefined, - ) - .filter(Boolean); - if (failed.length > 0) { - this.logger.error(`failed to queue some evaluate events.`, { - errors: failed, - }); - } - }); - } - let evaluatedFlags = evaluated.reduce( (acc, res) => { acc[res.flagKey as TypedFlagKey] = { diff --git a/packages/node-sdk/src/types.ts b/packages/node-sdk/src/types.ts index 51b9e34a..1e979626 100644 --- a/packages/node-sdk/src/types.ts +++ b/packages/node-sdk/src/types.ts @@ -18,13 +18,13 @@ export type TrackingMeta = { export type Attributes = Record; /** - * Describes a feature event. Can be "check" or "evaluate". + * Describes a feature event. Can be "check" . **/ export type FlagEvent = { /** * The action that was performed. **/ - action: "evaluate" | "evaluate-config" | "check" | "check-config"; + action: "check" | "check-config"; /** * The feature key. diff --git a/packages/node-sdk/test/client.test.ts b/packages/node-sdk/test/client.test.ts index 3f28d40e..4aed3e80 100644 --- a/packages/node-sdk/test/client.test.ts +++ b/packages/node-sdk/test/client.test.ts @@ -10,8 +10,6 @@ import { vi, } from "vitest"; -import { flattenJSON } from "@reflag/flag-evaluation"; - import { BoundReflagClient, ReflagClient } from "../src"; import { API_BASE_URL, @@ -1082,95 +1080,6 @@ describe("ReflagClient", () => { type: "user", userId: "user123", }, - { - type: "feature-flag-event", - action: "evaluate", - key: "flag1", - targetingVersion: 1, - evalContext: flattenJSON(context), - evalResult: true, - evalRuleResults: [true], - evalMissingFields: [], - }, - { - type: "feature-flag-event", - action: "evaluate-config", - key: "flag1", - targetingVersion: 1, - evalContext: flattenJSON(context), - evalResult: { - key: "config-1", - payload: { - something: "else", - }, - }, - evalRuleResults: [true], - evalMissingFields: [], - }, - { - type: "event", - event: "flag1", - userId: user.id, - companyId: company.id, - }, - ], - ); - }); - - it("`track` does not send evaluation events when `emitEvaluationEvents` is `false`", async () => { - client = new ReflagClient({ - ...validOptions, - emitEvaluationEvents: false, - }); - - const context = { - company, - user, - other: otherContext, - }; - - // test that the flag is returned - await client.initialize(); - const flag = client.getFlag( - { - ...context, - meta: { - active: true, - }, - enableTracking: true, - }, - "flag1", - ); - - await flag.track(); - await client.flush(); - - expect(httpClient.post).toHaveBeenCalledWith( - BULK_ENDPOINT, - expectedHeaders, - [ - { - attributes: { - employees: 100, - name: "Acme Inc.", - }, - companyId: "company123", - context: { - active: true, - }, - type: "company", - }, - { - attributes: { - age: 1, - name: "John", - }, - context: { - active: true, - }, - type: "user", - userId: "user123", - }, { type: "event", event: "flag1", @@ -1560,8 +1469,6 @@ describe("ReflagClient", () => { }); await client.flush(); - - expect(httpClient.post).toHaveBeenCalledTimes(1); }); it("should send `track` with user and company if provided", async () => { @@ -1775,41 +1682,6 @@ describe("ReflagClient", () => { ); }); - it("should not fail if sendFlagEvent fails to send evaluate event", async () => { - httpClient.post.mockRejectedValueOnce(new Error("Network error")); - const context = { user, company, other: otherContext }; - - await client.initialize(); - const flags = client.getFlags(context); - - await client.flush(); - - expect(logger.error).toHaveBeenCalledWith( - expect.stringMatching("post request .* failed with error"), - expect.any(Error), - ); - - expect(flags).toStrictEqual({ - flag1: { - key: "flag1", - isEnabled: true, - config: { - key: "config-1", - payload: { - something: "else", - }, - }, - track: expect.any(Function), - }, - flag2: { - key: "flag2", - isEnabled: false, - config: { key: undefined, payload: undefined }, - track: expect.any(Function), - }, - }); - }); - it("should not fail if sendFlagEvent fails to send check event", async () => { httpClient.post.mockResolvedValue({ status: 200, From ec64ac5363c61fa924df253a09a01906945e5ed2 Mon Sep 17 00:00:00 2001 From: Erik Hughes Date: Tue, 9 Sep 2025 15:38:45 +0200 Subject: [PATCH 2/2] chore: code comments and version bump --- packages/node-sdk/package.json | 2 +- packages/node-sdk/src/types.ts | 4 ++-- packages/openfeature-node-provider/package.json | 4 ++-- yarn.lock | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/node-sdk/package.json b/packages/node-sdk/package.json index 7862095c..c9906fb7 100644 --- a/packages/node-sdk/package.json +++ b/packages/node-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@reflag/node-sdk", - "version": "1.0.0", + "version": "1.0.1", "license": "MIT", "repository": { "type": "git", diff --git a/packages/node-sdk/src/types.ts b/packages/node-sdk/src/types.ts index 1e979626..b3638d54 100644 --- a/packages/node-sdk/src/types.ts +++ b/packages/node-sdk/src/types.ts @@ -18,7 +18,7 @@ export type TrackingMeta = { export type Attributes = Record; /** - * Describes a feature event. Can be "check" . + * Describes a flag event. Can be "check" or "check-config event". **/ export type FlagEvent = { /** @@ -27,7 +27,7 @@ export type FlagEvent = { action: "check" | "check-config"; /** - * The feature key. + * The flag key. **/ key: string; diff --git a/packages/openfeature-node-provider/package.json b/packages/openfeature-node-provider/package.json index 27839c13..610d04f8 100644 --- a/packages/openfeature-node-provider/package.json +++ b/packages/openfeature-node-provider/package.json @@ -1,6 +1,6 @@ { "name": "@reflag/openfeature-node-provider", - "version": "1.0.0", + "version": "1.0.1", "license": "MIT", "repository": { "type": "git", @@ -50,7 +50,7 @@ "vitest": "~1.6.0" }, "dependencies": { - "@reflag/node-sdk": "1.0.0" + "@reflag/node-sdk": "1.0.1" }, "peerDependencies": { "@openfeature/server-sdk": ">=1.16.1" diff --git a/yarn.lock b/yarn.lock index e483dbe1..015a0514 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3055,7 +3055,7 @@ __metadata: languageName: unknown linkType: soft -"@reflag/node-sdk@npm:1.0.0, @reflag/node-sdk@workspace:packages/node-sdk": +"@reflag/node-sdk@npm:1.0.1, @reflag/node-sdk@workspace:packages/node-sdk": version: 0.0.0-use.local resolution: "@reflag/node-sdk@workspace:packages/node-sdk" dependencies: @@ -3107,7 +3107,7 @@ __metadata: "@openfeature/core": "npm:^1.5.0" "@openfeature/server-sdk": "npm:>=1.16.1" "@reflag/eslint-config": "npm:~0.0.2" - "@reflag/node-sdk": "npm:1.0.0" + "@reflag/node-sdk": "npm:1.0.1" "@reflag/tsconfig": "npm:~0.0.2" "@types/node": "npm:^22.12.0" eslint: "npm:^9.21.0"