Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/node-sdk-push-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@reflag/node-sdk": minor
---

Change the default `flagsSyncMode` from `"polling"` to `"push"`.

New `ReflagClient` instances now subscribe to live SSE flag updates by default unless `flagsSyncMode` is set explicitly. The deprecated `cacheStrategy` option still maps `"periodically-update"` to `"polling"` and `"in-request"` to `"in-request"`.
5 changes: 5 additions & 0 deletions .changeset/openfeature-node-provider-push-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@reflag/openfeature-node-provider": minor
---

Updated to `@reflag/node-sdk` `1.6.0`, which defaults to `flagsSyncMode="push"`.
Comment thread
roncohen marked this conversation as resolved.
10 changes: 5 additions & 5 deletions packages/node-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ and downloads the flags with their targeting rules.
These rules are then matched against the user/company information you provide
to `getFlags()` (or through `bindClient(..).getFlags()`). That means the
`getFlags()` call does not need to contact the Reflag servers once
`initialize()` has completed. By default, `ReflagClient` will continue to
refresh the targeting rules from the Reflag servers in the background. You can
change this behavior with `flagsSyncMode` to use request-driven refreshes or
push-based updates instead.
`initialize()` has completed. By default, `ReflagClient` uses
`flagsSyncMode: "push"`, which keeps targeting rules up to date via live SSE
updates. You can switch `flagsSyncMode` to `polling` for periodic background
refreshes or `in-request` for request-driven refreshes instead.

### Batch Operations

Expand Down Expand Up @@ -569,7 +569,7 @@ current working directory.
| `apiBaseUrl` | string | The base API URL for the Reflag servers. | REFLAG_API_BASE_URL |
| `flagOverrides` | Record<string, boolean> | An object specifying flag overrides for testing or local development. See [examples/express/app.test.ts](https://github.com/reflagcom/javascript/tree/main/packages/node-sdk/examples/express/app.test.ts) for how to use `flagOverrides` in tests. | REFLAG_FLAGS_ENABLED, REFLAG_FLAGS_DISABLED |
| `flagsFallbackProvider` | `FlagsFallbackProvider` | Optional provider used to load and save raw flag definitions for fallback startup when the initial live fetch fails. Available only through the constructor. Ignored in offline mode. | - |
| `flagsSyncMode` | `"polling" \| "in-request" \| "push"` | Flag-definition sync mode. `polling` uses periodic background refresh, `in-request` refreshes stale flags during request handling, and `push` subscribes to live updates. Default: `"polling"`. | - |
| `flagsSyncMode` | `"polling" \| "in-request" \| "push"` | Flag-definition sync mode. `push` subscribes to live updates, `polling` uses periodic background refresh, and `in-request` refreshes stale flags during request handling. Default: `"push"`. | - |
| `flagsPushUrl` | string | Push endpoint used when `flagsSyncMode: "push"`. Default: `https://pubsub.reflag.com/sse`. | - |
| `configFile` | string | Load this config file from disk. Default: `reflag.config.json` | REFLAG_CONFIG_FILE |

Expand Down
1 change: 0 additions & 1 deletion packages/node-sdk/examples/express/reflag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,4 @@ export default new ReflagClient({
// Optional: Set a logger to log debug information, errors, etc.
// logger: console,
flagOverrides, // Optional: Set flag overrides
flagsSyncMode: "push",
});
8 changes: 6 additions & 2 deletions packages/node-sdk/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ export class ReflagClient {
* @param options.configFile - The path to the config file (optional).
* @param options.flagsFetchRetries - Number of retries for fetching flags (optional, defaults to 3).
* @param options.fetchTimeoutMs - Timeout for fetching flags (optional, defaults to 10000ms).
* @param options.flagsSyncMode - How flag definitions are synchronized (optional, defaults to "polling").
* @param options.flagsSyncMode - How flag definitions are synchronized (optional, defaults to "push").
*
* @throws An error if the options are invalid.
**/
Expand Down Expand Up @@ -462,7 +462,11 @@ export class ReflagClient {

const flagsSyncMode: FlagsSyncMode =
options.flagsSyncMode ??
(options.cacheStrategy === "in-request" ? "in-request" : "polling");
(options.cacheStrategy === "in-request"
? "in-request"
: options.cacheStrategy === "periodically-update"
? "polling"
: "push");
Comment thread
roncohen marked this conversation as resolved.

const secretKeyHash = config.secretKey ? hashString(config.secretKey) : "";
const secretKeyHashPrefix = secretKeyHash.slice(0, 16);
Expand Down
4 changes: 2 additions & 2 deletions packages/node-sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,9 +709,9 @@ export type ClientOptions = {
/**
* How flag definitions are synchronized.
*
* - `polling` (default): periodic background refresh.
* - `push` (default): live updates over SSE keep flag definitions up to date.
* - `polling`: periodic background refresh.
* - `in-request`: stale refresh is triggered during request handling.
* - `push`: live updates over SSE keep flag definitions up to date.
*/
flagsSyncMode?: FlagsSyncMode;

Expand Down
19 changes: 19 additions & 0 deletions packages/node-sdk/test/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const validOptions: ClientOptions = {
intervalMs: 10001,
flushOnExit: false,
},
flagsSyncMode: "polling",
offline: false,
};

Expand Down Expand Up @@ -314,6 +315,10 @@ describe("ReflagClient", () => {

expect(client["_config"].apiBaseUrl).toBe(API_BASE_URL);
expect(client["_config"].refetchInterval).toBe(FLAGS_REFETCH_MS);
expect(client["_config"].flagsSyncMode).toBe("push");
expect(client["_config"].flagsPushUrl).toBe(
"https://pubsub.reflag.com/sse?channels=flags-state%3A165d2650f1975f7f",
);
expect(client.httpClient).toBe(fetchClient);
expect(client["_config"].headers).toEqual(expectedHeaders);
expect(client["_config"].fallbackFlags).toBeUndefined();
Expand All @@ -323,6 +328,20 @@ describe("ReflagClient", () => {
});
});

it("should map deprecated cacheStrategy values to sync modes", () => {
const inRequestClient = new ReflagClient({
secretKey: "validSecretKeyWithMoreThan22Chars",
cacheStrategy: "in-request",
});
const pollingClient = new ReflagClient({
secretKey: "validSecretKeyWithMoreThan22Chars",
cacheStrategy: "periodically-update",
});

expect(inRequestClient["_config"].flagsSyncMode).toBe("in-request");
expect(pollingClient["_config"].flagsSyncMode).toBe("polling");
});

it("should throw an error if options are invalid", () => {
let invalidOptions: any = null;
expect(() => new ReflagClient(invalidOptions)).toThrow(
Expand Down
Loading