From 984877db1b1f4ccb698b597120c78ecdc1a4e91d Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Sun, 19 Apr 2026 13:46:18 +0200 Subject: [PATCH 1/2] fix(node-sdk): accept static fallback snapshots --- .../node-sdk/src/flagsFallbackProvider.ts | 2 +- packages/node-sdk/test/client.test.ts | 38 ++++++++++++++++++- .../test/flagsFallbackProvider.test.ts | 2 +- 3 files changed, 39 insertions(+), 3 deletions(-) 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: [ { From 543df11876c4c87f2ef98cd65c2e561231e8dcd2 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Sun, 19 Apr 2026 13:59:18 +0200 Subject: [PATCH 2/2] chore(changeset): add node-sdk release note --- .changeset/node-sdk-static-fallback-provider.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/node-sdk-static-fallback-provider.md 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.