Skip to content

feat(node-sdk): revalidate flag definitions with ETags - #760

Open
roncohen wants to merge 8 commits into
mainfrom
feat/node-sdk-etag
Open

roncohen wants to merge 8 commits into
mainfrom
feat/node-sdk-etag

Conversation

@roncohen

@roncohen roncohen commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Reduce bandwidth on warm /features refreshes using the origin's existing ETag support, without adding an HTTP cache or a new dependency.

  • Store accepted compiled definitions, version, and optional string ETag together as one snapshot. Late fallback saves update only their original snapshot, naturally isolating replacements and destruction without promise-valued cache fields or stale-result guards.
  • Discard older responses before writing fallback storage. Serialize each client's background saves with one promise chain so an older write cannot overwrite a newer snapshot. Keep flag availability independent of storage latency and enable conditional refreshes only after persistence succeeds. Failed/pending saves leave ordinary refreshes unconditional, naturally retrying persistence without a separate retry loop or delaying live flag availability.
  • Send If-None-Match on ordinary refreshes. Treat a bodyless 304 as successful revalidation: retain definitions/evaluators/version and reset freshness, without recompiling or saving a fallback snapshot.
  • Expose only optional HttpClientResponse.etag metadata; existing custom clients without an ETag continue using full GETs. The default transport reads response.headers.get("etag") directly, with no full header copy or case-insensitive record scan. It preserves ok: false on 304 and does not parse its empty body.
  • Keep cold/fallback initialization and waitForVersion requests unconditional. Recover once from an unexpected unconditional 304, preserve validators after failed/rejected refreshes, and clear them on replacement without an ETag or destruction.
  • Simplify refresh bookkeeping to one queued request, publish validators directly from asynchronous persistence, and use one response-returning GET helper without a body-copying adapter.
  • Add SDK documentation and a patch changeset.

Coverage

Regression tests cover 200 → repeated 304 → changed 200, default and custom HTTP clients, exact weak ETags, empty definitions, missing ETags, malformed/older/error responses, per-client isolation, fallback startup, bounded unexpected-304 recovery, version-targeted refreshes, a pending newer version during revalidation, polling, edge/request-driven TTL, and push reconnects. Includes a real loopback HTTP conditional GET test, transient fallback-save recovery, nonblocking pending saves, and guards against late saves modifying a newer or destroyed cache. Also covers v2 → rejected v1 → 304 without overwriting the v2 fallback snapshot, late saves completing after snapshot replacement/destruction, independent validators when snapshots share a definitions array, preservation of pending version targets when a plain refresh arrives, only one unexpected-304 recovery across ordinary retries, and ordered background persistence when an older save is delayed or fails, with subsequent 304s retaining the latest stored flags.

Validation

  • Node SDK: 265 tests passed across 12 files.
  • Latest SDK TypeScript build passed with --skipLibCheck; the full local build process was terminated before completion.
  • Node SDK lint and formatting checks passed; git diff --check passed.
  • All prior commits, including the additional simplification pass, passed full repository CI. The ordered-background-save fix will be validated again by CI.

Local tooling caveat: yarn install --immutable timed out during dependency fetching, so local checks use the existing installed toolchain (Node 24.14.0 / Vitest 3.2.6). The initial OpenFeature provider checks hit a Vitest 3 constructor-mock incompatibility also reproduced on the unchanged original branch; full CI subsequently passed with the locked toolchain. No provider code or dependency versions are changed here.

Scope

No server changes or new configuration are required. This avoids unchanged warm-refresh bodies, not origin requests or full downloads for cold processes/Worker isolates. Version-wait semantics remain unchanged.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 10:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 11:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 11:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 11:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 12:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 12:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 13:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 16:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants