@replanejs/sdk 0.7.8 → 0.8.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/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Replane JavaScript SDK
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@replanejs/sdk)](https://www.npmjs.com/package/@replanejs/sdk)
4
+ [![License](https://img.shields.io/github/license/replane-dev/replane-javascript)](https://github.com/replane-dev/replane-javascript/blob/main/LICENSE)
5
+ [![Community](https://img.shields.io/badge/discussions-join-blue?logo=github)](https://github.com/orgs/replane-dev/discussions)
6
+
3
7
  Small TypeScript client for watching configuration values from a Replane API with realtime updates and context-based override evaluation.
4
8
 
5
9
  Part of the Replane project: [replane-dev/replane](https://github.com/replane-dev/replane).
@@ -114,13 +118,15 @@ Parameters:
114
118
  - `name` (K extends keyof T) – config name to fetch. TypeScript will enforce that this is a valid config name from your `Configs` interface.
115
119
  - `options` (object) – optional configuration:
116
120
  - `context` (object) – context merged with client-level context for override evaluation.
121
+ - `default` (T[K]) – default value to return if the config is not found. When provided, the method will not throw.
117
122
 
118
123
  Returns the config value of type `T[K]` (synchronous). The return type is automatically inferred from your `Configs` interface.
119
124
 
120
125
  Notes:
121
126
 
122
127
  - The Replane client receives realtime updates via SSE in the background.
123
- - If the config is not found, throws a `ReplaneError` with code `not_found`.
128
+ - If the config is not found and no default is provided, throws a `ReplaneError` with code `not_found`.
129
+ - If the config is not found and a default is provided, returns the default value without throwing.
124
130
  - Context-based overrides are evaluated automatically based on context.
125
131
 
126
132
  Example:
@@ -144,6 +150,9 @@ const userEnabled = replane.get("billing-enabled", {
144
150
  context: { userId: "user-123", plan: "premium" },
145
151
  });
146
152
 
153
+ // Get value with default - won't throw if config doesn't exist
154
+ const maxConnections = replane.get("max-connections", { default: 10 });
155
+
147
156
  // Clean up when done
148
157
  replane.close();
149
158
  ```
@@ -469,12 +478,10 @@ unsubscribeMaxUsers();
469
478
  replane.close();
470
479
  ```
471
480
 
472
- ## Roadmap
481
+ ## Community
473
482
 
474
- - Config caching
475
- - Config invalidation
483
+ Have questions or want to discuss Replane? Join the conversation in [GitHub Discussions](https://github.com/orgs/replane-dev/discussions).
476
484
 
477
485
  ## License
478
486
 
479
487
  MIT
480
-
package/dist/index.cjs CHANGED
@@ -533,10 +533,13 @@ function createClientCore(options) {
533
533
  }
534
534
  function get(configName, getConfigOptions = {}) {
535
535
  const config = configs.get(String(configName));
536
- if (config === void 0) throw new ReplaneError({
537
- message: `Config not found: ${String(configName)}`,
538
- code: ReplaneErrorCode.NotFound
539
- });
536
+ if (config === void 0) {
537
+ if ("default" in getConfigOptions) return getConfigOptions.default;
538
+ throw new ReplaneError({
539
+ message: `Config not found: ${String(configName)}`,
540
+ code: ReplaneErrorCode.NotFound
541
+ });
542
+ }
540
543
  try {
541
544
  return evaluateOverrides(config.value, config.overrides, {
542
545
  ...context,
@@ -627,12 +630,15 @@ async function createReplaneClient(sdkOptions) {
627
630
  */
628
631
  function createInMemoryReplaneClient(initialData) {
629
632
  return {
630
- get: (configName) => {
633
+ get: (configName, options) => {
631
634
  const config = initialData[configName];
632
- if (config === void 0) throw new ReplaneError({
633
- message: `Config not found: ${String(configName)}`,
634
- code: ReplaneErrorCode.NotFound
635
- });
635
+ if (config === void 0) {
636
+ if (options && "default" in options) return options.default;
637
+ throw new ReplaneError({
638
+ message: `Config not found: ${String(configName)}`,
639
+ code: ReplaneErrorCode.NotFound
640
+ });
641
+ }
636
642
  return config;
637
643
  },
638
644
  subscribe: () => {
@@ -776,10 +782,10 @@ const clientCache = new Map();
776
782
  function getCacheKey(options) {
777
783
  return `${options.baseUrl}:${options.sdkKey}`;
778
784
  }
779
- function setupCleanupTimeout(cacheKey, cacheTtlMs) {
785
+ function setupCleanupTimeout(cacheKey, keepAliveMs) {
780
786
  return setTimeout(() => {
781
787
  clientCache.delete(cacheKey);
782
- }, cacheTtlMs);
788
+ }, keepAliveMs);
783
789
  }
784
790
  /**
785
791
  * Creates a Replane client and returns a snapshot.
@@ -795,41 +801,28 @@ function setupCleanupTimeout(cacheKey, cacheTtlMs) {
795
801
  * ```
796
802
  */
797
803
  async function getReplaneSnapshot(options) {
798
- const { cacheTtlMs = 6e4,...clientOptions } = options;
804
+ const { keepAliveMs = 6e4,...clientOptions } = options;
799
805
  const cacheKey = getCacheKey(clientOptions);
800
806
  const cached = clientCache.get(cacheKey);
801
807
  if (cached) {
802
808
  clearTimeout(cached.timeoutId);
803
- cached.timeoutId = setupCleanupTimeout(cacheKey, cacheTtlMs);
809
+ cached.timeoutId = setupCleanupTimeout(cacheKey, keepAliveMs);
804
810
  const client$1 = await cached.clientPromise;
805
811
  return client$1.getSnapshot();
806
812
  }
807
813
  const clientPromise = createReplaneClient(clientOptions);
808
814
  const entry = {
809
815
  clientPromise,
810
- timeoutId: setupCleanupTimeout(cacheKey, cacheTtlMs)
816
+ timeoutId: setupCleanupTimeout(cacheKey, keepAliveMs)
811
817
  };
812
818
  clientCache.set(cacheKey, entry);
813
819
  const client = await clientPromise;
814
820
  return client.getSnapshot();
815
821
  }
816
- /**
817
- * Clears the client cache used by getReplaneSnapshot.
818
- * Useful for testing or when you need to force re-initialization.
819
- */
820
- async function clearSnapshotCache() {
821
- const clientPromises = [...clientCache.values()].map((cached) => cached.clientPromise);
822
- clientCache.clear();
823
- for (const clientPromise of clientPromises) {
824
- const client = await clientPromise;
825
- client.close();
826
- }
827
- }
828
822
 
829
823
  //#endregion
830
824
  exports.ReplaneError = ReplaneError;
831
825
  exports.ReplaneErrorCode = ReplaneErrorCode;
832
- exports.clearSnapshotCache = clearSnapshotCache;
833
826
  exports.createInMemoryReplaneClient = createInMemoryReplaneClient;
834
827
  exports.createReplaneClient = createReplaneClient;
835
828
  exports.getReplaneSnapshot = getReplaneSnapshot;
package/dist/index.d.cts CHANGED
@@ -49,11 +49,16 @@ interface ReplaneLogger {
49
49
  /**
50
50
  * Options for getting a config value
51
51
  */
52
- interface GetConfigOptions {
52
+ interface GetConfigOptions<T> {
53
53
  /**
54
54
  * Context for override evaluation (merged with client-level context).
55
55
  */
56
56
  context?: ReplaneContext;
57
+ /**
58
+ * Default value to return if the config is not found.
59
+ * When provided, the method will not throw if the config doesn't exist.
60
+ */
61
+ default?: T;
57
62
  }
58
63
  /**
59
64
  * Helper type for mapping configs to their names and values
@@ -81,7 +86,7 @@ interface ReplaneSnapshot<_T extends object = object> {
81
86
  */
82
87
  interface ReplaneClient<T extends object> {
83
88
  /** Get a config by its name. */
84
- get<K extends keyof T>(configName: K, options?: GetConfigOptions): T[K];
89
+ get<K extends keyof T>(configName: K, options?: GetConfigOptions<T[K]>): T[K];
85
90
  /** Subscribe to config changes.
86
91
  * @param callback - A function to call when an config is changed. The callback will be called with the new config value.
87
92
  * @returns A function to unsubscribe from the config changes.
@@ -326,7 +331,7 @@ interface GetReplaneSnapshotOptions<T extends object> extends ReplaneClientOptio
326
331
  * for instant subsequent calls within this duration.
327
332
  * @default 60_000 (1 minute)
328
333
  */
329
- cacheTtlMs?: number;
334
+ keepAliveMs?: number;
330
335
  }
331
336
  /**
332
337
  * Creates a Replane client and returns a snapshot.
@@ -346,9 +351,7 @@ declare function getReplaneSnapshot<T extends object>(options: GetReplaneSnapsho
346
351
  * Clears the client cache used by getReplaneSnapshot.
347
352
  * Useful for testing or when you need to force re-initialization.
348
353
  */
349
- declare function clearSnapshotCache(): Promise<void>;
350
- //# sourceMappingURL=snapshot.d.ts.map
351
354
 
352
355
  //#endregion
353
- export { type GetConfigOptions, type GetReplaneSnapshotOptions, type ReplaneClient, type ReplaneClientOptions, type ReplaneContext, ReplaneError, ReplaneErrorCode, type ReplaneLogger, type ReplaneSnapshot, type RestoreReplaneClientOptions, clearSnapshotCache, createInMemoryReplaneClient, createReplaneClient, getReplaneSnapshot, restoreReplaneClient };
356
+ export { type GetConfigOptions, type GetReplaneSnapshotOptions, type ReplaneClient, type ReplaneClientOptions, type ReplaneContext, ReplaneError, ReplaneErrorCode, type ReplaneLogger, type ReplaneSnapshot, type RestoreReplaneClientOptions, createInMemoryReplaneClient, createReplaneClient, getReplaneSnapshot, restoreReplaneClient };
354
357
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","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.cts","names":[],"sources":["../src/types.ts","../src/client-types.ts","../src/client.ts","../src/error.ts","../src/snapshot.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -49,11 +49,16 @@ interface ReplaneLogger {
49
49
  /**
50
50
  * Options for getting a config value
51
51
  */
52
- interface GetConfigOptions {
52
+ interface GetConfigOptions<T> {
53
53
  /**
54
54
  * Context for override evaluation (merged with client-level context).
55
55
  */
56
56
  context?: ReplaneContext;
57
+ /**
58
+ * Default value to return if the config is not found.
59
+ * When provided, the method will not throw if the config doesn't exist.
60
+ */
61
+ default?: T;
57
62
  }
58
63
  /**
59
64
  * Helper type for mapping configs to their names and values
@@ -81,7 +86,7 @@ interface ReplaneSnapshot<_T extends object = object> {
81
86
  */
82
87
  interface ReplaneClient<T extends object> {
83
88
  /** Get a config by its name. */
84
- get<K extends keyof T>(configName: K, options?: GetConfigOptions): T[K];
89
+ get<K extends keyof T>(configName: K, options?: GetConfigOptions<T[K]>): T[K];
85
90
  /** Subscribe to config changes.
86
91
  * @param callback - A function to call when an config is changed. The callback will be called with the new config value.
87
92
  * @returns A function to unsubscribe from the config changes.
@@ -326,7 +331,7 @@ interface GetReplaneSnapshotOptions<T extends object> extends ReplaneClientOptio
326
331
  * for instant subsequent calls within this duration.
327
332
  * @default 60_000 (1 minute)
328
333
  */
329
- cacheTtlMs?: number;
334
+ keepAliveMs?: number;
330
335
  }
331
336
  /**
332
337
  * Creates a Replane client and returns a snapshot.
@@ -346,9 +351,7 @@ declare function getReplaneSnapshot<T extends object>(options: GetReplaneSnapsho
346
351
  * Clears the client cache used by getReplaneSnapshot.
347
352
  * Useful for testing or when you need to force re-initialization.
348
353
  */
349
- declare function clearSnapshotCache(): Promise<void>;
350
- //# sourceMappingURL=snapshot.d.ts.map
351
354
 
352
355
  //#endregion
353
- export { type GetConfigOptions, type GetReplaneSnapshotOptions, type ReplaneClient, type ReplaneClientOptions, type ReplaneContext, ReplaneError, ReplaneErrorCode, type ReplaneLogger, type ReplaneSnapshot, type RestoreReplaneClientOptions, clearSnapshotCache, createInMemoryReplaneClient, createReplaneClient, getReplaneSnapshot, restoreReplaneClient };
356
+ export { type GetConfigOptions, type GetReplaneSnapshotOptions, type ReplaneClient, type ReplaneClientOptions, type ReplaneContext, ReplaneError, ReplaneErrorCode, type ReplaneLogger, type ReplaneSnapshot, type RestoreReplaneClientOptions, createInMemoryReplaneClient, createReplaneClient, getReplaneSnapshot, restoreReplaneClient };
354
357
  //# 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":";;UAqBU,iBAAA;;ECfE,QAAA,EAAA,MAAA;EAKK,KAAA,EAAA,OAAA;AAUjB;AAUA,UDGU,qBAAA,CCHW;EAAA,QAAA,EAAA,cAAA;EAAA,QACP,EAAA,MAAA;EAAC,cACL,EAAA,MAAA;EAAC,YACA,EAAA,MAAA;EAAC,IAAC,EAAA,MAAA;;AAEJ,UDMC,YAAA,CCND;EAMQ,QAAA,EAAA,KAAA;EAAe,UAAA,EDElB,iBCFkB,EAAA;;UDKtB,WAAA,CCHC;EAAK,QAMJ,EAAA,IAAA;EAAc,UAAA,EDDZ,iBCCY,EAAA;AAM1B;UDJU,YAAA,CCIoB;EAAA,QAER,EAAA,KAAA;EAAC,SAAc,EDJxB,iBCIwB;;AAAgC,KDDzD,iBAAA,GACR,iBCAiE,GDCjE,qBCDiE,GDEjE,YCFiE,GDGjE,WCHiE,GDIjE,YCJiE;AAAE,UDMtD,gBAAA,CCNsD;EAAC,IAK/B,EAAA,MAAA;EAAC,UAAX,EDGjB,iBCHiB,EAAA;EAAS,KAMZ,EAAA,OAAA;;;;ADlDtB;AAEqB;AAaI;AAUA;AAQrB,KC9CE,cAAA,GAAiB,MDgDhB,CAAA,MAAA,EAAA,MAAiB,GAAA,MAAA,GAAA,OAAA,GAAA,IAAA,GAAA,SAAA,CAAA;AAG9B;;;AAEI,UChDa,aAAA,CDgDb;EAAqB,KACrB,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;EAAY,IACZ,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;EAAW,IACX,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;EAAY,KAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;AAEhB;;;;AC1DY,UAeK,gBAAA,CAfY;EAKZ;AAUjB;AAUA;EAAqB,OAAA,CAAA,EANT,cAMS;;;;;AAKb,KALI,SAKJ,CAAA,UAAA,MAAA,CAAA,GAAA,QAAC,MAJK,CAIL,GAAA;EAMQ,IAAA,EATP,CASO;EAAe,KAAA,EARrB,CAQqB,CARnB,CAQmB,CAAA;AAAA,CAAA,EAKD,CAAA,MAXvB,CAQG,CAAA;;AAMe;AAM1B;;AAEsB,UAhBL,eAgBK,CAAA,WAAA,MAAA,GAAA,MAAA,CAAA,CAAA;EAAC;EAAe,OAAY,EAdvC,KAcuC,CAAA;IAAmB,IAAA,EAAA,MAAA;IAAE,KAAA,EAAA,OAAA;IAK9B,SAAA,EAhB1B,gBAgB0B,EAAA;EAAC,CAAA,CAAA;EAAF;EAMX,OACb,CAAA,EApBJ,cAoBI;;;;;AAOiB,UArBhB,aAqBgB,CAAA,UAAA,MAAA,CAAA,CAAA;EAAC;EAAF,GAAA,CAAA,UAAA,MAnBV,CAmBU,CAAA,CAAA,UAAA,EAnBK,CAmBL,EAAA,OAAA,CAAA,EAnBkB,gBAmBlB,CAAA,EAnBqC,CAmBrC,CAnBuC,CAmBvC,CAAA;EAQf;;;;EA4CO,SAKZ,CAAA,QAAA,EAAA,CAAA,MAAA,EAvEmB,SAuEnB,CAvE6B,CAuE7B,CAAA,EAAA,GAAA,IAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAc;;;;;EAqCL,SAAC,CAAA,UAAA,MAtGM,CAsGN,CAAA,CAAA,UAAA,EArGN,CAqGM,EAAA,QAAA,EAAA,CAAA,MAAA,EApGC,SAoGD,CApGW,IAoGX,CApGgB,CAoGhB,EApGmB,CAoGnB,CAAA,CAAA,EAAA,GAAA,IAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAC;AAOvB;;;EAI6B,WAAjB,EAAA,EAzGK,eAyGL,CAzGqB,CAyGrB,CAAA;EAAe;EAkBD,KAmBb,EAAA,EAAA,IAAA;;AAKa;;;UA3IT;ECqHK;;;;;;;;EAEZ,OAAA,EAAA,MAAA;EAeM;;;;;EAEE,MAAf,EAAA,MAAA;EAAa;AA6ChB;;EAAoC,OAAoB,CAAA,EAAA,ODlKrC,KCkKqC;EAAM;;;;EAE9C,gBAAA,CAAA,EAAA,MAAA;;;;ACzQhB;EAgBa,uBAAa,CAAA,EAAQ,MAAK;;;;ACbvC;EAA0C,YAAA,CAAA,EAAA,MAAA;EAAA;;AAA+C;AA0CzF;;EAAwC,mBACH,CAAA,EAAA,MAAA;EAAC;;;EACZ,MAAvB,CAAA,EH+EQ,aG/ER;EAAO;AAgCV;;;YHoDY;;;;;;;;;;;;;;;;;;2BAqBQ,gBAEd,YAAY;;;;;;;;;;;;4BAcF,IAAI,EAAE;;;;;UAOL;;;;YAIL,gBAAgB;;;;;;;;;;;;;;;;;;qBAkBP;;;;;;;;;;;;;;;;;;;aAmBR;;;;;YAKD;;;;;;;AD7MN;AAEqB;AAaI;AAUA;AAKA;AAQ/B;;;;;;;AAKgB,iBE4IM,mBF5IN,CAAA,UAAA,MAAA,GE4I6C,MF5I7C,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,UAAA,EE6IF,oBF7IE,CE6ImB,CF7InB,CAAA,CAAA,EE8Ib,OF9Ia,CE8IL,aF9IK,CE8IS,CF9IT,CAAA,CAAA;AAEhB;;;;AC1DA;AAKA;AAUA;AAUA;;;AAEU,iBC0LM,2BD1LN,CAAA,UAAA,MAAA,GC0LqD,MD1LrD,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,WAAA,EC2LK,CD3LL,CAAA,EC4LP,aD5LO,CC4LO,CD5LP,CAAA;;;;AAGD;AAMT;;;;;AAQ0B;AAM1B;;;;;;;;;AAa4B,iBCqMZ,oBDrMY,CAAA,UAAA,MAAA,GCqM4B,MDrM5B,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,OAAA,ECsMjB,2BDtMiB,CCsMW,CDtMX,CAAA,CAAA,ECuMzB,aDvMyB,CCuMX,CDvMW,CAAA;;;;;ADlDtB;AAEqB;AAqBjB,aGvCE,gBAAA;EH4CF,QAAA,GAAA,WAAW;EAKX,OAAA,GAAA,SAAY;EAKV,YAAA,GAAA,eAAiB;EAAA,SAAA,GAAA,YAAA;EAAA,SACzB,GAAA,WAAA;EAAiB,WACjB,GAAA,cAAA;EAAqB,WACrB,GAAA,cAAA;EAAY,MACZ,GAAA,QAAA;EAAW,cACX,GAAA,iBAAA;EAAY,OAAA,GAAA,SAAA;AAEhB;;;;AC1DY,cEaC,YAAA,SAAqB,KAAK,CFbJ;EAKlB,IAAA,EAAA,MAAA;EAUA,WAAA,CAAA,MAAA,EAAgB;IAUrB,OAAA,EAAS,MAAA;IAAA,IAAA,EAAA,MAAA;IACP,KAAA,CAAA,EAAA,OAAA;EAAC,CAAA;;;;;ADbT;AAEqB;AAaI;AAarB,UIzCO,yBJ2CH,CAAA,UAAiB,MAAA,CAAA,SI3CsC,oBJ2CtC,CI3C2D,CJ2C3D,CAAA,CAAA;EAGrB;AAKV;;;;EAEyB,UACrB,CAAA,EAAA,MAAA;;;AAEY;AAEhB;;;;AC1DA;AAKA;AAUA;AAUA;;;;AAGW,iBGcW,kBHdX,CAAA,UAAA,MAAA,CAAA,CAAA,OAAA,EGeA,yBHfA,CGe0B,CHf1B,CAAA,CAAA,EGgBR,OHhBQ,CGgBA,eHhBA,CGgBgB,CHhBhB,CAAA,CAAA;;;AAEF;AAMT;AAAgC,iBGwCV,kBAAA,CAAA,CHxCU,EGwCY,OHxCZ,CAAA,IAAA,CAAA"}
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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"}
package/dist/index.js CHANGED
@@ -532,10 +532,13 @@ function createClientCore(options) {
532
532
  }
533
533
  function get(configName, getConfigOptions = {}) {
534
534
  const config = configs.get(String(configName));
535
- if (config === void 0) throw new ReplaneError({
536
- message: `Config not found: ${String(configName)}`,
537
- code: ReplaneErrorCode.NotFound
538
- });
535
+ if (config === void 0) {
536
+ if ("default" in getConfigOptions) return getConfigOptions.default;
537
+ throw new ReplaneError({
538
+ message: `Config not found: ${String(configName)}`,
539
+ code: ReplaneErrorCode.NotFound
540
+ });
541
+ }
539
542
  try {
540
543
  return evaluateOverrides(config.value, config.overrides, {
541
544
  ...context,
@@ -626,12 +629,15 @@ async function createReplaneClient(sdkOptions) {
626
629
  */
627
630
  function createInMemoryReplaneClient(initialData) {
628
631
  return {
629
- get: (configName) => {
632
+ get: (configName, options) => {
630
633
  const config = initialData[configName];
631
- if (config === void 0) throw new ReplaneError({
632
- message: `Config not found: ${String(configName)}`,
633
- code: ReplaneErrorCode.NotFound
634
- });
634
+ if (config === void 0) {
635
+ if (options && "default" in options) return options.default;
636
+ throw new ReplaneError({
637
+ message: `Config not found: ${String(configName)}`,
638
+ code: ReplaneErrorCode.NotFound
639
+ });
640
+ }
635
641
  return config;
636
642
  },
637
643
  subscribe: () => {
@@ -775,10 +781,10 @@ const clientCache = new Map();
775
781
  function getCacheKey(options) {
776
782
  return `${options.baseUrl}:${options.sdkKey}`;
777
783
  }
778
- function setupCleanupTimeout(cacheKey, cacheTtlMs) {
784
+ function setupCleanupTimeout(cacheKey, keepAliveMs) {
779
785
  return setTimeout(() => {
780
786
  clientCache.delete(cacheKey);
781
- }, cacheTtlMs);
787
+ }, keepAliveMs);
782
788
  }
783
789
  /**
784
790
  * Creates a Replane client and returns a snapshot.
@@ -794,37 +800,25 @@ function setupCleanupTimeout(cacheKey, cacheTtlMs) {
794
800
  * ```
795
801
  */
796
802
  async function getReplaneSnapshot(options) {
797
- const { cacheTtlMs = 6e4,...clientOptions } = options;
803
+ const { keepAliveMs = 6e4,...clientOptions } = options;
798
804
  const cacheKey = getCacheKey(clientOptions);
799
805
  const cached = clientCache.get(cacheKey);
800
806
  if (cached) {
801
807
  clearTimeout(cached.timeoutId);
802
- cached.timeoutId = setupCleanupTimeout(cacheKey, cacheTtlMs);
808
+ cached.timeoutId = setupCleanupTimeout(cacheKey, keepAliveMs);
803
809
  const client$1 = await cached.clientPromise;
804
810
  return client$1.getSnapshot();
805
811
  }
806
812
  const clientPromise = createReplaneClient(clientOptions);
807
813
  const entry = {
808
814
  clientPromise,
809
- timeoutId: setupCleanupTimeout(cacheKey, cacheTtlMs)
815
+ timeoutId: setupCleanupTimeout(cacheKey, keepAliveMs)
810
816
  };
811
817
  clientCache.set(cacheKey, entry);
812
818
  const client = await clientPromise;
813
819
  return client.getSnapshot();
814
820
  }
815
- /**
816
- * Clears the client cache used by getReplaneSnapshot.
817
- * Useful for testing or when you need to force re-initialization.
818
- */
819
- async function clearSnapshotCache() {
820
- const clientPromises = [...clientCache.values()].map((cached) => cached.clientPromise);
821
- clientCache.clear();
822
- for (const clientPromise of clientPromises) {
823
- const client = await clientPromise;
824
- client.close();
825
- }
826
- }
827
821
 
828
822
  //#endregion
829
- export { ReplaneError, ReplaneErrorCode, clearSnapshotCache, createInMemoryReplaneClient, createReplaneClient, getReplaneSnapshot, restoreReplaneClient };
823
+ export { ReplaneError, ReplaneErrorCode, createInMemoryReplaneClient, createReplaneClient, getReplaneSnapshot, restoreReplaneClient };
830
824
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["params: { message: string; code: string; cause?: unknown }","ms: number","averageDelay: number","signals: Array<AbortSignal | undefined | null>","input: string | URL | Request","init: RequestInit","timeoutMs: number","fetchFn: typeof fetch","response: Response","message: string","body: unknown","params: FetchSseOptions","dataLines: string[]","comment: string | null","options: StartReplicationStreamOptions","error: unknown","inactivityTimer: ReturnType<typeof setTimeout> | null","options: ReplaneFinalOptions","path: string","input: string","baseValue: T","overrides: RenderedOverride[]","context: ReplaneContext","logger: ReplaneLogger","overrideResult: EvaluationResult","condition: RenderedCondition","contextValue","value: never","message: string","expectedValue: unknown","contextValue: unknown","options: ClientCoreOptions","configs: Map<string, ConfigDto>","updatedConfigs: ConfigDto[]","configName: K","getConfigOptions: GetConfigOptions","callbackOrConfigName: keyof T | ((config: MapConfig<T>) => void)","callbackOrUndefined?: (config: MapConfig<T>) => void","configName: keyof T | undefined","callback: (config: MapConfig<T>) => void","client: ReplaneClient<T>","sdkOptions: ReplaneClientOptions<T>","initialData: T","options: RestoreReplaneClientOptions<T>","initialConfigs: ConfigDto[]","storage: ReplaneRemoteStorage | null","streamOptions: ReplaneFinalOptions | null","sdkOptions: ReplaneFinalOptions","storage: ReplaneStorage","missingRequiredConfigs: string[]","defaults: ReplaneClientOptions<T>","options: ReplaneClientOptions<T>","cacheKey: string","cacheTtlMs: number","options: GetReplaneSnapshotOptions<T>","client","entry: CachedClient"],"sources":["../src/error.ts","../src/utils.ts","../src/sse.ts","../src/storage.ts","../src/hash.ts","../src/evaluation.ts","../src/client.ts","../src/snapshot.ts"],"sourcesContent":["/**\n * Error codes for ReplaneError\n */\nexport enum ReplaneErrorCode {\n NotFound = \"not_found\",\n Timeout = \"timeout\",\n NetworkError = \"network_error\",\n AuthError = \"auth_error\",\n Forbidden = \"forbidden\",\n ServerError = \"server_error\",\n ClientError = \"client_error\",\n Closed = \"closed\",\n NotInitialized = \"not_initialized\",\n Unknown = \"unknown\",\n}\n\n/**\n * Custom error class for Replane SDK errors\n */\nexport class ReplaneError extends Error {\n code: string;\n\n constructor(params: { message: string; code: string; cause?: unknown }) {\n super(params.message, { cause: params.cause });\n this.name = \"ReplaneError\";\n this.code = params.code;\n }\n}\n","/**\n * Returns a promise that resolves after the specified delay\n *\n * @param ms - Delay in milliseconds\n */\nexport async function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Returns a promise that resolves after a delay with jitter.\n * The actual delay is the average delay ± 10% (jitter = averageDelay/5).\n *\n * @param averageDelay - The average delay in milliseconds\n */\nexport async function retryDelay(averageDelay: number): Promise<void> {\n const jitter = averageDelay / 5;\n const delayMs = averageDelay + Math.random() * jitter - jitter / 2;\n\n await delay(delayMs);\n}\n\n/**\n * Combines multiple abort signals into one.\n * When any of the input signals is aborted, the combined signal will also be aborted.\n *\n * @param signals - Array of AbortSignal instances (can contain undefined/null)\n * @returns An object containing the combined signal and a cleanup function\n */\nexport function combineAbortSignals(signals: Array<AbortSignal | undefined | null>): {\n signal: AbortSignal;\n cleanUpSignals: () => void;\n} {\n const controller = new AbortController();\n const onAbort = () => {\n controller.abort();\n cleanUpSignals();\n };\n\n const cleanUpSignals = () => {\n for (const s of signals) {\n s?.removeEventListener(\"abort\", onAbort);\n }\n };\n\n for (const s of signals) {\n s?.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n if (signals.some((s) => s?.aborted)) {\n onAbort();\n }\n\n return { signal: controller.signal, cleanUpSignals };\n}\n\n/**\n * A deferred promise that can be resolved or rejected from outside.\n * Useful for coordinating async operations.\n */\nexport class Deferred<T> {\n public readonly promise: Promise<T>;\n public resolve!: (value: T) => void;\n public reject!: (error: unknown) => void;\n\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\n","import { ReplaneError, ReplaneErrorCode } from \"./error\";\nimport { combineAbortSignals } from \"./utils\";\n\nconst SSE_DATA_PREFIX = \"data:\";\n\n/**\n * Parsed SSE event\n */\nexport type SseEvent = { type: \"comment\"; comment: string } | { type: \"data\"; data: string };\n\n/**\n * Options for fetchSse\n */\nexport interface FetchSseOptions {\n fetchFn: typeof fetch;\n url: string;\n timeoutMs: number;\n body?: string;\n headers?: Record<string, string>;\n method?: string;\n signal?: AbortSignal;\n onConnect?: () => void;\n}\n\n/**\n * Fetch with timeout support\n */\nexport async function fetchWithTimeout(\n input: string | URL | Request,\n init: RequestInit,\n timeoutMs: number,\n fetchFn: typeof fetch\n): Promise<Response> {\n if (!fetchFn) {\n throw new Error(\"Global fetch is not available. Provide options.fetchFn.\");\n }\n if (!timeoutMs) return fetchFn(input, init);\n\n const timeoutController = new AbortController();\n const t = setTimeout(() => timeoutController.abort(), timeoutMs);\n // Note: We intentionally don't call cleanUpSignals() here because for streaming\n // responses (like SSE), the connection remains open after the response headers\n // are received. The abort signal needs to remain connected so that close() can\n // propagate the abort through the signal chain.\n const { signal } = combineAbortSignals([init.signal, timeoutController.signal]);\n try {\n return await fetchFn(input, {\n ...init,\n signal,\n });\n } finally {\n clearTimeout(t);\n }\n}\n\n/**\n * Ensures the response is successful, throwing ReplaneError if not\n */\nexport async function ensureSuccessfulResponse(response: Response, message: string): Promise<void> {\n if (response.status === 404) {\n throw new ReplaneError({\n message: `Not found: ${message}`,\n code: ReplaneErrorCode.NotFound,\n });\n }\n\n if (response.status === 401) {\n throw new ReplaneError({\n message: `Unauthorized access: ${message}`,\n code: ReplaneErrorCode.AuthError,\n });\n }\n\n if (response.status === 403) {\n throw new ReplaneError({\n message: `Forbidden access: ${message}`,\n code: ReplaneErrorCode.Forbidden,\n });\n }\n\n if (!response.ok) {\n let body: unknown;\n try {\n body = await response.text();\n } catch {\n body = \"<unable to read response body>\";\n }\n\n const code =\n response.status >= 500\n ? ReplaneErrorCode.ServerError\n : response.status >= 400\n ? ReplaneErrorCode.ClientError\n : ReplaneErrorCode.Unknown;\n\n throw new ReplaneError({\n message: `Fetch response isn't successful (${message}): ${response.status} ${response.statusText} - ${body}`,\n code,\n });\n }\n}\n\n/**\n * Fetches a Server-Sent Events (SSE) stream and yields parsed events.\n *\n * @param params - Options for the SSE fetch\n * @yields SseEvent objects containing either data or comment events\n */\nexport async function* fetchSse(params: FetchSseOptions): AsyncGenerator<SseEvent> {\n const abortController = new AbortController();\n const { signal, cleanUpSignals } = params.signal\n ? combineAbortSignals([params.signal, abortController.signal])\n : { signal: abortController.signal, cleanUpSignals: () => {} };\n\n try {\n const res = await fetchWithTimeout(\n params.url,\n {\n method: params.method ?? \"GET\",\n headers: { Accept: \"text/event-stream\", ...(params.headers ?? {}) },\n body: params.body,\n signal,\n },\n params.timeoutMs,\n params.fetchFn\n );\n\n await ensureSuccessfulResponse(res, `SSE ${params.url}`);\n const responseContentType = res.headers.get(\"content-type\") ?? \"\";\n\n if (!responseContentType.includes(\"text/event-stream\")) {\n throw new ReplaneError({\n message: `Expected text/event-stream, got \"${responseContentType}\"`,\n code: ReplaneErrorCode.ServerError,\n });\n }\n\n if (!res.body) {\n throw new ReplaneError({\n message: `Failed to fetch SSE ${params.url}: body is empty`,\n code: ReplaneErrorCode.Unknown,\n });\n }\n\n if (params.onConnect) {\n params.onConnect();\n }\n\n const decoded = res.body.pipeThrough(new TextDecoderStream());\n const reader = decoded.getReader();\n\n let buffer = \"\";\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += value!;\n\n // Split on blank line; handle both \\n\\n and \\r\\n\\r\\n\n const frames = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = frames.pop() ?? \"\";\n\n for (const frame of frames) {\n // Parse lines inside a single SSE event frame\n const dataLines: string[] = [];\n let comment: string | null = null;\n\n for (const rawLine of frame.split(/\\r?\\n/)) {\n if (!rawLine) continue;\n if (rawLine.startsWith(\":\")) {\n // comment/keepalive\n comment = rawLine.slice(1);\n continue;\n }\n\n if (rawLine.startsWith(SSE_DATA_PREFIX)) {\n // Keep leading space after \"data:\" if present per spec\n const line = rawLine.slice(SSE_DATA_PREFIX.length).replace(/^\\s/, \"\");\n dataLines.push(line);\n }\n }\n\n if (dataLines.length) {\n const data = dataLines.join(\"\\n\");\n yield { type: \"data\", data };\n } else if (comment !== null) {\n yield { type: \"comment\", comment };\n }\n }\n }\n } finally {\n try {\n await reader.cancel();\n } catch {\n // ignore error\n }\n abortController.abort();\n }\n } finally {\n cleanUpSignals();\n }\n}\n","import type { ReplicationStreamRecord, StartReplicationStreamBody } from \"./types\";\nimport type { ReplaneFinalOptions } from \"./client-types\";\nimport { fetchSse } from \"./sse\";\nimport { combineAbortSignals, retryDelay } from \"./utils\";\n\nconst SUPPORTED_REPLICATION_STREAM_RECORD_TYPES = Object.keys({\n config_change: true,\n init: true,\n} satisfies Record<ReplicationStreamRecord[\"type\"], true>);\n\n/**\n * Options for starting a replication stream\n */\nexport interface StartReplicationStreamOptions extends ReplaneFinalOptions {\n // getBody is a function to get the latest configs when we are trying\n // to reestablish the replication stream\n getBody: () => StartReplicationStreamBody;\n signal?: AbortSignal;\n onConnect?: () => void;\n}\n\n/**\n * Interface for storage implementations\n */\nexport interface ReplaneStorage {\n startReplicationStream(\n options: StartReplicationStreamOptions\n ): AsyncIterable<ReplicationStreamRecord>;\n close(): void;\n}\n\n/**\n * Remote storage implementation that connects to the Replane server\n * and streams config updates via SSE.\n */\nexport class ReplaneRemoteStorage implements ReplaneStorage {\n private closeController = new AbortController();\n\n /**\n * Start a replication stream that yields config updates.\n * This method never throws - it retries on failure with exponential backoff.\n */\n async *startReplicationStream(\n options: StartReplicationStreamOptions\n ): AsyncIterable<ReplicationStreamRecord> {\n const { signal, cleanUpSignals } = combineAbortSignals([\n this.closeController.signal,\n options.signal,\n ]);\n try {\n let failedAttempts = 0;\n while (!signal.aborted) {\n try {\n for await (const event of this.startReplicationStreamImpl({\n ...options,\n signal,\n onConnect: () => {\n failedAttempts = 0;\n },\n })) {\n yield event;\n }\n } catch (error: unknown) {\n failedAttempts++;\n const retryDelayMs = Math.min(options.retryDelayMs * 2 ** (failedAttempts - 1), 10_000);\n if (!signal.aborted) {\n options.logger.error(\n `Failed to fetch project events, retrying in ${retryDelayMs}ms...`,\n error\n );\n\n await retryDelay(retryDelayMs);\n }\n }\n }\n } finally {\n cleanUpSignals();\n }\n }\n\n private async *startReplicationStreamImpl(\n options: StartReplicationStreamOptions\n ): AsyncIterable<ReplicationStreamRecord> {\n // Create an abort controller for inactivity timeout\n const inactivityAbortController = new AbortController();\n const { signal: combinedSignal, cleanUpSignals } = options.signal\n ? combineAbortSignals([options.signal, inactivityAbortController.signal])\n : { signal: inactivityAbortController.signal, cleanUpSignals: () => {} };\n\n let inactivityTimer: ReturnType<typeof setTimeout> | null = null;\n\n const resetInactivityTimer = () => {\n if (inactivityTimer) clearTimeout(inactivityTimer);\n inactivityTimer = setTimeout(() => {\n inactivityAbortController.abort();\n }, options.inactivityTimeoutMs);\n };\n\n try {\n const rawEvents = fetchSse({\n fetchFn: options.fetchFn,\n headers: {\n Authorization: this.getAuthHeader(options),\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(options.getBody()),\n timeoutMs: options.requestTimeoutMs,\n method: \"POST\",\n signal: combinedSignal,\n url: this.getApiEndpoint(`/sdk/v1/replication/stream`, options),\n onConnect: () => {\n resetInactivityTimer();\n options.onConnect?.();\n },\n });\n\n for await (const sseEvent of rawEvents) {\n resetInactivityTimer();\n\n if (sseEvent.type === \"comment\") continue;\n\n const event = JSON.parse(sseEvent.data);\n if (\n typeof event === \"object\" &&\n event !== null &&\n \"type\" in event &&\n typeof event.type === \"string\" &&\n (SUPPORTED_REPLICATION_STREAM_RECORD_TYPES as unknown as string[]).includes(event.type)\n ) {\n yield event as ReplicationStreamRecord;\n }\n }\n } finally {\n if (inactivityTimer) clearTimeout(inactivityTimer);\n cleanUpSignals();\n }\n }\n\n /**\n * Close the storage and abort any active connections\n */\n close(): void {\n this.closeController.abort();\n }\n\n private getAuthHeader(options: ReplaneFinalOptions): string {\n return `Bearer ${options.sdkKey}`;\n }\n\n private getApiEndpoint(path: string, options: ReplaneFinalOptions): string {\n return `${options.baseUrl}/api${path}`;\n }\n}\n","/**\n * FNV-1a 32-bit hash function\n *\n * FNV (Fowler–Noll–Vo) is a non-cryptographic hash function known for its\n * speed and good distribution. This implementation uses the FNV-1a variant\n * which XORs before multiplying for better avalanche characteristics.\n *\n * @param input - The string to hash\n * @returns A 32-bit unsigned integer hash value\n */\nexport function fnv1a32(input: string): number {\n // Convert string to bytes (UTF-8)\n const encoder = new TextEncoder();\n const bytes = encoder.encode(input);\n\n // FNV-1a core\n let hash = 0x811c9dc5 >>> 0; // 2166136261, force uint32\n\n for (let i = 0; i < bytes.length; i++) {\n hash ^= bytes[i]; // XOR with byte\n hash = Math.imul(hash, 0x01000193) >>> 0; // * 16777619 mod 2^32\n }\n\n return hash >>> 0; // ensure unsigned 32-bit\n}\n\n/**\n * Convert FNV-1a hash to [0, 1) for bucketing.\n *\n * This is useful for percentage-based segmentation where you need\n * to deterministically assign a value to a bucket based on a string input.\n *\n * @param input - The string to hash\n * @returns A number in the range [0, 1)\n */\nexport function fnv1a32ToUnit(input: string): number {\n const h = fnv1a32(input);\n return h / 2 ** 32; // double in [0, 1)\n}\n","import type { RenderedCondition, RenderedOverride } from \"./types\";\nimport type { ReplaneContext, ReplaneLogger } from \"./client-types\";\nimport { fnv1a32ToUnit } from \"./hash\";\n\n/**\n * Result of evaluating a condition\n */\nexport type EvaluationResult = \"matched\" | \"not_matched\" | \"unknown\";\n\n/**\n * Evaluate config overrides based on context.\n * Returns the first matching override's value, or the base value if no override matches.\n *\n * @param baseValue - The default value to return if no override matches\n * @param overrides - Array of overrides to evaluate\n * @param context - The context to evaluate conditions against\n * @param logger - Logger for warnings\n * @returns The evaluated value\n */\nexport function evaluateOverrides<T>(\n baseValue: T,\n overrides: RenderedOverride[],\n context: ReplaneContext,\n logger: ReplaneLogger\n): T {\n // Find first matching override\n for (const override of overrides) {\n // All conditions must match (implicit AND)\n let overrideResult: EvaluationResult = \"matched\";\n const results = override.conditions.map((c) => evaluateCondition(c, context, logger));\n // AND: false > unknown > true\n if (results.some((r) => r === \"not_matched\")) {\n overrideResult = \"not_matched\";\n } else if (results.some((r) => r === \"unknown\")) {\n overrideResult = \"unknown\";\n }\n\n // Only use override if all conditions matched (not unknown)\n if (overrideResult === \"matched\") {\n return override.value as T;\n }\n }\n\n return baseValue;\n}\n\n/**\n * Evaluate a single condition against a context.\n *\n * @param condition - The condition to evaluate\n * @param context - The context to evaluate against\n * @param logger - Logger for warnings\n * @returns The evaluation result\n */\nexport function evaluateCondition(\n condition: RenderedCondition,\n context: ReplaneContext,\n logger: ReplaneLogger\n): EvaluationResult {\n const operator = condition.operator;\n\n // Composite conditions\n if (operator === \"and\") {\n const results = condition.conditions.map((c) => evaluateCondition(c, context, logger));\n // AND: false > unknown > true\n if (results.some((r) => r === \"not_matched\")) return \"not_matched\";\n if (results.some((r) => r === \"unknown\")) return \"unknown\";\n return \"matched\";\n }\n\n if (operator === \"or\") {\n const results = condition.conditions.map((c) => evaluateCondition(c, context, logger));\n // OR: true > unknown > false\n if (results.some((r) => r === \"matched\")) return \"matched\";\n if (results.some((r) => r === \"unknown\")) return \"unknown\";\n return \"not_matched\";\n }\n\n if (operator === \"not\") {\n const result = evaluateCondition(condition.condition, context, logger);\n if (result === \"matched\") return \"not_matched\";\n if (result === \"not_matched\") return \"matched\";\n return \"unknown\"; // NOT unknown = unknown\n }\n\n // Segmentation\n if (operator === \"segmentation\") {\n const contextValue = context[condition.property];\n if (contextValue === undefined || contextValue === null) {\n return \"unknown\";\n }\n\n // FNV-1a hash to bucket [0, 100)\n const hashInput = String(contextValue) + condition.seed;\n const unitValue = fnv1a32ToUnit(hashInput);\n return unitValue >= condition.fromPercentage / 100 && unitValue < condition.toPercentage / 100\n ? \"matched\"\n : \"not_matched\";\n }\n\n // Property-based conditions\n const property = condition.property;\n const contextValue = context[property];\n const expectedValue = condition.value;\n\n if (contextValue === undefined) {\n return \"unknown\";\n }\n\n // Type casting\n const castedValue = castToContextType(expectedValue, contextValue);\n\n switch (operator) {\n case \"equals\":\n return contextValue === castedValue ? \"matched\" : \"not_matched\";\n\n case \"in\":\n if (!Array.isArray(castedValue)) return \"unknown\";\n return castedValue.includes(contextValue) ? \"matched\" : \"not_matched\";\n\n case \"not_in\":\n if (!Array.isArray(castedValue)) return \"unknown\";\n return !castedValue.includes(contextValue) ? \"matched\" : \"not_matched\";\n\n case \"less_than\":\n if (typeof contextValue === \"number\" && typeof castedValue === \"number\") {\n return contextValue < castedValue ? \"matched\" : \"not_matched\";\n }\n if (typeof contextValue === \"string\" && typeof castedValue === \"string\") {\n return contextValue < castedValue ? \"matched\" : \"not_matched\";\n }\n return \"not_matched\";\n\n case \"less_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof castedValue === \"number\") {\n return contextValue <= castedValue ? \"matched\" : \"not_matched\";\n }\n if (typeof contextValue === \"string\" && typeof castedValue === \"string\") {\n return contextValue <= castedValue ? \"matched\" : \"not_matched\";\n }\n return \"not_matched\";\n\n case \"greater_than\":\n if (typeof contextValue === \"number\" && typeof castedValue === \"number\") {\n return contextValue > castedValue ? \"matched\" : \"not_matched\";\n }\n if (typeof contextValue === \"string\" && typeof castedValue === \"string\") {\n return contextValue > castedValue ? \"matched\" : \"not_matched\";\n }\n return \"not_matched\";\n\n case \"greater_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof castedValue === \"number\") {\n return contextValue >= castedValue ? \"matched\" : \"not_matched\";\n }\n if (typeof contextValue === \"string\" && typeof castedValue === \"string\") {\n return contextValue >= castedValue ? \"matched\" : \"not_matched\";\n }\n return \"not_matched\";\n\n default:\n warnNever(operator, logger, `Unexpected operator: ${operator}`);\n return \"unknown\";\n }\n}\n\n/**\n * Helper to warn about exhaustive check failures\n */\nfunction warnNever(value: never, logger: ReplaneLogger, message: string): void {\n logger.warn(message, { value });\n}\n\n/**\n * Cast expected value to match context value type.\n * This enables loose matching between different types (e.g., \"25\" matches 25).\n *\n * @param expectedValue - The value from the condition\n * @param contextValue - The value from the context\n * @returns The expected value cast to match the context value's type\n */\nexport function castToContextType(expectedValue: unknown, contextValue: unknown): unknown {\n if (typeof contextValue === \"number\") {\n if (typeof expectedValue === \"string\") {\n const num = Number(expectedValue);\n return isNaN(num) ? expectedValue : num;\n }\n return expectedValue;\n }\n\n if (typeof contextValue === \"boolean\") {\n if (typeof expectedValue === \"string\") {\n if (expectedValue === \"true\") return true;\n if (expectedValue === \"false\") return false;\n }\n if (typeof expectedValue === \"number\") {\n return expectedValue !== 0;\n }\n return expectedValue;\n }\n\n if (typeof contextValue === \"string\") {\n if (typeof expectedValue === \"number\" || typeof expectedValue === \"boolean\") {\n return String(expectedValue);\n }\n return expectedValue;\n }\n\n return expectedValue;\n}\n","import type { ConfigDto } from \"./types\";\nimport type {\n ReplaneContext,\n ReplaneLogger,\n GetConfigOptions,\n MapConfig,\n ReplaneSnapshot,\n ReplaneClient,\n ReplaneClientOptions,\n RestoreReplaneClientOptions,\n ReplaneFinalOptions,\n} from \"./client-types\";\nimport type { ReplaneStorage } from \"./storage\";\nimport { ReplaneRemoteStorage } from \"./storage\";\nimport { ReplaneError, ReplaneErrorCode } from \"./error\";\nimport { evaluateOverrides } from \"./evaluation\";\nimport { Deferred } from \"./utils\";\n\n/**\n * Internal options for creating the client core\n */\ninterface ClientCoreOptions {\n initialConfigs: ConfigDto[];\n context: ReplaneContext;\n logger: ReplaneLogger;\n storage: ReplaneStorage | null;\n streamOptions: ReplaneFinalOptions | null;\n requiredConfigs: string[];\n}\n\n/**\n * Result from creating the client core\n */\ninterface ClientCoreResult<T extends object> {\n client: ReplaneClient<T>;\n configs: Map<string, ConfigDto>;\n startStreaming: () => Promise<void>;\n clientReady: Deferred<void>;\n}\n\n/**\n * Creates the core client logic shared between createReplaneClient and restoreReplaneClient\n */\nfunction createClientCore<T extends object = Record<string, unknown>>(\n options: ClientCoreOptions\n): ClientCoreResult<T> {\n const { initialConfigs, context, logger, storage, streamOptions, requiredConfigs } = options;\n\n const configs: Map<string, ConfigDto> = new Map(\n initialConfigs.map((config) => [config.name, config])\n );\n\n const clientReady = new Deferred<void>();\n const configSubscriptions = new Map<keyof T, Set<(config: MapConfig<T>) => void>>();\n const clientSubscriptions = new Set<(config: MapConfig<T>) => void>();\n\n function processConfigUpdates(updatedConfigs: ConfigDto[]) {\n for (const config of updatedConfigs) {\n configs.set(config.name, {\n name: config.name,\n overrides: config.overrides,\n value: config.value,\n });\n for (const callback of clientSubscriptions) {\n callback({ name: config.name as keyof T, value: config.value as T[keyof T] });\n }\n for (const callback of configSubscriptions.get(config.name as keyof T) ?? []) {\n callback({ name: config.name as keyof T, value: config.value as T[keyof T] });\n }\n }\n }\n\n async function startStreaming(): Promise<void> {\n if (!storage || !streamOptions) return;\n\n try {\n const replicationStream = storage.startReplicationStream({\n ...streamOptions,\n getBody: () => ({\n currentConfigs: [...configs.values()].map((config) => ({\n name: config.name,\n overrides: config.overrides,\n value: config.value,\n })),\n requiredConfigs,\n }),\n });\n\n for await (const event of replicationStream) {\n const updatedConfigs: ConfigDto[] =\n event.type === \"config_change\" ? [event.config] : event.configs;\n processConfigUpdates(updatedConfigs);\n clientReady.resolve();\n }\n } catch (error) {\n logger.error(\"Replane: error in SSE connection:\", error);\n clientReady.reject(error);\n throw error;\n }\n }\n\n function get<K extends keyof T>(configName: K, getConfigOptions: GetConfigOptions = {}): T[K] {\n const config = configs.get(String(configName));\n\n if (config === undefined) {\n throw new ReplaneError({\n message: `Config not found: ${String(configName)}`,\n code: ReplaneErrorCode.NotFound,\n });\n }\n\n try {\n return evaluateOverrides<T[K]>(\n config.value as T[K],\n config.overrides,\n { ...context, ...(getConfigOptions?.context ?? {}) },\n logger\n );\n } catch (error) {\n logger.error(`Replane: error evaluating overrides for config ${String(configName)}:`, error);\n return config.value as T[K];\n }\n }\n\n const subscribe = (\n callbackOrConfigName: keyof T | ((config: MapConfig<T>) => void),\n callbackOrUndefined?: (config: MapConfig<T>) => void\n ) => {\n let configName: keyof T | undefined = undefined;\n let callback: (config: MapConfig<T>) => void;\n if (typeof callbackOrConfigName === \"function\") {\n callback = callbackOrConfigName;\n } else {\n configName = callbackOrConfigName as keyof T;\n if (callbackOrUndefined === undefined) {\n throw new Error(\"callback is required when config name is provided\");\n }\n callback = callbackOrUndefined!;\n }\n\n // Wrap the callback to ensure that we have a unique reference\n const originalCallback = callback;\n callback = (...args: Parameters<typeof callback>) => {\n originalCallback(...args);\n };\n\n if (configName === undefined) {\n clientSubscriptions.add(callback);\n return () => {\n clientSubscriptions.delete(callback);\n };\n }\n\n if (!configSubscriptions.has(configName)) {\n configSubscriptions.set(configName, new Set());\n }\n configSubscriptions.get(configName)!.add(callback);\n return () => {\n configSubscriptions.get(configName)?.delete(callback);\n if (configSubscriptions.get(configName)?.size === 0) {\n configSubscriptions.delete(configName);\n }\n };\n };\n\n const getSnapshot = (): ReplaneSnapshot<T> => ({\n configs: [...configs.values()].map((config) => ({\n name: config.name,\n value: config.value,\n overrides: config.overrides.map((override) => ({\n name: override.name,\n conditions: override.conditions,\n value: override.value,\n })),\n })),\n context,\n });\n\n const close = () => storage?.close();\n\n const client: ReplaneClient<T> = {\n get,\n subscribe: subscribe as ReplaneClient<T>[\"subscribe\"],\n getSnapshot,\n close,\n };\n\n return { client, configs, startStreaming, clientReady };\n}\n\n/**\n * Create a Replane client bound to an SDK key.\n *\n * @example\n * ```typescript\n * const client = await createReplaneClient({\n * sdkKey: 'your-sdk-key',\n * baseUrl: 'https://app.replane.dev'\n * });\n * const value = client.get('my-config');\n * ```\n */\nexport async function createReplaneClient<T extends object = Record<string, unknown>>(\n sdkOptions: ReplaneClientOptions<T>\n): Promise<ReplaneClient<T>> {\n const storage = new ReplaneRemoteStorage();\n return await createReplaneClientInternal(toFinalOptions(sdkOptions), storage);\n}\n\n/**\n * Create a Replane client that uses in-memory storage.\n * Useful for testing or when you have static config values.\n *\n * @example\n * ```typescript\n * const client = createInMemoryReplaneClient({ 'my-config': 123 });\n * const value = client.get('my-config'); // 123\n * ```\n */\nexport function createInMemoryReplaneClient<T extends object = Record<string, unknown>>(\n initialData: T\n): ReplaneClient<T> {\n return {\n get: (configName) => {\n const config = initialData[configName];\n if (config === undefined) {\n throw new ReplaneError({\n message: `Config not found: ${String(configName)}`,\n code: ReplaneErrorCode.NotFound,\n });\n }\n return config;\n },\n subscribe: () => {\n return () => {};\n },\n getSnapshot: () => ({\n configs: Object.entries(initialData).map(([name, value]) => ({\n name,\n value,\n overrides: [],\n })),\n }),\n close: () => {},\n };\n}\n\n/**\n * Restore a Replane client from a snapshot.\n * This is useful for SSR/hydration scenarios where the server has already fetched configs.\n *\n * @example\n * ```typescript\n * // On the server:\n * const serverClient = await createReplaneClient({ ... });\n * const snapshot = serverClient.getSnapshot();\n * // Pass snapshot to client via props/serialization\n *\n * // On the client:\n * const client = restoreReplaneClient({\n * snapshot,\n * connection: { sdkKey, baseUrl }\n * });\n * const value = client.get('my-config');\n * ```\n */\nexport function restoreReplaneClient<T extends object = Record<string, unknown>>(\n options: RestoreReplaneClientOptions<T>\n): ReplaneClient<T> {\n const { snapshot, connection } = options;\n const context = options.context ?? snapshot.context ?? {};\n const logger = connection?.logger ?? console;\n\n // Initialize configs from snapshot\n const initialConfigs: ConfigDto[] = snapshot.configs.map((config) => ({\n name: config.name,\n value: config.value,\n overrides: config.overrides,\n }));\n\n let storage: ReplaneRemoteStorage | null = null;\n let streamOptions: ReplaneFinalOptions | null = null;\n\n if (connection) {\n storage = new ReplaneRemoteStorage();\n streamOptions = {\n sdkKey: connection.sdkKey,\n baseUrl: connection.baseUrl.replace(/\\/+$/, \"\"),\n fetchFn: connection.fetchFn ?? globalThis.fetch.bind(globalThis),\n requestTimeoutMs: connection.requestTimeoutMs ?? 2000,\n initializationTimeoutMs: 5000, // Not used for restore\n inactivityTimeoutMs: connection.inactivityTimeoutMs ?? 30_000,\n logger,\n retryDelayMs: connection.retryDelayMs ?? 200,\n context,\n requiredConfigs: [],\n fallbacks: [],\n };\n }\n\n const { client, startStreaming } = createClientCore<T>({\n initialConfigs,\n context,\n logger,\n storage,\n streamOptions,\n requiredConfigs: [],\n });\n\n // Start streaming in background (non-blocking) if connection is provided\n if (storage && streamOptions) {\n startStreaming().catch((error) => {\n logger.error(\"Replane: error in restored client SSE connection:\", error);\n });\n }\n\n return client;\n}\n\n/**\n * Internal function to create a Replane client with the given options and storage\n */\nasync function createReplaneClientInternal<T extends object = Record<string, unknown>>(\n sdkOptions: ReplaneFinalOptions,\n storage: ReplaneStorage\n): Promise<ReplaneClient<T>> {\n if (!sdkOptions.sdkKey) throw new Error(\"SDK key is required\");\n\n const { client, configs, startStreaming, clientReady } = createClientCore<T>({\n initialConfigs: sdkOptions.fallbacks,\n context: sdkOptions.context,\n logger: sdkOptions.logger,\n storage,\n streamOptions: sdkOptions,\n requiredConfigs: sdkOptions.requiredConfigs,\n });\n\n // Start streaming in background\n startStreaming().catch((error) => {\n sdkOptions.logger.error(\"Replane: error initializing client:\", error);\n });\n\n const initializationTimeoutId = setTimeout(() => {\n if (sdkOptions.fallbacks.length === 0) {\n // no fallbacks, we have nothing to work with\n client.close();\n\n clientReady.reject(\n new ReplaneError({\n message: \"Replane client initialization timed out\",\n code: ReplaneErrorCode.Timeout,\n })\n );\n\n return;\n }\n\n const missingRequiredConfigs: string[] = [];\n for (const requiredConfigName of sdkOptions.requiredConfigs) {\n if (!configs.has(requiredConfigName)) {\n missingRequiredConfigs.push(requiredConfigName);\n }\n }\n\n if (missingRequiredConfigs.length > 0) {\n client.close();\n clientReady.reject(\n new ReplaneError({\n message: `Required configs are missing: ${missingRequiredConfigs.join(\", \")}`,\n code: ReplaneErrorCode.NotFound,\n })\n );\n\n return;\n }\n\n clientReady.resolve();\n }, sdkOptions.initializationTimeoutMs);\n\n clientReady.promise.then(() => clearTimeout(initializationTimeoutId));\n\n await clientReady.promise;\n\n return client;\n}\n\n/**\n * Convert user options to final options with defaults\n */\nfunction toFinalOptions<T extends object>(defaults: ReplaneClientOptions<T>): ReplaneFinalOptions {\n return {\n sdkKey: defaults.sdkKey,\n baseUrl: defaults.baseUrl.replace(/\\/+$/, \"\"),\n fetchFn:\n defaults.fetchFn ??\n // some browsers require binding the fetch function to window\n globalThis.fetch.bind(globalThis),\n requestTimeoutMs: defaults.requestTimeoutMs ?? 2000,\n initializationTimeoutMs: defaults.initializationTimeoutMs ?? 5000,\n inactivityTimeoutMs: defaults.inactivityTimeoutMs ?? 30_000,\n logger: defaults.logger ?? console,\n retryDelayMs: defaults.retryDelayMs ?? 200,\n context: {\n ...(defaults.context ?? {}),\n },\n requiredConfigs: Array.isArray(defaults.required)\n ? defaults.required.map((name) => String(name))\n : Object.entries(defaults.required ?? {})\n .filter(([_, value]) => value !== undefined)\n .map(([name]) => name),\n fallbacks: Object.entries(defaults.fallbacks ?? {})\n .filter(([_, value]) => value !== undefined)\n .map(([name, value]) => ({\n name,\n overrides: [],\n version: -1,\n value,\n })),\n };\n}\n","import { createReplaneClient } from \"./client\";\nimport type { ReplaneClient, ReplaneClientOptions, ReplaneSnapshot } from \"./client-types\";\n\n/**\n * Extended options for getReplaneSnapshot with caching support.\n */\nexport interface GetReplaneSnapshotOptions<T extends object> extends ReplaneClientOptions<T> {\n /**\n * Cache TTL in milliseconds. When set, the client is cached and reused\n * for instant subsequent calls within this duration.\n * @default 60_000 (1 minute)\n */\n cacheTtlMs?: number;\n}\n\ninterface CachedClient {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n clientPromise: Promise<ReplaneClient<any>>;\n timeoutId: TimeoutId;\n}\n\nconst clientCache = new Map<string, CachedClient>();\n\nfunction getCacheKey<T extends object>(options: ReplaneClientOptions<T>): string {\n return `${options.baseUrl}:${options.sdkKey}`;\n}\n\ntype TimeoutId = ReturnType<typeof setTimeout>;\n\nfunction setupCleanupTimeout(cacheKey: string, cacheTtlMs: number): TimeoutId {\n return setTimeout(() => {\n clientCache.delete(cacheKey);\n }, cacheTtlMs);\n}\n\n/**\n * Creates a Replane client and returns a snapshot.\n * Useful for SSR/SSG scenarios where you need to fetch config once\n * and pass it to the client.\n *\n * @example\n * ```ts\n * const snapshot = await getReplaneSnapshot({\n * baseUrl: process.env.REPLANE_BASE_URL!,\n * sdkKey: process.env.REPLANE_SDK_KEY!,\n * });\n * ```\n */\nexport async function getReplaneSnapshot<T extends object>(\n options: GetReplaneSnapshotOptions<T>\n): Promise<ReplaneSnapshot<T>> {\n const { cacheTtlMs = 60_000, ...clientOptions } = options;\n\n const cacheKey = getCacheKey(clientOptions);\n const cached = clientCache.get(cacheKey);\n\n // Return from cache if valid\n if (cached) {\n clearTimeout(cached.timeoutId);\n cached.timeoutId = setupCleanupTimeout(cacheKey, cacheTtlMs);\n\n const client = await cached.clientPromise;\n return client.getSnapshot() as ReplaneSnapshot<T>;\n }\n\n // Create new client and cache it\n const clientPromise = createReplaneClient<T>(clientOptions);\n const entry: CachedClient = {\n clientPromise: clientPromise,\n timeoutId: setupCleanupTimeout(cacheKey, cacheTtlMs),\n };\n clientCache.set(cacheKey, entry);\n\n const client = await clientPromise;\n\n return client.getSnapshot();\n}\n\n/**\n * Clears the client cache used by getReplaneSnapshot.\n * Useful for testing or when you need to force re-initialization.\n */\nexport async function clearSnapshotCache(): Promise<void> {\n const clientPromises = [...clientCache.values()].map((cached) => cached.clientPromise);\n clientCache.clear();\n for (const clientPromise of clientPromises) {\n const client = await clientPromise;\n client.close();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["params: { message: string; code: string; cause?: unknown }","ms: number","averageDelay: number","signals: Array<AbortSignal | undefined | null>","input: string | URL | Request","init: RequestInit","timeoutMs: number","fetchFn: typeof fetch","response: Response","message: string","body: unknown","params: FetchSseOptions","dataLines: string[]","comment: string | null","options: StartReplicationStreamOptions","error: unknown","inactivityTimer: ReturnType<typeof setTimeout> | null","options: ReplaneFinalOptions","path: string","input: string","baseValue: T","overrides: RenderedOverride[]","context: ReplaneContext","logger: ReplaneLogger","overrideResult: EvaluationResult","condition: RenderedCondition","contextValue","value: never","message: string","expectedValue: unknown","contextValue: unknown","options: ClientCoreOptions","configs: Map<string, ConfigDto>","updatedConfigs: ConfigDto[]","configName: K","getConfigOptions: GetConfigOptions<T[K]>","callbackOrConfigName: keyof T | ((config: MapConfig<T>) => void)","callbackOrUndefined?: (config: MapConfig<T>) => void","configName: keyof T | undefined","callback: (config: MapConfig<T>) => void","client: ReplaneClient<T>","sdkOptions: ReplaneClientOptions<T>","initialData: T","options: RestoreReplaneClientOptions<T>","initialConfigs: ConfigDto[]","storage: ReplaneRemoteStorage | null","streamOptions: ReplaneFinalOptions | null","sdkOptions: ReplaneFinalOptions","storage: ReplaneStorage","missingRequiredConfigs: string[]","defaults: ReplaneClientOptions<T>","options: ReplaneClientOptions<T>","cacheKey: string","keepAliveMs: number","options: GetReplaneSnapshotOptions<T>","client","entry: CachedClient"],"sources":["../src/error.ts","../src/utils.ts","../src/sse.ts","../src/storage.ts","../src/hash.ts","../src/evaluation.ts","../src/client.ts","../src/snapshot.ts"],"sourcesContent":["/**\n * Error codes for ReplaneError\n */\nexport enum ReplaneErrorCode {\n NotFound = \"not_found\",\n Timeout = \"timeout\",\n NetworkError = \"network_error\",\n AuthError = \"auth_error\",\n Forbidden = \"forbidden\",\n ServerError = \"server_error\",\n ClientError = \"client_error\",\n Closed = \"closed\",\n NotInitialized = \"not_initialized\",\n Unknown = \"unknown\",\n}\n\n/**\n * Custom error class for Replane SDK errors\n */\nexport class ReplaneError extends Error {\n code: string;\n\n constructor(params: { message: string; code: string; cause?: unknown }) {\n super(params.message, { cause: params.cause });\n this.name = \"ReplaneError\";\n this.code = params.code;\n }\n}\n","/**\n * Returns a promise that resolves after the specified delay\n *\n * @param ms - Delay in milliseconds\n */\nexport async function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Returns a promise that resolves after a delay with jitter.\n * The actual delay is the average delay ± 10% (jitter = averageDelay/5).\n *\n * @param averageDelay - The average delay in milliseconds\n */\nexport async function retryDelay(averageDelay: number): Promise<void> {\n const jitter = averageDelay / 5;\n const delayMs = averageDelay + Math.random() * jitter - jitter / 2;\n\n await delay(delayMs);\n}\n\n/**\n * Combines multiple abort signals into one.\n * When any of the input signals is aborted, the combined signal will also be aborted.\n *\n * @param signals - Array of AbortSignal instances (can contain undefined/null)\n * @returns An object containing the combined signal and a cleanup function\n */\nexport function combineAbortSignals(signals: Array<AbortSignal | undefined | null>): {\n signal: AbortSignal;\n cleanUpSignals: () => void;\n} {\n const controller = new AbortController();\n const onAbort = () => {\n controller.abort();\n cleanUpSignals();\n };\n\n const cleanUpSignals = () => {\n for (const s of signals) {\n s?.removeEventListener(\"abort\", onAbort);\n }\n };\n\n for (const s of signals) {\n s?.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n if (signals.some((s) => s?.aborted)) {\n onAbort();\n }\n\n return { signal: controller.signal, cleanUpSignals };\n}\n\n/**\n * A deferred promise that can be resolved or rejected from outside.\n * Useful for coordinating async operations.\n */\nexport class Deferred<T> {\n public readonly promise: Promise<T>;\n public resolve!: (value: T) => void;\n public reject!: (error: unknown) => void;\n\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\n","import { ReplaneError, ReplaneErrorCode } from \"./error\";\nimport { combineAbortSignals } from \"./utils\";\n\nconst SSE_DATA_PREFIX = \"data:\";\n\n/**\n * Parsed SSE event\n */\nexport type SseEvent = { type: \"comment\"; comment: string } | { type: \"data\"; data: string };\n\n/**\n * Options for fetchSse\n */\nexport interface FetchSseOptions {\n fetchFn: typeof fetch;\n url: string;\n timeoutMs: number;\n body?: string;\n headers?: Record<string, string>;\n method?: string;\n signal?: AbortSignal;\n onConnect?: () => void;\n}\n\n/**\n * Fetch with timeout support\n */\nexport async function fetchWithTimeout(\n input: string | URL | Request,\n init: RequestInit,\n timeoutMs: number,\n fetchFn: typeof fetch\n): Promise<Response> {\n if (!fetchFn) {\n throw new Error(\"Global fetch is not available. Provide options.fetchFn.\");\n }\n if (!timeoutMs) return fetchFn(input, init);\n\n const timeoutController = new AbortController();\n const t = setTimeout(() => timeoutController.abort(), timeoutMs);\n // Note: We intentionally don't call cleanUpSignals() here because for streaming\n // responses (like SSE), the connection remains open after the response headers\n // are received. The abort signal needs to remain connected so that close() can\n // propagate the abort through the signal chain.\n const { signal } = combineAbortSignals([init.signal, timeoutController.signal]);\n try {\n return await fetchFn(input, {\n ...init,\n signal,\n });\n } finally {\n clearTimeout(t);\n }\n}\n\n/**\n * Ensures the response is successful, throwing ReplaneError if not\n */\nexport async function ensureSuccessfulResponse(response: Response, message: string): Promise<void> {\n if (response.status === 404) {\n throw new ReplaneError({\n message: `Not found: ${message}`,\n code: ReplaneErrorCode.NotFound,\n });\n }\n\n if (response.status === 401) {\n throw new ReplaneError({\n message: `Unauthorized access: ${message}`,\n code: ReplaneErrorCode.AuthError,\n });\n }\n\n if (response.status === 403) {\n throw new ReplaneError({\n message: `Forbidden access: ${message}`,\n code: ReplaneErrorCode.Forbidden,\n });\n }\n\n if (!response.ok) {\n let body: unknown;\n try {\n body = await response.text();\n } catch {\n body = \"<unable to read response body>\";\n }\n\n const code =\n response.status >= 500\n ? ReplaneErrorCode.ServerError\n : response.status >= 400\n ? ReplaneErrorCode.ClientError\n : ReplaneErrorCode.Unknown;\n\n throw new ReplaneError({\n message: `Fetch response isn't successful (${message}): ${response.status} ${response.statusText} - ${body}`,\n code,\n });\n }\n}\n\n/**\n * Fetches a Server-Sent Events (SSE) stream and yields parsed events.\n *\n * @param params - Options for the SSE fetch\n * @yields SseEvent objects containing either data or comment events\n */\nexport async function* fetchSse(params: FetchSseOptions): AsyncGenerator<SseEvent> {\n const abortController = new AbortController();\n const { signal, cleanUpSignals } = params.signal\n ? combineAbortSignals([params.signal, abortController.signal])\n : { signal: abortController.signal, cleanUpSignals: () => {} };\n\n try {\n const res = await fetchWithTimeout(\n params.url,\n {\n method: params.method ?? \"GET\",\n headers: { Accept: \"text/event-stream\", ...(params.headers ?? {}) },\n body: params.body,\n signal,\n },\n params.timeoutMs,\n params.fetchFn\n );\n\n await ensureSuccessfulResponse(res, `SSE ${params.url}`);\n const responseContentType = res.headers.get(\"content-type\") ?? \"\";\n\n if (!responseContentType.includes(\"text/event-stream\")) {\n throw new ReplaneError({\n message: `Expected text/event-stream, got \"${responseContentType}\"`,\n code: ReplaneErrorCode.ServerError,\n });\n }\n\n if (!res.body) {\n throw new ReplaneError({\n message: `Failed to fetch SSE ${params.url}: body is empty`,\n code: ReplaneErrorCode.Unknown,\n });\n }\n\n if (params.onConnect) {\n params.onConnect();\n }\n\n const decoded = res.body.pipeThrough(new TextDecoderStream());\n const reader = decoded.getReader();\n\n let buffer = \"\";\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += value!;\n\n // Split on blank line; handle both \\n\\n and \\r\\n\\r\\n\n const frames = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = frames.pop() ?? \"\";\n\n for (const frame of frames) {\n // Parse lines inside a single SSE event frame\n const dataLines: string[] = [];\n let comment: string | null = null;\n\n for (const rawLine of frame.split(/\\r?\\n/)) {\n if (!rawLine) continue;\n if (rawLine.startsWith(\":\")) {\n // comment/keepalive\n comment = rawLine.slice(1);\n continue;\n }\n\n if (rawLine.startsWith(SSE_DATA_PREFIX)) {\n // Keep leading space after \"data:\" if present per spec\n const line = rawLine.slice(SSE_DATA_PREFIX.length).replace(/^\\s/, \"\");\n dataLines.push(line);\n }\n }\n\n if (dataLines.length) {\n const data = dataLines.join(\"\\n\");\n yield { type: \"data\", data };\n } else if (comment !== null) {\n yield { type: \"comment\", comment };\n }\n }\n }\n } finally {\n try {\n await reader.cancel();\n } catch {\n // ignore error\n }\n abortController.abort();\n }\n } finally {\n cleanUpSignals();\n }\n}\n","import type { ReplicationStreamRecord, StartReplicationStreamBody } from \"./types\";\nimport type { ReplaneFinalOptions } from \"./client-types\";\nimport { fetchSse } from \"./sse\";\nimport { combineAbortSignals, retryDelay } from \"./utils\";\n\nconst SUPPORTED_REPLICATION_STREAM_RECORD_TYPES = Object.keys({\n config_change: true,\n init: true,\n} satisfies Record<ReplicationStreamRecord[\"type\"], true>);\n\n/**\n * Options for starting a replication stream\n */\nexport interface StartReplicationStreamOptions extends ReplaneFinalOptions {\n // getBody is a function to get the latest configs when we are trying\n // to reestablish the replication stream\n getBody: () => StartReplicationStreamBody;\n signal?: AbortSignal;\n onConnect?: () => void;\n}\n\n/**\n * Interface for storage implementations\n */\nexport interface ReplaneStorage {\n startReplicationStream(\n options: StartReplicationStreamOptions\n ): AsyncIterable<ReplicationStreamRecord>;\n close(): void;\n}\n\n/**\n * Remote storage implementation that connects to the Replane server\n * and streams config updates via SSE.\n */\nexport class ReplaneRemoteStorage implements ReplaneStorage {\n private closeController = new AbortController();\n\n /**\n * Start a replication stream that yields config updates.\n * This method never throws - it retries on failure with exponential backoff.\n */\n async *startReplicationStream(\n options: StartReplicationStreamOptions\n ): AsyncIterable<ReplicationStreamRecord> {\n const { signal, cleanUpSignals } = combineAbortSignals([\n this.closeController.signal,\n options.signal,\n ]);\n try {\n let failedAttempts = 0;\n while (!signal.aborted) {\n try {\n for await (const event of this.startReplicationStreamImpl({\n ...options,\n signal,\n onConnect: () => {\n failedAttempts = 0;\n },\n })) {\n yield event;\n }\n } catch (error: unknown) {\n failedAttempts++;\n const retryDelayMs = Math.min(options.retryDelayMs * 2 ** (failedAttempts - 1), 10_000);\n if (!signal.aborted) {\n options.logger.error(\n `Failed to fetch project events, retrying in ${retryDelayMs}ms...`,\n error\n );\n\n await retryDelay(retryDelayMs);\n }\n }\n }\n } finally {\n cleanUpSignals();\n }\n }\n\n private async *startReplicationStreamImpl(\n options: StartReplicationStreamOptions\n ): AsyncIterable<ReplicationStreamRecord> {\n // Create an abort controller for inactivity timeout\n const inactivityAbortController = new AbortController();\n const { signal: combinedSignal, cleanUpSignals } = options.signal\n ? combineAbortSignals([options.signal, inactivityAbortController.signal])\n : { signal: inactivityAbortController.signal, cleanUpSignals: () => {} };\n\n let inactivityTimer: ReturnType<typeof setTimeout> | null = null;\n\n const resetInactivityTimer = () => {\n if (inactivityTimer) clearTimeout(inactivityTimer);\n inactivityTimer = setTimeout(() => {\n inactivityAbortController.abort();\n }, options.inactivityTimeoutMs);\n };\n\n try {\n const rawEvents = fetchSse({\n fetchFn: options.fetchFn,\n headers: {\n Authorization: this.getAuthHeader(options),\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(options.getBody()),\n timeoutMs: options.requestTimeoutMs,\n method: \"POST\",\n signal: combinedSignal,\n url: this.getApiEndpoint(`/sdk/v1/replication/stream`, options),\n onConnect: () => {\n resetInactivityTimer();\n options.onConnect?.();\n },\n });\n\n for await (const sseEvent of rawEvents) {\n resetInactivityTimer();\n\n if (sseEvent.type === \"comment\") continue;\n\n const event = JSON.parse(sseEvent.data);\n if (\n typeof event === \"object\" &&\n event !== null &&\n \"type\" in event &&\n typeof event.type === \"string\" &&\n (SUPPORTED_REPLICATION_STREAM_RECORD_TYPES as unknown as string[]).includes(event.type)\n ) {\n yield event as ReplicationStreamRecord;\n }\n }\n } finally {\n if (inactivityTimer) clearTimeout(inactivityTimer);\n cleanUpSignals();\n }\n }\n\n /**\n * Close the storage and abort any active connections\n */\n close(): void {\n this.closeController.abort();\n }\n\n private getAuthHeader(options: ReplaneFinalOptions): string {\n return `Bearer ${options.sdkKey}`;\n }\n\n private getApiEndpoint(path: string, options: ReplaneFinalOptions): string {\n return `${options.baseUrl}/api${path}`;\n }\n}\n","/**\n * FNV-1a 32-bit hash function\n *\n * FNV (Fowler–Noll–Vo) is a non-cryptographic hash function known for its\n * speed and good distribution. This implementation uses the FNV-1a variant\n * which XORs before multiplying for better avalanche characteristics.\n *\n * @param input - The string to hash\n * @returns A 32-bit unsigned integer hash value\n */\nexport function fnv1a32(input: string): number {\n // Convert string to bytes (UTF-8)\n const encoder = new TextEncoder();\n const bytes = encoder.encode(input);\n\n // FNV-1a core\n let hash = 0x811c9dc5 >>> 0; // 2166136261, force uint32\n\n for (let i = 0; i < bytes.length; i++) {\n hash ^= bytes[i]; // XOR with byte\n hash = Math.imul(hash, 0x01000193) >>> 0; // * 16777619 mod 2^32\n }\n\n return hash >>> 0; // ensure unsigned 32-bit\n}\n\n/**\n * Convert FNV-1a hash to [0, 1) for bucketing.\n *\n * This is useful for percentage-based segmentation where you need\n * to deterministically assign a value to a bucket based on a string input.\n *\n * @param input - The string to hash\n * @returns A number in the range [0, 1)\n */\nexport function fnv1a32ToUnit(input: string): number {\n const h = fnv1a32(input);\n return h / 2 ** 32; // double in [0, 1)\n}\n","import type { RenderedCondition, RenderedOverride } from \"./types\";\nimport type { ReplaneContext, ReplaneLogger } from \"./client-types\";\nimport { fnv1a32ToUnit } from \"./hash\";\n\n/**\n * Result of evaluating a condition\n */\nexport type EvaluationResult = \"matched\" | \"not_matched\" | \"unknown\";\n\n/**\n * Evaluate config overrides based on context.\n * Returns the first matching override's value, or the base value if no override matches.\n *\n * @param baseValue - The default value to return if no override matches\n * @param overrides - Array of overrides to evaluate\n * @param context - The context to evaluate conditions against\n * @param logger - Logger for warnings\n * @returns The evaluated value\n */\nexport function evaluateOverrides<T>(\n baseValue: T,\n overrides: RenderedOverride[],\n context: ReplaneContext,\n logger: ReplaneLogger\n): T {\n // Find first matching override\n for (const override of overrides) {\n // All conditions must match (implicit AND)\n let overrideResult: EvaluationResult = \"matched\";\n const results = override.conditions.map((c) => evaluateCondition(c, context, logger));\n // AND: false > unknown > true\n if (results.some((r) => r === \"not_matched\")) {\n overrideResult = \"not_matched\";\n } else if (results.some((r) => r === \"unknown\")) {\n overrideResult = \"unknown\";\n }\n\n // Only use override if all conditions matched (not unknown)\n if (overrideResult === \"matched\") {\n return override.value as T;\n }\n }\n\n return baseValue;\n}\n\n/**\n * Evaluate a single condition against a context.\n *\n * @param condition - The condition to evaluate\n * @param context - The context to evaluate against\n * @param logger - Logger for warnings\n * @returns The evaluation result\n */\nexport function evaluateCondition(\n condition: RenderedCondition,\n context: ReplaneContext,\n logger: ReplaneLogger\n): EvaluationResult {\n const operator = condition.operator;\n\n // Composite conditions\n if (operator === \"and\") {\n const results = condition.conditions.map((c) => evaluateCondition(c, context, logger));\n // AND: false > unknown > true\n if (results.some((r) => r === \"not_matched\")) return \"not_matched\";\n if (results.some((r) => r === \"unknown\")) return \"unknown\";\n return \"matched\";\n }\n\n if (operator === \"or\") {\n const results = condition.conditions.map((c) => evaluateCondition(c, context, logger));\n // OR: true > unknown > false\n if (results.some((r) => r === \"matched\")) return \"matched\";\n if (results.some((r) => r === \"unknown\")) return \"unknown\";\n return \"not_matched\";\n }\n\n if (operator === \"not\") {\n const result = evaluateCondition(condition.condition, context, logger);\n if (result === \"matched\") return \"not_matched\";\n if (result === \"not_matched\") return \"matched\";\n return \"unknown\"; // NOT unknown = unknown\n }\n\n // Segmentation\n if (operator === \"segmentation\") {\n const contextValue = context[condition.property];\n if (contextValue === undefined || contextValue === null) {\n return \"unknown\";\n }\n\n // FNV-1a hash to bucket [0, 100)\n const hashInput = String(contextValue) + condition.seed;\n const unitValue = fnv1a32ToUnit(hashInput);\n return unitValue >= condition.fromPercentage / 100 && unitValue < condition.toPercentage / 100\n ? \"matched\"\n : \"not_matched\";\n }\n\n // Property-based conditions\n const property = condition.property;\n const contextValue = context[property];\n const expectedValue = condition.value;\n\n if (contextValue === undefined) {\n return \"unknown\";\n }\n\n // Type casting\n const castedValue = castToContextType(expectedValue, contextValue);\n\n switch (operator) {\n case \"equals\":\n return contextValue === castedValue ? \"matched\" : \"not_matched\";\n\n case \"in\":\n if (!Array.isArray(castedValue)) return \"unknown\";\n return castedValue.includes(contextValue) ? \"matched\" : \"not_matched\";\n\n case \"not_in\":\n if (!Array.isArray(castedValue)) return \"unknown\";\n return !castedValue.includes(contextValue) ? \"matched\" : \"not_matched\";\n\n case \"less_than\":\n if (typeof contextValue === \"number\" && typeof castedValue === \"number\") {\n return contextValue < castedValue ? \"matched\" : \"not_matched\";\n }\n if (typeof contextValue === \"string\" && typeof castedValue === \"string\") {\n return contextValue < castedValue ? \"matched\" : \"not_matched\";\n }\n return \"not_matched\";\n\n case \"less_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof castedValue === \"number\") {\n return contextValue <= castedValue ? \"matched\" : \"not_matched\";\n }\n if (typeof contextValue === \"string\" && typeof castedValue === \"string\") {\n return contextValue <= castedValue ? \"matched\" : \"not_matched\";\n }\n return \"not_matched\";\n\n case \"greater_than\":\n if (typeof contextValue === \"number\" && typeof castedValue === \"number\") {\n return contextValue > castedValue ? \"matched\" : \"not_matched\";\n }\n if (typeof contextValue === \"string\" && typeof castedValue === \"string\") {\n return contextValue > castedValue ? \"matched\" : \"not_matched\";\n }\n return \"not_matched\";\n\n case \"greater_than_or_equal\":\n if (typeof contextValue === \"number\" && typeof castedValue === \"number\") {\n return contextValue >= castedValue ? \"matched\" : \"not_matched\";\n }\n if (typeof contextValue === \"string\" && typeof castedValue === \"string\") {\n return contextValue >= castedValue ? \"matched\" : \"not_matched\";\n }\n return \"not_matched\";\n\n default:\n warnNever(operator, logger, `Unexpected operator: ${operator}`);\n return \"unknown\";\n }\n}\n\n/**\n * Helper to warn about exhaustive check failures\n */\nfunction warnNever(value: never, logger: ReplaneLogger, message: string): void {\n logger.warn(message, { value });\n}\n\n/**\n * Cast expected value to match context value type.\n * This enables loose matching between different types (e.g., \"25\" matches 25).\n *\n * @param expectedValue - The value from the condition\n * @param contextValue - The value from the context\n * @returns The expected value cast to match the context value's type\n */\nexport function castToContextType(expectedValue: unknown, contextValue: unknown): unknown {\n if (typeof contextValue === \"number\") {\n if (typeof expectedValue === \"string\") {\n const num = Number(expectedValue);\n return isNaN(num) ? expectedValue : num;\n }\n return expectedValue;\n }\n\n if (typeof contextValue === \"boolean\") {\n if (typeof expectedValue === \"string\") {\n if (expectedValue === \"true\") return true;\n if (expectedValue === \"false\") return false;\n }\n if (typeof expectedValue === \"number\") {\n return expectedValue !== 0;\n }\n return expectedValue;\n }\n\n if (typeof contextValue === \"string\") {\n if (typeof expectedValue === \"number\" || typeof expectedValue === \"boolean\") {\n return String(expectedValue);\n }\n return expectedValue;\n }\n\n return expectedValue;\n}\n","import type { ConfigDto } from \"./types\";\nimport type {\n ReplaneContext,\n ReplaneLogger,\n GetConfigOptions,\n MapConfig,\n ReplaneSnapshot,\n ReplaneClient,\n ReplaneClientOptions,\n RestoreReplaneClientOptions,\n ReplaneFinalOptions,\n} from \"./client-types\";\nimport type { ReplaneStorage } from \"./storage\";\nimport { ReplaneRemoteStorage } from \"./storage\";\nimport { ReplaneError, ReplaneErrorCode } from \"./error\";\nimport { evaluateOverrides } from \"./evaluation\";\nimport { Deferred } from \"./utils\";\n\n/**\n * Internal options for creating the client core\n */\ninterface ClientCoreOptions {\n initialConfigs: ConfigDto[];\n context: ReplaneContext;\n logger: ReplaneLogger;\n storage: ReplaneStorage | null;\n streamOptions: ReplaneFinalOptions | null;\n requiredConfigs: string[];\n}\n\n/**\n * Result from creating the client core\n */\ninterface ClientCoreResult<T extends object> {\n client: ReplaneClient<T>;\n configs: Map<string, ConfigDto>;\n startStreaming: () => Promise<void>;\n clientReady: Deferred<void>;\n}\n\n/**\n * Creates the core client logic shared between createReplaneClient and restoreReplaneClient\n */\nfunction createClientCore<T extends object = Record<string, unknown>>(\n options: ClientCoreOptions\n): ClientCoreResult<T> {\n const { initialConfigs, context, logger, storage, streamOptions, requiredConfigs } = options;\n\n const configs: Map<string, ConfigDto> = new Map(\n initialConfigs.map((config) => [config.name, config])\n );\n\n const clientReady = new Deferred<void>();\n const configSubscriptions = new Map<keyof T, Set<(config: MapConfig<T>) => void>>();\n const clientSubscriptions = new Set<(config: MapConfig<T>) => void>();\n\n function processConfigUpdates(updatedConfigs: ConfigDto[]) {\n for (const config of updatedConfigs) {\n configs.set(config.name, {\n name: config.name,\n overrides: config.overrides,\n value: config.value,\n });\n for (const callback of clientSubscriptions) {\n callback({ name: config.name as keyof T, value: config.value as T[keyof T] });\n }\n for (const callback of configSubscriptions.get(config.name as keyof T) ?? []) {\n callback({ name: config.name as keyof T, value: config.value as T[keyof T] });\n }\n }\n }\n\n async function startStreaming(): Promise<void> {\n if (!storage || !streamOptions) return;\n\n try {\n const replicationStream = storage.startReplicationStream({\n ...streamOptions,\n getBody: () => ({\n currentConfigs: [...configs.values()].map((config) => ({\n name: config.name,\n overrides: config.overrides,\n value: config.value,\n })),\n requiredConfigs,\n }),\n });\n\n for await (const event of replicationStream) {\n const updatedConfigs: ConfigDto[] =\n event.type === \"config_change\" ? [event.config] : event.configs;\n processConfigUpdates(updatedConfigs);\n clientReady.resolve();\n }\n } catch (error) {\n logger.error(\"Replane: error in SSE connection:\", error);\n clientReady.reject(error);\n throw error;\n }\n }\n\n function get<K extends keyof T>(configName: K, getConfigOptions: GetConfigOptions<T[K]> = {}): T[K] {\n const config = configs.get(String(configName));\n\n if (config === undefined) {\n if (\"default\" in getConfigOptions) {\n return getConfigOptions.default as T[K];\n }\n throw new ReplaneError({\n message: `Config not found: ${String(configName)}`,\n code: ReplaneErrorCode.NotFound,\n });\n }\n\n try {\n return evaluateOverrides<T[K]>(\n config.value as T[K],\n config.overrides,\n { ...context, ...(getConfigOptions?.context ?? {}) },\n logger\n );\n } catch (error) {\n logger.error(`Replane: error evaluating overrides for config ${String(configName)}:`, error);\n return config.value as T[K];\n }\n }\n\n const subscribe = (\n callbackOrConfigName: keyof T | ((config: MapConfig<T>) => void),\n callbackOrUndefined?: (config: MapConfig<T>) => void\n ) => {\n let configName: keyof T | undefined = undefined;\n let callback: (config: MapConfig<T>) => void;\n if (typeof callbackOrConfigName === \"function\") {\n callback = callbackOrConfigName;\n } else {\n configName = callbackOrConfigName as keyof T;\n if (callbackOrUndefined === undefined) {\n throw new Error(\"callback is required when config name is provided\");\n }\n callback = callbackOrUndefined!;\n }\n\n // Wrap the callback to ensure that we have a unique reference\n const originalCallback = callback;\n callback = (...args: Parameters<typeof callback>) => {\n originalCallback(...args);\n };\n\n if (configName === undefined) {\n clientSubscriptions.add(callback);\n return () => {\n clientSubscriptions.delete(callback);\n };\n }\n\n if (!configSubscriptions.has(configName)) {\n configSubscriptions.set(configName, new Set());\n }\n configSubscriptions.get(configName)!.add(callback);\n return () => {\n configSubscriptions.get(configName)?.delete(callback);\n if (configSubscriptions.get(configName)?.size === 0) {\n configSubscriptions.delete(configName);\n }\n };\n };\n\n const getSnapshot = (): ReplaneSnapshot<T> => ({\n configs: [...configs.values()].map((config) => ({\n name: config.name,\n value: config.value,\n overrides: config.overrides.map((override) => ({\n name: override.name,\n conditions: override.conditions,\n value: override.value,\n })),\n })),\n context,\n });\n\n const close = () => storage?.close();\n\n const client: ReplaneClient<T> = {\n get,\n subscribe: subscribe as ReplaneClient<T>[\"subscribe\"],\n getSnapshot,\n close,\n };\n\n return { client, configs, startStreaming, clientReady };\n}\n\n/**\n * Create a Replane client bound to an SDK key.\n *\n * @example\n * ```typescript\n * const client = await createReplaneClient({\n * sdkKey: 'your-sdk-key',\n * baseUrl: 'https://app.replane.dev'\n * });\n * const value = client.get('my-config');\n * ```\n */\nexport async function createReplaneClient<T extends object = Record<string, unknown>>(\n sdkOptions: ReplaneClientOptions<T>\n): Promise<ReplaneClient<T>> {\n const storage = new ReplaneRemoteStorage();\n return await createReplaneClientInternal(toFinalOptions(sdkOptions), storage);\n}\n\n/**\n * Create a Replane client that uses in-memory storage.\n * Useful for testing or when you have static config values.\n *\n * @example\n * ```typescript\n * const client = createInMemoryReplaneClient({ 'my-config': 123 });\n * const value = client.get('my-config'); // 123\n * ```\n */\nexport function createInMemoryReplaneClient<T extends object = Record<string, unknown>>(\n initialData: T\n): ReplaneClient<T> {\n return {\n get: (configName, options) => {\n const config = initialData[configName];\n if (config === undefined) {\n if (options && \"default\" in options) {\n return options.default as T[typeof configName];\n }\n throw new ReplaneError({\n message: `Config not found: ${String(configName)}`,\n code: ReplaneErrorCode.NotFound,\n });\n }\n return config;\n },\n subscribe: () => {\n return () => {};\n },\n getSnapshot: () => ({\n configs: Object.entries(initialData).map(([name, value]) => ({\n name,\n value,\n overrides: [],\n })),\n }),\n close: () => {},\n };\n}\n\n/**\n * Restore a Replane client from a snapshot.\n * This is useful for SSR/hydration scenarios where the server has already fetched configs.\n *\n * @example\n * ```typescript\n * // On the server:\n * const serverClient = await createReplaneClient({ ... });\n * const snapshot = serverClient.getSnapshot();\n * // Pass snapshot to client via props/serialization\n *\n * // On the client:\n * const client = restoreReplaneClient({\n * snapshot,\n * connection: { sdkKey, baseUrl }\n * });\n * const value = client.get('my-config');\n * ```\n */\nexport function restoreReplaneClient<T extends object = Record<string, unknown>>(\n options: RestoreReplaneClientOptions<T>\n): ReplaneClient<T> {\n const { snapshot, connection } = options;\n const context = options.context ?? snapshot.context ?? {};\n const logger = connection?.logger ?? console;\n\n // Initialize configs from snapshot\n const initialConfigs: ConfigDto[] = snapshot.configs.map((config) => ({\n name: config.name,\n value: config.value,\n overrides: config.overrides,\n }));\n\n let storage: ReplaneRemoteStorage | null = null;\n let streamOptions: ReplaneFinalOptions | null = null;\n\n if (connection) {\n storage = new ReplaneRemoteStorage();\n streamOptions = {\n sdkKey: connection.sdkKey,\n baseUrl: connection.baseUrl.replace(/\\/+$/, \"\"),\n fetchFn: connection.fetchFn ?? globalThis.fetch.bind(globalThis),\n requestTimeoutMs: connection.requestTimeoutMs ?? 2000,\n initializationTimeoutMs: 5000, // Not used for restore\n inactivityTimeoutMs: connection.inactivityTimeoutMs ?? 30_000,\n logger,\n retryDelayMs: connection.retryDelayMs ?? 200,\n context,\n requiredConfigs: [],\n fallbacks: [],\n };\n }\n\n const { client, startStreaming } = createClientCore<T>({\n initialConfigs,\n context,\n logger,\n storage,\n streamOptions,\n requiredConfigs: [],\n });\n\n // Start streaming in background (non-blocking) if connection is provided\n if (storage && streamOptions) {\n startStreaming().catch((error) => {\n logger.error(\"Replane: error in restored client SSE connection:\", error);\n });\n }\n\n return client;\n}\n\n/**\n * Internal function to create a Replane client with the given options and storage\n */\nasync function createReplaneClientInternal<T extends object = Record<string, unknown>>(\n sdkOptions: ReplaneFinalOptions,\n storage: ReplaneStorage\n): Promise<ReplaneClient<T>> {\n if (!sdkOptions.sdkKey) throw new Error(\"SDK key is required\");\n\n const { client, configs, startStreaming, clientReady } = createClientCore<T>({\n initialConfigs: sdkOptions.fallbacks,\n context: sdkOptions.context,\n logger: sdkOptions.logger,\n storage,\n streamOptions: sdkOptions,\n requiredConfigs: sdkOptions.requiredConfigs,\n });\n\n // Start streaming in background\n startStreaming().catch((error) => {\n sdkOptions.logger.error(\"Replane: error initializing client:\", error);\n });\n\n const initializationTimeoutId = setTimeout(() => {\n if (sdkOptions.fallbacks.length === 0) {\n // no fallbacks, we have nothing to work with\n client.close();\n\n clientReady.reject(\n new ReplaneError({\n message: \"Replane client initialization timed out\",\n code: ReplaneErrorCode.Timeout,\n })\n );\n\n return;\n }\n\n const missingRequiredConfigs: string[] = [];\n for (const requiredConfigName of sdkOptions.requiredConfigs) {\n if (!configs.has(requiredConfigName)) {\n missingRequiredConfigs.push(requiredConfigName);\n }\n }\n\n if (missingRequiredConfigs.length > 0) {\n client.close();\n clientReady.reject(\n new ReplaneError({\n message: `Required configs are missing: ${missingRequiredConfigs.join(\", \")}`,\n code: ReplaneErrorCode.NotFound,\n })\n );\n\n return;\n }\n\n clientReady.resolve();\n }, sdkOptions.initializationTimeoutMs);\n\n clientReady.promise.then(() => clearTimeout(initializationTimeoutId));\n\n await clientReady.promise;\n\n return client;\n}\n\n/**\n * Convert user options to final options with defaults\n */\nfunction toFinalOptions<T extends object>(defaults: ReplaneClientOptions<T>): ReplaneFinalOptions {\n return {\n sdkKey: defaults.sdkKey,\n baseUrl: defaults.baseUrl.replace(/\\/+$/, \"\"),\n fetchFn:\n defaults.fetchFn ??\n // some browsers require binding the fetch function to window\n globalThis.fetch.bind(globalThis),\n requestTimeoutMs: defaults.requestTimeoutMs ?? 2000,\n initializationTimeoutMs: defaults.initializationTimeoutMs ?? 5000,\n inactivityTimeoutMs: defaults.inactivityTimeoutMs ?? 30_000,\n logger: defaults.logger ?? console,\n retryDelayMs: defaults.retryDelayMs ?? 200,\n context: {\n ...(defaults.context ?? {}),\n },\n requiredConfigs: Array.isArray(defaults.required)\n ? defaults.required.map((name) => String(name))\n : Object.entries(defaults.required ?? {})\n .filter(([_, value]) => value !== undefined)\n .map(([name]) => name),\n fallbacks: Object.entries(defaults.fallbacks ?? {})\n .filter(([_, value]) => value !== undefined)\n .map(([name, value]) => ({\n name,\n overrides: [],\n version: -1,\n value,\n })),\n };\n}\n","import { createReplaneClient } from \"./client\";\nimport type { ReplaneClient, ReplaneClientOptions, ReplaneSnapshot } from \"./client-types\";\n\n/**\n * Extended options for getReplaneSnapshot with caching support.\n */\nexport interface GetReplaneSnapshotOptions<T extends object> extends ReplaneClientOptions<T> {\n /**\n * Cache TTL in milliseconds. When set, the client is cached and reused\n * for instant subsequent calls within this duration.\n * @default 60_000 (1 minute)\n */\n keepAliveMs?: number;\n}\n\ninterface CachedClient {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n clientPromise: Promise<ReplaneClient<any>>;\n timeoutId: TimeoutId;\n}\n\nconst clientCache = new Map<string, CachedClient>();\n\nfunction getCacheKey<T extends object>(options: ReplaneClientOptions<T>): string {\n return `${options.baseUrl}:${options.sdkKey}`;\n}\n\ntype TimeoutId = ReturnType<typeof setTimeout>;\n\nfunction setupCleanupTimeout(cacheKey: string, keepAliveMs: number): TimeoutId {\n return setTimeout(() => {\n clientCache.delete(cacheKey);\n }, keepAliveMs);\n}\n\n/**\n * Creates a Replane client and returns a snapshot.\n * Useful for SSR/SSG scenarios where you need to fetch config once\n * and pass it to the client.\n *\n * @example\n * ```ts\n * const snapshot = await getReplaneSnapshot({\n * baseUrl: process.env.REPLANE_BASE_URL!,\n * sdkKey: process.env.REPLANE_SDK_KEY!,\n * });\n * ```\n */\nexport async function getReplaneSnapshot<T extends object>(\n options: GetReplaneSnapshotOptions<T>\n): Promise<ReplaneSnapshot<T>> {\n const { keepAliveMs = 60_000, ...clientOptions } = options;\n\n const cacheKey = getCacheKey(clientOptions);\n const cached = clientCache.get(cacheKey);\n\n // Return from cache if valid\n if (cached) {\n clearTimeout(cached.timeoutId);\n cached.timeoutId = setupCleanupTimeout(cacheKey, keepAliveMs);\n\n const client = await cached.clientPromise;\n return client.getSnapshot() as ReplaneSnapshot<T>;\n }\n\n // Create new client and cache it\n const clientPromise = createReplaneClient<T>(clientOptions);\n const entry: CachedClient = {\n clientPromise: clientPromise,\n timeoutId: setupCleanupTimeout(cacheKey, keepAliveMs),\n };\n clientCache.set(cacheKey, entry);\n\n const client = await clientPromise;\n\n return client.getSnapshot();\n}\n\n/**\n * Clears the client cache used by getReplaneSnapshot.\n * Useful for testing or when you need to force re-initialization.\n */\nexport async function clearSnapshotCache(): Promise<void> {\n const clientPromises = [...clientCache.values()].map((cached) => cached.clientPromise);\n clientCache.clear();\n for (const clientPromise of clientPromises) {\n const client = await clientPromise;\n client.close();\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@replanejs/sdk",
3
- "version": "0.7.8",
3
+ "version": "0.8.0",
4
4
  "description": "Dynamic configuration SDK for browser and server environments (Node.js, Deno, Bun). Powered by Replane.",
5
5
  "type": "module",
6
6
  "license": "MIT",