chore: Add Node platform abstraction for node-client#1393
Conversation
|
@launchdarkly/js-sdk-common size report |
|
@launchdarkly/js-client-sdk size report |
|
@launchdarkly/js-client-sdk-common size report |
|
@launchdarkly/browser size report |
|
@cursor review |
|
@cursor review |
|
|
||
| encoding?: platform.Encoding = new NodeEncoding(); | ||
|
|
||
| storage?: platform.Storage; |
There was a problem hiding this comment.
I think we should allow for overriding the storage. Similar to what we do in the react-native sdk
There was a problem hiding this comment.
Filed SDK-2420 internally to track. Addressing separately as this will be a new feature for this SDK
e92eaf7 to
1f7be22
Compare
fef5d25 to
8eb2ea3
Compare
25f5b8f to
9bfa020
Compare
| proxyOptions?: LDProxyOptions; | ||
| tlsParams?: LDTLSOptions; | ||
| enableEventCompression?: boolean; | ||
| localStoragePath?: string; |
There was a problem hiding this comment.
We may want something like:
storage: {type: 'file', localStoragePath: string} | {type: 'custom', implementation: NCStorage}
There was a problem hiding this comment.
I'll include this when I add support for overriding (#1393 (comment))
Holistic-branch commit containing the entire migration of the
standalone launchdarkly/node-client-sdk repo into the js-core monorepo
as @launchdarkly/node-client-sdk. Sliced for review into atomic PRs per
the stack manifest at .claude/stacked-pr/plan.json (SDK-2309..SDK-2315).
This commit shrinks as each atomic PR merges to main and the holistic
branch is rebased.
Contents:
- packages/sdk/node-client/ -- the new SDK workspace
- Modern js-core layout: tsup dual ESM/CJS, ts-jest, eslint, typedoc
- tsconfig uses module=ESNext + moduleResolution=bundler (tsup
handles emit), types=[jest, node], skipLibCheck
- src/ ports the legacy SDK onto @launchdarkly/js-client-sdk-common
- Public API: createClient + start (no auto-start), basicLogger,
version, plus export * from common
- Node-specific options: localStoragePath, tlsParams (10-key
whitelist), hash for Secure Mode
- platform/ adapts NodeCrypto/Info/Requests/Response/HeaderWrapper
from packages/sdk/server-node and adds an fs/promises-backed
NodeStorage with the no-throw storage contract. Storage is a
process-level singleton matching the electron pattern, with an
@internal resetNodeStorage exported for tests.
- __tests__/ smoke test
- examples/hello-node-client/ following the EXAM/HELLO spec:
streaming flag-change listener, continuous-run mode with CI
opt-out, ASCII LAUNCHDARKLY banner on true, env-var-driven
credentials and flag key, tsconfig=nodenext for the ESM example
- contract-tests/ with sdk-test-harness service entity. Includes
run-contract-tests.sh for one-command local runs, npm scripts
(contract-tests, contract-test-service), bridging in
sdkClientEntity.ts that maps options.polling -> polling mode,
options.hooks[] -> ClientSideTestHook instances, and disables
the per-process flag cache so tests don't bleed state into each
other. testharness-suppressions.txt suppresses three hook
ordering tests pending an upstream fix in js-contract-test-utils.
- temp_docs/MIGRATION.md describing the v3 -> v4 breaking changes
- .github/workflows/node-client.yml -- CI build/lint/test plus
contract-tests run, mirroring server-node.yml
- Root package.json workspaces, tsconfig.json references, and
release-please-config extra-files wired up;
.release-please-manifest seeded at 0.0.1 (this is treated as a
fresh package; release-please will track from there)
BREAKING CHANGE: Package is renamed from launchdarkly-node-client-sdk to
@launchdarkly/node-client-sdk and rebuilt on the modern
@launchdarkly/js-client-sdk-common (FDv2-capable). Initialization now
uses the createClient + start pattern: createClient returns a client
that is not yet started, and the caller must await client.start()
before the first variation or identify call. identify() now resolves
to LDIdentifyResult instead of throwing. Minimum Node version is now
18. The persistent cache file format changed from node-localstorage's
per-key files to a single JSON file in the same directory; existing
v3 cache data will not be read.
chore: Mark scaffold slice merged (PR #1352)
chore: Mark port-platform slice in-flight (PR #1393)
chore: Replan stack -- add contract-tests-features and storage-override slices
- New `contract-tests-features` slice after `contract-tests` exercising
hooks, identify result statuses, connection-mode switching, and FDv2
init markers + fallback.
- New `storage-override` slice (SDK-2420) after `hello` providing
caller-supplied storage override on NodeOptions.
- per-slice MIGRATION.md updates: port-client owns hooks / inspectors /
plugins / connection-mode / applicationInfo / proxy / TLS sections;
storage-override owns its own section; archive becomes the final
doc-pass.
- Manifest now declares `tool: "sculptor"` so the SessionStart
watch-arm hook activates for future cycles.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
chore: Reconcile holistic with PR #1393 reviewed content + manifest scope-update
- Took PR #1393's reviewed source content as authoritative for the
port-platform-only files: NodeInfo, NodePlatform, NodeRequests,
NodeResponse, NodeStorage. The atomic's post-review versions
(e.g., sdkName = 'node-client-sdk', NodeStorage logger param,
direct getNodeStorage wiring) replace holistic's pre-review state.
Reconciliation follows the same pattern advance uses when rebasing
onto main.
- release-please-config.json reverted to atomic's version (re-adds
src/platform/NodeInfo.ts to extra-files for release-please version
bumping).
- Added atomic's PR-review additions: 10 platform unit tests under
__tests__/platform/, __tests__/testHelpers.ts, and a package-level
.gitignore. All 58 tests pass.
- Manifest port-platform paths expanded to reflect actual ship scope
(unit tests + .gitignore + testHelpers added during review);
contract-tests-features.jira_subtask set to SDK-2422.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
feat: Add storage override on NodeOptions (SDK-2420)
Replaces `localStoragePath` with a discriminated `storage` option:
storage?:
| { type: 'file'; localStoragePath?: string }
| { type: 'custom'; implementation: Storage }
- `undefined` or `{ type: 'file' }` -> file-backed default at
`<cwd>/ldclient-user-cache`.
- `{ type: 'file', localStoragePath: '/path' }` -> file-backed at
the given path.
- `{ type: 'custom', implementation }` -> caller-supplied store.
Re-exports the common `Storage` interface as `LDStorage` so consumers
can type their own implementations without depending on common.
Adds 10 new unit tests; all 68 tests pass. Lint and build are clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
test: Declare common-base capabilities and wire harness commands
Adds capability declarations for the new common-base features that
were missing from node-client's contract-test surface:
- anonymous-redaction
- strongly-typed
- event-gzip
- flag-change-listeners
- tls:skip-verify-peer
- tls:custom-ca
Wires the corresponding config + command handlers in sdkClientEntity:
- makeSdkConfig: TLS options (skipVerifyPeer / customCAFile),
proxy options (httpProxy URL -> proxyOptions), event-gzip
(enableGzip -> enableEventCompression).
- doCommand: RegisterFlagChangeListener (binds client.on('change'),
fans out per-flag POSTs to the callback URI) and UnregisterListener.
Also registers `packages/sdk/node-client/contract-tests` as a yarn
workspace in root package.json so `yarn workspace
@launchdarkly/node-client-sdk-contract-tests build` actually resolves.
This belongs to the contract-tests slice; the manifest has been
updated to claim root package.json with a single-line extraction
note.
The `http-proxy` capability is intentionally left undeclared --
node-client's NodeRequests only routes HTTPS targets through the
proxy (https-proxy-agent), so the harness's HTTP-target proxy
tests fail. Tracked separately as SDK-2423; the line in index.ts
references the follow-up.
Manifest also updated: contract-tests-features slice's paths now
include contract-tests/src/index.ts (capability declarations live
there), and its provides / extraction_notes reflect the revised
scope.
Harness baseline: 841 tests passed, 18 skipped, 0 failed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
docs: Add MIGRATION sections for new common-base features
Adds seven sections documenting feature surfaces that are new in
node-client (relative to the legacy launchdarkly-node-client-sdk)
and that are introduced by the port-client slice:
- Evaluation, identify, and track hooks (Hook type + addHook method)
- Inspectors (with deprecation note pointing to hooks)
- Plugins and application metadata (LDPlugin + applicationInfo)
- Runtime connection-mode control (setConnectionMode / getConnectionMode)
- HTTP proxy options (proxyOptions, with note on HTTPS-target-only)
- TLS configuration (tlsParams; fields mirror Node's https.request)
- (Storage configuration already documented as part of SDK-2420)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Holistic-branch commit containing the entire migration of the
standalone launchdarkly/node-client-sdk repo into the js-core monorepo
as @launchdarkly/node-client-sdk. Sliced for review into atomic PRs per
the stack manifest at .claude/stacked-pr/plan.json (SDK-2309..SDK-2315).
This commit shrinks as each atomic PR merges to main and the holistic
branch is rebased.
Contents:
- packages/sdk/node-client/ -- the new SDK workspace
- Modern js-core layout: tsup dual ESM/CJS, ts-jest, eslint, typedoc
- tsconfig uses module=ESNext + moduleResolution=bundler (tsup
handles emit), types=[jest, node], skipLibCheck
- src/ ports the legacy SDK onto @launchdarkly/js-client-sdk-common
- Public API: createClient + start (no auto-start), basicLogger,
version, plus export * from common
- Node-specific options: localStoragePath, tlsParams (10-key
whitelist), hash for Secure Mode
- platform/ adapts NodeCrypto/Info/Requests/Response/HeaderWrapper
from packages/sdk/server-node and adds an fs/promises-backed
NodeStorage with the no-throw storage contract. Storage is a
process-level singleton matching the electron pattern, with an
@internal resetNodeStorage exported for tests.
- __tests__/ smoke test
- examples/hello-node-client/ following the EXAM/HELLO spec:
streaming flag-change listener, continuous-run mode with CI
opt-out, ASCII LAUNCHDARKLY banner on true, env-var-driven
credentials and flag key, tsconfig=nodenext for the ESM example
- contract-tests/ with sdk-test-harness service entity. Includes
run-contract-tests.sh for one-command local runs, npm scripts
(contract-tests, contract-test-service), bridging in
sdkClientEntity.ts that maps options.polling -> polling mode,
options.hooks[] -> ClientSideTestHook instances, and disables
the per-process flag cache so tests don't bleed state into each
other. testharness-suppressions.txt suppresses three hook
ordering tests pending an upstream fix in js-contract-test-utils.
- temp_docs/MIGRATION.md describing the v3 -> v4 breaking changes
- .github/workflows/node-client.yml -- CI build/lint/test plus
contract-tests run, mirroring server-node.yml
- Root package.json workspaces, tsconfig.json references, and
release-please-config extra-files wired up;
.release-please-manifest seeded at 0.0.1 (this is treated as a
fresh package; release-please will track from there)
BREAKING CHANGE: Package is renamed from launchdarkly-node-client-sdk to
@launchdarkly/node-client-sdk and rebuilt on the modern
@launchdarkly/js-client-sdk-common (FDv2-capable). Initialization now
uses the createClient + start pattern: createClient returns a client
that is not yet started, and the caller must await client.start()
before the first variation or identify call. identify() now resolves
to LDIdentifyResult instead of throwing. Minimum Node version is now
18. The persistent cache file format changed from node-localstorage's
per-key files to a single JSON file in the same directory; existing
v3 cache data will not be read.
chore: Mark scaffold slice merged (PR #1352)
chore: Mark port-platform slice in-flight (PR #1393)
chore: Replan stack -- add contract-tests-features and storage-override slices
- New `contract-tests-features` slice after `contract-tests` exercising
hooks, identify result statuses, connection-mode switching, and FDv2
init markers + fallback.
- New `storage-override` slice (SDK-2420) after `hello` providing
caller-supplied storage override on NodeOptions.
- per-slice MIGRATION.md updates: port-client owns hooks / inspectors /
plugins / connection-mode / applicationInfo / proxy / TLS sections;
storage-override owns its own section; archive becomes the final
doc-pass.
- Manifest now declares `tool: "sculptor"` so the SessionStart
watch-arm hook activates for future cycles.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
chore: Reconcile holistic with PR #1393 reviewed content + manifest scope-update
- Took PR #1393's reviewed source content as authoritative for the
port-platform-only files: NodeInfo, NodePlatform, NodeRequests,
NodeResponse, NodeStorage. The atomic's post-review versions
(e.g., sdkName = 'node-client-sdk', NodeStorage logger param,
direct getNodeStorage wiring) replace holistic's pre-review state.
Reconciliation follows the same pattern advance uses when rebasing
onto main.
- release-please-config.json reverted to atomic's version (re-adds
src/platform/NodeInfo.ts to extra-files for release-please version
bumping).
- Added atomic's PR-review additions: 10 platform unit tests under
__tests__/platform/, __tests__/testHelpers.ts, and a package-level
.gitignore. All 58 tests pass.
- Manifest port-platform paths expanded to reflect actual ship scope
(unit tests + .gitignore + testHelpers added during review);
contract-tests-features.jira_subtask set to SDK-2422.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
feat: Add storage override on NodeOptions (SDK-2420)
Replaces `localStoragePath` with a discriminated `storage` option:
storage?:
| { type: 'file'; localStoragePath?: string }
| { type: 'custom'; implementation: Storage }
- `undefined` or `{ type: 'file' }` -> file-backed default at
`<cwd>/ldclient-user-cache`.
- `{ type: 'file', localStoragePath: '/path' }` -> file-backed at
the given path.
- `{ type: 'custom', implementation }` -> caller-supplied store.
Re-exports the common `Storage` interface as `LDStorage` so consumers
can type their own implementations without depending on common.
Adds 10 new unit tests; all 68 tests pass. Lint and build are clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
test: Declare common-base capabilities and wire harness commands
Adds capability declarations for the new common-base features that
were missing from node-client's contract-test surface:
- anonymous-redaction
- strongly-typed
- event-gzip
- flag-change-listeners
- tls:skip-verify-peer
- tls:custom-ca
Wires the corresponding config + command handlers in sdkClientEntity:
- makeSdkConfig: TLS options (skipVerifyPeer / customCAFile),
proxy options (httpProxy URL -> proxyOptions), event-gzip
(enableGzip -> enableEventCompression).
- doCommand: RegisterFlagChangeListener (binds client.on('change'),
fans out per-flag POSTs to the callback URI) and UnregisterListener.
Also registers `packages/sdk/node-client/contract-tests` as a yarn
workspace in root package.json so `yarn workspace
@launchdarkly/node-client-sdk-contract-tests build` actually resolves.
This belongs to the contract-tests slice; the manifest has been
updated to claim root package.json with a single-line extraction
note.
The `http-proxy` capability is intentionally left undeclared --
node-client's NodeRequests only routes HTTPS targets through the
proxy (https-proxy-agent), so the harness's HTTP-target proxy
tests fail. Tracked separately as SDK-2423; the line in index.ts
references the follow-up.
Manifest also updated: contract-tests-features slice's paths now
include contract-tests/src/index.ts (capability declarations live
there), and its provides / extraction_notes reflect the revised
scope.
Harness baseline: 841 tests passed, 18 skipped, 0 failed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
docs: Add MIGRATION sections for new common-base features
Adds seven sections documenting feature surfaces that are new in
node-client (relative to the legacy launchdarkly-node-client-sdk)
and that are introduced by the port-client slice:
- Evaluation, identify, and track hooks (Hook type + addHook method)
- Inspectors (with deprecation note pointing to hooks)
- Plugins and application metadata (LDPlugin + applicationInfo)
- Runtime connection-mode control (setConnectionMode / getConnectionMode)
- HTTP proxy options (proxyOptions, with note on HTTPS-target-only)
- TLS configuration (tlsParams; fields mirror Node's https.request)
- (Storage configuration already documented as part of SDK-2420)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
9a720a6 to
eb89832
Compare
Hardens the Node platform layer landed in #1393, ahead of the client-side SDK implementation that builds on it. First atomic in the node-client port stack. - **NodeStorage**: log (no longer swallow) flush errors; validate/log on malformed cache reads and ignore non-string cache values; write the temp file via an exclusive `wx` open so the write cannot be redirected through a symlink; warn when `getNodeStorage` is called with a `localStoragePath` that differs from the process singleton's. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes on-disk cache semantics and filesystem write behavior; low blast radius but incorrect handling could affect flag persistence or local file security. > > **Overview** > Hardens the Node client **platform** layer around flag disk cache and tightens related tests. > > **`NodeStorage`** now treats a missing cache file as a normal first run (no warning, no empty rewrite). Malformed or unreadable cache files trigger a **warn** and recovery write; loaded JSON must be a plain object and only **string** values are kept. Persists via an exclusive **`wx`** temp open (after removing any existing temp path) so writes cannot follow a symlink planted on the temp file path. **`getNodeStorage`** records the first `localStoragePath` and **warns** if a later call passes a different path; **`resetNodeStorage`** clears that path tracking too. > > **Tests** cover first-run behavior, malformed JSON warnings, non-string cache entries, symlink safety, singleton path mismatch warnings, and **`NodeInfo`** no longer pins the SDK **version** string in expectations. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1962f54. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
Summary
@launchdarkly/node-client-sdk:HeaderWrapper,NodeCrypto,NodeEncoding,NodeInfo,NodePlatform,NodeRequests,NodeResponse,NodeStorage. These implement thePlatformcontract from@launchdarkly/js-client-sdk-common.@launchdarkly/js-client-sdk-common,https-proxy-agent,launchdarkly-eventsource.packages/sdk/node-client/tsconfig.jsontomodule: ESNext+moduleResolution: bundler(tsup handles emit), addsesModuleInterop,types: ["jest", "node"],skipLibCheck. Matches the pattern used bypackages/sdk/server-ai.launchdarkly-node-client-sdkinto js-core. Follows PR chore: scaffolding node-client-sdk migration #1352 (scaffold).Note
Medium Risk
New TLS, HTTP streaming, and on-disk cache behavior affect runtime networking and local persistence, though it is isolated behind platform interfaces and covered by unit tests; the public client API is not wired yet.
Overview
Adds the Node platform layer for
@launchdarkly/node-client-sdkso the package can plug into@launchdarkly/js-client-sdk-common:NodePlatformwires info, crypto, encoding, file-backed storage, and HTTP/HTTPS + EventSource requests. NewNodeOptionscovers TLS (tlsParams), optional POST gzip for events, andlocalStoragePath(defaultldclient-user-cache).NodeRequests/NodeResponseimplement fetch-like behavior (timeouts, gzip on GET, optional body compression, custom CA for HTTPS) vialaunchdarkly-eventsource.NodeStoragepersists a JSON cache with atomic writes and a process singleton.Also adds Jest coverage for the platform modules, a
sdk/node-clientGitHub Actions job (Node 18 & 22), package test script and dependencies, tsconfig shift toESNext/bundler, and release-please bumpingNodeInfo.tsfor version stamps.Reviewed by Cursor Bugbot for commit eb89832. Bugbot is set up for automated code reviews on this repo. Configure here.