Skip to main content
The @westyx-nexus/openfeature-provider-angular sub-package provides an OpenFeature Provider that wraps an existing NexusClient from @westyx-nexus/sdk-angular. No second connection is opened and no second cache is kept. The bridge subscribes to the same NexusClient that the rest of your application uses. Whenever the client replaces its in-memory snapshot (TTL poll or stream push), the provider emits ProviderEvents.ConfigurationChanged so the OpenFeature SDK re-evaluates.

Installation

The bridge is a separate npm package:
Your existing @westyx-nexus/sdk-angular package is the peer dependency - you already have it.

npm registry

Both packages are on the GitLab npm Package Registry. Add to your .npmrc:

Usage

Wiring up in app.config.ts

The initializers run before Angular renders, so the cache is populated and setProviderAndWait has completed before the first evaluation.

Reading flags

Using @openfeature/angular-sdk:
Or using the raw OpenFeature client:

NgModule-based apps

Per-user targeting

When the evaluation context carries a targetingKey, a boolean evaluation is resolved for that user through the Nexus AB Testing add-on: the flag’s rollout percentage and cohort rules are applied to that identity, and the resolution reports TARGETING_MATCH.

Where the request happens

resolveBooleanEvaluation is synchronous in the OpenFeature Web SDK - there is no promise for it to await - and the Web SDK’s paradigm is a static evaluation context. So the provider asks the service when the context changes, not when a flag is read: One round trip covers every flag in the snapshot, so a page reading twenty flags costs one request, and concurrent triggers for the same identity coalesce into one. A snapshot with more than 200 flags is split into successive calls, which is the endpoint’s documented cap.

Attributes are strings

The service’s cohort matcher compares strings with eq / neq / in, so only string context fields are sent. A non-string field is left out and reported at debug level rather than converted - a coerced value that matches no rule is harder to diagnose than an absent one. Format at the call site (String(age), not age) and you know exactly what the rule is matched against. targetingKey is sent as the identity, never also as an attribute.

Reasons you will see

If the add-on is not active

Projects without the AB Testing add-on get a 403 from the endpoint. The provider serves the snapshot with a STATIC reason and stops asking for five minutes at a time (addonSuppressionMs), so an inactive add-on costs one request per window rather than one per context change. It is a throttle, not a latch: buying the add-on starts producing targeted results within the window, with nothing to restart, and any success clears it immediately.

Provider options

There is deliberately no cache-lifetime option, unlike the server-side bridges. The targeted values are replaced on a context change and on a configuration change - both events rather than deadlines - so a time-to-live would have nothing to govern.

Flag resolution

Boolean flags come from feature flags; string, number and object evaluations come from config values. Config values are never targeted - evaluate-ab is a flag concept, so there is no such thing as a targeted config value. Inside a resolved object or array, an integer beyond Number.MAX_SAFE_INTEGER is carried as its exact decimal string, at any depth - OpenFeature’s JsonValue has no numeric slot that holds it exactly, and the decimal string is the lossless one, so the resolved value survives JSON.stringify. Ordinary numbers are untouched; parse the string with BigInt(value) where the magnitude matters. A TYPE_MISMATCH message names the type that arrived, so it is actionable without opening the configuration.

Live updates

The provider calls client.subscribe(listener) in initialize() and stores the returned unsubscribe function. When the NexusClient replaces its snapshot the listener fires, the provider emits ProviderEvents.ConfigurationChanged, and the OpenFeature SDK re-evaluates - so any UI using @openfeature/angular-sdk re-renders. The client’s listener also fires for a stream state transition, for a 304 and for the billing and quarantine flags, none of which changed a flag; the provider compares client.snapshotRevision and acts only on a real configuration change, so a reconnect costs no request and triggers no re-render. The same listener re-asks for the targeted values. That refresh emits a second ConfigurationChanged only when the values actually moved: announcing an unchanged refresh would re-render every component bound to a flag on every sync. onClose() unsubscribes the listener and drops the stored identity.

NexusClientLike interface

The provider’s constructor accepts a NexusClientLike interface rather than the concrete NexusClient class, so the package needs no build-time dependency on @westyx-nexus/sdk-angular - an Angular library’s typings live in its build output. Any object satisfying it works:
The real NexusClient inherits every member from the shared browser core.

Version

Latest release: v0.17.0. The bridge requires @westyx-nexus/sdk-angular v0.17.0 or newer - it is declared as a peer dependency, so npm will tell you if the two are out of step. The floor follows the release, so a consumer never resolves an SDK older than the bridge that wraps it. @openfeature/core is a direct dependency of the bridge. @openfeature/web-sdk declares it as a peer and imports it at runtime, so it must be present; it is resolved for you.