Skip to content

feat(node-sdk): adopt collection values and Boolean-first reads - #790

Open
roncohen wants to merge 13 commits into
mainfrom
feature/node-sdk-v2
Open

roncohen wants to merge 13 commits into
mainfrom
feature/node-sdk-v2

Conversation

@roncohen

@roncohen roncohen commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Breaking Node SDK v2, stacked on #744's complete-collection evaluator. Companion server protocol/check ingestion: https://github.com/reflagcom/web/pull/3660.

reflag.getFlag(context, "release"); // boolean, implicit false
reflag.getFlag(context, "settings", { model: "Swift" }); // { model: string }
reflag.bindClient(context).getFlag("release");
  • Consume and atomically prepare complete protocol-v2 { flags, segments } snapshots. Evaluate only requested roots/dependencies, without dependency-result caching.
  • Return direct values, with Boolean-first reads and positional defaults that work without generated declarations. Preserve valid falsy values; non-null defaults enforce top-level JSON categories, not nested schemas. Explicit null accepts arbitrary/nullable JSON.
  • Register checks for requested roots immediately, with buffered, identity-aware delivery. Preserve genuine variant/source/snapshot identity; do not fabricate authored selections for caller defaults, category mismatches, overrides, or static values. Dependencies and bootstrap serialization do not emit extra checks.
  • Persist complete, isolated version-2 fallback snapshots, retain known-good state, serialize live saves, and preserve genuine restored selection metadata.
  • Preserve synchronization modes, context binding, ordinary usage tracking, and post-evaluation overrides.
  • Update the Express example and keep the existing OpenFeature provider and React bootstrap demo explicitly pinned to published Node SDK v1 until their separate migration.
  • Consolidate tests around distinct failure modes rather than repeating every value/getter combination. No React-specific Suspense behavior or reserved payload keys in Node.

Breaking changes

  • No flag wrappers: remove .value, .isEnabled, .config, and flag .track() access. Ordinary client tracking remains separate.
  • Bare singular reads are Boolean with implicit false. Supply positional defaults for other types; batch APIs retain raw JSON/undefined records.
  • Singular remote signature is getFlagRemote(key, defaultValue, userId?, companyId?, context?); old positional IDs move one position right. Use undefined for a Boolean read with explicit IDs.
  • V1 fallback and browser bootstrap formats are incompatible with v2; legacy CLI wrapper declarations are not a v2 value schema.

Verification

  • 219 Node SDK tests, including separate generated/ungenerated type-contract programs.
  • 301 evaluator tests and 28 published-v1-isolated OpenFeature tests.
  • Three ordinary Express example tests; SDK/test and example typechecks.
  • SDK/evaluator/OpenFeature package builds, Node lint, scoped formatting, diff checks, immutable install, and changeset release-plan checks.
  • Full JavaScript workspace build was not rerun; its previously observed unrelated Management SDK generation gate requires Java.

Scope and rollout

The machine-specific LAN demo and its script remain outside this PR. Browser/React/Vue v2 work will be a separate stacked PR. No package publication or shared deployment is included. Compatible server deployment and transactional saved-snapshot rebuild remain release gates. This PR intentionally targets feature/multivariate-evaluator-v2, not main; #744 must land first.

Copilot AI balanced review requested due to automatic review settings November 4, 2026 08:18

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.

🟡 Changes recommended

Valid fractional allocations are rejected, potentially blocking all flag refreshes, while bound clients lose context synchronization and can drop company associations from events.

3 open issues
What changed in this PR

Migrates the Node SDK to the collection evaluator introduced in #744, adding a breaking v2 direct-value API while keeping existing OpenFeature and React bootstrap consumers on published v1.

Changes:

  • Introduces Boolean-first reads, positional defaults, and immediate, identity-aware check registration.
  • Validates complete flag/segment collections and persists isolated v2 fallback snapshots with ordered saves.
  • Updates documentation, type contracts, tests, and the Express example; pins unmigrated consumers to v1.
File Description
yarn.lock Resolves the v2 evaluator and published v1 SDK alias.
packages/​react-sdk/​dev/​nextjs-bootstrap-demo/​package.json Pins the demo to published Node SDK v1.
packages/​react-sdk/​dev/​nextjs-bootstrap-demo/​app/​client.ts Imports the v1 SDK alias.
packages/​openfeature-node-provider/​src/​index.ts Uses the v1 SDK alias.
packages/​openfeature-node-provider/​src/​index.test.ts Updates imports and mocks for the alias.
packages/​openfeature-node-provider/​package.json Pins the provider to published Node SDK v1.
packages/​node-sdk/​type-tests/​defaults.ts Tests default-based inference without declarations.
packages/​node-sdk/​type-tests/​augmented-defaults.ts Tests augmented keys and Boolean-first contracts.
packages/​node-sdk/​tsconfig.type-tests.json Isolates unaugmented type-contract checks.
packages/​node-sdk/​tsconfig.type-tests-augmented.json Isolates augmented type-contract checks.
packages/​node-sdk/​tsconfig.test.json Configures SDK and selected test typechecking.
packages/​node-sdk/​test/​flagsFallbackProvider.test.ts Covers v2 snapshots and storage namespaces.
packages/​node-sdk/​test/​flag-definitions.test.ts Tests collection validation and ownership.
packages/​node-sdk/​test/​fixtures.ts Adds shared v2 collection fixtures.
packages/​node-sdk/​test/​client-sync.test.ts Covers synchronization modes and option validation.
packages/​node-sdk/​src/​types.ts Defines direct values and v2 protocol contracts.
packages/​node-sdk/​src/​index.ts Updates public type exports.
packages/​node-sdk/​src/​flagsFallbackProvider.ts Adds v2 fallback envelopes and namespaces.
packages/​node-sdk/​src/​flags-cache.ts Stores complete collections and exposes an apply callback.
packages/​node-sdk/​src/​flag-definitions.ts Validates and prepares complete collections.
packages/​node-sdk/​src/​flag-defaults.ts Implements default validation and category matching.
packages/​node-sdk/​src/​config.ts Accepts direct JSON overrides.
packages/​node-sdk/​src/​client.ts Implements v2 reads, checks, bootstrap, and persistence.
packages/​node-sdk/​README.md Documents v2 usage and migration boundaries.
packages/​node-sdk/​package.json Sets the v2 prerelease and evaluator dependency.
packages/​node-sdk/​examples/​express/​reflag.ts Migrates declarations and overrides to direct values.
packages/​node-sdk/​examples/​express/​app.ts Uses direct reads and separate usage tracking.
packages/​flag-evaluation/​test/​release.test.ts Checks v2 adoption and v1 consumer isolation.
.changeset/​pin-legacy-node-evaluator.md Removes the superseded evaluator-pinning changeset.
.changeset/​node-sdk-collection-values.md Records breaking SDK changes and provider isolation.

Review effort: Balanced

Comment on lines +110 to +124
value.allocations.every(
(a: unknown) =>
isObject(a) &&
Number.isInteger(a.percentage) &&
a.percentage >= 0 &&
a.percentage <= 100 &&
isObject(a.destination) &&
(a.destination.type === "nextRule" ||
(a.destination.type === "variant" &&
isResult(a.destination, variants))),
) &&
value.allocations.reduce(
(sum: number, a: { percentage: number }) => sum + a.percentage,
0,
) === 100

checkContextWithTracking(this._options);
void this._client["syncContext"](this._options);
checkContext(options);
Comment on lines +946 to +947
companyId: this.company?.id,
...options,
Base automatically changed from feature/multivariate-evaluator-v2 to main November 4, 2026 18:40
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