Skip to content

feat: expose js sdk identity on client metadata#1376

Draft
jonathannorris wants to merge 3 commits intomainfrom
feat/client-metadata-sdk-identity
Draft

feat: expose js sdk identity on client metadata#1376
jonathannorris wants to merge 3 commits intomainfrom
feat/client-metadata-sdk-identity

Conversation

@jonathannorris
Copy link
Copy Markdown
Member

Summary

  • extend ClientMetadata with JS-specific identity fields: sdk and framework
  • set sdk in the base web and server clients
  • expose framework metadata from the React, Angular, and Nest SDK layers so it is available on client.metadata and in hook clientMetadata

Motivation

Relates to #1375.

Today providers and hooks can access clientMetadata, but the JS SDKs do not expose enough identity to tell whether a call came from web vs server, or from react, angular, or nest.

Usage

const client = OpenFeature.getClient('my-domain');

client.metadata;
// web-sdk:
// {
//   domain: 'my-domain',
//   sdk: 'web',
//   providerMetadata: { name: '...' }
// }
hook.before = (hookContext) => {
  hookContext.clientMetadata;
  // react-sdk:
  // {
  //   domain: 'my-domain',
  //   sdk: 'web',
  //   framework: 'react',
  //   providerMetadata: { name: '...' }
  // }
};

Notes

  • the framework SDKs use a small Proxy wrapper so framework metadata is visible both via client.metadata and from evaluations that read this.metadata
  • this keeps the change isolated to the framework layers instead of expanding the core client constructor APIs

Related Issues

Expose stable sdk and framework identity through client metadata so providers and hooks can distinguish web/server usage and framework wrappers without custom vendor shims.

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
@jonathannorris jonathannorris requested a review from toddbaert April 8, 2026 20:03
Copy link
Copy Markdown
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 framework-specific metadata (Angular, Nest, and React) and SDK family identification ('web' or 'server') into OpenFeature clients. This is achieved by wrapping clients in a Proxy that intercepts metadata access. The changes include new utility functions for each framework, updates to the respective SDK providers/services to apply these wrappers, and expanded unit tests to verify metadata propagation. Review feedback highlights potential performance improvements in the Angular SDK, specifically regarding redundant client initialization in the directive and the need for caching proxied client instances in the service to avoid overhead during frequent flag evaluations.

this.disposeClient(this._client);
}
this._client = OpenFeature.getClient(this._featureFlagDomain);
this._client = withAngularFrameworkMetadata(OpenFeature.getClient(this._featureFlagDomain));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The initClient method is called both from the featureFlagDomain setter and from ngOnInit. When the domain is provided via an input binding, the setter will trigger initClient before ngOnInit runs, causing the client to be initialized twice and the first one to be immediately disposed. While not a functional bug, it is redundant.

options?: AngularFlagEvaluationOptions,
): Observable<EvaluationDetails<T>> {
const client = domain ? OpenFeature.getClient(domain) : OpenFeature.getClient();
const client = withAngularFrameworkMetadata(domain ? OpenFeature.getClient(domain) : OpenFeature.getClient());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Creating a new Proxy wrapper on every call to getFlagDetails (which occurs for every flag evaluation via the service) introduces unnecessary overhead. Since OpenFeature.getClient() returns a singleton for a given domain, consider caching the proxied client instances within the service to improve efficiency.

Move the framework metadata proxy into shared client utilities so the React, Angular, and Nest SDKs reuse one implementation.

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
@jonathannorris
Copy link
Copy Markdown
Member Author

Hum... should sdk actually reuse Paradigm instead of introducing a new union on ClientMetadata?

Right now this PR uses sdk?: 'web' | 'server', but Paradigm is already 'server' | 'client'.

I think it probably makes sense to decide whether this field is meant to represent JS package family (web | server) or runtime paradigm (client | server) before we merge this.

Define a minimal core client interface for metadata so shared framework wrappers can depend on an explicit contract instead of a broad object type.

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
@MattIPv4
Copy link
Copy Markdown
Member

MattIPv4 commented Apr 8, 2026

Hum... should sdk actually reuse Paradigm instead of introducing a new union on ClientMetadata?

Right now this PR uses sdk?: 'web' | 'server', but Paradigm is already 'server' | 'client'.

I think it probably makes sense to decide whether this field is meant to represent JS package family (web | server) or runtime paradigm (client | server) before we merge this.

Reusing makes sense to me. I think they are essentially representing the same thing? The server package sets its runsOn to 'server', and the web package sets its runsOn to 'client'. Seems silly to introduce a new union to also represent the same thing with different values?

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.

2 participants