@replanejs/sdk 0.9.4 → 1.0.0

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/dist/index.d.ts CHANGED
@@ -14,20 +14,20 @@ interface SegmentationCondition {
14
14
  }
15
15
  interface AndCondition {
16
16
  operator: "and";
17
- conditions: RenderedCondition[];
17
+ conditions: Condition[];
18
18
  }
19
19
  interface OrCondition {
20
20
  operator: "or";
21
- conditions: RenderedCondition[];
21
+ conditions: Condition[];
22
22
  }
23
23
  interface NotCondition {
24
24
  operator: "not";
25
- condition: RenderedCondition;
25
+ condition: Condition;
26
26
  }
27
- type RenderedCondition = PropertyCondition | SegmentationCondition | AndCondition | OrCondition | NotCondition;
28
- interface RenderedOverride {
27
+ type Condition = PropertyCondition | SegmentationCondition | AndCondition | OrCondition | NotCondition;
28
+ interface Override {
29
29
  name: string;
30
- conditions: RenderedCondition[];
30
+ conditions: Condition[];
31
31
  value: unknown;
32
32
  }
33
33
  //#endregion
@@ -73,7 +73,7 @@ interface ReplaneSnapshot<_T extends object = object> {
73
73
  configs: Array<{
74
74
  name: string;
75
75
  value: unknown;
76
- overrides: RenderedOverride[];
76
+ overrides: Override[];
77
77
  }>;
78
78
  }
79
79
  /**
@@ -278,7 +278,163 @@ declare function getReplaneSnapshot<T extends object>(options: GetReplaneSnapsho
278
278
  * Clears the client cache used by getReplaneSnapshot.
279
279
  * Useful for testing or when you need to force re-initialization.
280
280
  */
281
-
282
281
  //#endregion
283
- export { type ConnectOptions, type GetConfigOptions, type GetReplaneSnapshotOptions, Replane, type ReplaneContext, ReplaneError, ReplaneErrorCode, type ReplaneLogger, type ReplaneOptions, type ReplaneSnapshot, getReplaneSnapshot };
282
+ //#region src/in-memory.d.ts
283
+ /**
284
+ * Options for setting a config with overrides.
285
+ */
286
+ interface SetConfigOptions {
287
+ /** Override rules for context-based value selection */
288
+ overrides?: Override[];
289
+ }
290
+ /**
291
+ * Options for InMemoryReplaneClient constructor.
292
+ */
293
+ interface InMemoryReplaneClientOptions<T extends object> {
294
+ /**
295
+ * Optional logger (defaults to console).
296
+ */
297
+ logger?: ReplaneLogger;
298
+ /**
299
+ * Default context for all config evaluations.
300
+ * Can be overridden per-request in `client.get()`.
301
+ */
302
+ context?: ReplaneContext;
303
+ /**
304
+ * Initial config values.
305
+ * @example
306
+ * {
307
+ * defaults: {
308
+ * "feature-enabled": true,
309
+ * "rate-limit": 100,
310
+ * },
311
+ * }
312
+ */
313
+ defaults?: { [K in keyof T]?: T[K] };
314
+ }
315
+ /**
316
+ * An in-memory Replane client for testing.
317
+ *
318
+ * This client provides the same interface as `Replane` but stores
319
+ * all configs in memory. It's useful for unit tests where you don't want
320
+ * to connect to a real Replane server.
321
+ *
322
+ * @example
323
+ * ```typescript
324
+ * // Basic usage
325
+ * const client = new InMemoryReplaneClient({
326
+ * defaults: { "feature-enabled": true, "rate-limit": 100 },
327
+ * });
328
+ * expect(client.get("feature-enabled")).toBe(true);
329
+ *
330
+ * // Update config at runtime
331
+ * client.set("feature-enabled", false);
332
+ * expect(client.get("feature-enabled")).toBe(false);
333
+ *
334
+ * // With overrides
335
+ * client.setConfig("rate-limit", 100, {
336
+ * overrides: [{
337
+ * name: "premium-users",
338
+ * conditions: [{ operator: "equals", property: "plan", value: "premium" }],
339
+ * value: 1000,
340
+ * }],
341
+ * });
342
+ * expect(client.get("rate-limit")).toBe(100);
343
+ * expect(client.get("rate-limit", { context: { plan: "premium" } })).toBe(1000);
344
+ * ```
345
+ *
346
+ * @typeParam T - Type definition for config keys and values
347
+ */
348
+ declare class InMemoryReplaneClient<T extends object = Record<string, unknown>> {
349
+ constructor(options?: InMemoryReplaneClientOptions<T>);
350
+ /**
351
+ * Get a config value by name.
352
+ *
353
+ * Evaluates any overrides based on the client context and per-call context.
354
+ *
355
+ * @param configName - The name of the config to retrieve
356
+ * @param options - Optional settings for this call
357
+ * @returns The config value
358
+ * @throws {ReplaneError} If config not found and no default provided
359
+ */
360
+ get<K extends keyof T>(configName: K, options?: GetConfigOptions<T[K]>): T[K];
361
+ /**
362
+ * Subscribe to a specific config's changes.
363
+ *
364
+ * @param configName - The config to watch
365
+ * @param callback - Function called when the config changes
366
+ * @returns Unsubscribe function
367
+ */
368
+ subscribe<K extends keyof T>(configName: K, callback: (config: {
369
+ name: K;
370
+ value: T[K];
371
+ }) => void): () => void;
372
+ /**
373
+ * Get a serializable snapshot of the current client state.
374
+ *
375
+ * @returns Snapshot object that can be serialized to JSON
376
+ */
377
+ getSnapshot(): ReplaneSnapshot<T>;
378
+ /**
379
+ * Set a config value (simple form without overrides).
380
+ *
381
+ * @param name - Config name
382
+ * @param value - Config value
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * client.set("feature-enabled", true);
387
+ * client.set("rate-limit", 500);
388
+ * ```
389
+ */
390
+ set<K extends keyof T>(name: K, value: T[K]): void;
391
+ /**
392
+ * Set a config with optional overrides.
393
+ *
394
+ * @param name - Config name
395
+ * @param value - Base config value
396
+ * @param options - Optional settings including overrides
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * client.setConfig("rate-limit", 100, {
401
+ * overrides: [{
402
+ * name: "premium-users",
403
+ * conditions: [
404
+ * { operator: "in", property: "plan", value: ["pro", "enterprise"] }
405
+ * ],
406
+ * value: 1000,
407
+ * }],
408
+ * });
409
+ * ```
410
+ */
411
+ setConfig<K extends keyof T>(name: K, value: T[K], options?: SetConfigOptions): void;
412
+ /**
413
+ * Delete a config.
414
+ *
415
+ * @param name - Config name to delete
416
+ * @returns True if config was deleted, false if it didn't exist
417
+ */
418
+ delete<K extends keyof T>(name: K): boolean;
419
+ /**
420
+ * Clear all configs.
421
+ */
422
+ clear(): void;
423
+ /**
424
+ * Check if a config exists.
425
+ *
426
+ * @param name - Config name to check
427
+ * @returns True if config exists
428
+ */
429
+ has<K extends keyof T>(name: K): boolean;
430
+ /**
431
+ * Get all config names.
432
+ *
433
+ * @returns Array of config names
434
+ */
435
+ keys(): (keyof T)[];
436
+ }
437
+ //# sourceMappingURL=in-memory.d.ts.map
438
+ //#endregion
439
+ export { type Condition, type ConnectOptions, type GetConfigOptions, type GetReplaneSnapshotOptions, InMemoryReplaneClient, type InMemoryReplaneClientOptions, type Override, Replane, type ReplaneContext, ReplaneError, ReplaneErrorCode, type ReplaneLogger, type ReplaneOptions, type ReplaneSnapshot, type SetConfigOptions, getReplaneSnapshot };
284
440
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/client-types.ts","../src/client.ts","../src/error.ts","../src/snapshot.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/client-types.ts","../src/client.ts","../src/error.ts","../src/snapshot.ts","../src/in-memory.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -30,6 +30,20 @@ var ReplaneError = class extends Error {
30
30
  //#endregion
31
31
  //#region src/utils.ts
32
32
  /**
33
+ * Generates a random UUID using the Web Crypto API.
34
+ * Falls back to a simple implementation if crypto.randomUUID is not available.
35
+ *
36
+ * @returns A random UUID string
37
+ */
38
+ function generateClientId() {
39
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
40
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
41
+ const r = Math.random() * 16 | 0;
42
+ const v = c === "x" ? r : r & 3 | 8;
43
+ return v.toString(16);
44
+ });
45
+ }
46
+ /**
33
47
  * Returns a promise that resolves after the specified delay
34
48
  *
35
49
  * @param ms - Delay in milliseconds
@@ -481,11 +495,17 @@ function castToContextType(expectedValue, contextValue) {
481
495
 
482
496
  //#endregion
483
497
  //#region src/version.ts
484
- const VERSION = "0.9.4";
498
+ const VERSION = "1.0.0";
485
499
  const DEFAULT_AGENT = `replane-js-sdk/${VERSION}`;
486
500
 
487
501
  //#endregion
488
502
  //#region src/client.ts
503
+ /**
504
+ * The context key for the auto-generated client ID.
505
+ * This key is automatically set by the SDK and can be used for segmentation.
506
+ * User-provided values for this key take precedence over the auto-generated value.
507
+ */
508
+ const REPLANE_CLIENT_ID_KEY = "replaneClientId";
489
509
  function asReplaneHandle(replane) {
490
510
  return replane;
491
511
  }
@@ -563,7 +583,11 @@ var ReplaneImpl = class {
563
583
  */
564
584
  constructor(options = {}) {
565
585
  this.logger = options.logger ?? console;
566
- this.context = { ...options.context ?? {} };
586
+ const autoGeneratedContext = { [REPLANE_CLIENT_ID_KEY]: generateClientId() };
587
+ this.context = {
588
+ ...autoGeneratedContext,
589
+ ...options.context ?? {}
590
+ };
567
591
  const initialConfigs = [];
568
592
  if (options.snapshot) for (const config of options.snapshot.configs) initialConfigs.push({
569
593
  name: config.name,
@@ -744,8 +768,13 @@ var ReplaneImpl = class {
744
768
  })
745
769
  });
746
770
  for await (const event of replicationStream) {
747
- const updatedConfigs = event.type === "config_change" ? [event.config] : event.configs;
748
- this.processConfigUpdates(updatedConfigs);
771
+ if (event.type === "init") {
772
+ this.processConfigUpdates(event.configs);
773
+ this.logger.info(`Replane: initialized with ${event.configs.length} config(s)`);
774
+ } else {
775
+ this.processConfigUpdates([event.config]);
776
+ this.logger.info(`Replane: config "${event.config.name}" updated`);
777
+ }
749
778
  clientReady.resolve();
750
779
  }
751
780
  } catch (error) {
@@ -853,5 +882,248 @@ async function getReplaneSnapshot(options) {
853
882
  }
854
883
 
855
884
  //#endregion
856
- export { Replane, ReplaneError, ReplaneErrorCode, getReplaneSnapshot };
885
+ //#region src/in-memory.ts
886
+ function asHandle(client) {
887
+ return client;
888
+ }
889
+ /**
890
+ * An in-memory Replane client for testing.
891
+ *
892
+ * This client provides the same interface as `Replane` but stores
893
+ * all configs in memory. It's useful for unit tests where you don't want
894
+ * to connect to a real Replane server.
895
+ *
896
+ * @example
897
+ * ```typescript
898
+ * // Basic usage
899
+ * const client = new InMemoryReplaneClient({
900
+ * defaults: { "feature-enabled": true, "rate-limit": 100 },
901
+ * });
902
+ * expect(client.get("feature-enabled")).toBe(true);
903
+ *
904
+ * // Update config at runtime
905
+ * client.set("feature-enabled", false);
906
+ * expect(client.get("feature-enabled")).toBe(false);
907
+ *
908
+ * // With overrides
909
+ * client.setConfig("rate-limit", 100, {
910
+ * overrides: [{
911
+ * name: "premium-users",
912
+ * conditions: [{ operator: "equals", property: "plan", value: "premium" }],
913
+ * value: 1000,
914
+ * }],
915
+ * });
916
+ * expect(client.get("rate-limit")).toBe(100);
917
+ * expect(client.get("rate-limit", { context: { plan: "premium" } })).toBe(1000);
918
+ * ```
919
+ *
920
+ * @typeParam T - Type definition for config keys and values
921
+ */
922
+ var InMemoryReplaneClient = class {
923
+ constructor(options = {}) {
924
+ asHandle(this)._impl = new InMemoryReplaneClientImpl(options);
925
+ }
926
+ /**
927
+ * Get a config value by name.
928
+ *
929
+ * Evaluates any overrides based on the client context and per-call context.
930
+ *
931
+ * @param configName - The name of the config to retrieve
932
+ * @param options - Optional settings for this call
933
+ * @returns The config value
934
+ * @throws {ReplaneError} If config not found and no default provided
935
+ */
936
+ get(configName, options) {
937
+ return asHandle(this)._impl.get(configName, options);
938
+ }
939
+ /**
940
+ * Subscribe to a specific config's changes.
941
+ *
942
+ * @param configName - The config to watch
943
+ * @param callback - Function called when the config changes
944
+ * @returns Unsubscribe function
945
+ */
946
+ subscribe(configName, callback) {
947
+ return asHandle(this)._impl.subscribe(configName, callback);
948
+ }
949
+ /**
950
+ * Get a serializable snapshot of the current client state.
951
+ *
952
+ * @returns Snapshot object that can be serialized to JSON
953
+ */
954
+ getSnapshot() {
955
+ return asHandle(this)._impl.getSnapshot();
956
+ }
957
+ /**
958
+ * Set a config value (simple form without overrides).
959
+ *
960
+ * @param name - Config name
961
+ * @param value - Config value
962
+ *
963
+ * @example
964
+ * ```typescript
965
+ * client.set("feature-enabled", true);
966
+ * client.set("rate-limit", 500);
967
+ * ```
968
+ */
969
+ set(name, value) {
970
+ asHandle(this)._impl.set(name, value);
971
+ }
972
+ /**
973
+ * Set a config with optional overrides.
974
+ *
975
+ * @param name - Config name
976
+ * @param value - Base config value
977
+ * @param options - Optional settings including overrides
978
+ *
979
+ * @example
980
+ * ```typescript
981
+ * client.setConfig("rate-limit", 100, {
982
+ * overrides: [{
983
+ * name: "premium-users",
984
+ * conditions: [
985
+ * { operator: "in", property: "plan", value: ["pro", "enterprise"] }
986
+ * ],
987
+ * value: 1000,
988
+ * }],
989
+ * });
990
+ * ```
991
+ */
992
+ setConfig(name, value, options) {
993
+ asHandle(this)._impl.setConfig(name, value, options);
994
+ }
995
+ /**
996
+ * Delete a config.
997
+ *
998
+ * @param name - Config name to delete
999
+ * @returns True if config was deleted, false if it didn't exist
1000
+ */
1001
+ delete(name) {
1002
+ return asHandle(this)._impl.delete(name);
1003
+ }
1004
+ /**
1005
+ * Clear all configs.
1006
+ */
1007
+ clear() {
1008
+ asHandle(this)._impl.clear();
1009
+ }
1010
+ /**
1011
+ * Check if a config exists.
1012
+ *
1013
+ * @param name - Config name to check
1014
+ * @returns True if config exists
1015
+ */
1016
+ has(name) {
1017
+ return asHandle(this)._impl.has(name);
1018
+ }
1019
+ /**
1020
+ * Get all config names.
1021
+ *
1022
+ * @returns Array of config names
1023
+ */
1024
+ keys() {
1025
+ return asHandle(this)._impl.keys();
1026
+ }
1027
+ };
1028
+ var InMemoryReplaneClientImpl = class {
1029
+ configs;
1030
+ context;
1031
+ logger;
1032
+ configSubscriptions = new Map();
1033
+ constructor(options = {}) {
1034
+ this.logger = options.logger ?? console;
1035
+ this.context = options.context ?? {};
1036
+ const initialConfigs = [];
1037
+ if (options.defaults) {
1038
+ for (const [name, value] of Object.entries(options.defaults)) if (value !== void 0) initialConfigs.push({
1039
+ name,
1040
+ value,
1041
+ overrides: []
1042
+ });
1043
+ }
1044
+ this.configs = new Map(initialConfigs.map((config) => [config.name, config]));
1045
+ }
1046
+ get(configName, options = {}) {
1047
+ const config = this.configs.get(String(configName));
1048
+ if (config === void 0) {
1049
+ if ("default" in options) return options.default;
1050
+ throw new ReplaneError({
1051
+ message: `Config not found: ${String(configName)}`,
1052
+ code: ReplaneErrorCode.NotFound
1053
+ });
1054
+ }
1055
+ try {
1056
+ return evaluateOverrides(config.value, config.overrides, {
1057
+ ...this.context,
1058
+ ...options?.context ?? {}
1059
+ }, this.logger);
1060
+ } catch (error) {
1061
+ this.logger.error(`Replane: error evaluating overrides for config ${String(configName)}:`, error);
1062
+ return config.value;
1063
+ }
1064
+ }
1065
+ subscribe(configName, callback) {
1066
+ const wrappedCallback = (config) => {
1067
+ callback(config);
1068
+ };
1069
+ if (!this.configSubscriptions.has(configName)) this.configSubscriptions.set(configName, new Set());
1070
+ this.configSubscriptions.get(configName).add(wrappedCallback);
1071
+ return () => {
1072
+ this.configSubscriptions.get(configName)?.delete(wrappedCallback);
1073
+ if (this.configSubscriptions.get(configName)?.size === 0) this.configSubscriptions.delete(configName);
1074
+ };
1075
+ }
1076
+ getSnapshot() {
1077
+ return { configs: [...this.configs.values()].map((config) => ({
1078
+ name: config.name,
1079
+ value: config.value,
1080
+ overrides: config.overrides.map((override) => ({
1081
+ name: override.name,
1082
+ conditions: override.conditions,
1083
+ value: override.value
1084
+ }))
1085
+ })) };
1086
+ }
1087
+ set(name, value) {
1088
+ this.setConfig(name, value);
1089
+ }
1090
+ setConfig(name, value, options) {
1091
+ const overrides = options?.overrides ?? [];
1092
+ const config = {
1093
+ name: String(name),
1094
+ value,
1095
+ overrides
1096
+ };
1097
+ this.configs.set(String(name), config);
1098
+ this.notifySubscribers(name, value);
1099
+ }
1100
+ delete(name) {
1101
+ const existed = this.configs.has(String(name));
1102
+ this.configs.delete(String(name));
1103
+ return existed;
1104
+ }
1105
+ clear() {
1106
+ this.configs.clear();
1107
+ }
1108
+ has(name) {
1109
+ return this.configs.has(String(name));
1110
+ }
1111
+ keys() {
1112
+ return [...this.configs.keys()];
1113
+ }
1114
+ notifySubscribers(name, value) {
1115
+ const change = {
1116
+ name,
1117
+ value
1118
+ };
1119
+ for (const callback of this.configSubscriptions.get(name) ?? []) try {
1120
+ callback(change);
1121
+ } catch (error) {
1122
+ this.logger.error(`Replane: error in subscription callback for ${String(name)}:`, error);
1123
+ }
1124
+ }
1125
+ };
1126
+
1127
+ //#endregion
1128
+ export { InMemoryReplaneClient, Replane, ReplaneError, ReplaneErrorCode, getReplaneSnapshot };
857
1129
  //# sourceMappingURL=index.js.map