@replanejs/sdk 0.8.20 → 0.9.2
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 +78 -83
- package/dist/index.cjs +277 -264
- package/dist/index.d.cts +197 -186
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +197 -186
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +276 -261
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ yarn add @replanejs/sdk
|
|
|
36
36
|
> **Important:** Each SDK key is tied to a specific project. The client can only access configs from the project that the SDK key belongs to. If you need configs from multiple projects, create separate SDK keys and initialize separate clients—one per project.
|
|
37
37
|
|
|
38
38
|
```ts
|
|
39
|
-
import {
|
|
39
|
+
import { Replane } from "@replanejs/sdk";
|
|
40
40
|
|
|
41
41
|
// Define your config types
|
|
42
42
|
interface Configs {
|
|
@@ -50,8 +50,15 @@ interface PasswordRequirements {
|
|
|
50
50
|
requireSymbol: boolean;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
// Create the client with optional constructor options
|
|
54
|
+
const replane = new Replane<Configs>({
|
|
55
|
+
context: {
|
|
56
|
+
environment: "production",
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Connect to the server
|
|
61
|
+
await replane.connect({
|
|
55
62
|
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
56
63
|
baseUrl: "https://replane.my-hosting.com",
|
|
57
64
|
});
|
|
@@ -83,35 +90,42 @@ if (enabled) {
|
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
// When done, clean up resources
|
|
86
|
-
replane.
|
|
93
|
+
replane.disconnect();
|
|
87
94
|
```
|
|
88
95
|
|
|
89
96
|
## API
|
|
90
97
|
|
|
91
|
-
### `
|
|
98
|
+
### `new Replane<T>(options?)`
|
|
92
99
|
|
|
93
|
-
|
|
100
|
+
Creates a new Replane client instance.
|
|
94
101
|
|
|
95
102
|
Type parameter `T` defines the shape of your configs (a mapping of config names to their value types).
|
|
96
103
|
|
|
97
|
-
|
|
104
|
+
The client is usable immediately after construction if you provide `defaults` or a `snapshot`. Call `connect()` to establish a server connection for real-time updates.
|
|
105
|
+
|
|
106
|
+
#### Constructor Options
|
|
107
|
+
|
|
108
|
+
- `context` (object) – default context for all config evaluations. Can be overridden per-request in `get()`. Optional.
|
|
109
|
+
- `defaults` (object) – default values to use before connecting or if the connection fails. These values are available immediately. Optional.
|
|
110
|
+
- `snapshot` (object) – restore from a previous `getSnapshot()` call. Useful for SSR/hydration scenarios. Optional.
|
|
111
|
+
- `logger` (object) – custom logger with `debug`, `info`, `warn`, `error` methods. Default: `console`.
|
|
112
|
+
|
|
113
|
+
### `replane.connect(options)`
|
|
114
|
+
|
|
115
|
+
Connects to the Replane server and starts receiving real-time updates via SSE.
|
|
116
|
+
|
|
117
|
+
Returns a Promise that resolves when the connection is established and initial configs are loaded.
|
|
98
118
|
|
|
99
|
-
#### Options
|
|
119
|
+
#### Connect Options
|
|
100
120
|
|
|
101
121
|
- `baseUrl` (string) – Replane origin (no trailing slash needed). Required.
|
|
102
122
|
- `sdkKey` (string) – SDK key for authorization. Required. **Note:** Each SDK key is tied to a specific project and can only access configs from that project. To access configs from multiple projects, create multiple SDK keys and initialize separate client instances.
|
|
103
|
-
- `required` (object or array) – mark specific configs as required. If any required config is missing, the client will throw an error during initialization. Can be an object with boolean values or an array of config names. Optional.
|
|
104
|
-
- `defaults` (object) – default values to use if the initial request to fetch configs fails or times out. These values are used immediately while waiting for server connection. Allows the client to start even when the API is unavailable. Optional.
|
|
105
|
-
- `context` (object) – default context for all config evaluations. Can be overridden per-request in `get()`. Optional.
|
|
106
123
|
- `fetchFn` (function) – custom fetch (e.g. `undici.fetch` or mocked fetch in tests). Optional.
|
|
107
124
|
- `requestTimeoutMs` (number) – timeout for SSE requests in ms. Default: 2000.
|
|
108
|
-
- `
|
|
125
|
+
- `connectTimeoutMs` (number) – timeout for initial connection in ms. Default: 5000.
|
|
109
126
|
- `retryDelayMs` (number) – base delay between retries in ms. Default: 200.
|
|
110
127
|
- `inactivityTimeoutMs` (number) – timeout for SSE inactivity before reconnecting in ms. Default: 30000.
|
|
111
|
-
- `logger` (object) – custom logger with `debug`, `info`, `warn`, `error` methods. Default: `console`.
|
|
112
128
|
- `agent` (string) – agent identifier sent in User-Agent header.
|
|
113
|
-
- `onConnectionError` (function) – callback invoked when a connection error occurs during SSE streaming.
|
|
114
|
-
- `onConnected` (function) – callback invoked when the SSE connection is successfully established.
|
|
115
129
|
|
|
116
130
|
### `replane.get<K>(name, options?)`
|
|
117
131
|
|
|
@@ -141,7 +155,8 @@ interface Configs {
|
|
|
141
155
|
"max-connections": number;
|
|
142
156
|
}
|
|
143
157
|
|
|
144
|
-
const replane =
|
|
158
|
+
const replane = new Replane<Configs>();
|
|
159
|
+
await replane.connect({
|
|
145
160
|
sdkKey: "your-sdk-key",
|
|
146
161
|
baseUrl: "https://replane.my-host.com",
|
|
147
162
|
});
|
|
@@ -158,7 +173,7 @@ const userEnabled = replane.get("billing-enabled", {
|
|
|
158
173
|
const maxConnections = replane.get("max-connections", { default: 10 });
|
|
159
174
|
|
|
160
175
|
// Clean up when done
|
|
161
|
-
replane.
|
|
176
|
+
replane.disconnect();
|
|
162
177
|
```
|
|
163
178
|
|
|
164
179
|
### `replane.subscribe(callback)` or `replane.subscribe(configName, callback)`
|
|
@@ -197,7 +212,8 @@ interface Configs {
|
|
|
197
212
|
"max-connections": number;
|
|
198
213
|
}
|
|
199
214
|
|
|
200
|
-
const replane =
|
|
215
|
+
const replane = new Replane<Configs>();
|
|
216
|
+
await replane.connect({
|
|
201
217
|
sdkKey: "your-sdk-key",
|
|
202
218
|
baseUrl: "https://replane.my-host.com",
|
|
203
219
|
});
|
|
@@ -218,61 +234,55 @@ unsubscribeAll();
|
|
|
218
234
|
unsubscribeFeature();
|
|
219
235
|
|
|
220
236
|
// Clean up when done
|
|
221
|
-
replane.
|
|
237
|
+
replane.disconnect();
|
|
222
238
|
```
|
|
223
239
|
|
|
224
|
-
###
|
|
225
|
-
|
|
226
|
-
Creates a client backed by an in-memory store instead of making HTTP requests. Handy for unit tests or local development where you want deterministic config values without a server.
|
|
240
|
+
### In-memory client (testing)
|
|
227
241
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
- `initialData` (object) – map of config name to value.
|
|
231
|
-
|
|
232
|
-
Returns the same client shape as `createReplaneClient` (`{ get, subscribe, close }`).
|
|
233
|
-
|
|
234
|
-
Notes:
|
|
235
|
-
|
|
236
|
-
- `get(name)` resolves to the value from `initialData`.
|
|
237
|
-
- If a name is missing, it throws a `ReplaneError` (`Config not found: <name>`).
|
|
238
|
-
- The client works as usual but doesn't receive SSE updates (values remain whatever is in-memory).
|
|
239
|
-
|
|
240
|
-
Example:
|
|
242
|
+
For unit tests or local development where you want deterministic config values without a server, create a `Replane` instance with `defaults` and don't call `connect()`:
|
|
241
243
|
|
|
242
244
|
```ts
|
|
243
|
-
import {
|
|
245
|
+
import { Replane } from "@replanejs/sdk";
|
|
244
246
|
|
|
245
247
|
interface Configs {
|
|
246
248
|
"feature-a": boolean;
|
|
247
249
|
"max-items": { value: number; ttl: number };
|
|
248
250
|
}
|
|
249
251
|
|
|
250
|
-
const replane =
|
|
251
|
-
|
|
252
|
-
|
|
252
|
+
const replane = new Replane<Configs>({
|
|
253
|
+
defaults: {
|
|
254
|
+
"feature-a": true,
|
|
255
|
+
"max-items": { value: 10, ttl: 3600 },
|
|
256
|
+
},
|
|
253
257
|
});
|
|
254
258
|
|
|
259
|
+
// No connect() call - works purely from defaults
|
|
260
|
+
|
|
255
261
|
const featureA = replane.get("feature-a"); // TypeScript knows this is boolean
|
|
256
262
|
console.log(featureA); // true
|
|
257
263
|
|
|
258
264
|
const maxItems = replane.get("max-items"); // TypeScript knows the type
|
|
259
265
|
console.log(maxItems); // { value: 10, ttl: 3600 }
|
|
260
|
-
|
|
261
|
-
replane.close();
|
|
262
266
|
```
|
|
263
267
|
|
|
264
|
-
|
|
268
|
+
Notes:
|
|
269
|
+
|
|
270
|
+
- `get(name)` returns the value from `defaults`.
|
|
271
|
+
- If a name is missing, it throws a `ReplaneError` (`Config not found: <name>`).
|
|
272
|
+
- The client works as usual but doesn't receive SSE updates (values remain whatever is in-memory).
|
|
265
273
|
|
|
266
|
-
|
|
274
|
+
### `replane.disconnect()`
|
|
275
|
+
|
|
276
|
+
Gracefully shuts down the Replane client and cleans up resources. Safe to call multiple times. Use this in environments where you manage resource lifecycles explicitly (e.g. shutting down a server or worker).
|
|
267
277
|
|
|
268
278
|
```ts
|
|
269
279
|
// During shutdown
|
|
270
|
-
replane.
|
|
280
|
+
replane.disconnect();
|
|
271
281
|
```
|
|
272
282
|
|
|
273
283
|
### Errors
|
|
274
284
|
|
|
275
|
-
`
|
|
285
|
+
`replane.connect()` throws if the initial request to fetch configs fails with non‑2xx HTTP responses and network errors. A `ReplaneError` is thrown for HTTP failures; other errors may be thrown for network/parse issues.
|
|
276
286
|
|
|
277
287
|
The Replane client receives realtime updates via SSE in the background. SSE connection errors are logged and automatically retried, but don't affect `get` calls (which return the last known value).
|
|
278
288
|
|
|
@@ -295,7 +305,8 @@ interface Configs {
|
|
|
295
305
|
layout: LayoutConfig;
|
|
296
306
|
}
|
|
297
307
|
|
|
298
|
-
const replane =
|
|
308
|
+
const replane = new Replane<Configs>();
|
|
309
|
+
await replane.connect({
|
|
299
310
|
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
300
311
|
baseUrl: "https://replane.my-host.com",
|
|
301
312
|
});
|
|
@@ -311,7 +322,8 @@ interface Configs {
|
|
|
311
322
|
"advanced-features": boolean;
|
|
312
323
|
}
|
|
313
324
|
|
|
314
|
-
const replane =
|
|
325
|
+
const replane = new Replane<Configs>();
|
|
326
|
+
await replane.connect({
|
|
315
327
|
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
316
328
|
baseUrl: "https://replane.my-host.com",
|
|
317
329
|
});
|
|
@@ -336,14 +348,16 @@ interface Configs {
|
|
|
336
348
|
"feature-flag": boolean;
|
|
337
349
|
}
|
|
338
350
|
|
|
339
|
-
const replane =
|
|
340
|
-
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
341
|
-
baseUrl: "https://replane.my-host.com",
|
|
351
|
+
const replane = new Replane<Configs>({
|
|
342
352
|
context: {
|
|
343
353
|
userId: "user-123",
|
|
344
354
|
region: "us-east",
|
|
345
355
|
},
|
|
346
356
|
});
|
|
357
|
+
await replane.connect({
|
|
358
|
+
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
359
|
+
baseUrl: "https://replane.my-host.com",
|
|
360
|
+
});
|
|
347
361
|
|
|
348
362
|
// This context is used for all configs unless overridden
|
|
349
363
|
const value1 = replane.get("feature-flag"); // Uses client-level context
|
|
@@ -355,38 +369,14 @@ const value2 = replane.get("feature-flag", {
|
|
|
355
369
|
### Custom fetch (tests)
|
|
356
370
|
|
|
357
371
|
```ts
|
|
358
|
-
const replane =
|
|
372
|
+
const replane = new Replane();
|
|
373
|
+
await replane.connect({
|
|
359
374
|
sdkKey: "TKN",
|
|
360
375
|
baseUrl: "https://api",
|
|
361
376
|
fetchFn: mockFetch,
|
|
362
377
|
});
|
|
363
378
|
```
|
|
364
379
|
|
|
365
|
-
### Required configs
|
|
366
|
-
|
|
367
|
-
```ts
|
|
368
|
-
interface Configs {
|
|
369
|
-
"api-key": string;
|
|
370
|
-
"database-url": string;
|
|
371
|
-
"optional-feature": boolean;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const replane = await createReplaneClient<Configs>({
|
|
375
|
-
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
376
|
-
baseUrl: "https://replane.my-host.com",
|
|
377
|
-
required: {
|
|
378
|
-
"api-key": true,
|
|
379
|
-
"database-url": true,
|
|
380
|
-
"optional-feature": false, // Not required
|
|
381
|
-
},
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
// Alternative: use an array
|
|
385
|
-
// required: ["api-key", "database-url"]
|
|
386
|
-
|
|
387
|
-
// If any required config is missing, initialization will throw
|
|
388
|
-
```
|
|
389
|
-
|
|
390
380
|
### Default configs
|
|
391
381
|
|
|
392
382
|
```ts
|
|
@@ -396,15 +386,17 @@ interface Configs {
|
|
|
396
386
|
"timeout-ms": number;
|
|
397
387
|
}
|
|
398
388
|
|
|
399
|
-
const replane =
|
|
400
|
-
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
401
|
-
baseUrl: "https://replane.my-host.com",
|
|
389
|
+
const replane = new Replane<Configs>({
|
|
402
390
|
defaults: {
|
|
403
391
|
"feature-flag": false, // Use false if fetch fails
|
|
404
392
|
"max-connections": 10, // Use 10 if fetch fails
|
|
405
393
|
"timeout-ms": 5000, // Use 5s if fetch fails
|
|
406
394
|
},
|
|
407
395
|
});
|
|
396
|
+
await replane.connect({
|
|
397
|
+
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
398
|
+
baseUrl: "https://replane.my-host.com",
|
|
399
|
+
});
|
|
408
400
|
|
|
409
401
|
// If the initial fetch fails or times out, default values are used
|
|
410
402
|
// Once the client connects, it will receive realtime updates
|
|
@@ -425,12 +417,14 @@ interface ProjectBConfigs {
|
|
|
425
417
|
}
|
|
426
418
|
|
|
427
419
|
// Each project needs its own SDK key and Replane client instance
|
|
428
|
-
const projectAConfigs =
|
|
420
|
+
const projectAConfigs = new Replane<ProjectAConfigs>();
|
|
421
|
+
await projectAConfigs.connect({
|
|
429
422
|
sdkKey: process.env.PROJECT_A_SDK_KEY!,
|
|
430
423
|
baseUrl: "https://replane.my-host.com",
|
|
431
424
|
});
|
|
432
425
|
|
|
433
|
-
const projectBConfigs =
|
|
426
|
+
const projectBConfigs = new Replane<ProjectBConfigs>();
|
|
427
|
+
await projectBConfigs.connect({
|
|
434
428
|
sdkKey: process.env.PROJECT_B_SDK_KEY!,
|
|
435
429
|
baseUrl: "https://replane.my-host.com",
|
|
436
430
|
});
|
|
@@ -448,7 +442,8 @@ interface Configs {
|
|
|
448
442
|
"max-users": number;
|
|
449
443
|
}
|
|
450
444
|
|
|
451
|
-
const replane =
|
|
445
|
+
const replane = new Replane<Configs>();
|
|
446
|
+
await replane.connect({
|
|
452
447
|
sdkKey: process.env.REPLANE_SDK_KEY!,
|
|
453
448
|
baseUrl: "https://replane.my-host.com",
|
|
454
449
|
});
|
|
@@ -479,7 +474,7 @@ const unsubscribeMaxUsers = replane.subscribe("max-users", (config) => {
|
|
|
479
474
|
unsubscribeAll();
|
|
480
475
|
unsubscribeFeature();
|
|
481
476
|
unsubscribeMaxUsers();
|
|
482
|
-
replane.
|
|
477
|
+
replane.disconnect();
|
|
483
478
|
```
|
|
484
479
|
|
|
485
480
|
## Framework SDKs
|