@configdirector/react-web-sdk 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/configdirector-react-client-testing.cjs +1 -1
- package/dist/configdirector-react-client-testing.d.cts +12 -3
- package/dist/configdirector-react-client-testing.d.cts.map +1 -1
- package/dist/configdirector-react-client-testing.d.mts +12 -3
- package/dist/configdirector-react-client-testing.d.mts.map +1 -1
- package/dist/configdirector-react-client-testing.mjs +1 -1
- package/dist/configdirector-react-client-testing.mjs.map +1 -1
- package/dist/configdirector-react-client.cjs +1 -1
- package/dist/configdirector-react-client.d.cts +2 -2
- package/dist/configdirector-react-client.d.mts +2 -2
- package/dist/configdirector-react-client.mjs +1 -1
- package/dist/configdirector-react-client.mjs.map +1 -1
- package/dist/installedTestClient-CtAa-JtW.mjs +6 -0
- package/dist/installedTestClient-CtAa-JtW.mjs.map +1 -0
- package/dist/installedTestClient-e5GGVvz6.cjs +5 -0
- package/dist/{types-CTTaCWsq.d.cts → types-Bh2N89iB.d.cts} +69 -7
- package/dist/types-Bh2N89iB.d.cts.map +1 -0
- package/dist/{types-BcKqVLfU.d.mts → types-DEvHIkvY.d.mts} +69 -7
- package/dist/types-DEvHIkvY.d.mts.map +1 -0
- package/package.json +1 -1
- package/dist/installedTestClient-CeRd8PpZ.cjs +0 -5
- package/dist/installedTestClient-cBWU0-t8.mjs +0 -6
- package/dist/installedTestClient-cBWU0-t8.mjs.map +0 -1
- package/dist/types-BcKqVLfU.d.mts.map +0 -1
- package/dist/types-CTTaCWsq.d.cts.map +0 -1
|
@@ -22,24 +22,72 @@ interface ConfigDirectorLogger {
|
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Why an evaluation returned the value it did. `found-match` returns a value from ConfigDirector,
|
|
25
|
-
* and `cached` a value kept on the device while a client SDK waits for live values.
|
|
25
|
+
* and `cached` a value kept on the device while a client SDK waits for live values.
|
|
26
|
+
* `rollout-skipped-no-identifier` returns the default targeting rule value: a server SDK skipped a
|
|
27
|
+
* percentage rollout because the context has no `id` to place it in a share. `value-missing`
|
|
26
28
|
* returns the in-code default value because the config has no value. Every other reason returns the
|
|
27
29
|
* in-code default value because of an error: the config does not exist (`config-state-missing`), no
|
|
28
30
|
* values have arrived yet (`client-not-ready`), or the value cannot be read as the type of the in-code
|
|
29
31
|
* default value.
|
|
30
32
|
*/
|
|
31
|
-
type EvaluationReason = "found-match" | "config-state-missing" | "client-not-ready" | "type-mismatch" | "value-missing" | "invalid-number" | "invalid-json" | "invalid-boolean" | "cached";
|
|
33
|
+
type EvaluationReason = "found-match" | "rollout-skipped-no-identifier" | "config-state-missing" | "client-not-ready" | "type-mismatch" | "value-missing" | "invalid-number" | "invalid-json" | "invalid-boolean" | "cached";
|
|
34
|
+
/**
|
|
35
|
+
* One of the values a config can serve, such as the control or a treatment of an experiment.
|
|
36
|
+
*/
|
|
37
|
+
type Variation = {
|
|
38
|
+
/** The ID ConfigDirector assigned to the variation, which stays the same when it is renamed. */id: string; /** The variation's name, when it has one. */
|
|
39
|
+
name?: string;
|
|
40
|
+
};
|
|
32
41
|
/**
|
|
33
42
|
* One evaluation of a config: the value it returned, why, and the context it was evaluated for.
|
|
34
43
|
*/
|
|
35
44
|
type ConfigEvaluation<T extends ConfigValueType = ConfigValueType> = {
|
|
36
45
|
/** The config key that was evaluated. */key: string; /** The value returned, which is the in-code default value when {@link isDefaultValue} is `true`. */
|
|
37
46
|
value: T; /** The ID ConfigDirector assigned to the value returned, when ConfigDirector sent one with it. */
|
|
38
|
-
valueId?: string;
|
|
47
|
+
valueId?: string;
|
|
48
|
+
/**
|
|
49
|
+
* The variation that was served. It is `undefined` when the config has no variations or the
|
|
50
|
+
* in-code default value is returned.
|
|
51
|
+
*/
|
|
52
|
+
variation?: Variation; /** Whether the evaluation returned the in-code default value. */
|
|
39
53
|
isDefaultValue: boolean; /** Why the evaluation returned this value. */
|
|
40
54
|
reason: EvaluationReason; /** The context the config was evaluated for, if any. */
|
|
41
55
|
context?: ConfigDirectorContext;
|
|
42
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* A value in the details of a tracked event: a string, a number, a boolean, or an array or object
|
|
59
|
+
* of such values.
|
|
60
|
+
*/
|
|
61
|
+
type TrackedEventDetailValue = string | number | boolean | TrackedEventDetailValue[] | {
|
|
62
|
+
[key: string]: TrackedEventDetailValue;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Details of a tracked event, such as the plan a customer chose. Details with more than 20
|
|
66
|
+
* top-level keys, or larger than 1 KB as JSON, are left out and the event is still reported.
|
|
67
|
+
*/
|
|
68
|
+
type TrackedEventDetails = {
|
|
69
|
+
[key: string]: TrackedEventDetailValue;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* What a tracked event carries besides its name.
|
|
73
|
+
*/
|
|
74
|
+
type TrackOptions = {
|
|
75
|
+
/**
|
|
76
|
+
* A number the event measures, such as an amount of money, a count or a duration. A value that
|
|
77
|
+
* is not a finite number is left out and the event is still reported.
|
|
78
|
+
*/
|
|
79
|
+
value?: number; /** Details of the event. */
|
|
80
|
+
details?: TrackedEventDetails;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* An event the code under test tracked, as a test client recorded it.
|
|
84
|
+
*/
|
|
85
|
+
type TrackedEvent = {
|
|
86
|
+
/** The name the event was tracked with. */name: string; /** The context the event was tracked for, if any. */
|
|
87
|
+
context?: ConfigDirectorContext; /** The value the event was tracked with, when it is a finite number. */
|
|
88
|
+
value?: number; /** The details the event was tracked with, when they are within the limits. */
|
|
89
|
+
details?: TrackedEventDetails;
|
|
90
|
+
};
|
|
43
91
|
/**
|
|
44
92
|
* The context to be sent to ConfigDirector: the user or other entity, such as a device or an
|
|
45
93
|
* organization, that configs are evaluated for. This context will be used for targeting rules
|
|
@@ -256,8 +304,8 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
|
|
|
256
304
|
getValue<T extends ConfigValueType>(configKey: string, defaultValue: T): T;
|
|
257
305
|
/**
|
|
258
306
|
* Evaluates a config as {@link getValue} does and returns the evaluation: the value, the reason it
|
|
259
|
-
* was served
|
|
260
|
-
* telemetry.
|
|
307
|
+
* was served, its value ID and its variation. Like every read, it fires `configEvaluated` and is
|
|
308
|
+
* counted in telemetry.
|
|
261
309
|
*
|
|
262
310
|
* @returns The evaluation, whose `value` is what {@link getValue} returns
|
|
263
311
|
* @param configKey The config key to evaluate
|
|
@@ -289,6 +337,20 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
|
|
|
289
337
|
* Removes all subscribers from all config keys
|
|
290
338
|
*/
|
|
291
339
|
unwatchAll(): void;
|
|
340
|
+
/**
|
|
341
|
+
* Reports to ConfigDirector that something happened for the current context, such as a completed
|
|
342
|
+
* checkout, so it can be counted. The event is sent with the next telemetry batch. `track` never
|
|
343
|
+
* throws, and does nothing in `offline` mode.
|
|
344
|
+
*
|
|
345
|
+
* An event counts for an experiment only when the current context has an `id`, the one the
|
|
346
|
+
* experiment's config was evaluated for. Before the client has a context, or for a context
|
|
347
|
+
* without an `id`, the event is still reported.
|
|
348
|
+
*
|
|
349
|
+
* @param eventName The name of the event, 1 to 150 characters. An event with any other name is
|
|
350
|
+
* not reported and a warning is logged.
|
|
351
|
+
* @param options The event's {@link TrackOptions.value} and {@link TrackOptions.details} (optional)
|
|
352
|
+
*/
|
|
353
|
+
track(eventName: string, options?: TrackOptions): void;
|
|
292
354
|
/**
|
|
293
355
|
* Pauses the network connection without clearing event handlers, watch handlers, or config
|
|
294
356
|
* state. Intended for mobile environments where the OS may kill background connections (e.g.
|
|
@@ -311,5 +373,5 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
|
|
|
311
373
|
dispose(): void;
|
|
312
374
|
}
|
|
313
375
|
//#endregion
|
|
314
|
-
export { OfflineValue as a, NativeValue as c, ConfigDirectorLogger as d, ConfigDirectorLoggingLevel as f, EvaluationReason as g, ConnectionMode as h, ConfigDirectorClient as i, NativeValues as l, ConfigValueType as m, CachingProvider as n, OfflineValues as o, ConfigEvaluation as p, ClientHooks as r, NativeJsonValue as s, CachingOptions as t, ConfigDirectorContext as u };
|
|
315
|
-
//# sourceMappingURL=types-
|
|
376
|
+
export { TrackOptions as _, OfflineValue as a, TrackedEventDetails as b, NativeValue as c, ConfigDirectorLogger as d, ConfigDirectorLoggingLevel as f, EvaluationReason as g, ConnectionMode as h, ConfigDirectorClient as i, NativeValues as l, ConfigValueType as m, CachingProvider as n, OfflineValues as o, ConfigEvaluation as p, ClientHooks as r, NativeJsonValue as s, CachingOptions as t, ConfigDirectorContext as u, TrackedEvent as v, Variation as x, TrackedEventDetailValue as y };
|
|
377
|
+
//# sourceMappingURL=types-DEvHIkvY.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-DEvHIkvY.d.mts","names":[],"sources":["../../js-client-core/src/Emitter.ts","../../shared/src/types.ts","../../shared/src/native-values.ts","../../js-client-core/src/types.ts"],"mappings":";KAAK,SAAA;AAAA,KACA,YAAA,GAAe,MAAA,CAAO,SAAA;AAAA,KAEtB,OAAA,uBAA8B,YAAA,qBAAiC,aAAA,KAClE,OAAA,EAAS,aAAA,CAAc,IAAA;AAAA,UAGR,aAAA,uBAAoC,YAAA;EACnD,EAAA,qBAAuB,aAAA,EAAe,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,OAAA,CAAQ,aAAA,EAAe,KAAA;EACnF,GAAA,qBAAwB,aAAA,EAAe,IAAA,EAAM,KAAA,EAAO,OAAA,GAAU,OAAA,CAAQ,aAAA,EAAe,KAAA;EACrF,KAAA;AAAA;;;KCEU,kBAAA;EAAA,CAAwB,GAAA;AAAA;AAAA,KAExB,eAAA,wCAAuD,kBAAA;AAAA,KAkBvD,0BAAA;AAAA,UAEK,oBAAA;EACf,KAAA,CAAM,OAAA,aAAoB,IAAA;EAE1B,IAAA,CAAK,OAAA,aAAoB,IAAA;EAEzB,IAAA,CAAK,OAAA,aAAoB,IAAA;EAEzB,KAAA,CAAM,OAAA,aAAoB,IAAA;AAAA;;;;;;;;;;;KAiBhB,gBAAA;;;;KAeA,SAAA;EDjEP,gGCmEH,EAAA,UDnE4C;ECqE5C,IAAA;AAAA;;;;KAMU,gBAAA,WAA2B,eAAA,GAAkB,eAAA;ED1EnD,yCC4EJ,GAAA,UD5E6C;EC8E7C,KAAA,EAAO,CAAA,ED9EuD;ECgF9D,OAAA;EDhFqF;;;;ECqFrF,SAAA,GAAY,SAAA;EAEZ,cAAA;EAEA,MAAA,EAAQ,gBAAA,EAtFoB;EAwF5B,OAAA,GAAU,qBAAA;AAAA;;AAtFZ;;;KA6FY,uBAAA,+BAIR,uBAAA;EAAA,CACG,GAAA,WAAc,uBAAA;AAAA;;;;;KAMT,mBAAA;EAAA,CAAyB,GAAA,WAAc,uBAAA;AAAA;;;;KAKvC,YAAA;EAtFV;;;;EA2FA,KAAA,WAzFyB;EA2FzB,OAAA,GAAU,mBAAA;AAAA;;;;KAMA,YAAA;EA9EgB,2CAgF1B,IAAA,UAhF0B;EAkF1B,OAAA,GAAU,qBAAA,EAnEA;EAqEV,KAAA;EAEA,OAAA,GAAU,mBAAA;AAAA;AA7DZ;;;;;AAAA,KAqEY,qBAAA;EA1DE;;;;;;;;;;EAqEZ,EAAA;EA1EA;;;;;;;;;;AAkBF;EAqEE,IAAA;;;;;EAMA,IAAA;EAtE0C;;AAM5C;;EAsEE,MAAA;IAAA,CAAY,GAAA;EAAA;EAjEF;;;;;;;EA0EV,SAAA;AAAA;AAAA,KAYU,cAAA;;;KC9MA,eAAA,sCAAqD,eAAA;EAAA,CAAuB,GAAA,WAAc,eAAA;AAAA;AAAA,KAE1F,WAAA,+BAA0C,eAAA;EAAA,CAAuB,GAAA,WAAc,eAAA;AAAA;AAAA,KAE/E,YAAA,GAAe,MAAA,SAAe,WAAA;;;;;AFA1C;;;KG0CY,eAAA;EHzCa;;;EG6CvB,IAAA,gCAAoC,OAAA;EH7CwB;;;EGiD5D,KAAA,CAAM,KAAA,kBAAuB,OAAA;EHhDwD;;;EGoDrF,MAAA,WAAiB,OAAA;EHtDY;;;;EG2D7B,SAAA;AAAA;;;;;KAOU,cAAA;EHhEV;;;EGoEA,OAAA;EHpEuC;;;;EGyEvC,QAAA,GAAW,eAAA;AAAA;;;;;AFlDb;KEwEY,YAAA,GAAe,WAAA;;;;AFtE3B;KE4EY,aAAA,GAAgB,YAAA;AAAA,KA4GhB,WAAA;EACV,WAAA,GAAc,WAAA,kBAA6B,WAAA;EAC3C,cAAA,GAAiB,WAAA,qBAAgC,WAAA;EACjD,cAAA,GAAiB,WAAA,qBAAgC,WAAA;EACjD,eAAA,GAAkB,WAAA,sBAAiC,WAAA;EACnD,eAAA,GAAkB,WAAA,sBAAiC,WAAA;EACnD,kBAAA,GAAqB,WAAA,yBAAoC,WAAA;AAAA;AAAA,KAG/C,mBAAA;AAAA,KAEA,WAAA,sBAAiC,YAAA,KAAiB,OAAA,EAAS,YAAA,CAAa,MAAA;AAAA,KAExE,YAAA;EACV,cAAA;IAAkB,IAAA;IAAgB,WAAA;EAAA;EAClC,WAAA;IAAe,MAAA,EAAQ,mBAAA;EAAA;EACvB,cAAA;IAAkB,OAAA,EAAS,qBAAA;EAAA;EAC3B,eAAA;IAAmB,UAAA,EAAY,gBAAA;EAAA;EAC/B,eAAA;IAAmB,KAAA,EAAO,KAAA;EAAA;EAC1B,kBAAA,EAAoB,MAAA;AAAA;AAAA,KAGV,YAAA,WAAuB,eAAA,KAAoB,OAAA,EAAS,CAAA;AA/LhE;;;;;;;;;AAAA,UA0MiB,oBAAA,SAA6B,aAAA,CAAc,YAAA;EAlM1D;;;;;;;;AAgBF;;;;;;;;EAmME,UAAA,CAAW,OAAA,GAAU,qBAAA,GAAwB,OAAA;EApKnC;;;;;AAMZ;;;;EAyKE,aAAA,CAAc,OAAA,EAAS,qBAAA,GAAwB,OAAA;EA7DrC;;;;;;;;;EAAA,IAwEN,OAAA,IAAW,qBAAA;EApEoC;;;;;;EAAA,IA4E/C,OAAA;EA/EJ;;;;;;;EAAA,IAwFI,cAAA;EAtF6C;;;;;;;;;EAiGjD,QAAA,WAAmB,eAAA,EAAiB,SAAA,UAAmB,YAAA,EAAc,CAAA,GAAI,CAAA;EA9FL;;AAGtE;;;;;AAEA;;EAoGE,QAAA,WAAmB,eAAA,EAAiB,SAAA,UAAmB,YAAA,EAAc,CAAA,GAAI,gBAAA,CAAiB,CAAA;EApG/C;;;;;;;;;;;EAiH3C,KAAA,WAAgB,eAAA,EAAiB,SAAA,UAAmB,YAAA,EAAc,CAAA,EAAG,QAAA,EAAU,YAAA,CAAa,CAAA;EA/GlF;;;;;;;;EAyHV,OAAA,WAAkB,eAAA,EAAiB,SAAA,UAAmB,QAAA,GAAW,YAAA,CAAa,CAAA;EAnHpD;;;EAwH1B,UAAA;EA5HA;;;;;;;;;;;;;EA2IA,KAAA,CAAM,SAAA,UAAmB,OAAA,GAAU,YAAA;EAvIT;;AAG5B;;;;;EA6IE,YAAA;EA7I8D;;;;EAmJ9D,aAAA,IAAiB,OAAA;EAxImB;;;;;;EAgJpC,OAAA;AAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@configdirector/react-web-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "React web client SDK for ConfigDirector. ConfigDirector is a remote configuration and feature flag service.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ConfigDirector",
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
var e=class{constructor(){this.handlerMap=new Map}on(e,t){let n=this.handlerMap.get(e);n?n.push(t):this.handlerMap.set(e,[t])}once(e,t){let n=this;function r(i){n.off(e,r),t.apply(n,i)}this.on(e,r)}off(e,t){let n=this.handlerMap.get(e);if(n)if(t){let e=n.indexOf(t);e>=0&&n.splice(e,1)}else this.handlerMap.set(e,[])}clear(){this.handlerMap.clear()}emit(e,t){let n=this.handlerMap.get(e);n&&n.slice().map(e=>e(t))}},t=class e extends Error{constructor(t,n){super(t),this.name=`ConfigDirectorConnectionError`,this.status=n,Object.setPrototypeOf(this,e.prototype)}},n=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorValidationError`,Object.setPrototypeOf(this,e.prototype)}},r=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorInitializationError`,Object.setPrototypeOf(this,e.prototype)}},i=class e extends Error{constructor(t){super(t),this.name=`StreamClosedError`,Object.setPrototypeOf(this,e.prototype)}},a=class e extends Error{constructor(t){super(t),this.name=`MissingResponseBodyError`,Object.setPrototypeOf(this,e.prototype)}},o=class e extends Error{constructor(t){super(t),this.name=`InvalidOptionError`,Object.setPrototypeOf(this,e.prototype)}},s=class e extends Error{constructor(t){super(t),this.name=`ValueOutOfRangeError`,Object.setPrototypeOf(this,e.prototype)}},c=class{constructor(e){this.isFirstChunk=!0,this.bufferedInput=``,this.currentEvent={data:``},this.currentEvent={data:``},this.onEvent=e.onEvent??(()=>{}),this.onRetry=e.onRetry,this.onComment=e.onComment}parse(e){let t=e;this.isFirstChunk&&(this.isFirstChunk=!1,t.startsWith(``)?t=t.slice(1):t.startsWith(``)&&(t=t.slice(3)));let n=this.scanLines(this.bufferedInput+t);for(let e of n)this.dispatchLine(e)}finish(){this.bufferedInput=``}scanLines(e){let t=[],n=0,r=0;for(;r<e.length;){let i=e[r];i===`\r`||i===`
|
|
2
|
-
`?(t.push(e.slice(n,r)),i===`\r`&&e[r+1]===`
|
|
3
|
-
`&&r++,r++,n=r):r++}return this.bufferedInput=e.slice(n),t}dispatchLine(e){if(e.startsWith(`:`)){this.onComment?.(this.extractValue(e,1));return}if(e===``){this.emitEvent();return}this.applyField(this.parseField(e))}emitEvent(){let e=this.currentEvent.data.endsWith(`
|
|
4
|
-
`)?this.currentEvent.data.slice(0,-1):this.currentEvent.data;e!==``&&this.onEvent({...this.currentEvent,id:this.lastEventId,data:e}),this.currentEvent={data:``}}applyField(e){switch(e.field){case`event`:this.currentEvent.type=e.value;break;case`data`:this.currentEvent.data+=e.value+`
|
|
5
|
-
`;break;case`id`:e.value.includes(`\0`)||(this.lastEventId=e.value);break;case`retry`:/^\d+$/.test(e.value)&&this.onRetry?.(Number.parseInt(e.value,10));break;default:break}}parseField(e){let t=e.indexOf(`:`);return t===-1?{field:e,value:``}:{field:e.slice(0,t),value:this.extractValue(e,t+1)}}extractValue(e,t){return e[t]===` `?e.slice(t+1):e.slice(t)}};let l=function(e){return e.OPEN=`open`,e.CLOSED=`closed`,e.CONNECTING=`connecting`,e}({});var u=class{constructor(e){this.DEFAULT_SHOULD_RECONNECT=()=>!0,this.DEFAULT_CALCULATE_RECONNECT_DELAY=()=>this.serverReconnectionTime,this.reconnectAttempt=0,this.abortController=new AbortController,this._readyState=l.CLOSED,this.serverReconnectionTime=2e3,this.url=e.url.toString(),this.lastEventId=e.lastEventId,this.headers={Accept:`text/event-stream`,...e.headers};let t=e.body;this.body=typeof t==`function`?t:()=>t,this.requestOptions={method:e.method??`GET`,mode:e.mode,credentials:e.credentials,redirect:e.redirect,referrer:e.referrer,referrerPolicy:e.referrerPolicy},this._fetch=e.fetch??((e,t)=>fetch(e,t)),this._onError=this.resolveCallback(e.onError,()=>{},`onError`),this._onConnect=this.resolveCallback(e.onConnect,()=>{},`onConnect`),this._onDisconnect=this.resolveCallback(e.onDisconnect,()=>{},`onDisconnect`),this._onMessage=this.resolveCallback(e.onMessage,()=>{},`onMessage`),this._onComment=this.resolveCallback(e.onComment,()=>{},`onComment`),this._shouldReconnect=this.resolveCallback(e.shouldReconnect,this.DEFAULT_SHOULD_RECONNECT,`shouldReconnect`),this._calculateReconnectDelay=this.resolveCallback(e.calculateReconnectDelay,this.DEFAULT_CALCULATE_RECONNECT_DELAY,`calculateReconnectDelay`)}set onError(e){this._onError=this.resolveCallback(e,()=>{},`onError`)}set onMessage(e){this._onMessage=this.resolveCallback(e,()=>{},`onMessage`)}set onComment(e){this._onComment=this.resolveCallback(e,()=>{},`onComment`)}set onConnect(e){this._onConnect=this.resolveCallback(e,()=>{},`onConnect`)}set onDisconnect(e){this._onDisconnect=this.resolveCallback(e,()=>{},`onDisconnect`)}set shouldReconnect(e){this._shouldReconnect=this.resolveCallback(e,this.DEFAULT_SHOULD_RECONNECT,`shouldReconnect`)}set calculateReconnectDelay(e){this._calculateReconnectDelay=this.resolveCallback(e,this.DEFAULT_CALCULATE_RECONNECT_DELAY,`shouldReconnect`)}get readyState(){return this._readyState}connect(){this._readyState===l.CLOSED&&(this.reconnectAttempt=0,this.initiateConnection())}close(){clearTimeout(this.reconnectTimeout),this._readyState=l.CLOSED,this.abortController.abort()}initiateConnection(){this.abortController=new AbortController,this._readyState=l.CONNECTING,this._fetch(this.url,{...this.requestOptions,body:this.body(),headers:this.buildRequestHeaders(),signal:this.abortController.signal,cache:`no-store`}).then(e=>this.handleFetchResponse(e)).catch(e=>{if(e.name===`AbortError`||this.abortController.signal.aborted){this.close();return}this._onError(e),this.scheduleReconnect({error:e})})}async handleFetchResponse(e){let{body:t,status:n}=e;if(n===204){this.disconnected();return}if(n>=400){this.scheduleReconnect({status:n});return}if(!t)throw new a(`The server response did not have a body`);this._readyState=l.OPEN,this._onConnect(),this.reconnectAttempt=0;let r=new c({onEvent:e=>{typeof e.id==`string`&&(this.lastEventId=e.id),this._onMessage(e)},onComment:e=>this._onComment(e),onRetry:e=>this.serverReconnectionTime=e});await this.readResponseStream(t,r),this.scheduleReconnect({status:n,error:new i(`The server response stream was closed`)})}async readResponseStream(e,t){let n=e.getReader(),r=new TextDecoder,i=!1;for(;!i;){let e=await n.read();e.value&&t.parse(r.decode(e.value,{stream:!0})),i=e.done}t.finish()}disconnected(){clearTimeout(this.reconnectTimeout),this._readyState=l.CLOSED,this._onDisconnect()}buildRequestHeaders(){let e=this.lastEventId?{"Last-Event-ID":this.lastEventId}:void 0;return{...this.headers,...e}}scheduleReconnect(e){if(this.abortController.signal.aborted)return;clearTimeout(this.reconnectTimeout),this.reconnectAttempt+=1;let t={attempt:this.reconnectAttempt,status:e.status,error:e.error,serverReconnectionTime:this.serverReconnectionTime};if(!this._shouldReconnect(t)){this.disconnected();return}this._readyState=l.CONNECTING;let n=this._calculateReconnectDelay(t);(!Number.isFinite(n)||n<1||n>1e3*60*60)&&(this._onError(new s(`The calculated reconnect delay is out of range: ${n}. Defaulting to ${this.serverReconnectionTime}`)),n=this.serverReconnectionTime),this.reconnectTimeout=setTimeout(()=>this.initiateConnection(),n)}resolveCallback(e,t,n){if(e==null)return t;if(typeof e!=`function`)throw new o(`${n} must be a function`);return e}};const d=e=>new u(e);var ee=class{constructor(t){this.options=t,this.eventEmitter=new e,this.connectionGeneration=0,this.options=t,this.logger=t.logger,this.url=t.resolveUrl(`client/sse/v1`,t.baseUrl)}async connect(e,t){let n=++this.connectionGeneration,r=await this.options.clientSession;if(n!==this.connectionGeneration)return this;this.eventSource&&this.close();let i=new Promise((t,n)=>{this.eventSource=d({url:this.url,method:`POST`,headers:{"Content-Type":`application/json`},fetch:this.options.fetch,body:JSON.stringify({givenContext:e,metaContext:this.options.metaContext,clientSdkKey:this.options.clientSdkKey,instanceId:r.instanceId,ephemeral:r.ephemeral}),onMessage:({data:e})=>{this.dispatchMessage(e)},onConnect:()=>{this.logger.debug(`[StreamingTransport] Connected`),t(this)},shouldReconnect:e=>{let t=!this.isStatusFatal(e.status);if(!t){let t=this.prepareFatalError(e.status,e.error);this.eventEmitter.emit(`connectionError`,t),n(t)}return t},calculateReconnectDelay:e=>{let t=this.options.connectionRetryDelay(e.attempt),n=`[StreamingTransport] Scheduling reconnect attempt #${e.attempt} in ${t}ms.`;return e.attempt<=5?this.logger.info(n):this.logger.warn(n),t},onError:e=>{this.logger.debug(`[StreamingTransport] Error: `,e)},onDisconnect:()=>{this.logger.debug(`[StreamingTransport] Disconnected`)}}),this.eventSource.connect()});return clearTimeout(this.timeoutTimer),this.timeoutTimer=void 0,Promise.race([i,new Promise(e=>{this.timeoutTimer=setTimeout(()=>e(this),t)})]).finally(()=>clearTimeout(this.timeoutTimer))}dispatchMessage(e){try{let t=JSON.parse(e);this.eventEmitter.emit(`configSetReceived`,t)}catch(e){this.logger.error(`[StreamingTransport] Error parsing and dispatching config data update: `,e)}}prepareFatalError(e,n){let r=e??0;return new t(`${`Connection failed with status: ${e??`unknown`}.`}${n?` Error: ${n}`:``}. This is an unrecoverable error, will not attempt to reconnect.`,r)}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.eventEmitter.clear()}close(){this.connectionGeneration++,this.eventSource?.close(),clearTimeout(this.timeoutTimer)}dispose(){this.close(),this.clear()}};const f=(e,t)=>{if(e.trim().length==0)throw new n(`Invalid config key. The key of a value cannot be empty.`);return p(e,t)},p=(e,t)=>{switch(typeof t){case`boolean`:return{type:`boolean`,value:t?`true`:`false`};case`number`:return m(e,t);case`string`:return{type:`string`,value:t};case`object`:if(t!==null)return g(e,t,``),{type:`json`,value:JSON.stringify(t)}}throw new n(`Invalid value for '${e}': ${y(t)}. Use a boolean, a number, a string, a plain object, or an array.`)},m=(e,t)=>{if(!Number.isFinite(t))throw new n(`Invalid value for '${e}': ${y(t)} is not a finite number.`);if(Number.isInteger(t)){if(!Number.isSafeInteger(t))throw new n(`Invalid value for '${e}': ${t} is not a safe integer, so the SDK could not read it back exactly.`);return{type:`integer`,value:String(t)}}return{type:`float`,value:h(t)}},h=e=>{let t=String(e),n=t.indexOf(`e-`);if(n<0)return t;let r=t.startsWith(`-`)?`-`:``,[i=``,a=``]=t.slice(r.length,n).split(`.`),o=Number(t.slice(n+2))-i.length;return`${r}0.${`0`.repeat(o)}${i}${a}`},g=(e,t,n)=>{if(!(t===null||typeof t==`boolean`||typeof t==`string`)){if(typeof t==`number`){if(!Number.isFinite(t))throw _(e,n,`${y(t)} is not a finite number`);return}if(Array.isArray(t)){t.forEach((t,r)=>g(e,t,`${n}[${r}]`));return}if(v(t)){for(let[r,i]of Object.entries(t))g(e,i,n?`${n}.${r}`:r);return}throw _(e,n,`${y(t)} cannot be encoded as JSON`)}},_=(e,t,r)=>new n(`Invalid value for '${e}'${t?` at '${t}'`:``}: ${r}. JSON contents can hold booleans, finite numbers, strings, null, arrays, and plain objects.`),v=e=>{if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},y=e=>e===null?`null`:typeof e==`function`?`a function`:typeof e==`object`?`a ${e.constructor?.name??`object`} instance`:typeof e==`symbol`?`a symbol`:String(e),b=(e,t,n,r)=>{let i=f(t,n);return{id:e,key:t,type:i.type,value:i.value,valueId:r}},x={environmentId:`offline`,projectId:`offline`};var te=class{constructor(t){this.source=t,this.emitter=new e,this.on=(e,t)=>this.emitter.on(e,t),this.off=(e,t)=>this.emitter.off(e,t)}async connect(){let e=ne(this.source);return this.emitter.emit(`configSetReceived`,{...x,kind:`full`,configs:e}),this}clear(){this.emitter.clear()}close(){}dispose(){this.clear()}};const ne=e=>{switch(e.kind){case`in-code-defaults`:return{};case`values`:return re(e.values);case`rejected`:throw new r(e.message)}},re=e=>{try{return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,b(`offline:${e}`,e,t,void 0)]))}catch(e){throw e instanceof n?new r(`The offline values could not be loaded. ${e.message}`):e}},ie=(e,t,r)=>{if(t?.mode===`offline`)return{kind:`stay-offline`,source:oe(t)};let i=t?.mode??`streaming`;if(!e||e.trim().length==0)throw new n(`No client SDK key was provided, the client cannot be instantiated without a valid client SDK key`);return t?.values===void 0?{kind:`connect`,mode:i,clientSdkKey:e,baseUrl:ae(t?.url,r)}:{kind:`stay-offline`,source:{kind:`rejected`,message:`The connection option 'values' applies only when the connection mode is 'offline', but the mode is '${i}'.`}}},ae=(e,t)=>{if(!e)return`https://client-sdk-api.configdirector.com`;try{return t(e)}catch(t){throw new n(`Invalid base URL '${e}'. Parsing failed: ${t}`)}},oe=e=>e.values===void 0?{kind:`in-code-defaults`}:{kind:`values`,values:e.values},S=e=>{let t=typeof e;if(t===`object`)try{return e.constructor?.name??t}catch{return t}else if(t===`function`)try{let n=e.name;return n?`function: ${n}`:t}catch{return t}return t},C=e=>e===`number`||e===`bigint`,w=new Set([`boolean`,`integer`,`float`]),T=(e,t)=>{let n=e.value,r=S(t);if(n==null||n===``)return{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`value-missing`};if(e.type===`json`)return j(n,t,r,e.valueId);if(typeof t==`string`)return w.has(e.type)?{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`type-mismatch`}:{parsedValue:n,parsedValueId:e.valueId,requestedType:r,usedDefault:!1,reason:`found-match`};if(typeof t==`boolean`&&(e.type===`boolean`||e.type===`string`||e.type===`enum`)){let i=E(n),a=typeof i==`boolean`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-boolean`}}if(C(typeof t)&&e.type===`integer`){let i=D(n),a=typeof i==`number`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-number`}}if(C(typeof t)&&(e.type===`float`||e.type===`enum`||e.type===`string`)){let i=O(n),a=typeof i==`number`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-number`}}return{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`type-mismatch`}},E=e=>{if(!e)return;let t=e.toLowerCase();if(!(t!=`true`&&t!=`false`))return t===`true`},D=e=>{let t=k(e);return t==null?void 0:Math.trunc(t)},O=e=>k(e),k=e=>{if(!e||!A(e))return;let t=Number(e);if(!(isNaN(t)||!isFinite(t)))return t},A=e=>{for(let t of e)if(!(t>=`0`&&t<=`9`)&&!`+-.eE`.includes(t))return!1;return!0},j=(e,t,n,r)=>{if(typeof t==`string`)return{parsedValue:e,parsedValueId:r,requestedType:n,usedDefault:!1,reason:`found-match`};try{let i=JSON.parse(e);return M(i,t)?{parsedValue:i,parsedValueId:r,requestedType:n,usedDefault:!1,reason:`found-match`}:{parsedValue:t,parsedValueId:void 0,requestedType:n,usedDefault:!0,reason:`type-mismatch`}}catch{return{parsedValue:t,parsedValueId:void 0,requestedType:n,usedDefault:!0,reason:`invalid-json`}}},M=(e,t)=>e===null?!1:N(e)===N(t),N=e=>{if(Array.isArray(e))return`array`;let t=typeof e;return t===`bigint`?`number`:t},P={off:-1,error:0,warn:1,info:2,debug:3},F=()=>{let e={year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,timeZoneName:`short`};try{return new Intl.DateTimeFormat(void 0,{...e,fractionalSecondDigits:3})}catch{return new Intl.DateTimeFormat(void 0,e)}};var I=class{constructor(e,t){this.level=e,this.decorator=t,this.level=e,this.decorator=t,this.dateFormatter=F()}debug(e,...t){this.log(console.debug,`debug`,e,...t)}info(e,...t){this.log(console.info,`info`,e,...t)}warn(e,...t){this.log(console.warn,`warn`,e,...t)}error(e,...t){this.log(console.error,`error`,e,...t)}log(e,t,n,...r){P[this.level]>=P[t]&&e(`[${this.dateFormatter.format(new Date)}] ${this.decorator?.decorateMessage(n)}`,...r)}},L=class{decorateMessage(e){return`[ConfigDirector:js-client-sdk] ${e}`}};const R=(e,t)=>new I(e??`warn`,t??new L),z={updateContext:async()=>{},evaluatedConfig:()=>{},recordInvalidContext:()=>{},close:async()=>{}},B=(e,t)=>new URL(e,t?.toString()),V=(e,t)=>e===void 0?{seconds:t.defaultSeconds,warning:void 0}:e>=t.minimumSeconds?{seconds:e,warning:void 0}:{seconds:t.minimumSeconds,warning:`pollingInterval of ${e} seconds is below the minimum of ${t.minimumSeconds} seconds. Using ${t.minimumSeconds} seconds.`},H=()=>typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)}),U=e=>{try{return e(globalThis)}catch{return}},W=()=>U(e=>e.navigator?.userAgent),G=()=>U(e=>e.location?.host),K=()=>{try{return globalThis.localStorage??void 0}catch{return}},q=`configdirector-sdk:instance-id`,J=1e3,se=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,Y=(e,t)=>{let n=t;for(let t=0;t<e.length;t++)n^=e.charCodeAt(t),n=Math.imul(n,16777619);return n>>>0},X=(e,t)=>{let n=`configdirector.instanceId.v1|${e}|${t}`,r=Y(n,2166136261);return Y(`${r}|${n}`,16777619).toString(16).padStart(8,`0`)+r.toString(16).padStart(8,`0`)},ce=e=>{if(!e||typeof e!=`object`)return!1;let{v:t,id:n,createdAt:r,checksum:i}=e;return t!==1||typeof n!=`string`||typeof i!=`string`||typeof r!=`number`||!Number.isInteger(r)||r<=0||!se.test(n)?!1:i===X(n,r)},le=async(e,t)=>{let n;try{n=await e.getItem(q)}catch(e){return t.debug(`[ConfigDirectorClient] Could not read the stored instance id, using an ephemeral one`,e),{outcome:`failed`}}if(typeof n!=`string`||n===``)return{outcome:`nothing usable`};let r;try{r=JSON.parse(n)}catch{return t.debug(`[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one`),{outcome:`nothing usable`}}return ce(r)?{outcome:`stored`,instanceId:r.id}:(t.debug(`[ConfigDirectorClient] The stored instance id failed validation, generating a new one`),{outcome:`nothing usable`})},ue=async(e,t,n)=>{let r=Date.now(),i={v:1,id:t,createdAt:r,checksum:X(t,r)};try{return await e.setItem(q,JSON.stringify(i)),!0}catch(e){return n.debug(`[ConfigDirectorClient] Could not persist the instance id, using it as an ephemeral one`,e),!1}},de=async(e,t,n,r)=>{let i=await le(e,r);switch(i.outcome){case`stored`:return{instanceId:i.instanceId};case`failed`:return{instanceId:t,ephemeral:!0};case`nothing usable`:break}return n.passed?{instanceId:t,ephemeral:!0}:await ue(e,t,r)?{instanceId:t}:{instanceId:t,ephemeral:!0}},fe=(e,t=K())=>{let n=H();if(!t)return e.debug(`[ConfigDirectorClient] No instance id storage is available, using an ephemeral instance id`),Promise.resolve({instanceId:n,ephemeral:!0});let r={passed:!1},i,a=new Promise(t=>{i=setTimeout(()=>{r.passed=!0,e.warn(`[ConfigDirectorClient] The instance id storage did not respond within ${J}ms, using an ephemeral instance id`),t({instanceId:n,ephemeral:!0})},J)});return Promise.race([de(t,n,r,e),a]).finally(()=>clearTimeout(i))};var pe=class{constructor(){this.fatalError=!1}clearPollingInterval(){clearInterval(this.pollingInterval)}schedulePollingInterval(e){clearInterval(this.pollingInterval),!(this.pollingIntervalSeconds<=0)&&(this.pollingInterval=setInterval(e,this.pollingIntervalSeconds*1e3))}async handleNonOkResponse(e){if(!e.ok)throw this.isStatusFatal(e.status)?(this.fatalError=!0,this.close(),this.prepareFatalResponseStatusError(e.status,await e.text())):new t(`Connection failed with status: ${e.status}`,e.status)}handleFetchError(e){throw this.isFetchErrorFatal(e)?(this.fatalError=!0,this.close(),new t(`Connection failed with fatal error: ${e}. This is an unrecoverable error, retry attempts will be ignored.`)):e instanceof SyntaxError?new t(`Failed to parse the response from the server: ${e}`):new t(`Connection failed with error: ${e}.`)}prepareFatalResponseStatusError(e,n){let r=e??0;return new t(`${`Connection failed with status: ${e??`unknown`}`}${(n?.trim()?.length??0)>0?` (${n})`:``}. This is an unrecoverable error, retry attempts will be ignored.`,r)}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}isFetchErrorFatal(e){return e?.name===`NotAllowedError`}get isConnected(){return this.pollingInterval!==void 0}close(){clearInterval(this.pollingInterval),this.pollingInterval=void 0}dispose(){this.close(),this.clear()}};const me=async(e,t,n,r)=>{let i=new AbortController,a=setTimeout(()=>{r.debug(`[fetchWithTimeout] Reached timeout, aborting request`),i.abort()},e);try{let e=await fetch(typeof t==`string`||t instanceof Request?t:t.toString(),{...n,signal:i.signal});return clearTimeout(a),e}catch(e){throw r.warn(`[fetchWithTimeout] Fetch error: `,e),clearTimeout(a),e}};var he=class extends pe{constructor(t){super(),this.options=t,this.eventEmitter=new e,this.connectionGeneration=0,this.options=t,this.logger=t.logger,this.url=t.resolveUrl(`client/polling/v1`,t.baseUrl),this.pollingIntervalSeconds=t.pollingInterval??60}async connect(e,t){let n=++this.connectionGeneration;this.clearPollingInterval();let r=await this.options.clientSession;if(n!==this.connectionGeneration)return this;try{await this.fetchConfigs(e,t,r)}finally{this.fatalError||this.schedulePollingInterval(()=>{this.fetchConfigs(e,t,r).catch(e=>{this.logger.error(`[PollingTransport] Error during polling:`,e)})})}return this}close(){this.connectionGeneration++,super.close()}async fetchConfigs(e,t,n){if(this.fatalError){this.logger.warn(`[PollingTransport] There was a prior unrecoverable error. Ignoring attempt to reconnect.`);return}try{let r=await me(t,this.url,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({givenContext:e,metaContext:this.options.metaContext,clientSdkKey:this.options.clientSdkKey,instanceId:n.instanceId,ephemeral:n.ephemeral,lastUpdateTimestamp:this.lastUpdateTimestamp})},this.logger);if(await this.handleNonOkResponse(r),r.status==200){let e=JSON.parse(await r.text());this.lastUpdateTimestamp=e.timestamp,this.eventEmitter.emit(`configSetReceived`,e)}}catch(e){try{this.handleFetchError(e)}catch(e){throw this.fatalError&&this.eventEmitter.emit(`connectionError`,e),e}}}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.eventEmitter.clear()}};const ge=e=>e>=`a`&&e<=`z`||e>=`0`&&e<=`9`||e===`-`||e===`_`,_e=e=>{if(e.length<1||e.length>64)return!1;for(let t of e)if(!ge(t))return!1;return!0},ve=e=>e==null||typeof e==`string`&&_e(e),ye=e=>{if(typeof e==`string`)return e;try{return String(e)}catch{return Object.prototype.toString.call(e)}},be=(e,t)=>{let n=``,r=0;for(let i of e){if(r===t)break;n+=i,r+=1}return n},xe=e=>{let t=e?.kind;return ve(t)?{outcome:`admitted`,context:e}:{outcome:`ignored`,kindSample:be(ye(t),128)}},Se=e=>e>=55296&&e<=56319,Ce=e=>e>=56320&&e<=57343,we=e=>{let t=0;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);r<=127?t+=1:r<=2047?t+=2:Se(r)&&n+1<e.length&&Ce(e.charCodeAt(n+1))?(t+=4,n++):t+=3}return t},Te=(e,t,n,r)=>{if(e.kind===`stay-offline`)return{kind:`no cache`,reason:`offline mode`};if(t?.enabled===!1)return{kind:`no cache`,reason:`turned off`};if(!n)return{kind:`no cache`,reason:`no SHA-256 available`};let i=n(e.clientSdkKey),a=t?.provider??r?.(i);return a?{kind:`cache`,provider:a,clientSdkKeyDigest:i}:{kind:`no cache`,reason:`no provider available`}},Z=(e,t)=>{let n=e?.kind??`user`;return e?.id==null?{contextKind:n,anonymousInstanceId:t}:{contextKind:n,contextId:e.id}},Ee=(e,t)=>e.contextKind===t.contextKind?`contextId`in e&&`contextId`in t?e.contextId===t.contextId:`anonymousInstanceId`in e&&`anonymousInstanceId`in t?e.anonymousInstanceId===t.anonymousInstanceId:!1:!1,De=(e,t,n)=>n?`live values already arrived`:Ee(e.contextTag,t)?`adopt`:`context mismatch`,Oe=e=>{if(!e||typeof e!=`object`)return!1;let{contextKind:t,contextId:n,anonymousInstanceId:r}=e;return typeof t==`string`?typeof n==`string`||typeof r==`string`:!1},ke=e=>!e||typeof e!=`object`||Array.isArray(e)?!1:Object.values(e).every(e=>e&&typeof e==`object`&&typeof e.id==`string`&&typeof e.key==`string`),Ae=(e,t)=>{if(!t||typeof t!=`object`)return!1;let n=t;return n.formatVersion===2&&n.clientSdkKeyDigest===e&&Oe(n.contextTag)&&typeof n.environmentId==`string`&&typeof n.projectId==`string`&&ke(n.configs)&&typeof n.receivedAt==`number`},je=e=>!!e&&typeof e==`object`&&e.formatVersion===1,Q=(e,t)=>{let n;try{n=JSON.parse(e)}catch{return{outcome:`unreadable`}}return Ae(t,n)?{outcome:`stored`,cachedValues:n}:je(n)?{outcome:`first format`}:{outcome:`unreadable`}};var Me=class{constructor(e,t,n){this.provider=e,this.clientSdkKeyDigest=t,this.logger=n,this.warned=new Set,this.writing=!1}read(){return this.pendingRead??=this.readEntry(),this.pendingRead}replace(e){this.queuedCachedValues=e,this.writeQueued()}async readEntry(){let e;try{e=await this.provider.read()}catch(e){return this.warnOnce(`read failed`,`Could not read the values kept on the device, starting without them:`,e),{outcome:`failed`}}if(e==null||e===``)return{outcome:`nothing stored`};let t=Q(e,await this.clientSdkKeyDigest);switch(t.outcome){case`stored`:return t;case`first format`:return await this.removeEntry(),t;case`unreadable`:return this.warnOnce(`unreadable`,`The values kept on the device could not be read and were removed, starting without them`),await this.removeEntry(),t}}async writeQueued(){if(!this.writing){this.writing=!0;try{for(;this.queuedCachedValues;){let e=this.queuedCachedValues;this.queuedCachedValues=void 0,await this.writeEntry(e)}}finally{this.writing=!1}}}async writeEntry(e){let t={formatVersion:2,clientSdkKeyDigest:await this.clientSdkKeyDigest,...e},n=JSON.stringify(t),r=we(n),i=this.provider.sizeLimit();if(r>i){this.warnOnce(`over the size limit`,`The values received (${r} bytes) exceed the caching provider's limit of ${i} bytes, so no values are kept on the device`),await this.removeEntry();return}try{await this.provider.write(n)}catch(e){this.warnOnce(`write failed`,`Could not keep the values on the device:`,e)}}async removeEntry(){try{await this.provider.remove()}catch(e){this.warnOnce(`remove failed`,`Could not remove the values kept on the device:`,e)}}warnOnce(e,t,...n){this.warned.has(e)||(this.warned.add(e),this.logger.warn(`[ConfigDirectorClient] ${t}`,...n))}},Ne=class t{static from(e,n,r,i,a){return typeof n==`object`?new t(e,void 0,r,n,a):new t(e,n,r,i,a)}constructor(t,n,r,i,a){this.handlersMap=new Map,this.eventEmitter=new e,this.ready=!1,this.initializing=!1,this.hasReceivedConfigSet=!1,this.servingCachedValues=!1,this.cachedValuesAdoptionStarted=!1,this.logger=i?.logger??R(),this.clientSession=fe(this.logger,a?.instanceIdStorage),this.timeout=i?.connection?.timeout??3e3;let o=a?.urlFactory??B;this.connectionPlan=ie(n,i?.connection,o),this.cachedValuesStore=this.buildCachedValuesStore(Te(this.connectionPlan,i?.caching,a?.sha256HexDigest,a?.platformCachingProvider)),this.telemetryClient=this.buildTelemetryClient(t,i),this.transport=a?.transport??this.buildTransport(r,i,o,a),this.transport.on(`configSetReceived`,e=>{this.hasReceivedConfigSet=!0,this.servingCachedValues=!1,this.readyResolve?.();let t=this.findKeysRemovedBy(e);!this.configSet||e.kind==`full`?this.configSet=e:this.configSet.configs={...this.configSet.configs,...e.configs},this.keepValuesOnTheDevice(this.configSet);let n=Object.keys(e.configs);this.emit(`configsUpdated`,{keys:n,removedKeys:t}),this.updateWatchers([...n,...t]),this.logger.debug(`[ConfigDirectorClient] ConfigSet updated from server:`,{keys:n,removedKeys:t})}),this.transport.on(`connectionError`,e=>{this.initializing=!1,this.logger.error(`[ConfigDirectorClient] The connection encountered an unrecoverable error and will not be retried. Configs will no longer receive updates.`,e),this.emit(`connectionError`,{error:e})}),this.registerHandler(`clientReady`,i?.hooks?.clientReady),this.registerHandler(`configEvaluated`,i?.hooks?.configEvaluated),this.registerHandler(`configsUpdated`,i?.hooks?.configsUpdated),this.registerHandler(`contextUpdated`,i?.hooks?.contextUpdated),this.registerHandler(`connectionError`,i?.hooks?.connectionError),this.registerHandler(`cachedValuesLoaded`,i?.hooks?.cachedValuesLoaded)}buildCachedValuesStore(e){switch(e.kind){case`no cache`:this.logger.debug(`[ConfigDirectorClient] No values are kept on the device: ${e.reason}`);return;case`cache`:{let t=new Me(e.provider,e.clientSdkKeyDigest,this.logger);return t.read(),t}}}startCachedValuesAdoption(){let e=this.cachedValuesStore;!e||this.cachedValuesAdoptionStarted||(this.cachedValuesAdoptionStarted=!0,this.adoptCachedValues(e))}async adoptCachedValues(e){let t=await e.read();switch(t.outcome){case`nothing stored`:case`first format`:case`unreadable`:case`failed`:return;case`stored`:break}let{instanceId:n}=await this.clientSession,r=Z(this.submittedContext,n),i=De(t.cachedValues,r,this.hasReceivedConfigSet);switch(i){case`adopt`:this.serveCachedValues(t.cachedValues);return;case`live values already arrived`:case`context mismatch`:this.logger.debug(`[ConfigDirectorClient] The values kept on the device were not adopted: ${i}`);return}}serveCachedValues(e){let{environmentId:t,projectId:n,configs:r}=e;this.configSet={environmentId:t,projectId:n,configs:r,kind:`full`},this.servingCachedValues=!0;let i=Object.keys(r);this.emit(`cachedValuesLoaded`,{}),this.emit(`configsUpdated`,{keys:i,removedKeys:[]}),this.updateWatchers(i),this.logger.debug(`[ConfigDirectorClient] Serving the values kept on the device until live values arrive:`,{keys:i})}keepValuesOnTheDevice(e){let t=this.cachedValuesStore;if(!t)return;let n=this.submittedContext,r=Date.now();this.clientSession.then(({instanceId:i})=>t.replace({contextTag:Z(n,i),environmentId:e.environmentId,projectId:e.projectId,configs:e.configs,receivedAt:r}))}servedReason(e){return this.servingCachedValues&&e===`found-match`?`cached`:e}registerHandler(e,t){if(!t)return;let n=Array.isArray(t)?t:[t];for(let t of n)typeof t==`function`&&this.on(e,t)}pollingIntervalFor(e,t){if(e!==`polling`)return;let n=V(t,{defaultSeconds:60,minimumSeconds:30});return n.warning&&this.logger.warn(`[ConfigDirectorClient] ${n.warning}`),n.seconds}buildTelemetryClient(e,t){let n=this.connectionPlan;switch(n.kind){case`stay-offline`:return z;case`connect`:return e({clientSdkKey:n.clientSdkKey,baseUrl:n.baseUrl,logger:this.logger,metadata:t?.metadata,clientSession:this.clientSession})}}buildTransport(e,t,n,r){let i=this.connectionPlan;switch(i.kind){case`stay-offline`:return new te(i.source);case`connect`:return new(this.getTransportConstructor(i.mode))({clientSession:this.clientSession,clientSdkKey:i.clientSdkKey,baseUrl:i.baseUrl,resolveUrl:n,metaContext:{...t?.metadata,sdkName:e.sdkName,sdkVersion:e.sdkVersion,userAgent:W(),host:G()},logger:this.logger,fetch:r?.fetch,connectionRetryDelay:r?.connectionRetryDelay??(e=>2**Math.min(e,9)*1e3),pollingInterval:this.pollingIntervalFor(i.mode,t?.connection?.pollingInterval)})}}getTransportConstructor(e){switch(e){case`polling`:return he;case`streaming`:return ee}}async initialize(e){this.hasReceivedConfigSet||(this.initializing=!0),await this.submitContext(e,`initialization`)}async updateContext(e){switch(this.connectionPlan.kind){case`connect`:await this.submitContext(e,`context update`);return;case`stay-offline`:this.storeContext(this.admittedContextFor(e,`context update`));return}}storeContext(e){this.currentContext=e,this.emit(`contextUpdated`,{context:e})}async submitContext(e,t){await this.connectToTransport(this.admittedContextFor(e,t),t)}admittedContextFor(e,t){let n=xe(e);switch(n.outcome){case`admitted`:return n.context;case`ignored`:this.logger.error(`[ConfigDirectorClient] Ignored the context supplied for ${t} because its kind '${n.kindSample}' is invalid; continuing as if no context was supplied. A context kind has 1 to 64 characters, using only lowercase letters, digits, '-' and '_'.`),this.telemetryClient.recordInvalidContext(n.kindSample);return}}get context(){return this.currentContext}async connectToTransport(e,t){this.submittedContext=e,t===`initialization`&&this.startCachedValuesAdoption();try{this.ready=!1,this.readyPromise=new Promise(e=>{this.readyResolve=e}).then(e=>{e||(this.ready=!0,this.initializing=!1,this.emit(`clientReady`,{action:t}),this.logger.debug(`[ConfigDirectorClient] Received initial payload from the server, client is ready`))});let n=new Date().getTime();await this.transport.connect(e??{},this.timeout,t),this.currentContext=e,this.telemetryClient.updateContext(e).catch(e=>this.logger.warn(`[ConfigDirectorClient] Telemetry could not update the context: `,e)),this.emit(`contextUpdated`,{context:e});let r=new Date().getTime()-n,i=this.timeout-r;clearTimeout(this.timeoutTimer),this.timeoutTimer=void 0,i>0&&await Promise.race([this.readyPromise,new Promise(e=>{this.timeoutTimer=setTimeout(()=>e(),i)})]).finally(()=>clearTimeout(this.timeoutTimer)),this.ready||this.logger.warn(`[ConfigDirectorClient] Timed out waiting for ${t} after ${this.timeout}ms. ${this.timeoutWarningDetails()}`)}catch(e){if(e instanceof r)throw this.initializing=!1,e;this.logger.error(`[ConfigDirectorClient] An error occurred during ${t}: `,e)}}timeoutWarningDetails(){switch(this.connectionPlan.kind){case`connect`:return`The client will continue to retry since there were no fatal errors detected. Configs will return the default value until the connection succeeds.`;case`stay-offline`:return`The offline values were not delivered, so configs return the default value.`}}findKeysRemovedBy(e){return!this.configSet||e.kind!=`full`?[]:Object.keys(this.configSet.configs).filter(t=>!Object.prototype.hasOwnProperty.call(e.configs,t))}updateWatchers(e){e.forEach(e=>this.updateWatchersForConfig(e))}updateWatchersForConfig(e){let t=this.configSet?.configs[e];this.handlersMap.get(e)?.forEach(n=>{let r=this.evaluationOf(e,t,n.defaultValue).value;n.handler(r)})}watch(e,t,n){this.validateDefaultValue(t);let r=this.handlersMap.get(e),i={handler:n,defaultValue:t,requestedType:typeof t};return r?r.push(i):this.handlersMap.set(e,[i]),()=>this.unwatch(e,n)}unwatch(e,t){let n=this.handlersMap.get(e);if(n)if(t){let e=n.findIndex(e=>e.handler==t);e>=0&&n?.splice(e,1)}else n.splice(0)}getValue(e,t){return this.evaluate(e,t).value}evaluate(e,t){this.validateDefaultValue(t);let n=this.configSet?.configs[e];return this.evaluationOf(e,n,t)}evaluationOf(e,t,n){if(!t){this.logger.debug(`[ConfigDirectorClient] No config state found for '${e}', returning default value '${n}'`);let t=this.isReady?`config-state-missing`:`client-not-ready`;this.telemetryClient.evaluatedConfig({contextId:this.currentContext?.id,key:e,defaultValue:n,requestedType:S(n),evaluatedValue:n,usedDefault:!0,evaluationReason:t});let r={key:e,value:n,isDefaultValue:!0,reason:t,context:this.context};return this.dispatchEvaluationEvent(r),r}let r=T(t,n),i=this.servedReason(r.reason);this.telemetryClient.evaluatedConfig({contextId:this.currentContext?.id,type:t.type,key:e,defaultValue:n,requestedType:r.requestedType,evaluatedValue:r.parsedValue,evaluatedValueId:r.parsedValueId,usedDefault:r.usedDefault,evaluationReason:i});let a={key:e,value:r.parsedValue,valueId:r.parsedValueId??void 0,isDefaultValue:r.usedDefault,reason:i,context:this.context};return this.dispatchEvaluationEvent(a),this.logger.debug(`[ConfigDirectorClient] Evaluated '${e}' to '${r.parsedValue}'`),a}dispatchEvaluationEvent(e){setTimeout(()=>this.emit(`configEvaluated`,{evaluation:e}),0)}emit(e,t){try{this.eventEmitter.emit(e,t)}catch(t){this.logger.error(`[ConfigDirectorClient] Error executing event handlers for '${e}'`,t)}}validateDefaultValue(e){if(e==null)throw new n(`Invalid default value. The default value for a config must be defined and non-null.`);if(typeof e==`function`)throw new n(`Invalid default value. The default value for a config cannot be a function.`)}get isReady(){return this.ready}get isInitializing(){return this.initializing}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.logger.debug(`[ConfigDirectorClient] clear() has been called, removing all observers`),this.eventEmitter.clear(),this.handlersMap.clear()}unwatchAll(){this.handlersMap.clear()}pauseNetwork(){switch(this.connectionPlan.kind){case`stay-offline`:return;case`connect`:this.logger.debug(`[ConfigDirectorClient] pauseNetwork() called, pausing transport connection`),clearTimeout(this.timeoutTimer),this.timeoutTimer=void 0,this.transport.close(),this.ready=!1;return}}async resumeNetwork(){switch(this.connectionPlan.kind){case`stay-offline`:return;case`connect`:await this.connectToTransport(this.currentContext,`network resume`);return}}async close(){this.logger.debug(`[ConfigDirectorClient] close() has been called, closing connection to server`),clearTimeout(this.timeoutTimer),this.readyResolve?.(!0),this.telemetryClient.close().catch(e=>this.logger.warn(`[ConfigDirectorClient] Telemetry could not close: `,e)),this.transport.close(),this.ready=!1,this.initializing=!1}dispose(){this.clear(),this.close()}};const $=Symbol.for(`@configdirector/installed-test-client`),Pe=()=>globalThis[$];Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return 262144}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return z}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return`configdirector-sdk:cached-values:`}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return Pe}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return Ne}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return B}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return $}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return b}});
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
function e(t){"@babel/helpers - typeof";return e=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},e(t)}function t(t,n){if(e(t)!=`object`||!t)return t;var r=t[Symbol.toPrimitive];if(r!==void 0){var i=r.call(t,n||`default`);if(e(i)!=`object`)return i;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(n===`string`?String:Number)(t)}function n(n){var r=t(n,`string`);return e(r)==`symbol`?r:r+``}function r(e,t,r){return(t=n(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?i(Object(n),!0).forEach(function(t){r(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}var o=class{constructor(){this.handlerMap=new Map}on(e,t){let n=this.handlerMap.get(e);n?n.push(t):this.handlerMap.set(e,[t])}once(e,t){let n=this;function r(i){n.off(e,r),t.apply(n,i)}this.on(e,r)}off(e,t){let n=this.handlerMap.get(e);if(n)if(t){let e=n.indexOf(t);e>=0&&n.splice(e,1)}else this.handlerMap.set(e,[])}clear(){this.handlerMap.clear()}emit(e,t){let n=this.handlerMap.get(e);n&&n.slice().map(e=>e(t))}},s=class e extends Error{constructor(t,n){super(t),this.name=`ConfigDirectorConnectionError`,this.status=n,Object.setPrototypeOf(this,e.prototype)}},c=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorValidationError`,Object.setPrototypeOf(this,e.prototype)}},l=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorInitializationError`,Object.setPrototypeOf(this,e.prototype)}},u=class e extends Error{constructor(t){super(t),this.name=`StreamClosedError`,Object.setPrototypeOf(this,e.prototype)}},d=class e extends Error{constructor(t){super(t),this.name=`MissingResponseBodyError`,Object.setPrototypeOf(this,e.prototype)}},f=class e extends Error{constructor(t){super(t),this.name=`InvalidOptionError`,Object.setPrototypeOf(this,e.prototype)}},p=class e extends Error{constructor(t){super(t),this.name=`ValueOutOfRangeError`,Object.setPrototypeOf(this,e.prototype)}},m=class{constructor(e){var t;this.isFirstChunk=!0,this.bufferedInput=``,this.currentEvent={data:``},this.currentEvent={data:``},this.onEvent=(t=e.onEvent)==null?(()=>{}):t,this.onRetry=e.onRetry,this.onComment=e.onComment}parse(e){let t=e;this.isFirstChunk&&(this.isFirstChunk=!1,t.startsWith(``)?t=t.slice(1):t.startsWith(``)&&(t=t.slice(3)));let n=this.scanLines(this.bufferedInput+t);for(let e of n)this.dispatchLine(e)}finish(){this.bufferedInput=``}scanLines(e){let t=[],n=0,r=0;for(;r<e.length;){let i=e[r];i===`\r`||i===`
|
|
2
|
-
`?(t.push(e.slice(n,r)),i===`\r`&&e[r+1]===`
|
|
3
|
-
`&&r++,r++,n=r):r++}return this.bufferedInput=e.slice(n),t}dispatchLine(e){if(e.startsWith(`:`)){var t;(t=this.onComment)==null||t.call(this,this.extractValue(e,1));return}if(e===``){this.emitEvent();return}this.applyField(this.parseField(e))}emitEvent(){let e=this.currentEvent.data.endsWith(`
|
|
4
|
-
`)?this.currentEvent.data.slice(0,-1):this.currentEvent.data;e!==``&&this.onEvent(a(a({},this.currentEvent),{},{id:this.lastEventId,data:e})),this.currentEvent={data:``}}applyField(e){switch(e.field){case`event`:this.currentEvent.type=e.value;break;case`data`:this.currentEvent.data+=e.value+`
|
|
5
|
-
`;break;case`id`:e.value.includes(`\0`)||(this.lastEventId=e.value);break;case`retry`:if(/^\d+$/.test(e.value)){var t;(t=this.onRetry)==null||t.call(this,Number.parseInt(e.value,10))}break;default:break}}parseField(e){let t=e.indexOf(`:`);return t===-1?{field:e,value:``}:{field:e.slice(0,t),value:this.extractValue(e,t+1)}}extractValue(e,t){return e[t]===` `?e.slice(t+1):e.slice(t)}};let h=function(e){return e.OPEN=`open`,e.CLOSED=`closed`,e.CONNECTING=`connecting`,e}({});var g=class{constructor(e){var t,n;this.DEFAULT_SHOULD_RECONNECT=()=>!0,this.DEFAULT_CALCULATE_RECONNECT_DELAY=()=>this.serverReconnectionTime,this.reconnectAttempt=0,this.abortController=new AbortController,this._readyState=h.CLOSED,this.serverReconnectionTime=2e3,this.url=e.url.toString(),this.lastEventId=e.lastEventId,this.headers=a({Accept:`text/event-stream`},e.headers);let r=e.body;this.body=typeof r==`function`?r:()=>r,this.requestOptions={method:(t=e.method)==null?`GET`:t,mode:e.mode,credentials:e.credentials,redirect:e.redirect,referrer:e.referrer,referrerPolicy:e.referrerPolicy},this._fetch=(n=e.fetch)==null?((e,t)=>fetch(e,t)):n,this._onError=this.resolveCallback(e.onError,()=>{},`onError`),this._onConnect=this.resolveCallback(e.onConnect,()=>{},`onConnect`),this._onDisconnect=this.resolveCallback(e.onDisconnect,()=>{},`onDisconnect`),this._onMessage=this.resolveCallback(e.onMessage,()=>{},`onMessage`),this._onComment=this.resolveCallback(e.onComment,()=>{},`onComment`),this._shouldReconnect=this.resolveCallback(e.shouldReconnect,this.DEFAULT_SHOULD_RECONNECT,`shouldReconnect`),this._calculateReconnectDelay=this.resolveCallback(e.calculateReconnectDelay,this.DEFAULT_CALCULATE_RECONNECT_DELAY,`calculateReconnectDelay`)}set onError(e){this._onError=this.resolveCallback(e,()=>{},`onError`)}set onMessage(e){this._onMessage=this.resolveCallback(e,()=>{},`onMessage`)}set onComment(e){this._onComment=this.resolveCallback(e,()=>{},`onComment`)}set onConnect(e){this._onConnect=this.resolveCallback(e,()=>{},`onConnect`)}set onDisconnect(e){this._onDisconnect=this.resolveCallback(e,()=>{},`onDisconnect`)}set shouldReconnect(e){this._shouldReconnect=this.resolveCallback(e,this.DEFAULT_SHOULD_RECONNECT,`shouldReconnect`)}set calculateReconnectDelay(e){this._calculateReconnectDelay=this.resolveCallback(e,this.DEFAULT_CALCULATE_RECONNECT_DELAY,`shouldReconnect`)}get readyState(){return this._readyState}connect(){this._readyState===h.CLOSED&&(this.reconnectAttempt=0,this.initiateConnection())}close(){clearTimeout(this.reconnectTimeout),this._readyState=h.CLOSED,this.abortController.abort()}initiateConnection(){this.abortController=new AbortController,this._readyState=h.CONNECTING,this._fetch(this.url,a(a({},this.requestOptions),{},{body:this.body(),headers:this.buildRequestHeaders(),signal:this.abortController.signal,cache:`no-store`})).then(e=>this.handleFetchResponse(e)).catch(e=>{if(e.name===`AbortError`||this.abortController.signal.aborted){this.close();return}this._onError(e),this.scheduleReconnect({error:e})})}async handleFetchResponse(e){var t=this;let{body:n,status:r}=e;if(r===204){t.disconnected();return}if(r>=400){t.scheduleReconnect({status:r});return}if(!n)throw new d(`The server response did not have a body`);t._readyState=h.OPEN,t._onConnect(),t.reconnectAttempt=0;let i=new m({onEvent:e=>{typeof e.id==`string`&&(t.lastEventId=e.id),t._onMessage(e)},onComment:e=>t._onComment(e),onRetry:e=>t.serverReconnectionTime=e});await t.readResponseStream(n,i),t.scheduleReconnect({status:r,error:new u(`The server response stream was closed`)})}async readResponseStream(e,t){let n=e.getReader(),r=new TextDecoder,i=!1;for(;!i;){let e=await n.read();e.value&&t.parse(r.decode(e.value,{stream:!0})),i=e.done}t.finish()}disconnected(){clearTimeout(this.reconnectTimeout),this._readyState=h.CLOSED,this._onDisconnect()}buildRequestHeaders(){let e=this.lastEventId?{"Last-Event-ID":this.lastEventId}:void 0;return a(a({},this.headers),e)}scheduleReconnect(e){if(this.abortController.signal.aborted)return;clearTimeout(this.reconnectTimeout),this.reconnectAttempt+=1;let t={attempt:this.reconnectAttempt,status:e.status,error:e.error,serverReconnectionTime:this.serverReconnectionTime};if(!this._shouldReconnect(t)){this.disconnected();return}this._readyState=h.CONNECTING;let n=this._calculateReconnectDelay(t);(!Number.isFinite(n)||n<1||n>1e3*60*60)&&(this._onError(new p(`The calculated reconnect delay is out of range: ${n}. Defaulting to ${this.serverReconnectionTime}`)),n=this.serverReconnectionTime),this.reconnectTimeout=setTimeout(()=>this.initiateConnection(),n)}resolveCallback(e,t,n){if(e==null)return t;if(typeof e!=`function`)throw new f(`${n} must be a function`);return e}};const _=e=>new g(e);var v=class{constructor(e){this.options=e,this.eventEmitter=new o,this.connectionGeneration=0,this.options=e,this.logger=e.logger,this.url=e.resolveUrl(`client/sse/v1`,e.baseUrl)}async connect(e,t){var n=this;let r=++n.connectionGeneration,i=await n.options.clientSession;if(r!==n.connectionGeneration)return n;n.eventSource&&n.close();let a=new Promise((t,r)=>{n.eventSource=_({url:n.url,method:`POST`,headers:{"Content-Type":`application/json`},fetch:n.options.fetch,body:JSON.stringify({givenContext:e,metaContext:n.options.metaContext,clientSdkKey:n.options.clientSdkKey,instanceId:i.instanceId,ephemeral:i.ephemeral}),onMessage:({data:e})=>{n.dispatchMessage(e)},onConnect:()=>{n.logger.debug(`[StreamingTransport] Connected`),t(n)},shouldReconnect:e=>{let t=!n.isStatusFatal(e.status);if(!t){let t=n.prepareFatalError(e.status,e.error);n.eventEmitter.emit(`connectionError`,t),r(t)}return t},calculateReconnectDelay:e=>{let t=n.options.connectionRetryDelay(e.attempt),r=`[StreamingTransport] Scheduling reconnect attempt #${e.attempt} in ${t}ms.`;return e.attempt<=5?n.logger.info(r):n.logger.warn(r),t},onError:e=>{n.logger.debug(`[StreamingTransport] Error: `,e)},onDisconnect:()=>{n.logger.debug(`[StreamingTransport] Disconnected`)}}),n.eventSource.connect()});return clearTimeout(n.timeoutTimer),n.timeoutTimer=void 0,Promise.race([a,new Promise(e=>{n.timeoutTimer=setTimeout(()=>e(n),t)})]).finally(()=>clearTimeout(n.timeoutTimer))}dispatchMessage(e){try{let t=JSON.parse(e);this.eventEmitter.emit(`configSetReceived`,t)}catch(e){this.logger.error(`[StreamingTransport] Error parsing and dispatching config data update: `,e)}}prepareFatalError(e,t){let n=e==null?0:e;return new s(`${`Connection failed with status: ${e==null?`unknown`:e}.`}${t?` Error: ${t}`:``}. This is an unrecoverable error, will not attempt to reconnect.`,n)}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.eventEmitter.clear()}close(){var e;this.connectionGeneration++,(e=this.eventSource)==null||e.close(),clearTimeout(this.timeoutTimer)}dispose(){this.close(),this.clear()}};const ee=(e,t)=>{if(e.trim().length==0)throw new c(`Invalid config key. The key of a value cannot be empty.`);return te(e,t)},te=(e,t)=>{switch(typeof t){case`boolean`:return{type:`boolean`,value:t?`true`:`false`};case`number`:return y(e,t);case`string`:return{type:`string`,value:t};case`object`:if(t!==null)return x(e,t,``),{type:`json`,value:JSON.stringify(t)}}throw new c(`Invalid value for '${e}': ${w(t)}. Use a boolean, a number, a string, a plain object, or an array.`)},y=(e,t)=>{if(!Number.isFinite(t))throw new c(`Invalid value for '${e}': ${w(t)} is not a finite number.`);if(Number.isInteger(t)){if(!Number.isSafeInteger(t))throw new c(`Invalid value for '${e}': ${t} is not a safe integer, so the SDK could not read it back exactly.`);return{type:`integer`,value:String(t)}}return{type:`float`,value:b(t)}},b=e=>{let t=String(e),n=t.indexOf(`e-`);if(n<0)return t;let r=t.startsWith(`-`)?`-`:``,[i=``,a=``]=t.slice(r.length,n).split(`.`),o=Number(t.slice(n+2))-i.length;return`${r}0.${`0`.repeat(o)}${i}${a}`},x=(e,t,n)=>{if(!(t===null||typeof t==`boolean`||typeof t==`string`)){if(typeof t==`number`){if(!Number.isFinite(t))throw S(e,n,`${w(t)} is not a finite number`);return}if(Array.isArray(t)){t.forEach((t,r)=>x(e,t,`${n}[${r}]`));return}if(C(t)){for(let[r,i]of Object.entries(t))x(e,i,n?`${n}.${r}`:r);return}throw S(e,n,`${w(t)} cannot be encoded as JSON`)}},S=(e,t,n)=>new c(`Invalid value for '${e}'${t?` at '${t}'`:``}: ${n}. JSON contents can hold booleans, finite numbers, strings, null, arrays, and plain objects.`),C=e=>{if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},w=e=>{if(e===null)return`null`;if(typeof e==`function`)return`a function`;if(typeof e==`object`){var t,n;return`a ${(t=(n=e.constructor)==null?void 0:n.name)==null?`object`:t} instance`}return typeof e==`symbol`?`a symbol`:String(e)},T=(e,t,n,r)=>{let i=ee(t,n);return{id:e,key:t,type:i.type,value:i.value,valueId:r}},E={environmentId:`offline`,projectId:`offline`};var D=class{constructor(e){this.source=e,this.emitter=new o,this.on=(e,t)=>this.emitter.on(e,t),this.off=(e,t)=>this.emitter.off(e,t)}async connect(){var e=this;let t=O(e.source);return e.emitter.emit(`configSetReceived`,a(a({},E),{},{kind:`full`,configs:t})),e}clear(){this.emitter.clear()}close(){}dispose(){this.clear()}};const O=e=>{switch(e.kind){case`in-code-defaults`:return{};case`values`:return ne(e.values);case`rejected`:throw new l(e.message)}},ne=e=>{try{return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,T(`offline:${e}`,e,t,void 0)]))}catch(e){throw e instanceof c?new l(`The offline values could not be loaded. ${e.message}`):e}},re=(e,t,n)=>{var r;if((t==null?void 0:t.mode)===`offline`)return{kind:`stay-offline`,source:ae(t)};let i=(r=t==null?void 0:t.mode)==null?`streaming`:r;if(!e||e.trim().length==0)throw new c(`No client SDK key was provided, the client cannot be instantiated without a valid client SDK key`);return(t==null?void 0:t.values)===void 0?{kind:`connect`,mode:i,clientSdkKey:e,baseUrl:ie(t==null?void 0:t.url,n)}:{kind:`stay-offline`,source:{kind:`rejected`,message:`The connection option 'values' applies only when the connection mode is 'offline', but the mode is '${i}'.`}}},ie=(e,t)=>{if(!e)return`https://client-sdk-api.configdirector.com`;try{return t(e)}catch(t){throw new c(`Invalid base URL '${e}'. Parsing failed: ${t}`)}},ae=e=>e.values===void 0?{kind:`in-code-defaults`}:{kind:`values`,values:e.values},k=e=>{let t=typeof e;if(t===`object`)try{var n,r;return(n=(r=e.constructor)==null?void 0:r.name)==null?t:n}catch(e){return t}else if(t===`function`)try{let n=e.name;return n?`function: ${n}`:t}catch(e){return t}return t},A=e=>e===`number`||e===`bigint`,oe=new Set([`boolean`,`integer`,`float`]),se=(e,t)=>{let n=e.value,r=k(t);if(n==null||n===``)return{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`value-missing`};if(e.type===`json`)return P(n,t,r,e.valueId);if(typeof t==`string`)return oe.has(e.type)?{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`type-mismatch`}:{parsedValue:n,parsedValueId:e.valueId,requestedType:r,usedDefault:!1,reason:`found-match`};if(typeof t==`boolean`&&(e.type===`boolean`||e.type===`string`||e.type===`enum`)){let i=ce(n),a=typeof i==`boolean`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-boolean`}}if(A(typeof t)&&e.type===`integer`){let i=le(n),a=typeof i==`number`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-number`}}if(A(typeof t)&&(e.type===`float`||e.type===`enum`||e.type===`string`)){let i=j(n),a=typeof i==`number`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-number`}}return{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`type-mismatch`}},ce=e=>{if(!e)return;let t=e.toLowerCase();if(!(t!=`true`&&t!=`false`))return t===`true`},le=e=>{let t=M(e);return t==null?void 0:Math.trunc(t)},j=e=>M(e),M=e=>{if(!e||!N(e))return;let t=Number(e);if(!(isNaN(t)||!isFinite(t)))return t},N=e=>{for(let t of e)if(!(t>=`0`&&t<=`9`)&&!`+-.eE`.includes(t))return!1;return!0},P=(e,t,n,r)=>{if(typeof t==`string`)return{parsedValue:e,parsedValueId:r,requestedType:n,usedDefault:!1,reason:`found-match`};try{let i=JSON.parse(e);return F(i,t)?{parsedValue:i,parsedValueId:r,requestedType:n,usedDefault:!1,reason:`found-match`}:{parsedValue:t,parsedValueId:void 0,requestedType:n,usedDefault:!0,reason:`type-mismatch`}}catch(e){return{parsedValue:t,parsedValueId:void 0,requestedType:n,usedDefault:!0,reason:`invalid-json`}}},F=(e,t)=>e===null?!1:I(e)===I(t),I=e=>{if(Array.isArray(e))return`array`;let t=typeof e;return t===`bigint`?`number`:t},L={off:-1,error:0,warn:1,info:2,debug:3},R=()=>{let e={year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,timeZoneName:`short`};try{return new Intl.DateTimeFormat(void 0,a(a({},e),{},{fractionalSecondDigits:3}))}catch(t){return new Intl.DateTimeFormat(void 0,e)}};var z=class{constructor(e,t){this.level=e,this.decorator=t,this.level=e,this.decorator=t,this.dateFormatter=R()}debug(e,...t){this.log(console.debug,`debug`,e,...t)}info(e,...t){this.log(console.info,`info`,e,...t)}warn(e,...t){this.log(console.warn,`warn`,e,...t)}error(e,...t){this.log(console.error,`error`,e,...t)}log(e,t,n,...r){if(L[this.level]>=L[t]){var i;e(`[${this.dateFormatter.format(new Date)}] ${(i=this.decorator)==null?void 0:i.decorateMessage(n)}`,...r)}}},B=class{decorateMessage(e){return`[ConfigDirector:js-client-sdk] ${e}`}};const V=(e,t)=>new z(e==null?`warn`:e,t==null?new B:t),H={updateContext:async()=>{},evaluatedConfig:()=>{},recordInvalidContext:()=>{},close:async()=>{}},U=(e,t)=>new URL(e,t==null?void 0:t.toString()),W=(e,t)=>e===void 0?{seconds:t.defaultSeconds,warning:void 0}:e>=t.minimumSeconds?{seconds:e,warning:void 0}:{seconds:t.minimumSeconds,warning:`pollingInterval of ${e} seconds is below the minimum of ${t.minimumSeconds} seconds. Using ${t.minimumSeconds} seconds.`},ue=()=>typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)}),G=e=>{try{return e(globalThis)}catch(e){return}},de=()=>G(e=>{var t;return(t=e.navigator)==null?void 0:t.userAgent}),fe=()=>G(e=>{var t;return(t=e.location)==null?void 0:t.host}),K=()=>{try{var e;return(e=globalThis.localStorage)==null?void 0:e}catch(e){return}},q=`configdirector-sdk:instance-id`,J=1e3,pe=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,Y=(e,t)=>{let n=t;for(let t=0;t<e.length;t++)n^=e.charCodeAt(t),n=Math.imul(n,16777619);return n>>>0},X=(e,t)=>{let n=`configdirector.instanceId.v1|${e}|${t}`,r=Y(n,2166136261);return Y(`${r}|${n}`,16777619).toString(16).padStart(8,`0`)+r.toString(16).padStart(8,`0`)},me=e=>{if(!e||typeof e!=`object`)return!1;let{v:t,id:n,createdAt:r,checksum:i}=e;return t!==1||typeof n!=`string`||typeof i!=`string`||typeof r!=`number`||!Number.isInteger(r)||r<=0||!pe.test(n)?!1:i===X(n,r)},he=async(e,t)=>{let n;try{n=await e.getItem(q)}catch(e){return t.debug(`[ConfigDirectorClient] Could not read the stored instance id, using an ephemeral one`,e),{outcome:`failed`}}if(typeof n!=`string`||n===``)return{outcome:`nothing usable`};let r;try{r=JSON.parse(n)}catch(e){return t.debug(`[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one`),{outcome:`nothing usable`}}return me(r)?{outcome:`stored`,instanceId:r.id}:(t.debug(`[ConfigDirectorClient] The stored instance id failed validation, generating a new one`),{outcome:`nothing usable`})},ge=async(e,t,n)=>{let r=Date.now(),i={v:1,id:t,createdAt:r,checksum:X(t,r)};try{return await e.setItem(q,JSON.stringify(i)),!0}catch(e){return n.debug(`[ConfigDirectorClient] Could not persist the instance id, using it as an ephemeral one`,e),!1}},_e=async(e,t,n,r)=>{let i=await he(e,r);switch(i.outcome){case`stored`:return{instanceId:i.instanceId};case`failed`:return{instanceId:t,ephemeral:!0};case`nothing usable`:break}return n.passed?{instanceId:t,ephemeral:!0}:await ge(e,t,r)?{instanceId:t}:{instanceId:t,ephemeral:!0}},ve=(e,t=K())=>{let n=ue();if(!t)return e.debug(`[ConfigDirectorClient] No instance id storage is available, using an ephemeral instance id`),Promise.resolve({instanceId:n,ephemeral:!0});let r={passed:!1},i,a=new Promise(t=>{i=setTimeout(()=>{r.passed=!0,e.warn(`[ConfigDirectorClient] The instance id storage did not respond within ${J}ms, using an ephemeral instance id`),t({instanceId:n,ephemeral:!0})},J)});return Promise.race([_e(t,n,r,e),a]).finally(()=>clearTimeout(i))};var ye=class{constructor(){this.fatalError=!1}clearPollingInterval(){clearInterval(this.pollingInterval)}schedulePollingInterval(e){clearInterval(this.pollingInterval),!(this.pollingIntervalSeconds<=0)&&(this.pollingInterval=setInterval(e,this.pollingIntervalSeconds*1e3))}async handleNonOkResponse(e){var t=this;if(!e.ok)throw t.isStatusFatal(e.status)?(t.fatalError=!0,t.close(),t.prepareFatalResponseStatusError(e.status,await e.text())):new s(`Connection failed with status: ${e.status}`,e.status)}handleFetchError(e){throw this.isFetchErrorFatal(e)?(this.fatalError=!0,this.close(),new s(`Connection failed with fatal error: ${e}. This is an unrecoverable error, retry attempts will be ignored.`)):e instanceof SyntaxError?new s(`Failed to parse the response from the server: ${e}`):new s(`Connection failed with error: ${e}.`)}prepareFatalResponseStatusError(e,t){var n,r;let i=e==null?0:e;return new s(`${`Connection failed with status: ${e==null?`unknown`:e}`}${((n=t==null||(r=t.trim())==null?void 0:r.length)==null?0:n)>0?` (${t})`:``}. This is an unrecoverable error, retry attempts will be ignored.`,i)}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}isFetchErrorFatal(e){return(e==null?void 0:e.name)===`NotAllowedError`}get isConnected(){return this.pollingInterval!==void 0}close(){clearInterval(this.pollingInterval),this.pollingInterval=void 0}dispose(){this.close(),this.clear()}};const be=async(e,t,n,r)=>{let i=new AbortController,o=setTimeout(()=>{r.debug(`[fetchWithTimeout] Reached timeout, aborting request`),i.abort()},e);try{let e=await fetch(typeof t==`string`||t instanceof Request?t:t.toString(),a(a({},n),{},{signal:i.signal}));return clearTimeout(o),e}catch(e){throw r.warn(`[fetchWithTimeout] Fetch error: `,e),clearTimeout(o),e}};var xe=class extends ye{constructor(e){var t;super(),this.options=e,this.eventEmitter=new o,this.connectionGeneration=0,this.options=e,this.logger=e.logger,this.url=e.resolveUrl(`client/polling/v1`,e.baseUrl),this.pollingIntervalSeconds=(t=e.pollingInterval)==null?60:t}async connect(e,t){var n=this;let r=++n.connectionGeneration;n.clearPollingInterval();let i=await n.options.clientSession;if(r!==n.connectionGeneration)return n;try{await n.fetchConfigs(e,t,i)}finally{n.fatalError||n.schedulePollingInterval(()=>{n.fetchConfigs(e,t,i).catch(e=>{n.logger.error(`[PollingTransport] Error during polling:`,e)})})}return n}close(){this.connectionGeneration++,super.close()}async fetchConfigs(e,t,n){var r=this;if(r.fatalError){r.logger.warn(`[PollingTransport] There was a prior unrecoverable error. Ignoring attempt to reconnect.`);return}try{let i=await be(t,r.url,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({givenContext:e,metaContext:r.options.metaContext,clientSdkKey:r.options.clientSdkKey,instanceId:n.instanceId,ephemeral:n.ephemeral,lastUpdateTimestamp:r.lastUpdateTimestamp})},r.logger);if(await r.handleNonOkResponse(i),i.status==200){let e=JSON.parse(await i.text());r.lastUpdateTimestamp=e.timestamp,r.eventEmitter.emit(`configSetReceived`,e)}}catch(e){try{r.handleFetchError(e)}catch(e){throw r.fatalError&&r.eventEmitter.emit(`connectionError`,e),e}}}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.eventEmitter.clear()}};const Se=e=>e>=`a`&&e<=`z`||e>=`0`&&e<=`9`||e===`-`||e===`_`,Ce=e=>{if(e.length<1||e.length>64)return!1;for(let t of e)if(!Se(t))return!1;return!0},we=e=>e==null||typeof e==`string`&&Ce(e),Te=e=>{if(typeof e==`string`)return e;try{return String(e)}catch(t){return Object.prototype.toString.call(e)}},Ee=(e,t)=>{let n=``,r=0;for(let i of e){if(r===t)break;n+=i,r+=1}return n},De=e=>{let t=e==null?void 0:e.kind;return we(t)?{outcome:`admitted`,context:e}:{outcome:`ignored`,kindSample:Ee(Te(t),128)}},Oe=e=>e>=55296&&e<=56319,ke=e=>e>=56320&&e<=57343,Ae=e=>{let t=0;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);r<=127?t+=1:r<=2047?t+=2:Oe(r)&&n+1<e.length&&ke(e.charCodeAt(n+1))?(t+=4,n++):t+=3}return t},je=`configdirector-sdk:cached-values:`,Me=256*1024,Ne=(e,t,n,r)=>{var i;if(e.kind===`stay-offline`)return{kind:`no cache`,reason:`offline mode`};if((t==null?void 0:t.enabled)===!1)return{kind:`no cache`,reason:`turned off`};if(!n)return{kind:`no cache`,reason:`no SHA-256 available`};let a=n(e.clientSdkKey),o=(i=t==null?void 0:t.provider)==null?r==null?void 0:r(a):i;return o?{kind:`cache`,provider:o,clientSdkKeyDigest:a}:{kind:`no cache`,reason:`no provider available`}},Z=(e,t)=>{var n;let r=(n=e==null?void 0:e.kind)==null?`user`:n;return(e==null?void 0:e.id)==null?{contextKind:r,anonymousInstanceId:t}:{contextKind:r,contextId:e.id}},Pe=(e,t)=>e.contextKind===t.contextKind?`contextId`in e&&`contextId`in t?e.contextId===t.contextId:`anonymousInstanceId`in e&&`anonymousInstanceId`in t?e.anonymousInstanceId===t.anonymousInstanceId:!1:!1,Fe=(e,t,n)=>n?`live values already arrived`:Pe(e.contextTag,t)?`adopt`:`context mismatch`,Q=e=>{if(!e||typeof e!=`object`)return!1;let{contextKind:t,contextId:n,anonymousInstanceId:r}=e;return typeof t==`string`?typeof n==`string`||typeof r==`string`:!1},Ie=e=>!e||typeof e!=`object`||Array.isArray(e)?!1:Object.values(e).every(e=>e&&typeof e==`object`&&typeof e.id==`string`&&typeof e.key==`string`),Le=(e,t)=>{if(!t||typeof t!=`object`)return!1;let n=t;return n.formatVersion===2&&n.clientSdkKeyDigest===e&&Q(n.contextTag)&&typeof n.environmentId==`string`&&typeof n.projectId==`string`&&Ie(n.configs)&&typeof n.receivedAt==`number`},Re=e=>!!e&&typeof e==`object`&&e.formatVersion===1,ze=(e,t)=>{let n;try{n=JSON.parse(e)}catch(e){return{outcome:`unreadable`}}return Le(t,n)?{outcome:`stored`,cachedValues:n}:Re(n)?{outcome:`first format`}:{outcome:`unreadable`}};var Be=class{constructor(e,t,n){this.provider=e,this.clientSdkKeyDigest=t,this.logger=n,this.warned=new Set,this.writing=!1}read(){return this.pendingRead!=null||(this.pendingRead=this.readEntry()),this.pendingRead}replace(e){this.queuedCachedValues=e,this.writeQueued()}async readEntry(){var e=this;let t;try{t=await e.provider.read()}catch(t){return e.warnOnce(`read failed`,`Could not read the values kept on the device, starting without them:`,t),{outcome:`failed`}}if(t==null||t===``)return{outcome:`nothing stored`};let n=ze(t,await e.clientSdkKeyDigest);switch(n.outcome){case`stored`:return n;case`first format`:return await e.removeEntry(),n;case`unreadable`:return e.warnOnce(`unreadable`,`The values kept on the device could not be read and were removed, starting without them`),await e.removeEntry(),n}}async writeQueued(){var e=this;if(!e.writing){e.writing=!0;try{for(;e.queuedCachedValues;){let t=e.queuedCachedValues;e.queuedCachedValues=void 0,await e.writeEntry(t)}}finally{e.writing=!1}}}async writeEntry(e){var t=this;let n=a({formatVersion:2,clientSdkKeyDigest:await t.clientSdkKeyDigest},e),r=JSON.stringify(n),i=Ae(r),o=t.provider.sizeLimit();if(i>o){t.warnOnce(`over the size limit`,`The values received (${i} bytes) exceed the caching provider's limit of ${o} bytes, so no values are kept on the device`),await t.removeEntry();return}try{await t.provider.write(r)}catch(e){t.warnOnce(`write failed`,`Could not keep the values on the device:`,e)}}async removeEntry(){var e=this;try{await e.provider.remove()}catch(t){e.warnOnce(`remove failed`,`Could not remove the values kept on the device:`,t)}}warnOnce(e,t,...n){this.warned.has(e)||(this.warned.add(e),this.logger.warn(`[ConfigDirectorClient] ${t}`,...n))}},Ve=class e{static from(t,n,r,i,a){return typeof n==`object`?new e(t,void 0,r,n,a):new e(t,n,r,i,a)}constructor(e,t,n,r,i){var s,c,l,u,d,f,p,m,h,g,_;this.handlersMap=new Map,this.eventEmitter=new o,this.ready=!1,this.initializing=!1,this.hasReceivedConfigSet=!1,this.servingCachedValues=!1,this.cachedValuesAdoptionStarted=!1,this.logger=(s=r==null?void 0:r.logger)==null?V():s,this.clientSession=ve(this.logger,i==null?void 0:i.instanceIdStorage),this.timeout=(c=r==null||(l=r.connection)==null?void 0:l.timeout)==null?3e3:c;let v=(u=i==null?void 0:i.urlFactory)==null?U:u;this.connectionPlan=re(t,r==null?void 0:r.connection,v),this.cachedValuesStore=this.buildCachedValuesStore(Ne(this.connectionPlan,r==null?void 0:r.caching,i==null?void 0:i.sha256HexDigest,i==null?void 0:i.platformCachingProvider)),this.telemetryClient=this.buildTelemetryClient(e,r),this.transport=(d=i==null?void 0:i.transport)==null?this.buildTransport(n,r,v,i):d,this.transport.on(`configSetReceived`,e=>{var t;this.hasReceivedConfigSet=!0,this.servingCachedValues=!1,(t=this.readyResolve)==null||t.call(this);let n=this.findKeysRemovedBy(e);!this.configSet||e.kind==`full`?this.configSet=e:this.configSet.configs=a(a({},this.configSet.configs),e.configs),this.keepValuesOnTheDevice(this.configSet);let r=Object.keys(e.configs);this.emit(`configsUpdated`,{keys:r,removedKeys:n}),this.updateWatchers([...r,...n]),this.logger.debug(`[ConfigDirectorClient] ConfigSet updated from server:`,{keys:r,removedKeys:n})}),this.transport.on(`connectionError`,e=>{this.initializing=!1,this.logger.error(`[ConfigDirectorClient] The connection encountered an unrecoverable error and will not be retried. Configs will no longer receive updates.`,e),this.emit(`connectionError`,{error:e})}),this.registerHandler(`clientReady`,r==null||(f=r.hooks)==null?void 0:f.clientReady),this.registerHandler(`configEvaluated`,r==null||(p=r.hooks)==null?void 0:p.configEvaluated),this.registerHandler(`configsUpdated`,r==null||(m=r.hooks)==null?void 0:m.configsUpdated),this.registerHandler(`contextUpdated`,r==null||(h=r.hooks)==null?void 0:h.contextUpdated),this.registerHandler(`connectionError`,r==null||(g=r.hooks)==null?void 0:g.connectionError),this.registerHandler(`cachedValuesLoaded`,r==null||(_=r.hooks)==null?void 0:_.cachedValuesLoaded)}buildCachedValuesStore(e){switch(e.kind){case`no cache`:this.logger.debug(`[ConfigDirectorClient] No values are kept on the device: ${e.reason}`);return;case`cache`:{let t=new Be(e.provider,e.clientSdkKeyDigest,this.logger);return t.read(),t}}}startCachedValuesAdoption(){let e=this.cachedValuesStore;!e||this.cachedValuesAdoptionStarted||(this.cachedValuesAdoptionStarted=!0,this.adoptCachedValues(e))}async adoptCachedValues(e){var t=this;let n=await e.read();switch(n.outcome){case`nothing stored`:case`first format`:case`unreadable`:case`failed`:return;case`stored`:break}let{instanceId:r}=await t.clientSession,i=Z(t.submittedContext,r),a=Fe(n.cachedValues,i,t.hasReceivedConfigSet);switch(a){case`adopt`:t.serveCachedValues(n.cachedValues);return;case`live values already arrived`:case`context mismatch`:t.logger.debug(`[ConfigDirectorClient] The values kept on the device were not adopted: ${a}`);return}}serveCachedValues(e){let{environmentId:t,projectId:n,configs:r}=e;this.configSet={environmentId:t,projectId:n,configs:r,kind:`full`},this.servingCachedValues=!0;let i=Object.keys(r);this.emit(`cachedValuesLoaded`,{}),this.emit(`configsUpdated`,{keys:i,removedKeys:[]}),this.updateWatchers(i),this.logger.debug(`[ConfigDirectorClient] Serving the values kept on the device until live values arrive:`,{keys:i})}keepValuesOnTheDevice(e){let t=this.cachedValuesStore;if(!t)return;let n=this.submittedContext,r=Date.now();this.clientSession.then(({instanceId:i})=>t.replace({contextTag:Z(n,i),environmentId:e.environmentId,projectId:e.projectId,configs:e.configs,receivedAt:r}))}servedReason(e){return this.servingCachedValues&&e===`found-match`?`cached`:e}registerHandler(e,t){if(!t)return;let n=Array.isArray(t)?t:[t];for(let t of n)typeof t==`function`&&this.on(e,t)}pollingIntervalFor(e,t){if(e!==`polling`)return;let n=W(t,{defaultSeconds:60,minimumSeconds:30});return n.warning&&this.logger.warn(`[ConfigDirectorClient] ${n.warning}`),n.seconds}buildTelemetryClient(e,t){let n=this.connectionPlan;switch(n.kind){case`stay-offline`:return H;case`connect`:return e({clientSdkKey:n.clientSdkKey,baseUrl:n.baseUrl,logger:this.logger,metadata:t==null?void 0:t.metadata,clientSession:this.clientSession})}}buildTransport(e,t,n,r){let i=this.connectionPlan;switch(i.kind){case`stay-offline`:return new D(i.source);case`connect`:var o,s;return new(this.getTransportConstructor(i.mode))({clientSession:this.clientSession,clientSdkKey:i.clientSdkKey,baseUrl:i.baseUrl,resolveUrl:n,metaContext:a(a({},t==null?void 0:t.metadata),{},{sdkName:e.sdkName,sdkVersion:e.sdkVersion,userAgent:de(),host:fe()}),logger:this.logger,fetch:r==null?void 0:r.fetch,connectionRetryDelay:(o=r==null?void 0:r.connectionRetryDelay)==null?(e=>2**Math.min(e,9)*1e3):o,pollingInterval:this.pollingIntervalFor(i.mode,t==null||(s=t.connection)==null?void 0:s.pollingInterval)})}}getTransportConstructor(e){switch(e){case`polling`:return xe;case`streaming`:return v}}async initialize(e){var t=this;t.hasReceivedConfigSet||(t.initializing=!0),await t.submitContext(e,`initialization`)}async updateContext(e){var t=this;switch(t.connectionPlan.kind){case`connect`:await t.submitContext(e,`context update`);return;case`stay-offline`:t.storeContext(t.admittedContextFor(e,`context update`));return}}storeContext(e){this.currentContext=e,this.emit(`contextUpdated`,{context:e})}async submitContext(e,t){var n=this;await n.connectToTransport(n.admittedContextFor(e,t),t)}admittedContextFor(e,t){let n=De(e);switch(n.outcome){case`admitted`:return n.context;case`ignored`:this.logger.error(`[ConfigDirectorClient] Ignored the context supplied for ${t} because its kind '${n.kindSample}' is invalid; continuing as if no context was supplied. A context kind has 1 to 64 characters, using only lowercase letters, digits, '-' and '_'.`),this.telemetryClient.recordInvalidContext(n.kindSample);return}}get context(){return this.currentContext}async connectToTransport(e,t){var n=this;n.submittedContext=e,t===`initialization`&&n.startCachedValuesAdoption();try{n.ready=!1,n.readyPromise=new Promise(e=>{n.readyResolve=e}).then(e=>{e||(n.ready=!0,n.initializing=!1,n.emit(`clientReady`,{action:t}),n.logger.debug(`[ConfigDirectorClient] Received initial payload from the server, client is ready`))});let r=new Date().getTime();await n.transport.connect(e==null?{}:e,n.timeout,t),n.currentContext=e,n.telemetryClient.updateContext(e).catch(e=>n.logger.warn(`[ConfigDirectorClient] Telemetry could not update the context: `,e)),n.emit(`contextUpdated`,{context:e});let i=new Date().getTime()-r,a=n.timeout-i;clearTimeout(n.timeoutTimer),n.timeoutTimer=void 0,a>0&&await Promise.race([n.readyPromise,new Promise(e=>{n.timeoutTimer=setTimeout(()=>e(),a)})]).finally(()=>clearTimeout(n.timeoutTimer)),n.ready||n.logger.warn(`[ConfigDirectorClient] Timed out waiting for ${t} after ${n.timeout}ms. ${n.timeoutWarningDetails()}`)}catch(e){if(e instanceof l)throw n.initializing=!1,e;n.logger.error(`[ConfigDirectorClient] An error occurred during ${t}: `,e)}}timeoutWarningDetails(){switch(this.connectionPlan.kind){case`connect`:return`The client will continue to retry since there were no fatal errors detected. Configs will return the default value until the connection succeeds.`;case`stay-offline`:return`The offline values were not delivered, so configs return the default value.`}}findKeysRemovedBy(e){return!this.configSet||e.kind!=`full`?[]:Object.keys(this.configSet.configs).filter(t=>!Object.prototype.hasOwnProperty.call(e.configs,t))}updateWatchers(e){e.forEach(e=>this.updateWatchersForConfig(e))}updateWatchersForConfig(e){var t,n;let r=(t=this.configSet)==null?void 0:t.configs[e];(n=this.handlersMap.get(e))==null||n.forEach(t=>{let n=this.evaluationOf(e,r,t.defaultValue).value;t.handler(n)})}watch(e,t,n){this.validateDefaultValue(t);let r=this.handlersMap.get(e),i={handler:n,defaultValue:t,requestedType:typeof t};return r?r.push(i):this.handlersMap.set(e,[i]),()=>this.unwatch(e,n)}unwatch(e,t){let n=this.handlersMap.get(e);if(n)if(t){let e=n.findIndex(e=>e.handler==t);e>=0&&(n==null||n.splice(e,1))}else n.splice(0)}getValue(e,t){return this.evaluate(e,t).value}evaluate(e,t){var n;this.validateDefaultValue(t);let r=(n=this.configSet)==null?void 0:n.configs[e];return this.evaluationOf(e,r,t)}evaluationOf(e,t,n){var r,i;if(!t){var a;this.logger.debug(`[ConfigDirectorClient] No config state found for '${e}', returning default value '${n}'`);let t=this.isReady?`config-state-missing`:`client-not-ready`;this.telemetryClient.evaluatedConfig({contextId:(a=this.currentContext)==null?void 0:a.id,key:e,defaultValue:n,requestedType:k(n),evaluatedValue:n,usedDefault:!0,evaluationReason:t});let r={key:e,value:n,isDefaultValue:!0,reason:t,context:this.context};return this.dispatchEvaluationEvent(r),r}let o=se(t,n),s=this.servedReason(o.reason);this.telemetryClient.evaluatedConfig({contextId:(r=this.currentContext)==null?void 0:r.id,type:t.type,key:e,defaultValue:n,requestedType:o.requestedType,evaluatedValue:o.parsedValue,evaluatedValueId:o.parsedValueId,usedDefault:o.usedDefault,evaluationReason:s});let c={key:e,value:o.parsedValue,valueId:(i=o.parsedValueId)==null?void 0:i,isDefaultValue:o.usedDefault,reason:s,context:this.context};return this.dispatchEvaluationEvent(c),this.logger.debug(`[ConfigDirectorClient] Evaluated '${e}' to '${o.parsedValue}'`),c}dispatchEvaluationEvent(e){setTimeout(()=>this.emit(`configEvaluated`,{evaluation:e}),0)}emit(e,t){try{this.eventEmitter.emit(e,t)}catch(t){this.logger.error(`[ConfigDirectorClient] Error executing event handlers for '${e}'`,t)}}validateDefaultValue(e){if(e==null)throw new c(`Invalid default value. The default value for a config must be defined and non-null.`);if(typeof e==`function`)throw new c(`Invalid default value. The default value for a config cannot be a function.`)}get isReady(){return this.ready}get isInitializing(){return this.initializing}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.logger.debug(`[ConfigDirectorClient] clear() has been called, removing all observers`),this.eventEmitter.clear(),this.handlersMap.clear()}unwatchAll(){this.handlersMap.clear()}pauseNetwork(){switch(this.connectionPlan.kind){case`stay-offline`:return;case`connect`:this.logger.debug(`[ConfigDirectorClient] pauseNetwork() called, pausing transport connection`),clearTimeout(this.timeoutTimer),this.timeoutTimer=void 0,this.transport.close(),this.ready=!1;return}}async resumeNetwork(){var e=this;switch(e.connectionPlan.kind){case`stay-offline`:return;case`connect`:await e.connectToTransport(e.currentContext,`network resume`);return}}async close(){var e=this,t;e.logger.debug(`[ConfigDirectorClient] close() has been called, closing connection to server`),clearTimeout(e.timeoutTimer),(t=e.readyResolve)==null||t.call(e,!0),e.telemetryClient.close().catch(t=>e.logger.warn(`[ConfigDirectorClient] Telemetry could not close: `,t)),e.transport.close(),e.ready=!1,e.initializing=!1}dispose(){this.clear(),this.close()}};const $=Symbol.for(`@configdirector/installed-test-client`),He=()=>globalThis[$];export{Me as a,H as c,s as d,c as f,je as i,V as l,a as m,He as n,K as o,o as p,Ve as r,U as s,$ as t,T as u};
|
|
6
|
-
//# sourceMappingURL=installedTestClient-cBWU0-t8.mjs.map
|