Skip to content

Commit e55c1db

Browse files
authored
fix(openfeature-node-server): updating public README and CHANGELOG (#1782)
SDK-2621 <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only edits with no changes to provider behavior or dependencies. > > **Overview** > Updates **public docs only** for `@launchdarkly/openfeature-node-server`—no runtime or API code changes. > > The **1.3.0 CHANGELOG** now states the package was moved into the `js-core` monorepo and points readers to the old repo for history before this release. > > The **README** adds multi-user / Node 20+ guidance and replaces the minimal usage snippet with a fuller example (`LaunchDarklyProvider` options, `setProviderAndWait`, `getClient()`, `ProviderEvents.ConfigurationChanged`, `OpenFeature.close()`). A new **OpenFeature Specific Considerations** section documents how `EvaluationContext` maps to LaunchDarkly contexts (`kind`, `targetingKey` vs `key`, and `privateAttributes` / `anonymous` / `name`) with copy-paste examples for single, multi, and private-attribute contexts. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 823d9ce. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 94307ea commit e55c1db

2 files changed

Lines changed: 115 additions & 2 deletions

File tree

packages/sdk/openfeature-node-server/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## [1.3.0](https://github.com/launchdarkly/js-core/compare/openfeature-node-server-v1.2.5...openfeature-node-server-v1.3.0) (2026-06-30)
44

5+
Migrates the implemenation of `@launchdarkly/openfeature-node-server` to
6+
the `js-core` monorepo.
7+
8+
For older changelogs please see https://github.com/launchdarkly/openfeature-node-server/blob/main/CHANGELOG.md
9+
510

611
### Features
712

packages/sdk/openfeature-node-server/README.md

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
This package provides an [OpenFeature](https://openfeature.dev/) provider that wraps the [LaunchDarkly Server-Side SDK for Node.js](https://github.com/launchdarkly/js-core/tree/main/packages/sdk/server-node).
1010

11+
This provider is designed primarily for use in multi-user systems such as web servers and applications. It is not intended for use in desktop and embedded systems applications.
12+
13+
## Supported Node versions
14+
15+
This version of the LaunchDarkly OpenFeature provider is compatible with Node.js versions 20 and above.
16+
1117
## Installation
1218

1319
```bash
@@ -17,16 +23,118 @@ npm install @openfeature/server-sdk @launchdarkly/node-server-sdk @launchdarkly/
1723
## Usage
1824

1925
```typescript
20-
import { OpenFeature } from '@openfeature/server-sdk';
26+
import { OpenFeature, ProviderEvents } from '@openfeature/server-sdk';
2127
import { LaunchDarklyProvider } from '@launchdarkly/openfeature-node-server';
2228

23-
const provider = new LaunchDarklyProvider('your-sdk-key');
29+
// The optional third parameter controls how long to wait for initialization (default: 10 seconds).
30+
const provider = new LaunchDarklyProvider('your-sdk-key', {/* LDOptions here */});
31+
32+
// setProviderAndWait throws if initialization fails; catch as needed.
2433
await OpenFeature.setProviderAndWait(provider);
2534

35+
// Access the underlying LDClient directly if needed.
36+
const ldClient = provider.getClient();
37+
2638
const client = OpenFeature.getClient();
2739
const flagValue = await client.getBooleanValue('flag-key', false, {
2840
targetingKey: 'user-key',
2941
});
42+
43+
// The provider emits ConfigurationChanged for each flag key that may have changed.
44+
// Each event contains a single key in the flagsChanged array.
45+
OpenFeature.addHandler(ProviderEvents.ConfigurationChanged, (eventDetails) => {
46+
console.log(`Changed: ${eventDetails.flagsChanged}`);
47+
});
48+
49+
// Calling close() flushes SDK events - useful for short-lived processes.
50+
await OpenFeature.close();
51+
```
52+
53+
## OpenFeature Specific Considerations
54+
55+
LaunchDarkly evaluates contexts, and it can either evaluate a single-context or a multi-context. When using OpenFeature, both single and multi-contexts must be encoded into a single `EvaluationContext`. This is accomplished by looking for an attribute named `kind` in the `EvaluationContext`.
56+
57+
There are 4 different scenarios related to the `kind`:
58+
1. There is no `kind` attribute. The provider will treat the context as a single context of kind `"user"`.
59+
2. There is a `kind` attribute with the value `"multi"`. The provider will treat the context as a multi-context.
60+
3. There is a `kind` attribute with a string value other than `"multi"`. The provider will treat it as a single context of the specified kind.
61+
4. There is a `kind` attribute, but its value is not a string. The value will be discarded, the context will be treated as kind `"user"`, and a warning will be logged.
62+
63+
The `kind` attribute should be a string containing only ASCII letters, numbers, `.`, `_`, or `-`.
64+
65+
The OpenFeature specification allows for an optional targeting key, but LaunchDarkly requires a key for evaluation. A targeting key must be specified for each context being evaluated. It may be specified using either `targetingKey`, as defined in the OpenFeature specification, or `key`, which is the typical LaunchDarkly identifier. If both are specified, `targetingKey` takes precedence.
66+
67+
There are several attributes with special handling within a single or multi-context:
68+
- `privateAttributes` - Must be an array of strings. Equivalent to `_meta.privateAttributes` in the SDK.
69+
- `anonymous` - Must be a boolean. Equivalent to `anonymous` in the SDK.
70+
- `name` - Must be a string. Equivalent to `name` in the SDK.
71+
72+
### Examples
73+
74+
#### A single user context
75+
76+
```typescript
77+
const evaluationContext = {
78+
targetingKey: 'my-user-key',
79+
};
80+
```
81+
82+
#### A single context of kind "organization"
83+
84+
```typescript
85+
const evaluationContext = {
86+
kind: 'organization',
87+
targetingKey: 'my-org-key',
88+
};
89+
```
90+
91+
#### A multi-context containing a "user" and an "organization"
92+
93+
```typescript
94+
const evaluationContext = {
95+
kind: 'multi',
96+
organization: {
97+
targetingKey: 'my-org-key',
98+
myCustomAttribute: 'myAttributeValue',
99+
},
100+
user: {
101+
targetingKey: 'my-user-key',
102+
},
103+
};
104+
```
105+
106+
#### Setting private attributes in a single context
107+
108+
```typescript
109+
const evaluationContext = {
110+
kind: 'organization',
111+
name: 'the-org-name',
112+
targetingKey: 'my-org-key',
113+
myCustomAttribute: 'myCustomValue',
114+
privateAttributes: ['myCustomAttribute'],
115+
};
116+
```
117+
118+
#### Setting private attributes in a multi-context
119+
120+
```typescript
121+
const evaluationContext = {
122+
kind: 'multi',
123+
organization: {
124+
targetingKey: 'my-org-key',
125+
name: 'the-org-name',
126+
// privateAttributes only applies to the "organization" context.
127+
privateAttributes: ['myCustomAttribute'],
128+
// This attribute will be private.
129+
myCustomAttribute: 'myAttributeValue',
130+
},
131+
user: {
132+
targetingKey: 'my-user-key',
133+
anonymous: true,
134+
// This attribute will not be private.
135+
myCustomAttribute: 'myAttributeValue',
136+
},
137+
};
30138
```
31139

32140
## Contributing

0 commit comments

Comments
 (0)