flagmint-js-sdk 1.2.20 → 1.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -55
- package/dist/flagmint.cjs.js +8 -8
- package/dist/flagmint.es.js +4659 -4616
- package/dist/flagmint.umd.js +8 -8
- package/dist/index.d.ts +2 -1
- package/dist/sdk/core/client.d.ts +2 -0
- package/dist/sdk/core/evaluation/rolloutUtils.d.ts +2 -2
- package/dist/sdk/core/evaluation/types.d.ts +3 -1
- package/dist/sdk/core/helpers/ensureContextSource.d.ts +1 -0
- package/dist/sdk/core/helpers/logger.d.ts +11 -0
- package/dist/sdk/core/transports/WebsocketTransport.d.ts +1 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Flagmint JavaScript SDK
|
|
2
2
|
|
|
3
|
-
**Version: 1.2.
|
|
3
|
+
**Version: 1.2.21**
|
|
4
4
|
|
|
5
|
-
This SDK provides a framework-agnostic client for evaluating feature flags, with pluggable caching (sync or async) and transport strategies (WebSocket or long-polling). It's designed for both browser and server-side Node.js environments.
|
|
5
|
+
This SDK provides a javascript framework-agnostic client for evaluating feature flags, with pluggable caching (sync or async) and transport strategies (WebSocket or long-polling). It's designed for both browser and server-side Node.js environments.
|
|
6
6
|
|
|
7
7
|
## ✨ Key Features
|
|
8
8
|
|
|
@@ -21,10 +21,10 @@ npm install flagmint-js-sdk
|
|
|
21
21
|
yarn add flagmint-js-sdk
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Quick Start
|
|
25
25
|
|
|
26
26
|
```ts
|
|
27
|
-
import { FlagClient } from 'flagmint-sdk';
|
|
27
|
+
import { FlagClient } from 'flagmint-js-sdk';
|
|
28
28
|
|
|
29
29
|
// Create a client instance
|
|
30
30
|
const client = new FlagClient({
|
|
@@ -36,7 +36,7 @@ const client = new FlagClient({
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
// Wait for initial connection
|
|
39
|
+
// Wait for initial connection and flag synchronization
|
|
40
40
|
await client.ready();
|
|
41
41
|
|
|
42
42
|
// Get flag values
|
|
@@ -44,7 +44,10 @@ const showBanner = client.getFlag('show_banner', false);
|
|
|
44
44
|
const featureVersion = client.getFlag('feature_version', 'v1');
|
|
45
45
|
|
|
46
46
|
// Update context and re-evaluate
|
|
47
|
-
client.updateContext({
|
|
47
|
+
await client.updateContext({
|
|
48
|
+
kind: "user",
|
|
49
|
+
user: { kind: "user", key: 'user456', email: 'user456@example.com' }
|
|
50
|
+
});
|
|
48
51
|
```
|
|
49
52
|
|
|
50
53
|
## FlagClientOptions
|
|
@@ -53,14 +56,14 @@ client.updateContext({ user_id: 'user456' });
|
|
|
53
56
|
| --------------------- | ----------------------------------------- | ------------------ | --------------------------------------------------------------------- |
|
|
54
57
|
| `apiKey` | `string` | **Required** | Your environment API key. |
|
|
55
58
|
| `context` | `Record<string, any>` | `{}` | Initial evaluation context (e.g. user attributes). |
|
|
56
|
-
| `enableOfflineCache` | `boolean` | `
|
|
59
|
+
| `enableOfflineCache` | `boolean` | `true` | Enable caching of flags locally. |
|
|
57
60
|
| `persistContext` | `boolean` | `false` | Persist evaluation context across sessions. | |
|
|
58
61
|
| `cacheAdapter` | `CacheAdapter<C>` | Sync `cacheHelper` | Custom cache implementation (see examples). |
|
|
59
62
|
| `transportMode` | `'auto' \| 'websocket' \| 'long-polling'` | `'auto'` | How to fetch flags: prefer WebSocket, or use long-polling transport. |
|
|
60
|
-
| `onError` | `(error: Error) => void` | — | Callback for transport or initialization errors.
|
|
63
|
+
| `onError` | `(error: Error) => void` | — | Callback for transport or initialization errors. Called when operating in degraded mode with cached flags. |
|
|
61
64
|
| `previewMode` | `boolean` | `false` | Evaluate using `rawFlags` only, bypassing remote fetch. |
|
|
62
65
|
| `rawFlags` | `Record<string, FlagValue>` | — | Local-only flag definitions used when `previewMode: true`. |
|
|
63
|
-
| `deferInitialization` | `boolean` | `false` | If `true`, client initialization is deferred until you call `
|
|
66
|
+
| `deferInitialization` | `boolean` | `false` | If `true`, client initialization is deferred until you call `ready()`. |
|
|
64
67
|
|
|
65
68
|
## 🔧 Cache Adapters
|
|
66
69
|
|
|
@@ -69,10 +72,9 @@ client.updateContext({ user_id: 'user456' });
|
|
|
69
72
|
By default, the SDK uses a **sync** `localStorage`-based helper in browsers or a `Map` in Node.js:
|
|
70
73
|
|
|
71
74
|
```ts
|
|
72
|
-
import { FlagClient } from 'flagmint-sdk';
|
|
75
|
+
import { FlagClient, syncCache } from 'flagmint-js-sdk';
|
|
73
76
|
// No setup needed for browser; for Node you can override:
|
|
74
|
-
|
|
75
|
-
setCacheStorage({
|
|
77
|
+
syncCache.setCacheStorage({
|
|
76
78
|
getItem: key => myMap.get(key) ?? null,
|
|
77
79
|
setItem: (key, val) => myMap.set(key, val),
|
|
78
80
|
});
|
|
@@ -83,8 +85,7 @@ setCacheStorage({
|
|
|
83
85
|
Use the **async** helper for server-side or React Native:
|
|
84
86
|
|
|
85
87
|
```ts
|
|
86
|
-
import { FlagClient } from 'flagmint-sdk';
|
|
87
|
-
import * as asyncCache from 'flagmint-sdk/core/cacheHelper.async';
|
|
88
|
+
import { FlagClient, asyncCache } from 'flagmint-js-sdk';
|
|
88
89
|
|
|
89
90
|
const client = new FlagClient({
|
|
90
91
|
apiKey: '...',
|
|
@@ -125,7 +126,7 @@ The SDK includes utilities to evaluate flag targeting rules and rollouts:
|
|
|
125
126
|
### `evaluateFlagValue(flag, context)`
|
|
126
127
|
|
|
127
128
|
```ts
|
|
128
|
-
import { evaluateFlagValue } from 'flagmint-sdk
|
|
129
|
+
import { evaluateFlagValue } from 'flagmint-js-sdk';
|
|
129
130
|
|
|
130
131
|
const result = evaluateFlagValue(flagValue, userContext);
|
|
131
132
|
```
|
|
@@ -137,7 +138,7 @@ const result = evaluateFlagValue(flagValue, userContext);
|
|
|
137
138
|
### `evaluateRollout(rollout, context)`
|
|
138
139
|
|
|
139
140
|
```ts
|
|
140
|
-
import { evaluateRollout } from 'flagmint-sdk
|
|
141
|
+
import { evaluateRollout } from 'flagmint-js-sdk';
|
|
141
142
|
|
|
142
143
|
const rolloutValue = evaluateRollout(rolloutConfig, userContext);
|
|
143
144
|
```
|
|
@@ -148,16 +149,16 @@ const rolloutValue = evaluateRollout(rolloutConfig, userContext);
|
|
|
148
149
|
### `rolloutUtils`
|
|
149
150
|
|
|
150
151
|
* `hashToPercentage(value: string): number`
|
|
151
|
-
* `pickVariant(value: string, variants:
|
|
152
|
+
* `pickVariant(value: string, variants: VariantOption[]): string | number | boolean | null`
|
|
152
153
|
|
|
153
154
|
These helpers underpin reliable, deterministic assignment of users to flag variants.
|
|
154
155
|
|
|
155
|
-
### `isInSegment(
|
|
156
|
+
### `isInSegment(segment, context)`
|
|
156
157
|
|
|
157
158
|
```ts
|
|
158
|
-
import { isInSegment } from 'flagmint-sdk
|
|
159
|
+
import { isInSegment } from 'flagmint-js-sdk';
|
|
159
160
|
|
|
160
|
-
const inBetaSegment = isInSegment(
|
|
161
|
+
const inBetaSegment = isInSegment(betaSegment, userContext);
|
|
161
162
|
```
|
|
162
163
|
|
|
163
164
|
Evaluates whether a user context matches a segment's criteria.
|
|
@@ -168,7 +169,7 @@ Evaluates whether a user context matches a segment's criteria.
|
|
|
168
169
|
|
|
169
170
|
```tsx
|
|
170
171
|
import { useEffect, useState } from 'react';
|
|
171
|
-
import { FlagClient } from 'flagmint-sdk';
|
|
172
|
+
import { FlagClient } from 'flagmint-js-sdk';
|
|
172
173
|
|
|
173
174
|
const client = new FlagClient({
|
|
174
175
|
apiKey: 'ff_...',
|
|
@@ -189,6 +190,16 @@ export function App() {
|
|
|
189
190
|
theme: client.getFlag('theme', 'light')
|
|
190
191
|
});
|
|
191
192
|
});
|
|
193
|
+
|
|
194
|
+
// Subscribe to flag updates
|
|
195
|
+
const unsubscribe = client.subscribe((updatedFlags) => {
|
|
196
|
+
setFlags({
|
|
197
|
+
showBeta: client.getFlag('show_beta', false),
|
|
198
|
+
theme: client.getFlag('theme', 'light')
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return () => unsubscribe();
|
|
192
203
|
}, []);
|
|
193
204
|
|
|
194
205
|
return (
|
|
@@ -202,8 +213,7 @@ export function App() {
|
|
|
202
213
|
### Node.js / Express
|
|
203
214
|
|
|
204
215
|
```ts
|
|
205
|
-
import { FlagClient } from 'flagmint-sdk';
|
|
206
|
-
import * as asyncCache from 'flagmint-sdk/core/cacheHelper.async';
|
|
216
|
+
import { FlagClient, asyncCache } from 'flagmint-js-sdk';
|
|
207
217
|
|
|
208
218
|
const client = new FlagClient({
|
|
209
219
|
apiKey: 'ff_...',
|
|
@@ -215,9 +225,26 @@ const client = new FlagClient({
|
|
|
215
225
|
}
|
|
216
226
|
});
|
|
217
227
|
|
|
228
|
+
// Wait for initialization
|
|
229
|
+
await client.ready();
|
|
230
|
+
|
|
218
231
|
app.get('/api/feature', async (req, res) => {
|
|
219
|
-
|
|
220
|
-
|
|
232
|
+
// Update context with proper structure
|
|
233
|
+
await client.updateContext({
|
|
234
|
+
kind: "multi",
|
|
235
|
+
user: {
|
|
236
|
+
kind: "user",
|
|
237
|
+
key: req.user.id,
|
|
238
|
+
email: req.user.email
|
|
239
|
+
},
|
|
240
|
+
organization: {
|
|
241
|
+
kind: "organization",
|
|
242
|
+
key: req.user.orgId,
|
|
243
|
+
plan: req.user.plan
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const isEnabled = client.getFlag('new_api', false);
|
|
221
248
|
|
|
222
249
|
res.json({ enabled: isEnabled });
|
|
223
250
|
});
|
|
@@ -231,14 +258,26 @@ app.get('/api/feature', async (req, res) => {
|
|
|
231
258
|
// Initial context
|
|
232
259
|
const client = new FlagClient({
|
|
233
260
|
apiKey: '...',
|
|
234
|
-
context: {
|
|
261
|
+
context: {
|
|
262
|
+
kind: "user",
|
|
263
|
+
user: { kind: "user", key: 'user123' }
|
|
264
|
+
}
|
|
235
265
|
});
|
|
236
266
|
|
|
237
|
-
// Update context later
|
|
238
|
-
client.updateContext({
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
267
|
+
// Update context later (e.g., after user upgrades)
|
|
268
|
+
await client.updateContext({
|
|
269
|
+
kind: "multi",
|
|
270
|
+
user: {
|
|
271
|
+
kind: "user",
|
|
272
|
+
key: 'user123',
|
|
273
|
+
email: 'user@example.com'
|
|
274
|
+
},
|
|
275
|
+
organization: {
|
|
276
|
+
kind: "organization",
|
|
277
|
+
key: 'org456',
|
|
278
|
+
plan: 'premium',
|
|
279
|
+
country: 'CA'
|
|
280
|
+
}
|
|
242
281
|
});
|
|
243
282
|
```
|
|
244
283
|
|
|
@@ -248,7 +287,10 @@ client.updateContext({
|
|
|
248
287
|
const client = new FlagClient({
|
|
249
288
|
apiKey: '...',
|
|
250
289
|
persistContext: true, // Saves to localStorage/AsyncStorage
|
|
251
|
-
context: {
|
|
290
|
+
context: {
|
|
291
|
+
kind: "user",
|
|
292
|
+
user: { kind: "user", key: 'user123', email: 'user@example.com' }
|
|
293
|
+
}
|
|
252
294
|
});
|
|
253
295
|
```
|
|
254
296
|
|
|
@@ -263,8 +305,11 @@ const client = new FlagClient({
|
|
|
263
305
|
});
|
|
264
306
|
|
|
265
307
|
// Later, when context is ready:
|
|
266
|
-
client.updateContext({
|
|
267
|
-
|
|
308
|
+
await client.updateContext({
|
|
309
|
+
kind: "user",
|
|
310
|
+
user: { kind: "user", key: 'user123', email: 'user@example.com' }
|
|
311
|
+
});
|
|
312
|
+
await client.ready(); // Initializes and connects
|
|
268
313
|
```
|
|
269
314
|
|
|
270
315
|
## 🌍 Advanced Usage
|
|
@@ -282,6 +327,42 @@ const client = new FlagClient({
|
|
|
282
327
|
});
|
|
283
328
|
```
|
|
284
329
|
|
|
330
|
+
**Important: Offline Fallback & Cache Behavior**
|
|
331
|
+
|
|
332
|
+
The SDK gracefully handles connection failures using cached flags as a fallback:
|
|
333
|
+
|
|
334
|
+
**When the server is unreachable:**
|
|
335
|
+
|
|
336
|
+
| Scenario | `ready()` Promise | Behavior |
|
|
337
|
+
|----------|-------------------|----------|
|
|
338
|
+
| ✅ Cached flags available | Resolves | Operates in degraded mode with cached flags |
|
|
339
|
+
| ❌ No cached flags | Rejects | Initialization fails |
|
|
340
|
+
| ✅ Connected successfully | Resolves | Normal operation with live updates |
|
|
341
|
+
|
|
342
|
+
**Degraded Mode:** When `ready()` resolves but the connection failed, the `onError` callback is triggered to notify you:
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
const client = new FlagClient({
|
|
346
|
+
apiKey: '...',
|
|
347
|
+
enableOfflineCache: true,
|
|
348
|
+
onError: (error) => {
|
|
349
|
+
// Called when operating in degraded mode with cached flags
|
|
350
|
+
console.warn('⚠️ Degraded mode - using cached flags:', error.message);
|
|
351
|
+
// Optionally report to monitoring service
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
await client.ready();
|
|
357
|
+
// ✅ Resolves successfully even if server is down (when cached flags exist)
|
|
358
|
+
console.log('Client ready');
|
|
359
|
+
const feature = client.getFlag('my_feature', false); // Always works
|
|
360
|
+
} catch (error) {
|
|
361
|
+
// ❌ Only throws if NO cached flags AND server is unreachable
|
|
362
|
+
console.error('Completely offline:', error);
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
285
366
|
### Preview Mode
|
|
286
367
|
|
|
287
368
|
For testing or preview environments where you want to bypass remote flag fetching:
|
|
@@ -304,7 +385,7 @@ const checkout = client.getFlag('new_checkout', false); // true
|
|
|
304
385
|
### Custom Cache Implementations
|
|
305
386
|
|
|
306
387
|
```ts
|
|
307
|
-
import { FlagClient } from 'flagmint-sdk';
|
|
388
|
+
import { FlagClient } from 'flagmint-js-sdk';
|
|
308
389
|
import redis from 'redis';
|
|
309
390
|
|
|
310
391
|
const redisClient = redis.createClient();
|
|
@@ -343,17 +424,26 @@ const client = new FlagClient({
|
|
|
343
424
|
### `FlagClient`
|
|
344
425
|
|
|
345
426
|
**Methods:**
|
|
346
|
-
- `ready(): Promise<void>` - Wait for initial connection
|
|
347
|
-
- `getFlag<
|
|
348
|
-
- `
|
|
349
|
-
- `
|
|
350
|
-
- `
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
427
|
+
- `ready(timeoutMs?: number): Promise<void>` - Wait for initial connection (default timeout: 3000ms)
|
|
428
|
+
- `getFlag<K>(key: K, fallback?: T): T` - Get flag value with optional fallback
|
|
429
|
+
- `getFlags(): FeatureFlags<T>` - Get all flags as an object
|
|
430
|
+
- `updateContext(context: Record<string, any>): Promise<void>` - Update evaluation context (async)
|
|
431
|
+
- `subscribe(callback: (flags) => void): () => void` - Subscribe to flag updates, returns unsubscribe function
|
|
432
|
+
- `destroy(): void` - Close transport connection and cleanup resources
|
|
433
|
+
|
|
434
|
+
### Subscribing to Flag Updates
|
|
435
|
+
|
|
436
|
+
Instead of event listeners, use the `subscribe()` method:
|
|
437
|
+
|
|
438
|
+
```ts
|
|
439
|
+
const unsubscribe = client.subscribe((flags) => {
|
|
440
|
+
console.log('Flags updated:', flags);
|
|
441
|
+
// Handle flag updates
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// Later, to unsubscribe:
|
|
445
|
+
unsubscribe();
|
|
446
|
+
```
|
|
357
447
|
|
|
358
448
|
### Cache Adapter Interface
|
|
359
449
|
|
|
@@ -403,9 +493,20 @@ sdk/
|
|
|
403
493
|
|
|
404
494
|
### Flags not updating
|
|
405
495
|
|
|
406
|
-
- Confirm `enableOfflineCache
|
|
496
|
+
- Confirm `enableOfflineCache` setting matches your needs
|
|
407
497
|
- Check transport mode (WebSocket vs long-polling)
|
|
408
|
-
- Verify context is properly set with `updateContext()`
|
|
498
|
+
- Verify context is properly set with `await updateContext()`
|
|
499
|
+
- Use `subscribe()` to listen for flag changes instead of polling
|
|
500
|
+
|
|
501
|
+
### Cache behavior when server is down
|
|
502
|
+
|
|
503
|
+
**Important**: When `enableOfflineCache: true` (default):
|
|
504
|
+
- Cached flags are loaded even if the server is unreachable
|
|
505
|
+
- `ready()` will still throw an error on connection failure
|
|
506
|
+
- You can still access cached flags via `getFlag()` after catching the error
|
|
507
|
+
- Consider wrapping `ready()` in try/catch and continuing with cached data
|
|
508
|
+
|
|
509
|
+
See the "Error Handling with Cache" section above for examples.
|
|
409
510
|
|
|
410
511
|
### Performance issues
|
|
411
512
|
|
|
@@ -419,14 +520,9 @@ sdk/
|
|
|
419
520
|
- **Issues**: Report on [GitHub](https://github.com/flagmint/js-sdk/issues)
|
|
420
521
|
- **Email**: support@flagmint.io
|
|
421
522
|
|
|
422
|
-
## 🚀 Changelog
|
|
523
|
+
## 🚀 Releases & Changelog
|
|
423
524
|
|
|
424
|
-
|
|
425
|
-
- Enhanced async cache helper for better server-side support
|
|
426
|
-
- Improved WebSocket connection stability
|
|
427
|
-
- Better error reporting and handling
|
|
428
|
-
- Added support for context persistence
|
|
429
|
-
- Performance optimizations for large flag sets
|
|
525
|
+
See [GitHub Releases](https://github.com/flagmint/js-sdk/releases) for the complete version history, changelog, and upgrade guides.
|
|
430
526
|
|
|
431
527
|
## 📖 References
|
|
432
528
|
|