diff --git a/.changeset/node-sdk-static-fallback-provider.md b/.changeset/node-sdk-static-fallback-provider.md new file mode 100644 index 00000000..b4580784 --- /dev/null +++ b/.changeset/node-sdk-static-fallback-provider.md @@ -0,0 +1,5 @@ +--- +"@reflag/node-sdk": patch +--- + +Fix `fallbackProviders.static()` so it returns a valid fallback snapshot that `ReflagClient` accepts during fallback initialization. diff --git a/packages/node-sdk/src/flagsFallbackProvider.ts b/packages/node-sdk/src/flagsFallbackProvider.ts index d373d1f1..5caeb900 100644 --- a/packages/node-sdk/src/flagsFallbackProvider.ts +++ b/packages/node-sdk/src/flagsFallbackProvider.ts @@ -371,7 +371,7 @@ export function createStaticFallbackProvider({ return { async load() { return { - version: 0, + version: 1, savedAt: new Date().toISOString(), flags: Object.entries(flags).map(([key, isEnabled]) => staticFlagApiResponse(key, isEnabled), diff --git a/packages/node-sdk/test/client.test.ts b/packages/node-sdk/test/client.test.ts index e2cf65cb..e3570145 100644 --- a/packages/node-sdk/test/client.test.ts +++ b/packages/node-sdk/test/client.test.ts @@ -10,7 +10,7 @@ import { vi, } from "vitest"; -import { BoundReflagClient, ReflagClient } from "../src"; +import { BoundReflagClient, fallbackProviders, ReflagClient } from "../src"; import { API_BASE_URL, API_TIMEOUT_MS, @@ -1194,6 +1194,42 @@ describe("ReflagClient", () => { } }); + it("should load static fallback flag definitions when live fetch fails", async () => { + httpClient.get.mockResolvedValue({ success: false }); + + const client = new ReflagClient({ + ...validOptions, + flagsFallbackProvider: fallbackProviders.static({ + flags: { + huddle: true, + "smart-summaries": false, + }, + }), + flagsFetchRetries: 0, + }); + + await client.initialize(); + + expect(client.getFlag({}, "huddle")).toStrictEqual({ + key: "huddle", + isEnabled: true, + config: { + key: undefined, + payload: undefined, + }, + track: expect.any(Function), + }); + expect(client.getFlag({}, "smart-summaries")).toStrictEqual({ + key: "smart-summaries", + isEnabled: false, + config: { + key: undefined, + payload: undefined, + }, + track: expect.any(Function), + }); + }); + it("should log remote flag fetch failures at debug level when using fallback definitions", async () => { const error = new Error("fetch failed"); const savedAt = "2026-03-09T00:00:00.000Z"; diff --git a/packages/node-sdk/test/flagsFallbackProvider.test.ts b/packages/node-sdk/test/flagsFallbackProvider.test.ts index f94429ff..c3d4382f 100644 --- a/packages/node-sdk/test/flagsFallbackProvider.test.ts +++ b/packages/node-sdk/test/flagsFallbackProvider.test.ts @@ -46,7 +46,7 @@ describe("flagsFallbackProvider", () => { }); await expect(provider.load(context)).resolves.toEqual({ - version: 0, + version: 1, savedAt: expect.any(String), flags: [ {