@replanejs/sdk 0.9.4 → 1.0.1

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,150 @@ 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.set("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 with optional overrides.
380
+ *
381
+ * @param name - Config name
382
+ * @param value - Base config value
383
+ * @param options - Optional settings including overrides
384
+ *
385
+ * @example
386
+ * ```typescript
387
+ * client.set("rate-limit", 100, {
388
+ * overrides: [{
389
+ * name: "premium-users",
390
+ * conditions: [
391
+ * { operator: "in", property: "plan", value: ["pro", "enterprise"] }
392
+ * ],
393
+ * value: 1000,
394
+ * }],
395
+ * });
396
+ * ```
397
+ */
398
+ set<K extends keyof T>(name: K, value: T[K], options?: SetConfigOptions): void;
399
+ /**
400
+ * Delete a config.
401
+ *
402
+ * @param name - Config name to delete
403
+ * @returns True if config was deleted, false if it didn't exist
404
+ */
405
+ delete<K extends keyof T>(name: K): boolean;
406
+ /**
407
+ * Clear all configs.
408
+ */
409
+ clear(): void;
410
+ /**
411
+ * Check if a config exists.
412
+ *
413
+ * @param name - Config name to check
414
+ * @returns True if config exists
415
+ */
416
+ has<K extends keyof T>(name: K): boolean;
417
+ /**
418
+ * Get all config names.
419
+ *
420
+ * @returns Array of config names
421
+ */
422
+ keys(): (keyof T)[];
423
+ }
424
+ //# sourceMappingURL=in-memory.d.ts.map
425
+ //#endregion
426
+ 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
427
  //# 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.1";
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,230 @@ 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.set("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 with optional overrides.
959
+ *
960
+ * @param name - Config name
961
+ * @param value - Base config value
962
+ * @param options - Optional settings including overrides
963
+ *
964
+ * @example
965
+ * ```typescript
966
+ * client.set("rate-limit", 100, {
967
+ * overrides: [{
968
+ * name: "premium-users",
969
+ * conditions: [
970
+ * { operator: "in", property: "plan", value: ["pro", "enterprise"] }
971
+ * ],
972
+ * value: 1000,
973
+ * }],
974
+ * });
975
+ * ```
976
+ */
977
+ set(name, value, options) {
978
+ asHandle(this)._impl.set(name, value, options);
979
+ }
980
+ /**
981
+ * Delete a config.
982
+ *
983
+ * @param name - Config name to delete
984
+ * @returns True if config was deleted, false if it didn't exist
985
+ */
986
+ delete(name) {
987
+ return asHandle(this)._impl.delete(name);
988
+ }
989
+ /**
990
+ * Clear all configs.
991
+ */
992
+ clear() {
993
+ asHandle(this)._impl.clear();
994
+ }
995
+ /**
996
+ * Check if a config exists.
997
+ *
998
+ * @param name - Config name to check
999
+ * @returns True if config exists
1000
+ */
1001
+ has(name) {
1002
+ return asHandle(this)._impl.has(name);
1003
+ }
1004
+ /**
1005
+ * Get all config names.
1006
+ *
1007
+ * @returns Array of config names
1008
+ */
1009
+ keys() {
1010
+ return asHandle(this)._impl.keys();
1011
+ }
1012
+ };
1013
+ var InMemoryReplaneClientImpl = class {
1014
+ configs;
1015
+ context;
1016
+ logger;
1017
+ configSubscriptions = new Map();
1018
+ constructor(options = {}) {
1019
+ this.logger = options.logger ?? console;
1020
+ this.context = options.context ?? {};
1021
+ const initialConfigs = [];
1022
+ if (options.defaults) {
1023
+ for (const [name, value] of Object.entries(options.defaults)) if (value !== void 0) initialConfigs.push({
1024
+ name,
1025
+ value,
1026
+ overrides: []
1027
+ });
1028
+ }
1029
+ this.configs = new Map(initialConfigs.map((config) => [config.name, config]));
1030
+ }
1031
+ get(configName, options = {}) {
1032
+ const config = this.configs.get(String(configName));
1033
+ if (config === void 0) {
1034
+ if ("default" in options) return options.default;
1035
+ throw new ReplaneError({
1036
+ message: `Config not found: ${String(configName)}`,
1037
+ code: ReplaneErrorCode.NotFound
1038
+ });
1039
+ }
1040
+ try {
1041
+ return evaluateOverrides(config.value, config.overrides, {
1042
+ ...this.context,
1043
+ ...options?.context ?? {}
1044
+ }, this.logger);
1045
+ } catch (error) {
1046
+ this.logger.error(`Replane: error evaluating overrides for config ${String(configName)}:`, error);
1047
+ return config.value;
1048
+ }
1049
+ }
1050
+ subscribe(configName, callback) {
1051
+ const wrappedCallback = (config) => {
1052
+ callback(config);
1053
+ };
1054
+ if (!this.configSubscriptions.has(configName)) this.configSubscriptions.set(configName, new Set());
1055
+ this.configSubscriptions.get(configName).add(wrappedCallback);
1056
+ return () => {
1057
+ this.configSubscriptions.get(configName)?.delete(wrappedCallback);
1058
+ if (this.configSubscriptions.get(configName)?.size === 0) this.configSubscriptions.delete(configName);
1059
+ };
1060
+ }
1061
+ getSnapshot() {
1062
+ return { configs: [...this.configs.values()].map((config) => ({
1063
+ name: config.name,
1064
+ value: config.value,
1065
+ overrides: config.overrides.map((override) => ({
1066
+ name: override.name,
1067
+ conditions: override.conditions,
1068
+ value: override.value
1069
+ }))
1070
+ })) };
1071
+ }
1072
+ set(name, value, options) {
1073
+ const overrides = options?.overrides ?? [];
1074
+ const config = {
1075
+ name: String(name),
1076
+ value,
1077
+ overrides
1078
+ };
1079
+ this.configs.set(String(name), config);
1080
+ this.notifySubscribers(name, value);
1081
+ }
1082
+ delete(name) {
1083
+ const existed = this.configs.has(String(name));
1084
+ this.configs.delete(String(name));
1085
+ return existed;
1086
+ }
1087
+ clear() {
1088
+ this.configs.clear();
1089
+ }
1090
+ has(name) {
1091
+ return this.configs.has(String(name));
1092
+ }
1093
+ keys() {
1094
+ return [...this.configs.keys()];
1095
+ }
1096
+ notifySubscribers(name, value) {
1097
+ const change = {
1098
+ name,
1099
+ value
1100
+ };
1101
+ for (const callback of this.configSubscriptions.get(name) ?? []) try {
1102
+ callback(change);
1103
+ } catch (error) {
1104
+ this.logger.error(`Replane: error in subscription callback for ${String(name)}:`, error);
1105
+ }
1106
+ }
1107
+ };
1108
+
1109
+ //#endregion
1110
+ export { InMemoryReplaneClient, Replane, ReplaneError, ReplaneErrorCode, getReplaneSnapshot };
857
1111
  //# sourceMappingURL=index.js.map