Skip to content

Commit e570f76

Browse files
rochdevclaude
authored andcommitted
feat(openfeature): vendor the flagging provider instead of an optional peer dependency (#9570)
* feat(openfeature): return a ready provider from the openfeature entrypoint dd-trace/openfeature previously only existed as a side-effect require for file tracers (#9324). Turn it into the real public entrypoint: it now returns a usable FlaggingProvider instance after tracer.init(), and tracer.openfeature is deprecated in its favor since it doesn't work in bundled applications. Extract the base provider class into a factory so it can be constructed from either the bundler-opaque require-provider wrapper (legacy tracer.openfeature) or a plain require (the new entrypoint) without duplicating the class body. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * test(openfeature): raise nft trace timeout for the entrypoint test openfeature.js now pulls in the full tracer package to check tracer.init() state, so nodeFileTrace has a much larger dependency tree to walk. The default 5s mocha timeout was tight enough that CI runners under load exceeded it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * feat(openfeature): vendor the flagging provider instead of an optional peer `@datadog/openfeature-node-server` was an optional peer dependency resolved through a bundler-opaque require, requiring dedicated esbuild/webpack plugin code to keep the require invisible when the peer wasn't installed (#8635) and to inline it so bundles survived relocation when it was (#8980). Vendoring the provider into `vendor/dist/` removes the need for a peer at all, so all of that machinery (`feature-registry.js`, `register.js`, `require-provider.js`, the optional-peer esbuild/webpack loaders, and their integration tests) is deleted in favor of a single lazy `tracer.openfeature` property. The vendored provider's only remaining external dependency is `@openfeature/server-sdk`, used solely for `OpenFeatureEventEmitter` and `ProviderEvents`. Bundling our own copy would give those a different identity than the customer's, so it's externalized to a small bridge module (`server-sdk-bridge.js`) that a new `openfeature-server-sdk` instrumentation fills in from the customer's own `require()`. `FlaggingProvider#initialize` also unrefs the vendored provider's initialization timer, which otherwise keeps an idle process (a short script, a serverless handler) alive for up to `initializationTimeoutMs` while waiting for configuration to arrive. TODO left to remove this once `@datadog/openfeature-node-server` unrefs it upstream. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(build): exclude unresolved peer entries from license check scripts/check_licenses.js treated every non-dev entry in vendor/package-lock.json as requiring license attribution, including `peer: true` entries. Those record an unresolved peer dependency range that npm never actually installs, so nothing is shipped for them. The official dd-license-attribution tool used in CI already excludes these, so the local script disagreed with CI and had two extraneous rows (@openfeature/core, @openfeature/server-sdk) added to satisfy it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * test(licenses): stop expecting npm peer dependencies to need attribution The prior fix's comment claimed npm never installs peer entries, which is false under npm 7+ auto-install-peers - vendor/node_modules physically has @openfeature/core and @openfeature/server-sdk installed. The real reason they don't need attribution is that peer dependencies are supplied by the consumer rather than shipped by this package, matching how the yarn.lock walk already excludes peerDependencies. The pre-existing vendor-peer test fixture assumed the opposite and was never validated against real CI behavior for a peer case, so it broke once the npm-lock scan started excluding peers too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(openfeature): implement full ProviderEventEmitter contract in the deferred bridge emitter @openfeature/core's transferListeners always calls oldProvider.events?.removeHandler(...) on every subsequent OpenFeature.setProvider() call for a domain, regardless of whether the app registered any handlers itself. The deferred emitter only implemented addHandler/emit, so replacing the Datadog OpenFeature provider with another provider at runtime threw "oldProvider.events.removeHandler is not a function", crashing the customer's app. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(openfeature): address review feedback on tests and SSI scope - Fix test:openfeature script so the instrumentation spec actually runs: mocha treats a brace-only glob segment as a literal filename, so add a wildcard segment that both mocha and verify-exercised-tests resolve. - Add real esbuild/webpack black-box tests that bundle @openfeature/server-sdk (not marked external) and assert dd-trace's bundler-instrumentation mechanism still bridges the real event emitter into the vendored provider. - Correct comments in proxy.js and the dd-trace-api plugin: SSI itself is fixed by this PR's vendoring; the only remaining gap is that the dd-trace-api shim has no openfeature handoff. Generated with Claude Code. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * feat(openfeature): drop the server-sdk event-emitter bridge @datadog/openfeature-node-server 2.1.0 ships its own ProviderEventEmitter and no longer depends on @openfeature/server-sdk at all (neither as a dependency nor a peer), so the identity-preserving bridge this PR introduced is no longer needed: - Bump @datadog/openfeature-node-server to 2.1.0 everywhere it's pinned (vendor, root devDependencies, plugin versions matrix) and rebuild vendor/dist. - Remove the @openfeature/server-sdk external redirect from vendor/rspack.config.js -- the vendored provider no longer references that package at all. - Delete server-sdk-bridge.js, the openfeature-server-sdk require-hook instrumentation, and their specs. - Remove the now-obsolete esbuild/webpack black-box tests that verified the bridge survived bundling -- there's no bridge left to verify. - Update file-tracing.spec.js's expected traced files and loaded-modules list to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(openfeature): update stale yarn.lock entry for openfeature-node-server root package.json's devDependency was bumped to 2.1.0 but yarn.lock still pinned 2.0.2, which made bun's yarn.lock-migration fail to resolve the package in plugin test CI. --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 324b6cd commit e570f76

37 files changed

Lines changed: 190 additions & 1015 deletions

README.md

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,6 @@ Regardless of where you open the issue, someone at Datadog will try to help.
9393

9494
If you would like to trace your bundled application then please read this page on [bundling and dd-trace](https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/dd_libraries/nodejs/#bundling). It includes information on how to use our ESBuild plugin and includes caveats for other bundlers.
9595

96-
When using the experimental OpenFeature provider, file-traced deployments can force the optional provider and
97-
its dependencies into the output with a side-effect import before accessing `tracer.openfeature`:
98-
99-
CommonJS:
100-
101-
```js
102-
require('dd-trace/openfeature')
103-
```
104-
105-
ES modules:
106-
107-
```js
108-
import 'dd-trace/openfeature.js'
109-
```
110-
111-
This is a fallback for build tools that do not recognize the provider's optional-require wrapper.
112-
11396

11497
## Security Vulnerabilities
11598

integration-tests/esbuild/build-and-test-openfeature.js

Lines changed: 0 additions & 94 deletions
This file was deleted.

integration-tests/esbuild/index.spec.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,6 @@ esbuildVersions.forEach((version) => {
9595
})
9696
})
9797

98-
it('bundles the optional OpenFeature peer so it survives bundle relocation', () => {
99-
execSync('node ./build-and-test-openfeature.js', {
100-
timeout,
101-
})
102-
})
103-
10498
it('injects Git metadata into bundled applications', () => {
10599
execSync('node ./build-and-test-git-tags.js', {
106100
timeout,

integration-tests/esbuild/openfeature-app.js

Lines changed: 0 additions & 25 deletions
This file was deleted.

integration-tests/webpack/build-and-test-openfeature.js

Lines changed: 0 additions & 151 deletions
This file was deleted.

integration-tests/webpack/index.spec.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,6 @@ webpackVersions.forEach((version) => {
5858
execSync('node ./build-and-test-skip-external.js', { timeout })
5959
})
6060

61-
it('does not follow `@datadog/openfeature-node-server` into its optional peer chain', () => {
62-
execSync('node ./build-and-test-openfeature.js', { timeout })
63-
})
64-
6561
it('injects Git metadata into bundled applications', () => {
6662
execSync('node ./build-and-test-git-tags.js', { timeout })
6763
})

integration-tests/webpack/openfeature-app.js

Lines changed: 0 additions & 25 deletions
This file was deleted.

openfeature.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
'use strict'
22

3-
// Static fallback for file tracers that do not recognize the optional-peer wrapper.
4-
require('@datadog/openfeature-node-server')
3+
// Static fallback for file tracers that do not recognize the vendored provider's lazy require.
4+
require('./vendor/dist/@datadog/openfeature-node-server')

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@
184184
"@datadog/native-appsec": "11.0.1",
185185
"@datadog/native-iast-taint-tracking": "4.2.0",
186186
"@datadog/native-metrics": "3.1.2",
187-
"@datadog/openfeature-node-server": "2.0.2",
188187
"@datadog/pprof": "5.18.0",
189188
"@datadog/wasm-js-rewriter": "5.0.1",
190189
"@opentelemetry/api": ">=1.0.0 <1.10.0",
@@ -197,6 +196,7 @@
197196
"@babel/helpers": "^8.0.0",
198197
"@eslint/eslintrc": "^3.3.5",
199198
"@eslint/js": "^10.0.1",
199+
"@datadog/openfeature-node-server": "2.1.0",
200200
"@msgpack/msgpack": "^3.1.3",
201201
"@openfeature/core": "^1.11.0",
202202
"@openfeature/server-sdk": "~1.22.0",

0 commit comments

Comments
 (0)