fix(openfeature): support file-traced optional provider loading - #9324
Conversation
Overall package sizeSelf size: 6.78 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.3.1 | 122.62 kB | 438.86 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
BenchmarksBenchmark execution time: 2026-07-15 18:17:16 Comparing candidate commit 404a1fb in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 2315 metrics, 43 unstable metrics.
|
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 404a1fb | Docs | Datadog PR Page | Give us feedback! |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #9324 +/- ##
=======================================
Coverage 96.90% 96.91%
=======================================
Files 923 923
Lines 122993 122994 +1
Branches 21479 21385 -94
=======================================
+ Hits 119189 119194 +5
+ Misses 3804 3800 -4 Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2c07b16731
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
2c07b16 to
3a9d4b5
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 96b851aad3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Next.js standalone builds using pnpm omitted the OpenFeature provider because the shared optional-peer wrapper was invisible to nft, leaving tracer.openfeature as the no-op provider at runtime. Keep the bundler escape hatch while exposing a file-traceable fallback entrypoint for tools that cannot recognize the wrapper. Refs: #8635
Webpack parses a bare dynamic require even behind the non-webpack branch, reintroducing a critical expression-dependency warning when the peer is absent. The fallback must remain recognizable to nft without exposing that expression dependency to webpack.
Moving the provider call inside the createRequire fallback left webpack's runtime on `__non_webpack_require__`, so relocated bundles could not find the installed peer and silently selected NoopFlaggingProvider. Keep the final load at the rewrite site while preserving nft's createRequire binding.
Node's ESM resolver does not append `.js` to package subpaths without an exports map, so the extensionless fallback fails before file tracing starts. Pin both the ESM import and automatic nft discovery from the default entrypoint.
96b851a to
78bff46
Compare
Node 18 and 20 require the `.js` suffix for ESM package subpaths, while CommonJS resolves the extensionless form. The full-root nft assertion exceeded Mocha's timeout under coverage; the runtime-wrapper trace keeps the automatic nft contract pinned without tracing the whole package again.
Next.js standalone builds using pnpm omitted the OpenFeature provider because the shared optional-peer wrapper was invisible to nft, leaving tracer.openfeature as the no-op provider at runtime. Keep the bundler escape hatch while exposing a file-traceable fallback entrypoint for tools that cannot recognize the wrapper. Also document CommonJS and ESM entrypoints. Fixes: #8635
Next.js standalone builds using pnpm omitted the OpenFeature provider because the shared optional-peer wrapper was invisible to nft, leaving tracer.openfeature as the no-op provider at runtime. Keep the bundler escape hatch while exposing a file-traceable fallback entrypoint for tools that cannot recognize the wrapper. Also document CommonJS and ESM entrypoints. Fixes: #8635
…point 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>
…point 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>
…point 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>
…l 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>
…l 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>
…l 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>
…l 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>
…l 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>
Summary
Next.js standalone builds using pnpm omitted the optional OpenFeature provider because nft could not follow the shared dynamic optional-peer wrapper. This keeps the existing lazy loading behavior, makes the provider file-traceable, and adds
dd-trace/openfeatureas a fallback for build tools that do not recognize the wrapper.Why
The optional provider must remain a peer dependency and must not be pulled into builds that do not use OpenFeature. The file-traceable wrapper and bundler rewrites preserve that opt-in behavior while allowing relocated standalone output to load the provider when it is installed or explicitly imported.
Refs: #8635