From 75d57317b8868bd08b486545c5df39b6b3f8410f Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Thu, 10 Sep 2026 18:44:46 +0200 Subject: [PATCH 1/4] Send flag evaluation diagnostics from SDKs --- .changeset/send-evaluation-diagnostics.md | 7 +++++ packages/browser-sdk/src/bulkQueue.ts | 2 ++ packages/browser-sdk/src/client.ts | 2 ++ packages/browser-sdk/src/flag/flagCache.ts | 21 +++++++++++++++ packages/browser-sdk/src/flag/flags.ts | 30 +++++++++++++++++++++ packages/browser-sdk/src/index.ts | 1 + packages/browser-sdk/test/flagCache.test.ts | 13 +++++++++ packages/browser-sdk/test/mocks/handlers.ts | 15 +++++++++++ packages/browser-sdk/test/usage.test.ts | 22 +++++++++++++++ packages/node-sdk/src/client.ts | 9 +++++++ packages/node-sdk/src/types.ts | 6 +++++ packages/node-sdk/test/client.test.ts | 26 ++++++++++++++++++ packages/react-sdk/src/index.tsx | 2 ++ 13 files changed, 156 insertions(+) create mode 100644 .changeset/send-evaluation-diagnostics.md diff --git a/.changeset/send-evaluation-diagnostics.md b/.changeset/send-evaluation-diagnostics.md new file mode 100644 index 00000000..17b6e8d8 --- /dev/null +++ b/.changeset/send-evaluation-diagnostics.md @@ -0,0 +1,7 @@ +--- +"@reflag/node-sdk": patch +"@reflag/browser-sdk": patch +"@reflag/react-sdk": patch +--- + +Include non-fatal flag evaluation diagnostics in check events sent by the Node, browser, and React SDKs. diff --git a/packages/browser-sdk/src/bulkQueue.ts b/packages/browser-sdk/src/bulkQueue.ts index 568178e7..2d281ef4 100644 --- a/packages/browser-sdk/src/bulkQueue.ts +++ b/packages/browser-sdk/src/bulkQueue.ts @@ -1,4 +1,5 @@ import { BULK_QUEUE_FLUSH_DELAY_MS, BULK_QUEUE_MAX_SIZE } from "./config"; +import type { EvaluationError } from "./flag/flags"; import { Logger } from "./logger"; import { logResponseError } from "./utils/responseError"; @@ -39,6 +40,7 @@ export type BulkEvent = evalContext?: Record; evalRuleResults?: boolean[]; evalMissingFields?: string[]; + evalErrors?: EvaluationError[]; } | { type: "prompt-event"; diff --git a/packages/browser-sdk/src/client.ts b/packages/browser-sdk/src/client.ts index 66b942d6..379c3278 100644 --- a/packages/browser-sdk/src/client.ts +++ b/packages/browser-sdk/src/client.ts @@ -1417,6 +1417,7 @@ export class ReflagClient { version: f?.targetingVersion, ruleEvaluationResults: f?.ruleEvaluationResults, missingContextFields: f?.missingContextFields, + evaluationErrors: f?.evaluationErrors, value, }) .catch(() => { @@ -1432,6 +1433,7 @@ export class ReflagClient { version: f?.config?.version, ruleEvaluationResults: f?.config?.ruleEvaluationResults, missingContextFields: f?.config?.missingContextFields, + evaluationErrors: f?.config?.evaluationErrors, value: f?.config && { key: f.config.key, payload: f.config.payload, diff --git a/packages/browser-sdk/src/flag/flagCache.ts b/packages/browser-sdk/src/flag/flagCache.ts index ddad0fd7..c1f1f682 100644 --- a/packages/browser-sdk/src/flag/flagCache.ts +++ b/packages/browser-sdk/src/flag/flagCache.ts @@ -1,4 +1,5 @@ import { StorageAdapter } from "../storage"; +import type { EvaluationError } from "./flags"; import { RawFlagOptIn, RawFlags } from "./flags"; import { isValidFlagStateVersion } from "./flagStateVersion"; @@ -28,6 +29,21 @@ function parseOptIn(optIn: any): RawFlagOptIn | null | undefined { }; } +function isEvaluationErrorArray(value: any): value is EvaluationError[] { + return ( + Array.isArray(value) && + value.every( + (error) => + isObject(error) && + typeof error.code === "string" && + typeof error.field === "string" && + typeof error.message === "string" && + (typeof error.operator === "undefined" || + typeof error.operator === "string"), + ) + ); +} + interface cacheEntry { expireAt: number; staleAt: number; @@ -57,6 +73,10 @@ export function parseAPIFlagsResponse(flagsInput: any): RawFlags | undefined { !Array.isArray(flag.missingContextFields)) || (flag.ruleEvaluationResults && !Array.isArray(flag.ruleEvaluationResults)) || + (typeof flag.evaluationErrors !== "undefined" && + !isEvaluationErrorArray(flag.evaluationErrors)) || + (typeof flag.config?.evaluationErrors !== "undefined" && + !isEvaluationErrorArray(flag.config.evaluationErrors)) || (typeof flag.optInEnabled !== "undefined" && typeof flag.optInEnabled !== "boolean") || (typeof flag.optIn !== "undefined" && typeof optIn === "undefined") @@ -71,6 +91,7 @@ export function parseAPIFlagsResponse(flagsInput: any): RawFlags | undefined { config: flag.config, missingContextFields: flag.missingContextFields, ruleEvaluationResults: flag.ruleEvaluationResults, + evaluationErrors: flag.evaluationErrors, ...(typeof flag.optInEnabled !== "undefined" && { optInEnabled: flag.optInEnabled, }), diff --git a/packages/browser-sdk/src/flag/flags.ts b/packages/browser-sdk/src/flag/flags.ts index 1bdb207f..08938104 100644 --- a/packages/browser-sdk/src/flag/flags.ts +++ b/packages/browser-sdk/src/flag/flags.ts @@ -55,6 +55,16 @@ export type OptInFlag = RawFlagOptIn & { isEnabled: boolean; }; +/** + * A non-fatal diagnostic produced while evaluating targeting rules. + */ +export type EvaluationError = { + code: string; + field: string; + operator?: string; + message: string; +}; + /** * A flag fetched from the server. */ @@ -87,9 +97,15 @@ export type RawFlag = { /** * Missing context fields. + * @deprecated Use `evaluationErrors` and check for `MISSING_CONTEXT_FIELD`. */ missingContextFields?: string[]; + /** + * Non-fatal diagnostics produced while evaluating targeting rules. + */ + evaluationErrors?: EvaluationError[]; + /** * Whether end-user opt-in is enabled for this flag. */ @@ -126,8 +142,14 @@ export type RawFlag = { /** * The missing context fields. + * @deprecated Use `evaluationErrors` and check for `MISSING_CONTEXT_FIELD`. */ missingContextFields?: string[]; + + /** + * Non-fatal diagnostics produced while evaluating targeting rules. + */ + evaluationErrors?: EvaluationError[]; }; }; @@ -243,8 +265,14 @@ export interface CheckEvent { /** * Missing context fields. + * @deprecated Use `evaluationErrors` and check for `MISSING_CONTEXT_FIELD`. */ missingContextFields?: string[]; + + /** + * Non-fatal diagnostics produced while evaluating targeting rules. + */ + evaluationErrors?: EvaluationError[]; } const storageOverridesKey = `__reflag_overrides`; @@ -663,6 +691,7 @@ export class FlagsClient { evalResult: checkEvent.value, evalRuleResults: checkEvent.ruleEvaluationResults, evalMissingFields: checkEvent.missingContextFields, + evalErrors: checkEvent.evaluationErrors, }; if (this.enqueueBulkEvent) { @@ -675,6 +704,7 @@ export class FlagsClient { evalResult: payload.evalResult, evalRuleResults: payload.evalRuleResults, evalMissingFields: payload.evalMissingFields, + evalErrors: payload.evalErrors, }).catch((e: any) => { this.logger.warn(`failed to enqueue flag check event`, e); }); diff --git a/packages/browser-sdk/src/index.ts b/packages/browser-sdk/src/index.ts index 34555b0e..96d90066 100644 --- a/packages/browser-sdk/src/index.ts +++ b/packages/browser-sdk/src/index.ts @@ -39,6 +39,7 @@ export type { } from "./feedback/ui/types"; export type { CheckEvent, + EvaluationError, FallbackFlagOverride, FlagOverrides, OptInFlag, diff --git a/packages/browser-sdk/test/flagCache.test.ts b/packages/browser-sdk/test/flagCache.test.ts index 70c795b6..1e794e7c 100644 --- a/packages/browser-sdk/test/flagCache.test.ts +++ b/packages/browser-sdk/test/flagCache.test.ts @@ -50,6 +50,19 @@ describe("parseAPIFlagsResponse", () => { test("rejects malformed flag entries without throwing", () => { expect(parseAPIFlagsResponse({ flagA: null })).toBeUndefined(); }); + + test("rejects malformed evaluation errors", () => { + expect( + parseAPIFlagsResponse({ + flagA: { + isEnabled: true, + key: "flagA", + targetingVersion: 1, + evaluationErrors: [{ code: "MISSING_CONTEXT_FIELD" }], + }, + }), + ).toBeUndefined(); + }); }); describe("cache", () => { diff --git a/packages/browser-sdk/test/mocks/handlers.ts b/packages/browser-sdk/test/mocks/handlers.ts index 79a202f1..d1d1a08e 100644 --- a/packages/browser-sdk/test/mocks/handlers.ts +++ b/packages/browser-sdk/test/mocks/handlers.ts @@ -14,6 +14,13 @@ export const flagResponse = { config: undefined, ruleEvaluationResults: [false, true], missingContextFields: ["field1", "field2"], + evaluationErrors: [ + { + code: "MISSING_CONTEXT_FIELD", + field: "field1", + message: 'Context field "field1" is required.', + }, + ], }, flagB: { isEnabled: true, @@ -25,6 +32,14 @@ export const flagResponse = { payload: { model: "gpt-something", temperature: 0.5 }, ruleEvaluationResults: [true, false, false], missingContextFields: ["field3"], + evaluationErrors: [ + { + code: "UNSUPPORTED_ARRAY_OPERATOR", + field: "field3", + operator: "IS", + message: 'Operator "IS" does not support array values.', + }, + ], }, }, }, diff --git a/packages/browser-sdk/test/usage.test.ts b/packages/browser-sdk/test/usage.test.ts index b61bf8aa..f80d31cb 100644 --- a/packages/browser-sdk/test/usage.test.ts +++ b/packages/browser-sdk/test/usage.test.ts @@ -498,6 +498,13 @@ describe(`sends "check" events `, () => { version: 1, missingContextFields: ["field1", "field2"], ruleEvaluationResults: [false, true], + evaluationErrors: [ + { + code: "MISSING_CONTEXT_FIELD", + field: "field1", + message: 'Context field "field1" is required.', + }, + ], }, expect.any(Function), ); @@ -529,6 +536,13 @@ describe(`sends "check" events `, () => { evalResult: true, evalRuleResults: [false, true], evalMissingFields: ["field1", "field2"], + evalErrors: [ + { + code: "MISSING_CONTEXT_FIELD", + field: "field1", + message: 'Context field "field1" is required.', + }, + ], }), ]), ); @@ -580,6 +594,14 @@ describe(`sends "check" events `, () => { }, evalRuleResults: [true, false, false], evalMissingFields: ["field3"], + evalErrors: [ + { + code: "UNSUPPORTED_ARRAY_OPERATOR", + field: "field3", + operator: "IS", + message: 'Operator "IS" does not support array values.', + }, + ], }), ]), ); diff --git a/packages/node-sdk/src/client.ts b/packages/node-sdk/src/client.ts index 293ee46d..9ce079e1 100644 --- a/packages/node-sdk/src/client.ts +++ b/packages/node-sdk/src/client.ts @@ -157,6 +157,7 @@ type BulkEvent = evalContext?: Record; evalRuleResults?: boolean[]; evalMissingFields?: string[]; + evalErrors?: EvaluationError[]; } | { type: "event"; @@ -1250,6 +1251,7 @@ export class ReflagClient { * @param event.evalContext - The evaluation context of the flag to send. * @param event.evalRuleResults - The evaluation rule results of the flag to send. * @param event.evalMissingFields - The evaluation missing fields of the flag to send. + * @param event.evalErrors - The non-fatal evaluation diagnostics of the flag to send. * * @throws An error if the event is invalid. * @@ -1290,6 +1292,10 @@ export class ReflagClient { Array.isArray(event.evalMissingFields), "event missing fields must be an array", ); + ok( + event.evalErrors === undefined || Array.isArray(event.evalErrors), + "event evaluation errors must be an array", + ); const contextKey = new URLSearchParams( flattenJSON(event.evalContext || {}), @@ -1322,6 +1328,7 @@ export class ReflagClient { evalResult: event.evalResult, evalRuleResults: event.evalRuleResults, evalMissingFields: event.evalMissingFields, + evalErrors: event.evalErrors, }); } @@ -1596,6 +1603,7 @@ export class ReflagClient { evalContext: context, evalRuleResults: flag.ruleEvaluationResults, evalMissingFields: flag.missingContextFields, + evalErrors: flag.evaluationErrors, }) .catch((err) => { client.logger?.error( @@ -1619,6 +1627,7 @@ export class ReflagClient { evalContext: context, evalRuleResults: config?.ruleEvaluationResults, evalMissingFields: config?.missingContextFields, + evalErrors: config?.evaluationErrors, }) .catch((err) => { client.logger?.error( diff --git a/packages/node-sdk/src/types.ts b/packages/node-sdk/src/types.ts index d7bd0123..13e79928 100644 --- a/packages/node-sdk/src/types.ts +++ b/packages/node-sdk/src/types.ts @@ -60,8 +60,14 @@ export type FlagEvent = { /** * The missing fields in the evaluation context (optional). + * @deprecated Use `evalErrors` and check for `MISSING_CONTEXT_FIELD`. **/ evalMissingFields?: string[]; + + /** + * Non-fatal diagnostics produced while evaluating targeting rules (optional). + **/ + evalErrors?: EvaluationError[]; }; /** diff --git a/packages/node-sdk/test/client.test.ts b/packages/node-sdk/test/client.test.ts index 7a2e0155..90fefdbb 100644 --- a/packages/node-sdk/test/client.test.ts +++ b/packages/node-sdk/test/client.test.ts @@ -1716,10 +1716,34 @@ describe("ReflagClient", () => { evalContext: context, evalRuleResults: [true], evalMissingFields: [], + evalErrors: undefined, }, ]); }); + it("`isEnabled` sends evaluation errors", async () => { + const context = { + company, + user, + other: otherContext, + }; + + await client.initialize(); + expect(client.getFlag(context, "flag2").isEnabled).toBe(false); + await client.flush(); + + const checkEvents = httpClient.post.mock.calls + .flatMap((call) => call[2]) + .filter((item) => item.action === "check"); + + expect(checkEvents).toEqual([ + expect.objectContaining({ + key: "flag2", + evalErrors: [missingContextFieldError("attributeKey")], + }), + ]); + }); + it("`isEnabled` warns about missing context fields", async () => { const context = { company, @@ -1989,6 +2013,7 @@ describe("ReflagClient", () => { evalContext: context, evalRuleResults: [true], evalMissingFields: [], + evalErrors: undefined, }, ]); }); @@ -2023,6 +2048,7 @@ describe("ReflagClient", () => { evalResult: false, evalRuleResults: undefined, evalMissingFields: undefined, + evalErrors: undefined, }, ]); }); diff --git a/packages/react-sdk/src/index.tsx b/packages/react-sdk/src/index.tsx index 31e9bde3..0cd400e4 100644 --- a/packages/react-sdk/src/index.tsx +++ b/packages/react-sdk/src/index.tsx @@ -15,6 +15,7 @@ import { BootstrappedState as BrowserBootstrappedState, CheckEvent, CompanyContext, + EvaluationError, HookArgs, InitOptions, Logger, @@ -39,6 +40,7 @@ const useIsomorphicLayoutEffect = export type { CheckEvent, CompanyContext, + EvaluationError, SetOptInOptions, StorageAdapter, TrackEvent, From 2b018279472ac0579def58feae07de67d7d7d0a7 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Thu, 10 Sep 2026 19:00:46 +0200 Subject: [PATCH 2/4] Keep evaluation error types internal --- packages/browser-sdk/src/index.ts | 1 - packages/react-sdk/src/index.tsx | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/browser-sdk/src/index.ts b/packages/browser-sdk/src/index.ts index 96d90066..34555b0e 100644 --- a/packages/browser-sdk/src/index.ts +++ b/packages/browser-sdk/src/index.ts @@ -39,7 +39,6 @@ export type { } from "./feedback/ui/types"; export type { CheckEvent, - EvaluationError, FallbackFlagOverride, FlagOverrides, OptInFlag, diff --git a/packages/react-sdk/src/index.tsx b/packages/react-sdk/src/index.tsx index 0cd400e4..31e9bde3 100644 --- a/packages/react-sdk/src/index.tsx +++ b/packages/react-sdk/src/index.tsx @@ -15,7 +15,6 @@ import { BootstrappedState as BrowserBootstrappedState, CheckEvent, CompanyContext, - EvaluationError, HookArgs, InitOptions, Logger, @@ -40,7 +39,6 @@ const useIsomorphicLayoutEffect = export type { CheckEvent, CompanyContext, - EvaluationError, SetOptInOptions, StorageAdapter, TrackEvent, From 9b43582fa4c4db743bbbfda86609d26ac42c2a1b Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Thu, 10 Sep 2026 19:23:36 +0200 Subject: [PATCH 3/4] Simplify evaluation diagnostics transport --- packages/browser-sdk/src/bulkQueue.ts | 4 ++-- packages/browser-sdk/src/flag/flagCache.ts | 7 +++--- packages/browser-sdk/src/flag/flags.ts | 11 ++-------- packages/browser-sdk/test/usage.test.ts | 25 +++------------------- packages/node-sdk/src/client.ts | 24 ++------------------- 5 files changed, 13 insertions(+), 58 deletions(-) diff --git a/packages/browser-sdk/src/bulkQueue.ts b/packages/browser-sdk/src/bulkQueue.ts index 2d281ef4..4ce9ff06 100644 --- a/packages/browser-sdk/src/bulkQueue.ts +++ b/packages/browser-sdk/src/bulkQueue.ts @@ -1,5 +1,5 @@ import { BULK_QUEUE_FLUSH_DELAY_MS, BULK_QUEUE_MAX_SIZE } from "./config"; -import type { EvaluationError } from "./flag/flags"; +import type { CheckEvent } from "./flag/flags"; import { Logger } from "./logger"; import { logResponseError } from "./utils/responseError"; @@ -40,7 +40,7 @@ export type BulkEvent = evalContext?: Record; evalRuleResults?: boolean[]; evalMissingFields?: string[]; - evalErrors?: EvaluationError[]; + evalErrors?: CheckEvent["evaluationErrors"]; } | { type: "prompt-event"; diff --git a/packages/browser-sdk/src/flag/flagCache.ts b/packages/browser-sdk/src/flag/flagCache.ts index c1f1f682..442e86b6 100644 --- a/packages/browser-sdk/src/flag/flagCache.ts +++ b/packages/browser-sdk/src/flag/flagCache.ts @@ -1,6 +1,5 @@ import { StorageAdapter } from "../storage"; -import type { EvaluationError } from "./flags"; -import { RawFlagOptIn, RawFlags } from "./flags"; +import { RawFlag, RawFlagOptIn, RawFlags } from "./flags"; import { isValidFlagStateVersion } from "./flagStateVersion"; const DEFAULT_STORAGE_KEY = "__reflag_fetched_flags"; @@ -29,7 +28,9 @@ function parseOptIn(optIn: any): RawFlagOptIn | null | undefined { }; } -function isEvaluationErrorArray(value: any): value is EvaluationError[] { +function isEvaluationErrorArray( + value: any, +): value is NonNullable { return ( Array.isArray(value) && value.every( diff --git a/packages/browser-sdk/src/flag/flags.ts b/packages/browser-sdk/src/flag/flags.ts index 08938104..a9c9f1f2 100644 --- a/packages/browser-sdk/src/flag/flags.ts +++ b/packages/browser-sdk/src/flag/flags.ts @@ -58,7 +58,7 @@ export type OptInFlag = RawFlagOptIn & { /** * A non-fatal diagnostic produced while evaluating targeting rules. */ -export type EvaluationError = { +type EvaluationError = { code: string; field: string; operator?: string; @@ -697,14 +697,7 @@ export class FlagsClient { if (this.enqueueBulkEvent) { this.enqueueBulkEvent({ type: "feature-flag-event", - action: payload.action, - key: payload.key, - targetingVersion: payload.targetingVersion, - evalContext: payload.evalContext, - evalResult: payload.evalResult, - evalRuleResults: payload.evalRuleResults, - evalMissingFields: payload.evalMissingFields, - evalErrors: payload.evalErrors, + ...payload, }).catch((e: any) => { this.logger.warn(`failed to enqueue flag check event`, e); }); diff --git a/packages/browser-sdk/test/usage.test.ts b/packages/browser-sdk/test/usage.test.ts index f80d31cb..b39ac8e9 100644 --- a/packages/browser-sdk/test/usage.test.ts +++ b/packages/browser-sdk/test/usage.test.ts @@ -498,13 +498,7 @@ describe(`sends "check" events `, () => { version: 1, missingContextFields: ["field1", "field2"], ruleEvaluationResults: [false, true], - evaluationErrors: [ - { - code: "MISSING_CONTEXT_FIELD", - field: "field1", - message: 'Context field "field1" is required.', - }, - ], + evaluationErrors: flagsResult.flagA.evaluationErrors, }, expect.any(Function), ); @@ -536,13 +530,7 @@ describe(`sends "check" events `, () => { evalResult: true, evalRuleResults: [false, true], evalMissingFields: ["field1", "field2"], - evalErrors: [ - { - code: "MISSING_CONTEXT_FIELD", - field: "field1", - message: 'Context field "field1" is required.', - }, - ], + evalErrors: flagsResult.flagA.evaluationErrors, }), ]), ); @@ -594,14 +582,7 @@ describe(`sends "check" events `, () => { }, evalRuleResults: [true, false, false], evalMissingFields: ["field3"], - evalErrors: [ - { - code: "UNSUPPORTED_ARRAY_OPERATOR", - field: "field3", - operator: "IS", - message: 'Operator "IS" does not support array values.', - }, - ], + evalErrors: flagsResult.flagB.config?.evaluationErrors, }), ]), ); diff --git a/packages/node-sdk/src/client.ts b/packages/node-sdk/src/client.ts index 9ce079e1..3548a55e 100644 --- a/packages/node-sdk/src/client.ts +++ b/packages/node-sdk/src/client.ts @@ -145,20 +145,7 @@ type BulkEvent = attributes?: Attributes; context?: TrackingMeta; } - | { - type: "feature-flag-event"; - action: "check" | "check-config"; - key: string; - targetingVersion?: number; - evalResult: - | boolean - | { key: string; payload: any } - | { key: undefined; payload: undefined }; - evalContext?: Record; - evalRuleResults?: boolean[]; - evalMissingFields?: string[]; - evalErrors?: EvaluationError[]; - } + | ({ type: "feature-flag-event" } & FlagEvent) | { type: "event"; event: string; @@ -1321,14 +1308,7 @@ export class ReflagClient { await this.batchBuffer.add({ type: "feature-flag-event", - action: event.action, - key: event.key, - targetingVersion: event.targetingVersion, - evalContext: event.evalContext, - evalResult: event.evalResult, - evalRuleResults: event.evalRuleResults, - evalMissingFields: event.evalMissingFields, - evalErrors: event.evalErrors, + ...event, }); } From 21b2fc327724cc3a134964a7b6a791e488a3d48e Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Thu, 10 Sep 2026 20:50:29 +0200 Subject: [PATCH 4/4] Inline private evaluation diagnostic shape --- packages/browser-sdk/src/flag/flags.ts | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/packages/browser-sdk/src/flag/flags.ts b/packages/browser-sdk/src/flag/flags.ts index a9c9f1f2..5809774b 100644 --- a/packages/browser-sdk/src/flag/flags.ts +++ b/packages/browser-sdk/src/flag/flags.ts @@ -55,16 +55,6 @@ export type OptInFlag = RawFlagOptIn & { isEnabled: boolean; }; -/** - * A non-fatal diagnostic produced while evaluating targeting rules. - */ -type EvaluationError = { - code: string; - field: string; - operator?: string; - message: string; -}; - /** * A flag fetched from the server. */ @@ -104,7 +94,12 @@ export type RawFlag = { /** * Non-fatal diagnostics produced while evaluating targeting rules. */ - evaluationErrors?: EvaluationError[]; + evaluationErrors?: Array<{ + code: string; + field: string; + operator?: string; + message: string; + }>; /** * Whether end-user opt-in is enabled for this flag. @@ -149,7 +144,7 @@ export type RawFlag = { /** * Non-fatal diagnostics produced while evaluating targeting rules. */ - evaluationErrors?: EvaluationError[]; + evaluationErrors?: RawFlag["evaluationErrors"]; }; }; @@ -272,7 +267,7 @@ export interface CheckEvent { /** * Non-fatal diagnostics produced while evaluating targeting rules. */ - evaluationErrors?: EvaluationError[]; + evaluationErrors?: RawFlag["evaluationErrors"]; } const storageOverridesKey = `__reflag_overrides`;