Skip to content

feat(core): pass bound domain to provider initialize and enforce domain-scoped binding#1433

Open
jonathannorris wants to merge 12 commits into
mainfrom
feat/ofrep-domain-cache-key
Open

feat(core): pass bound domain to provider initialize and enforce domain-scoped binding#1433
jonathannorris wants to merge 12 commits into
mainfrom
feat/ofrep-domain-cache-key

Conversation

@jonathannorris

@jonathannorris jonathannorris commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

  • Add optional domain parameter to provider initialize and pass the bound domain from the provider mutator (spec 1.1.2.2, 2.4.1)
  • Add domainScoped provider declaration and reject binding a domain-scoped instance to more than one domain (spec 2.4.3, 1.1.8.1)
  • Forward domain through web and server MultiProvider initialize
  • Add conformance tests in web and server SDK test suites, including legacy single-argument initialize backward compatibility

Motivation

Unblocks OFREP static-context providers that need the bound domain at init time to scope persisted cache keys per open-feature/spec#393 and protocol ADR 0009.

Notes

  • Non-breaking: domain is an optional second parameter to initialize
  • Non-domain-scoped providers retain existing behavior (single instance can back multiple domains; initialize runs once)
  • Legacy providers that only implement initialize(context) remain compatible; the extra domain argument is ignored if unused

Related Issues

Closes #1434

Relates to: open-feature/spec#393

Test plan

  • npx jest --selectProjects=shared --selectProjects=web --selectProjects=server

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Provider initialization now accepts an optional domain and forwards it through shared, server, and web provider paths. The API also adds a domainScoped provider flag and enforces single-domain binding for such providers. Tests cover legacy providers and domain-binding rules.

Changes

Provider domain handling

Layer / File(s) Summary
Contract and legacy helper
packages/shared/src/provider/provider.ts, packages/shared/test/legacy-initialize-provider.ts
CommonProvider adds domainScoped and a second initialize argument, and the shared legacy test helper tracks initialization calls and resolver stubs.
Domain-aware initialization forwarding
packages/shared/src/open-feature.ts, packages/server/test/open-feature.spec.ts, packages/web/test/open-feature.spec.ts, packages/web/test/evaluation-context.spec.ts
setAwaitableProvider passes domain into provider initialization, and tests cover default/domain initialization plus legacy single-argument providers.
MultiProvider domain forwarding
packages/server/src/provider/multi-provider/multi-provider.ts, packages/web/src/provider/multi-provider/multi-provider-web.ts, packages/server/test/multi-provider.spec.ts, packages/web/test/multi-provider-web.spec.ts
Both MultiProvider implementations forward (context, domain) to child providers, and the matching tests check legacy and regular child providers.
Domain-scoped binding guard
packages/shared/src/open-feature.ts, packages/server/test/open-feature.spec.ts, packages/web/test/open-feature.spec.ts
setAwaitableProvider now rejects reusing a domainScoped provider across domains, and tests cover the thrown error and shared-provider reuse cases.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The domain-passing and domain-scoped enforcement are implemented, but the linked issue also asked for docs updates, which are not present. Add the missing documentation updates to match #1434's requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: passing bound domains to initialize and enforcing domain-scoped binding.
Description check ✅ Passed The description matches the implemented domain-aware initialization, domainScoped enforcement, and test coverage.
Out of Scope Changes check ✅ Passed All changes align with the stated domain-init and domain-scoping work, with related tests and helpers only.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the SDK provider lifecycle to support domain-aware initialization by adding an optional domain argument to Provider.initialize, forwarding it through MultiProvider, and enforcing that domainScoped provider instances cannot be bound to multiple domains. It also adds conformance tests (web + server) and introduces a shared legacy-provider test helper to validate backwards compatibility with single-argument initialize implementations.

Changes:

  • Extend Provider.initialize to accept (context?, domain?) and pass the bound domain during provider registration/initialization.
  • Add domainScoped provider declaration and reject binding the same domain-scoped instance to more than one domain.
  • Forward domain through web/server MultiProvider.initialize and add conformance + legacy compatibility tests.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/shared/src/provider/provider.ts Adds domainScoped to provider interface and updates initialize signature/docs.
packages/shared/src/open-feature.ts Enforces domain-scoped single-domain binding and forwards (context, domain) into provider initialization.
packages/web/src/provider/multi-provider/multi-provider-web.ts Forwards domain through MultiProvider.initialize to child providers.
packages/server/src/provider/multi-provider/multi-provider.ts Forwards domain through MultiProvider.initialize to child providers.
packages/shared/test/legacy-initialize-provider.ts Adds reusable legacy single-arg initialize test provider helper for web/server suites.
packages/web/test/open-feature.spec.ts Adds conformance tests for passing domain to initialize, enforcing domainScoped, and legacy init compatibility.
packages/web/test/multi-provider-web.spec.ts Adds test asserting MultiProvider forwards domain without breaking legacy child providers.
packages/web/test/evaluation-context.spec.ts Updates expectations to include (context, domain) in initialize calls.
packages/server/test/open-feature.spec.ts Mirrors web conformance tests for server SDK behavior + legacy init compatibility.
packages/server/test/multi-provider.spec.ts Mirrors web MultiProvider legacy-domain-forwarding test for server SDK.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/shared/src/open-feature.ts
Comment thread packages/shared/src/provider/provider.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/shared/test/legacy-initialize-provider.ts (1)

47-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add JSDoc @param/@returns to satisfy format-lint.

The format-lint check warns that the JSDoc blocks on legacyInitializeProvider (Line 47) and legacyInitTestProvider (Line 78) are missing @param and @returns declarations.

📝 Proposed JSDoc additions
 /**
  * Provider with a single-argument initialize that ignores any extra arguments passed by the SDK.
+ * `@param` options provider configuration (paradigm, name, resolver mode)
+ * `@returns` a legacy single-argument initialize provider
  */
 export function legacyInitializeProvider(options: LegacyInitializeProviderOptions): LegacyInitializeProvider {
 /**
  * Legacy initialize provider with the stubs MultiProvider expects on child providers.
+ * `@param` options provider configuration (paradigm, name, resolver mode)
+ * `@param` extras MultiProvider child stubs (events, hooks, track)
+ * `@returns` a legacy provider augmented with MultiProvider child stubs
  */
 export function legacyInitTestProvider(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared/test/legacy-initialize-provider.ts` around lines 47 - 50, Add
the missing JSDoc tags on legacyInitializeProvider and legacyInitTestProvider so
format-lint passes: update each function’s docblock to include an `@param` entry
for the options argument and an `@returns` entry describing the provider returned.
Keep the existing function names and doc comments intact, and apply the same
JSDoc pattern to both legacyInitializeProvider and legacyInitTestProvider.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/shared/test/legacy-initialize-provider.ts`:
- Around line 47-50: Add the missing JSDoc tags on legacyInitializeProvider and
legacyInitTestProvider so format-lint passes: update each function’s docblock to
include an `@param` entry for the options argument and an `@returns` entry
describing the provider returned. Keep the existing function names and doc
comments intact, and apply the same JSDoc pattern to both
legacyInitializeProvider and legacyInitTestProvider.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b35fb910-9cfc-4133-b796-ea1f346e78c5

📥 Commits

Reviewing files that changed from the base of the PR and between 3c01041 and 62e2e99.

📒 Files selected for processing (10)
  • packages/server/src/provider/multi-provider/multi-provider.ts
  • packages/server/test/multi-provider.spec.ts
  • packages/server/test/open-feature.spec.ts
  • packages/shared/src/open-feature.ts
  • packages/shared/src/provider/provider.ts
  • packages/shared/test/legacy-initialize-provider.ts
  • packages/web/src/provider/multi-provider/multi-provider-web.ts
  • packages/web/test/evaluation-context.spec.ts
  • packages/web/test/multi-provider-web.spec.ts
  • packages/web/test/open-feature.spec.ts

@jonathannorris
jonathannorris marked this pull request as ready for review June 26, 2026 15:01
@jonathannorris
jonathannorris requested review from a team as code owners June 26, 2026 15:01

@MattIPv4 MattIPv4 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How does the MultiProvider handle domain-scoped providers? Or is wrapping a provider in MultiProvider essentially a way to bypass that restriction?

Comment thread packages/server/test/multi-provider.spec.ts
Comment thread packages/web/test/multi-provider-web.spec.ts
@jonathannorris

Copy link
Copy Markdown
Member Author

@MattIPv4 MultiProvider forwards (context, domain) to children; it doesn't enforce domainScoped. The SDK guard only runs on direct setProvider(domain, provider) binding, so wrapping in MultiProvider doesn't bypass that.

Reusing the same domain-scoped child across multiple MultiProviders isn't caught at registration (children aren't in allProviders); the child should reject a second domain in initialize. Happy to add a conformance test if useful.

…in-scoped binding

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
@jonathannorris
jonathannorris force-pushed the feat/ofrep-domain-cache-key branch from 199f03b to 50bdb4d Compare July 2, 2026 20:43
* @param domain the bound domain, if any
*/
initialize?(context?: EvaluationContext): Promise<void>;
initialize?(context?: EvaluationContext, domain?: string): Promise<void>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if we should make this an initialization config object so we can extend it in the future without breaking anything.

@toddbaert toddbaert Jul 3, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think it matters as much here due to overloading, but it's possible and maybe a good idea. We could have an InitializationContext (we already have a HookContext that is comparable). "Context" is already a bit overloaded, but this is mostly a provider author interface so I'm not that worried about that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think we need an object here; overloading gives us room to extend without breaking existing initialize(context) implementations. I'd keep positional (context?, domain?) for this PR per spec#393.

If we do move to an options bag for the second arg later, I'd avoid another *Context name. Some options: ProviderBinding, ProviderRegistration, ProviderScope, InitializeMetadata.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ya I think my recommendation is we don't do this, but I'm open to disagreements.

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/web/test/open-feature.spec.ts`:
- Around line 120-129: The test expectation in OpenFeature provider resolution
is inverted for the named domain check. In the `it('MUST NOT bind a
domain-scoped default provider to a named domain'...)` case, update the
`OpenFeature.getProvider('domain-a')` assertion to verify it resolves to the
default provider instance rather than asserting it is different; use the
`OpenFeature.getProvider` and `provider.metadata.name` checks to confirm object
identity or matching metadata as appropriate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c951b358-c438-4d73-a985-ca5b37391151

📥 Commits

Reviewing files that changed from the base of the PR and between 50bdb4d and da94f44.

📒 Files selected for processing (6)
  • packages/server/test/multi-provider.spec.ts
  • packages/server/test/open-feature.spec.ts
  • packages/shared/src/open-feature.ts
  • packages/shared/test/legacy-initialize-provider.ts
  • packages/web/test/multi-provider-web.spec.ts
  • packages/web/test/open-feature.spec.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/server/test/multi-provider.spec.ts
  • packages/server/test/open-feature.spec.ts
  • packages/web/test/multi-provider-web.spec.ts
  • packages/shared/src/open-feature.ts

Comment thread packages/web/test/open-feature.spec.ts
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Comment thread packages/shared/test/legacy-initialize-provider.ts
Comment thread packages/shared/src/open-feature.ts Outdated

@toddbaert toddbaert left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm approving because I see no fundamental problems, but consider mine and other's nits, and since this is a fundamentally new thing, let's leave it open for a few days at least.

I'm somewhat interested in doing what @beeme1mr said here, but I don't feel 100% sure. Interested in the opinions of others.

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/shared/test/legacy-initialize-provider.ts`:
- Around line 47-49: The JSDoc in legacy-initialize-provider is missing the type
annotations required by the format-lint rule. Update the docblock for the
initialize provider helper to include typed `@param` entries for options and
extras, and a typed `@returns` annotation, matching the actual function signature
and return value. Keep the symbols for the documented function and its
parameters consistent so the lint rule can validate the block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: daf14d01-bad0-42da-b6fa-49c3cbf10520

📥 Commits

Reviewing files that changed from the base of the PR and between da94f44 and 249b9b2.

📒 Files selected for processing (3)
  • packages/server/test/open-feature.spec.ts
  • packages/shared/test/legacy-initialize-provider.ts
  • packages/web/test/open-feature.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/server/test/open-feature.spec.ts
  • packages/web/test/open-feature.spec.ts

Comment thread packages/shared/test/legacy-initialize-provider.ts
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
…eBinding

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread packages/shared/src/provider/provider.ts
Comment thread packages/shared/src/open-feature.ts
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
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.

Supply the bound domain to provider initialization

5 participants