|
7 | 7 | </picture> |
8 | 8 | </p> |
9 | 9 |
|
10 | | -<h2 align="center">OpenFeature Node.js SDK</h2> |
11 | | - |
12 | | -<!-- x-hide-in-docs-end --> |
13 | | -<!-- The 'github-badges' class is used in the docs --> |
14 | | -<p align="center" class="github-badges"> |
15 | | - <a href="https://github.com/open-feature/spec/tree/v0.7.0"> |
16 | | - <img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.7.0&color=yellow&style=for-the-badge" /> |
17 | | - </a> |
18 | | - <!-- x-release-please-start-version --> |
19 | | - <a href="https://github.com/open-feature/js-sdk/releases/tag/js-sdk-v1.6.0"> |
20 | | - <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.6.0&color=blue&style=for-the-badge" /> |
21 | | - </a> |
22 | | - <!-- x-release-please-end --> |
23 | | - <br/> |
24 | | - <a href="https://open-feature.github.io/js-sdk/modules/OpenFeature_JS_SDK.html"> |
25 | | - <img alt="API Reference" src="https://img.shields.io/badge/reference-teal?logo=javascript&logoColor=white" /> |
26 | | - </a> |
27 | | - <a href="https://www.npmjs.com/package/@openfeature/js-sdk"> |
28 | | - <img alt="NPM Download" src="https://img.shields.io/npm/dm/%40openfeature%2Fjs-sdk" /> |
29 | | - </a> |
30 | | - <a href="https://codecov.io/gh/open-feature/js-sdk"> |
31 | | - <img alt="codecov" src="https://codecov.io/gh/open-feature/js-sdk/branch/main/graph/badge.svg?token=3DC5XOEHMY" /> |
32 | | - </a> |
33 | | - <a href="https://bestpractices.coreinfrastructure.org/projects/6594"> |
34 | | - <img alt="CII Best Practices" src="https://bestpractices.coreinfrastructure.org/projects/6594/badge" /> |
35 | | - </a> |
36 | | -</p> |
37 | | -<!-- x-hide-in-docs-start --> |
38 | | - |
39 | | -[OpenFeature](https://openfeature.dev) is an open standard that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool. |
40 | | - |
41 | | -<!-- x-hide-in-docs-end --> |
42 | | - |
43 | | -## 🚀 Quick start |
44 | | - |
45 | | -### Requirements |
46 | | - |
47 | | -- Node.js version 16+ |
48 | | - |
49 | | -### Install |
50 | | - |
51 | | -#### npm |
52 | | - |
53 | | -```sh |
54 | | -npm install --save @openfeature/js-sdk |
55 | | -``` |
56 | | - |
57 | | -#### yarn |
58 | | - |
59 | | -```sh |
60 | | -yarn add @openfeature/js-sdk |
61 | | -``` |
62 | | - |
63 | | -### Usage |
64 | | - |
65 | | -```ts |
66 | | -import { OpenFeature } from '@openfeature/js-sdk'; |
67 | | - |
68 | | -// Register your feature flag provider |
69 | | -OpenFeature.setProvider(new YourProviderOfChoice()); |
70 | | - |
71 | | -// create a new client |
72 | | -const client = OpenFeature.getClient(); |
73 | | - |
74 | | -// Evaluate your feature flag |
75 | | -const v2Enabled = await client.getBooleanValue('v2_enabled', false); |
76 | | - |
77 | | -if (v2Enabled) { |
78 | | - console.log("v2 is enabled"); |
79 | | -} |
80 | | -``` |
81 | | - |
82 | | -### API Reference |
83 | | - |
84 | | -See [here](https://open-feature.github.io/js-sdk/modules/OpenFeature_JS_SDK.html) for the complete API documentation. |
85 | | - |
86 | | -## 🌟 Features |
87 | | - |
88 | | -| Status | Features | Description | |
89 | | -| ------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | |
90 | | -| ✅ | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. | |
91 | | -| ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). | |
92 | | -| ✅ | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. | |
93 | | -| ✅ | [Logging](#logging) | Integrate with popular logging packages. | |
94 | | -| ✅ | [Named clients](#named-clients) | Utilize multiple providers in a single application. | |
95 | | -| ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. | |
96 | | -| ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. | |
97 | | -| ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. | |
98 | | - |
99 | | -<sub>Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌</sub> |
100 | | - |
101 | | -### Providers |
102 | | - |
103 | | -[Providers](https://openfeature.dev/docs/reference/concepts/provider) are an abstraction between a flag management system and the OpenFeature SDK. |
104 | | -Look [here](https://openfeature.dev/ecosystem/?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Provider&instant_search%5BrefinementList%5D%5Bcategory%5D%5B0%5D=Server-side&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=JavaScript) for a complete list of available providers. |
105 | | -If the provider you're looking for hasn't been created yet, see the [develop a provider](#develop-a-provider) section to learn how to build it yourself. |
106 | | - |
107 | | -Once you've added a provider as a dependency, it can be registered with OpenFeature like this: |
108 | | - |
109 | | -```ts |
110 | | -OpenFeature.setProvider(new MyProvider()) |
111 | | -``` |
112 | | - |
113 | | -In some situations, it may be beneficial to register multiple providers in the same application. |
114 | | -This is possible using [named clients](#named-clients), which is covered in more details below. |
115 | | - |
116 | | -### Targeting |
117 | | - |
118 | | -Sometimes, the value of a flag must consider some dynamic criteria about the application or user, such as the user's location, IP, email address, or the server's location. |
119 | | -In OpenFeature, we refer to this as [targeting](https://openfeature.dev/specification/glossary#targeting). |
120 | | -If the flag management system you're using supports targeting, you can provide the input data using the [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
121 | | - |
122 | | -```ts |
123 | | -// set a value to the global context |
124 | | -OpenFeature.setContext({ region: "us-east-1" }); |
125 | | - |
126 | | -// set a value to the client context |
127 | | -const client = OpenFeature.getClient(); |
128 | | -client.setContext({ version: process.env.APP_VERSION }); |
129 | | - |
130 | | -// set a value to the invocation context |
131 | | -const requestContext = { |
132 | | - targetingKey: req.session.id, |
133 | | - email: req.session.email, |
134 | | - product: req.productId |
135 | | -}; |
136 | | - |
137 | | -const boolValue = await client.getBooleanValue('some-flag', false, requestContext); |
138 | | -``` |
139 | | - |
140 | | -### Hooks |
141 | | - |
142 | | -[Hooks](https://openfeature.dev/docs/reference/concepts/hooks) allow for custom logic to be added at well-defined points of the flag evaluation life-cycle |
143 | | -Look [here](https://openfeature.dev/ecosystem/?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Hook&instant_search%5BrefinementList%5D%5Bcategory%5D%5B0%5D=Server-side&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=JavaScript) for a complete list of available hooks. |
144 | | -If the hook you're looking for hasn't been created yet, see the [develop a hook](#develop-a-hook) section to learn how to build it yourself. |
145 | | - |
146 | | -Once you've added a hook as a dependency, it can be registered at the global, client, or flag invocation level. |
147 | | - |
148 | | -```ts |
149 | | -import { OpenFeature } from "@openfeature/js-sdk"; |
150 | | - |
151 | | -// add a hook globally, to run on all evaluations |
152 | | -OpenFeature.addHooks(new ExampleGlobalHook()); |
153 | | - |
154 | | -// add a hook on this client, to run on all evaluations made by this client |
155 | | -const client = OpenFeature.getClient(); |
156 | | -client.addHooks(new ExampleClientHook()); |
157 | | - |
158 | | -// add a hook for this evaluation only |
159 | | -const boolValue = await client.getBooleanValue("bool-flag", false, { hooks: [new ExampleHook()]}); |
160 | | -``` |
161 | | - |
162 | | -### Logging |
163 | | - |
164 | | -The JS SDK will log warning and errors to the console by default. |
165 | | -This behavior can be overridden by passing a custom logger either globally or per client. |
166 | | -A custom logger must implement the [Logger interface](../shared/src/logger/logger.ts). |
167 | | - |
168 | | -```ts |
169 | | -import type { Logger } from "@openfeature/js-sdk"; |
170 | | - |
171 | | -// The logger can be anything that conforms with the Logger interface |
172 | | -const logger: Logger = console; |
173 | | - |
174 | | -// Sets a global logger |
175 | | -OpenFeature.setLogger(logger); |
176 | | - |
177 | | -// Sets a client logger |
178 | | -const client = OpenFeature.getClient(); |
179 | | -client.setLogger(logger); |
180 | | -``` |
181 | | - |
182 | | -### Named clients |
183 | | - |
184 | | -Clients can be given a name. |
185 | | -A name is a logical identifier which can be used to associate clients with a particular provider. |
186 | | -If a name has no associated provider, the global provider is used. |
187 | | - |
188 | | -```ts |
189 | | -import { OpenFeature, InMemoryProvider } from "@openfeature/js-sdk"; |
190 | | - |
191 | | -const myFlags = { |
192 | | - 'v2_enabled': { |
193 | | - variants: { |
194 | | - on: true, |
195 | | - off: false |
196 | | - }, |
197 | | - disabled: false, |
198 | | - defaultVariant: "on" |
199 | | - } |
200 | | -}; |
201 | | - |
202 | | -// Registering the default provider |
203 | | -OpenFeature.setProvider(InMemoryProvider(myFlags)); |
204 | | -// Registering a named provider |
205 | | -OpenFeature.setProvider("otherClient", new InMemoryProvider(someOtherFlags)); |
206 | | - |
207 | | -// A Client backed by default provider |
208 | | -const clientWithDefault = OpenFeature.getClient(); |
209 | | -// A Client backed by NewCachedProvider |
210 | | -const clientForCache = OpenFeature.getClient("otherClient"); |
211 | | -``` |
212 | | - |
213 | | -### Eventing |
214 | | - |
215 | | -Events allow you to react to state changes in the provider or underlying flag management system, such as flag definition changes, provider readiness, or error conditions. |
216 | | -Initialization events (`PROVIDER_READY` on success, `PROVIDER_ERROR` on failure) are dispatched for every provider. |
217 | | -Some providers support additional events, such as `PROVIDER_CONFIGURATION_CHANGED`. |
218 | | - |
219 | | -Please refer to the documentation of the provider you're using to see what events are supported. |
220 | | - |
221 | | -```ts |
222 | | -import { OpenFeature, ProviderEvents } from '@openfeature/js-sdk'; |
223 | | - |
224 | | -// OpenFeature API |
225 | | -OpenFeature.addHandler(ProviderEvents.Ready, (eventDetails) => { |
226 | | - console.log(`Ready event from: ${eventDetails?.clientName}:`, eventDetails); |
227 | | -}); |
228 | | - |
229 | | -// Specific client |
230 | | -const client = OpenFeature.getClient(); |
231 | | -client.addHandler(ProviderEvents.Error, (eventDetails) => { |
232 | | - console.log(`Error event from: ${eventDetails?.clientName}:`, eventDetails); |
233 | | -}); |
234 | | -``` |
235 | | - |
236 | | -### Shutdown |
237 | | - |
238 | | -The OpenFeature API provides a close function to perform a cleanup of all registered providers. |
239 | | -This should only be called when your application is in the process of shutting down. |
240 | | - |
241 | | -```ts |
242 | | -import { OpenFeature } from '@openfeature/js-sdk'; |
243 | | - |
244 | | -await OpenFeature.close() |
245 | | -``` |
246 | | - |
247 | | -## Extending |
248 | | - |
249 | | -### Develop a provider |
250 | | - |
251 | | -To develop a provider, you need to create a new project and include the OpenFeature SDK as a dependency. |
252 | | -This can be a new repository or included in [the existing contrib repository](https://github.com/open-feature/js-sdk-contrib) available under the OpenFeature organization. |
253 | | -You’ll then need to write the provider by implementing the [Provider interface](./src/provider/provider.ts) exported by the OpenFeature SDK. |
254 | | - |
255 | | -```ts |
256 | | -import { JsonValue, Provider, ResolutionDetails } from '@openfeature/js-sdk'; |
257 | | - |
258 | | -// implement the provider interface |
259 | | -class MyProvider implements Provider { |
260 | | - |
261 | | - readonly metadata = { |
262 | | - name: 'My Provider', |
263 | | - } as const; |
264 | | - |
265 | | - // Optional provider managed hooks |
266 | | - hooks?: Hook<FlagValue>[]; |
267 | | - |
268 | | - resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<boolean>> { |
269 | | - // code to evaluate a boolean |
270 | | - } |
271 | | - |
272 | | - resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<string>> { |
273 | | - // code to evaluate a string |
274 | | - } |
275 | | - |
276 | | - resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<number>> { |
277 | | - // code to evaluate a number |
278 | | - } |
279 | | - |
280 | | - resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<T>> { |
281 | | - // code to evaluate an object |
282 | | - } |
283 | | - |
284 | | - status?: ProviderStatus | undefined; |
285 | | - events?: OpenFeatureEventEmitter | undefined; |
286 | | - |
287 | | - initialize?(context?: EvaluationContext | undefined): Promise<void> { |
288 | | - // code to initialize your provider |
289 | | - } |
290 | | - |
291 | | - onClose?(): Promise<void> { |
292 | | - // code to shut down your provider |
293 | | - } |
294 | | -} |
295 | | -``` |
296 | | - |
297 | | -> Built a new provider? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=provider&projects=&template=document-provider.yaml&title=%5BProvider%5D%3A+) so we can add it to the docs! |
298 | | -
|
299 | | -### Develop a hook |
300 | | - |
301 | | -To develop a hook, you need to create a new project and include the OpenFeature SDK as a dependency. |
302 | | -This can be a new repository or included in [the existing contrib repository](https://github.com/open-feature/js-sdk-contrib) available under the OpenFeature organization. |
303 | | -Implement your own hook by conforming to the [Hook interface](../shared/src/hooks/hook.ts). |
304 | | - |
305 | | -```ts |
306 | | -import type { Hook, HookContext, EvaluationDetails, FlagValue } from "@openfeature/js-sdk"; |
307 | | - |
308 | | -export class MyHook implements Hook { |
309 | | - after(hookContext: HookContext, evaluationDetails: EvaluationDetails<FlagValue>) { |
310 | | - // code that runs when there's an error during a flag evaluation |
311 | | - } |
312 | | -} |
313 | | -``` |
314 | | - |
315 | | -> Built a new hook? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=hook&projects=&template=document-hook.yaml&title=%5BHook%5D%3A+) so we can add it to the docs! |
| 10 | +<h2 align="center">This package has been deprecated. It's been renamed (moved without changes) to @openfeature/server-sdk.</h2> |
0 commit comments