Skip to content

Conversation

@jonathannorris
Copy link
Member

Summary

  • Adds createIsolatedOpenFeatureAPI() function accessible via /isolated sub-path export for both web and server SDKs
  • Enables micro-frontend architectures and testing scenarios where isolated OpenFeature instances are needed
  • Updates React SDK's OpenFeatureProvider to accept an optional openfeature prop for using isolated instances

Motivation

Addresses the singleton limitations discussed in open-feature/spec#359. The global singleton can cause issues in:

  • Micro-frontend architectures where different parts of an app need isolated providers
  • Tests that mutate the singleton and trample on each other
  • DI frameworks that don't work well with externally-managed singletons

Usage

// Web SDK
import { createIsolatedOpenFeatureAPI } from '@openfeature/web-sdk/isolated';

const MyOpenFeature = createIsolatedOpenFeatureAPI();
MyOpenFeature.setProvider(myProvider);
const client = MyOpenFeature.getClient();

// React SDK
<OpenFeatureProvider openfeature={MyOpenFeature}>
  {children}
</OpenFeatureProvider>

// Server SDK
import { createIsolatedOpenFeatureAPI } from '@openfeature/server-sdk/isolated';

Implementation

  • Extracts core logic into OpenFeatureAPIBase class (~380 lines for web, ~220 lines for server)
  • OpenFeatureAPI becomes a thin singleton wrapper (~35 lines)
  • Isolated instances are only accessible via the /isolated sub-path - no changes to OpenFeatureAPI class interface
  • Each isolated instance has its own providers, context, hooks, and event handlers

Changes

Package Files Added Files Modified
@openfeature/web-sdk 4 3
@openfeature/server-sdk 4 3
@openfeature/react-sdk 0 1

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jonathannorris, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses the limitations of a global singleton OpenFeature API by introducing the capability to create isolated instances. This feature is crucial for complex application architectures like micro-frontends, where different components require independent feature flag configurations, and for robust testing scenarios that prevent state mutation across tests. The change involves a significant refactoring of the core API into a base class, ensuring that the existing singleton API remains unchanged while providing a flexible foundation for isolated usage.

Highlights

  • Isolated OpenFeature API Instances: Introduced a new createIsolatedOpenFeatureAPI() function, accessible via a dedicated /isolated sub-path export for both web and server SDKs, allowing for non-singleton OpenFeature API instances.
  • React SDK Integration: The React SDK's OpenFeatureProvider now accepts an optional openfeature prop, enabling it to utilize these newly introduced isolated OpenFeature API instances.
  • Core Logic Refactoring: The core OpenFeature API logic has been extracted into a new OpenFeatureAPIBase class, which is now extended by both the existing singleton OpenFeatureAPI and the new isolated instances. This ensures no breaking changes to the existing API interface.
  • Complete Isolation: Each isolated instance maintains its own independent providers, evaluation contexts, hooks, event handlers, and (for the server SDK) transaction context propagators, preventing state leakage between instances.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

- Add createIsolatedOpenFeatureAPI() via /isolated sub-path export for web and server SDKs
- Extract core logic into OpenFeatureAPIBase class, keeping OpenFeatureAPI as thin singleton wrapper
- Update React SDK OpenFeatureProvider to accept optional openfeature prop for isolated instances
- Add comprehensive tests for isolation of providers, context, hooks, and event handlers

Addresses singleton limitations for micro-frontend architectures and testing scenarios.
See: open-feature/spec#359

Signed-off-by: Jonathan Norris <jonathan@taplytics.com>
@jonathannorris jonathannorris force-pushed the feat/isolated-openfeature-api branch from bdb2c19 to 09f0c5f Compare January 2, 2026 19:20
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant and well-architected feature: isolated OpenFeature API instances. The changes are cleanly implemented by extracting common logic into a new OpenFeatureAPIBase class, which both the existing singleton and new isolated instances use. This is a great approach that minimizes code duplication and maintains a clear separation of concerns. The new functionality is exposed via a /isolated sub-path for both server and web SDKs, which is a smart way to make this an opt-in feature. The React SDK is also updated to support these isolated instances. The addition of comprehensive test suites for the isolated APIs is excellent and ensures the new functionality is robust and reliable. I have a couple of minor suggestions to make the code even more concise.

*/
export function OpenFeatureProvider({ client, domain, children, ...options }: ProviderProps) {
const stableClient = React.useMemo(() => client || OpenFeature.getClient(domain), [client, domain]);
export function OpenFeatureProvider({ client, domain, openfeature, children, ...options }: ProviderProps) {
Copy link
Member Author

Choose a reason for hiding this comment

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

I will see if there is a way to have a separate React package like the other SDKs.

Copy link

Copilot AI left a comment

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 introduces support for isolated (non-singleton) OpenFeature API instances to address limitations in micro-frontend architectures, testing scenarios, and dependency injection frameworks where the global singleton can cause conflicts.

Key Changes:

  • Extracts core functionality into OpenFeatureAPIBase class for both web (~380 lines) and server (~220 lines) SDKs
  • Creates createIsolatedOpenFeatureAPI() factory function accessible via /isolated sub-path exports
  • Updates React SDK's OpenFeatureProvider to accept optional openfeature prop for using isolated instances

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/web/src/open-feature-base.ts New base class containing core OpenFeature API logic extracted from the singleton implementation
packages/web/src/open-feature.ts Refactored singleton to extend base class, reducing from ~420 to ~35 lines
packages/web/src/isolated.ts New isolated API implementation with factory function for creating non-singleton instances
packages/web/src/index.ts Added export of OpenFeatureAPIBase (potential API surface expansion issue)
packages/web/package.json Added /isolated sub-path export with ESM/CJS/types support
packages/web/rollup.isolated.config.mjs New rollup config for bundling isolated module types
packages/web/test/isolated.spec.ts Comprehensive test suite verifying isolation of providers, context, hooks, and event handlers
packages/server/src/open-feature-base.ts Server SDK base class with transaction context propagator support
packages/server/src/open-feature.ts Refactored server singleton extending base class
packages/server/src/isolated.ts Server SDK isolated API implementation
packages/server/src/index.ts Added export of OpenFeatureAPIBase (potential API surface expansion issue)
packages/server/package.json Added /isolated sub-path export configuration
packages/server/rollup.isolated.config.mjs Rollup config for server isolated module types
packages/server/test/isolated.spec.ts Test suite including server-specific transaction context isolation tests
packages/react/src/provider/provider.tsx Enhanced provider to accept optional openfeature prop for isolated instances

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

Comment on lines +23 to +27
class OpenFeatureIsolatedAPIImpl extends OpenFeatureAPIBase {
constructor() {
super();
}
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The OpenFeatureIsolatedAPIImpl constructor doesn't add any functionality beyond calling super(). Consider removing this unnecessary constructor to simplify the code. TypeScript will implicitly call the parent constructor when no constructor is defined.

Copilot uses AI. Check for mistakes.
export * from './provider';
export * from './evaluation';
export * from './open-feature';
export * from './open-feature-base';
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The OpenFeatureAPIBase class is being exported from the main entry point (packages/web/src/index.ts), which contradicts the PR description's claim that "Isolated instances are only accessible via the /isolated sub-path - no changes to OpenFeatureAPI class interface".

While the protected constructor prevents direct instantiation by consumers, exporting the base class exposes implementation details and creates an unintended public API surface. This could lead to confusion, allow users to extend the base class in unexpected ways, or create breaking changes in the future when you might want to refactor the base class.

Consider removing this export from the main entry point. The React SDK's OpenFeatureProvider can import OpenFeatureAPIBase as a type only, and users should interact with isolated instances through the OpenFeatureIsolatedAPI type alias exported from the /isolated sub-path.

Suggested change
export * from './open-feature-base';

Copilot uses AI. Check for mistakes.
export * from './provider';
export * from './evaluation';
export * from './open-feature';
export * from './open-feature-base';
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The OpenFeatureAPIBase class is being exported from the main entry point (packages/server/src/index.ts), which exposes implementation details that should remain internal. This contradicts the PR's stated goal of keeping isolated instances accessible only via the /isolated sub-path.

While the protected constructor prevents direct instantiation, exporting the base class unnecessarily expands the public API surface and could lead to confusion or misuse. Consider removing this export to keep the base class as an internal implementation detail.

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +21
* An isolated (non-singleton) OpenFeature API instance.
* This class is NOT exported from the main entry point.
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The comment states "This class is NOT exported from the main entry point" but this is inaccurate. While the OpenFeatureIsolatedAPIImpl class itself is not exported, its base class OpenFeatureAPIBase is exported from the main entry point in index.ts. This comment could be misleading. Consider updating it to reflect the actual visibility or removing the export of OpenFeatureAPIBase from the main entry point.

Suggested change
* An isolated (non-singleton) OpenFeature API instance.
* This class is NOT exported from the main entry point.
* Internal implementation of an isolated (non-singleton) OpenFeature API instance.
* Consumers should use {@link createIsolatedOpenFeatureAPI} instead of this class directly.

Copilot uses AI. Check for mistakes.

/**
* An isolated (non-singleton) OpenFeature API instance.
* This class is NOT exported from the main entry point.
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The comment states "This class is NOT exported from the main entry point" but this is inaccurate. While the OpenFeatureIsolatedAPIImpl class itself is not exported, its base class OpenFeatureAPIBase is exported from the main entry point in index.ts. This comment could be misleading. Consider updating it to reflect the actual visibility or removing the export of OpenFeatureAPIBase from the main entry point.

Suggested change
* This class is NOT exported from the main entry point.
* This concrete implementation class is not exported from the main entry point;
* only the base {@link OpenFeatureAPIBase} is exported there.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +27
constructor() {
super();
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The OpenFeatureIsolatedAPIImpl constructor doesn't add any functionality beyond calling super(). Consider removing this unnecessary constructor to simplify the code. TypeScript will implicitly call the parent constructor when no constructor is defined.

Suggested change
constructor() {
super();
}

Copilot uses AI. Check for mistakes.
*/
domain?: string;
/**
* An isolated OpenFeature API instance to use instead of the global singleton.
Copy link
Member

Choose a reason for hiding this comment

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

Am I right that this openfeature prop should ONLY be used when someone is doing the advanced isolated stuff? If so I think we should add that clearly in the docstring - "WARNING: this is only required for special cases where an isolated instance is needed. If you don't know what that means, you should not be using this prop".

We could also call it isolatedOpenFeature to make it clearer that it's a special-case thing, not a generally-used thing.

/**
* @module @openfeature/server-sdk/isolated
* Provides non-singleton OpenFeature API instances for testing and multi-tenant scenarios.
* WARNING: This module provides non-singleton instances that do NOT share state
Copy link
Member

Choose a reason for hiding this comment

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

I think this warning could be a little stronger/clearer

* This is a singleton class that provides access to the global OpenFeature API instance.
*
* For isolated (non-singleton) instances, use the `createIsolatedOpenFeatureAPI` function
* from `@openfeature/server-sdk/isolated`.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* from `@openfeature/server-sdk/isolated`.
* from `@openfeature/server-sdk/isolated` (this is an advanced use case; only use it if you know you need it)

@moredip
Copy link
Member

moredip commented Jan 15, 2026

If we do add this feature we should also add a writeup to the docs, and link to it from the docstring here. Just a quick summary of what the isolated use case is, and an extolation to only use it if you know what you're doing.

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.

3 participants