@configdirector/nuxt-sdk 0.2.0 → 0.5.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/module.json CHANGED
@@ -4,5 +4,5 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.0.0"
6
6
  },
7
- "version": "0.2.0"
7
+ "version": "0.5.0"
8
8
  }
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorClient } from "../../types-KSnINlzh.mjs";
1
+ import { t as ConfigDirectorClient } from "../../types-D9IS8RoC.mjs";
2
2
 
3
3
  //#region src/runtime/app/composables/useConfigDirectorClient.d.ts
4
4
  declare const useConfigDirectorClient: () => {
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorClient } from "../../types-KSnINlzh.mjs";
1
+ import { t as ConfigDirectorClient } from "../../types-D9IS8RoC.mjs";
2
2
 
3
3
  //#region src/runtime/app/composables/useConfigDirectorClient.d.ts
4
4
  declare const useConfigDirectorClient: () => {
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorContext } from "../../types-CQWNx-gI.mjs";
1
+ import { t as ConfigDirectorContext } from "../../types-BWxsGnk2.mjs";
2
2
  import { Ref } from "vue";
3
3
 
4
4
  //#region src/runtime/app/composables/useConfigDirectorContext.d.ts
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorContext } from "../../types-CQWNx-gI.mjs";
1
+ import { t as ConfigDirectorContext } from "../../types-BWxsGnk2.mjs";
2
2
  import { Ref } from "vue";
3
3
 
4
4
  //#region src/runtime/app/composables/useConfigDirectorContext.d.ts
@@ -1,4 +1,4 @@
1
- import { n as ConfigValueType } from "../../types-CQWNx-gI.mjs";
1
+ import { r as ConfigValueType } from "../../types-BWxsGnk2.mjs";
2
2
  import { t as ClientStatus } from "../../types-CkzBXJwA.mjs";
3
3
  import { DeepReadonly, Ref, ShallowRef } from "vue";
4
4
 
@@ -1,4 +1,4 @@
1
- import { n as ConfigValueType } from "../../types-CQWNx-gI.mjs";
1
+ import { r as ConfigValueType } from "../../types-BWxsGnk2.mjs";
2
2
  import { t as ClientStatus } from "../../types-CkzBXJwA.mjs";
3
3
  import { DeepReadonly, Ref, ShallowRef } from "vue";
4
4
 
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorClient } from "../types-D9MFb76Q.mjs";
1
+ import { t as ConfigDirectorClient } from "../types-DGQ1B6mZ.mjs";
2
2
  import * as _$nitropack from "nitropack";
3
3
 
4
4
  //#region src/runtime/nitro/plugin.d.ts
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorClient } from "../types-D9MFb76Q.mjs";
1
+ import { t as ConfigDirectorClient } from "../types-DGQ1B6mZ.mjs";
2
2
  import * as _$nitropack from "nitropack";
3
3
 
4
4
  //#region src/runtime/nitro/plugin.d.ts
@@ -380,7 +380,7 @@ var StreamingTransport = class {
380
380
  this.dispatchMessage(data);
381
381
  },
382
382
  onConnect: () => {
383
- this.logger.debug("[EventSourceTransport] Connected");
383
+ this.logger.debug("[StreamingTransport] Connected");
384
384
  resolve(this);
385
385
  },
386
386
  shouldReconnect: (state) => {
@@ -390,11 +390,13 @@ var StreamingTransport = class {
390
390
  },
391
391
  calculateReconnectDelay: (state) => {
392
392
  const delay = Math.pow(2, Math.min(state.attempt, MAX_EXPONENTIAL_DELAY)) * 1e3;
393
- this.logger.warn(`[EventSourceTransport] Scheduling reconnect in ${delay}ms.`);
393
+ const logMessage = `[StreamingTransport] Scheduling reconnect attempt #${state.attempt} in ${delay}ms.`;
394
+ if (state.attempt <= 5) this.logger.info(logMessage);
395
+ else this.logger.warn(logMessage);
394
396
  return delay;
395
397
  },
396
398
  onDisconnect: () => {
397
- this.logger.debug("[EventSourceTransport] Disconnected");
399
+ this.logger.debug("[StreamingTransport] Disconnected");
398
400
  }
399
401
  });
400
402
  this.eventSource.connect();
@@ -408,7 +410,7 @@ var StreamingTransport = class {
408
410
  const json = JSON.parse(data);
409
411
  this.eventEmitter.emit("configBundleReceived", json);
410
412
  } catch (error) {
411
- this.logger.error("[EventSourceTransport] Error parsing and dispatching config data update: ", error);
413
+ this.logger.error("[StreamingTransport] Error parsing and dispatching config data update: ", error);
412
414
  }
413
415
  }
414
416
  prepareFatalError(responseStatus, error) {
@@ -851,6 +853,7 @@ const parseConfigValue = (configState, defaultValue) => {
851
853
  usedDefault: true,
852
854
  reason: "value-missing"
853
855
  };
856
+ if (configState.type === "json") return parseJson(value, defaultValue, requestedType);
854
857
  if (typeof defaultValue === "string") return {
855
858
  parsedValue: value,
856
859
  requestedType,
@@ -912,6 +915,29 @@ const parseConfigFloat = (value) => {
912
915
  if (isNaN(num) || !isFinite(num)) return;
913
916
  return num;
914
917
  };
918
+ const parseJson = (jsonString, defaultValue, requestedType) => {
919
+ if (typeof defaultValue === "string") return {
920
+ parsedValue: jsonString,
921
+ requestedType,
922
+ usedDefault: false,
923
+ reason: "found-match"
924
+ };
925
+ try {
926
+ return {
927
+ parsedValue: JSON.parse(jsonString),
928
+ requestedType,
929
+ usedDefault: false,
930
+ reason: "found-match"
931
+ };
932
+ } catch {
933
+ return {
934
+ parsedValue: defaultValue,
935
+ requestedType,
936
+ usedDefault: true,
937
+ reason: "invalid-json"
938
+ };
939
+ }
940
+ };
915
941
  //#endregion
916
942
  //#region ../shared/src/logger.ts
917
943
  const LEVELS = {
@@ -982,7 +1008,7 @@ const defaultUrlFactory = (input, base) => new URL(input, base?.toString());
982
1008
  //#region ../shared/src/telemetry/utils.ts
983
1009
  const CONFIG_VALUE_MAX_LENGTH = 500;
984
1010
  const sanitizeValue = (value, type) => {
985
- if (type === "json") try {
1011
+ if (type === "json" || type == null && typeof value === "object") try {
986
1012
  return djb2Hash(JSON.stringify(value));
987
1013
  } catch {
988
1014
  return value.toString().slice(0, CONFIG_VALUE_MAX_LENGTH);
@@ -1420,14 +1446,16 @@ var DefaultConfigDirectorClient = class {
1420
1446
  }
1421
1447
  getValueFromConfigDefinition(configKey, configDefinition, defaultValue, context) {
1422
1448
  if (configDefinition) {
1423
- const parseResult = parseConfigValue(this.configEvaluator.evaluate(configDefinition, {
1449
+ const configState = this.configEvaluator.evaluate(configDefinition, {
1424
1450
  context,
1425
1451
  metadata: this.metaContext
1426
- }), defaultValue);
1452
+ });
1453
+ const parseResult = parseConfigValue(configState, defaultValue);
1427
1454
  this.usageEventCollector.evaluatedConfig({
1428
1455
  context,
1429
1456
  evaluation: {
1430
1457
  key: configKey,
1458
+ type: configState.type,
1431
1459
  defaultValue,
1432
1460
  requestedType: parseResult.requestedType,
1433
1461
  evaluatedValue: parseResult.parsedValue,
@@ -1483,6 +1511,15 @@ var DefaultConfigDirectorClient = class {
1483
1511
  unwatchAll() {
1484
1512
  this.handlersMap.clear();
1485
1513
  }
1514
+ getAllConfigs(options) {
1515
+ if (!this.configSet) return {};
1516
+ const entries = Object.entries(this.configSet.configs);
1517
+ const filtered = options?.configKeys ? entries.filter(([key]) => options.configKeys?.includes(key)) : entries;
1518
+ return Object.fromEntries(filtered.map(([key, config]) => [key, this.configEvaluator.evaluate(config, {
1519
+ context: options?.context,
1520
+ metadata: this.metaContext
1521
+ })]));
1522
+ }
1486
1523
  closeConnection() {
1487
1524
  this.logger.debug("[ConfigDirectorClient] closeConnection() has been called, closing connection to server");
1488
1525
  this.transport.close();
@@ -1514,7 +1551,7 @@ var plugin_default = defineNitroPlugin((nitroApp) => {
1514
1551
  const { serverSdkKey, baseUrl } = runtimeConfig.configdirector;
1515
1552
  const client = new DefaultConfigDirectorClient(serverSdkKey, {
1516
1553
  sdkName: "nuxt-sdk",
1517
- sdkVersion: "0.2.0"
1554
+ sdkVersion: "0.5.0"
1518
1555
  }, {
1519
1556
  logger,
1520
1557
  ...baseUrl ? { connection: { url: baseUrl } } : {}
@@ -413,7 +413,7 @@ var StreamingTransport = class {
413
413
  this.dispatchMessage(data);
414
414
  },
415
415
  onConnect: () => {
416
- this.logger.debug("[EventSourceTransport] Connected");
416
+ this.logger.debug("[StreamingTransport] Connected");
417
417
  resolve(this);
418
418
  },
419
419
  shouldReconnect: (state) => {
@@ -423,14 +423,16 @@ var StreamingTransport = class {
423
423
  },
424
424
  calculateReconnectDelay: (state) => {
425
425
  const delay = this.options.connectionRetryDelay(state.attempt);
426
- this.logger.warn(`[EventSourceTransport] Scheduling reconnect in ${delay}ms.`);
426
+ const logMessage = `[StreamingTransport] Scheduling reconnect attempt #${state.attempt} in ${delay}ms.`;
427
+ if (state.attempt <= 5) this.logger.info(logMessage);
428
+ else this.logger.warn(logMessage);
427
429
  return delay;
428
430
  },
429
431
  onError: (error) => {
430
- this.logger.debug("[EventSourceTransport] Error: ", error);
432
+ this.logger.debug("[StreamingTransport] Error: ", error);
431
433
  },
432
434
  onDisconnect: () => {
433
- this.logger.debug("[EventSourceTransport] Disconnected");
435
+ this.logger.debug("[StreamingTransport] Disconnected");
434
436
  }
435
437
  });
436
438
  this.eventSource.connect();
@@ -446,7 +448,7 @@ var StreamingTransport = class {
446
448
  const json = JSON.parse(data);
447
449
  this.eventEmitter.emit("configSetReceived", json);
448
450
  } catch (error) {
449
- this.logger.error("[EventSourceTransport] Error parsing and dispatching config data update: ", error);
451
+ this.logger.error("[StreamingTransport] Error parsing and dispatching config data update: ", error);
450
452
  }
451
453
  }
452
454
  prepareFatalError(responseStatus, error) {
@@ -503,6 +505,7 @@ const parseConfigValue = (configState, defaultValue) => {
503
505
  usedDefault: true,
504
506
  reason: "value-missing"
505
507
  };
508
+ if (configState.type === "json") return parseJson(value, defaultValue, requestedType);
506
509
  if (typeof defaultValue === "string") return {
507
510
  parsedValue: value,
508
511
  requestedType,
@@ -564,6 +567,29 @@ const parseConfigFloat = (value) => {
564
567
  if (isNaN(num) || !isFinite(num)) return;
565
568
  return num;
566
569
  };
570
+ const parseJson = (jsonString, defaultValue, requestedType) => {
571
+ if (typeof defaultValue === "string") return {
572
+ parsedValue: jsonString,
573
+ requestedType,
574
+ usedDefault: false,
575
+ reason: "found-match"
576
+ };
577
+ try {
578
+ return {
579
+ parsedValue: JSON.parse(jsonString),
580
+ requestedType,
581
+ usedDefault: false,
582
+ reason: "found-match"
583
+ };
584
+ } catch {
585
+ return {
586
+ parsedValue: defaultValue,
587
+ requestedType,
588
+ usedDefault: true,
589
+ reason: "invalid-json"
590
+ };
591
+ }
592
+ };
567
593
  //#endregion
568
594
  //#region ../shared/src/logger.ts
569
595
  const LEVELS = {
@@ -937,6 +963,7 @@ var DefaultConfigDirectorClient = class {
937
963
  const parseResult = parseConfigValue(configState, defaultValue);
938
964
  this.telemetryClient.evaluatedConfig({
939
965
  contextId: this.currentContext?.id,
966
+ type: configState.type,
940
967
  key: configKey,
941
968
  defaultValue,
942
969
  requestedType: parseResult.requestedType,
@@ -1006,7 +1033,7 @@ var DefaultConfigDirectorClient = class {
1006
1033
  //#region ../shared/src/telemetry/utils.ts
1007
1034
  const CONFIG_VALUE_MAX_LENGTH = 500;
1008
1035
  const sanitizeValue = (value, type) => {
1009
- if (type === "json") try {
1036
+ if (type === "json" || type == null && typeof value === "object") try {
1010
1037
  return djb2Hash(JSON.stringify(value));
1011
1038
  } catch {
1012
1039
  return value.toString().slice(0, CONFIG_VALUE_MAX_LENGTH);
@@ -1044,7 +1071,7 @@ var WebWorkerTelemetryClient = class {
1044
1071
  flushIntervalDelay: options.flushIntervalDelay ?? 3e4
1045
1072
  }
1046
1073
  };
1047
- this.worker = new Worker(URL.createObjectURL(new Blob(["(function(){let e=(e,n)=>{if(n===`json`)try{return t(JSON.stringify(e))}catch{return e.toString().slice(0,500)}return e.toString().slice(0,500)},t=e=>n(new TextEncoder().encode(e)).toString(16).padStart(8,`0`),n=e=>{let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+(e[n]??0),t>>>=0;return t},r=e=>{let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]?.length??0)>0)return!1;return!0},i=e=>{if(!e)return!0;let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]??0)>0)return!1;return!0},a=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}},o=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var s=class{constructor(e){this.executeRequests=!0,this.sdkKey=e.sdkKey,this.logger=e.logger,this.url=e.urlFactory(`client/telemetry/v1`,e.baseUrl)}async report({context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r}){if(!this.executeRequests)return{success:!1,fatalError:!0};let i={clientSdkKey:this.sdkKey,context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r};if(this.isReportEmpty(i))return{success:!0,fatalError:!1};let a=await this.sendReport(i);return a.fatalError&&(this.executeRequests=!1),a}isReportEmpty(e){return r(e.discreteEvents)&&r(e.aggregatedEvents)&&i(e.droppedEvents)}async sendReport(e){try{let t=await a(5e3,this.url,{method:`POST`,body:JSON.stringify(e),keepalive:!0},this.logger),n=this.isStatusFatal(t.status);return n&&this.logger.warn(`[EventReporter] Received a fatal status response (${t.status}) from the telemetry endpoint. No more telemetry data will be sent.`),{success:t.ok,fatalError:n}}catch(e){let t=o(e);return this.logger.warn(`[EventReporter] Error attempting to send telemetry data: ${e}`,{error:e}),{success:!1,fatalError:t}}}isStatusFatal(e){return!!e&&e>=400&&e<500}},c=class{aggregate(e){if(e.events.length==0)return[];let t=new Map;for(let n of e.events){let e=JSON.stringify(n),r=t.get(e)?.count||0;t.set(e,{event:n,count:r+1})}return Array.from(t).map(([,t])=>({startTime:e.startTime,endTime:e.endTime,count:t.count,event:t.event}))}},l=class{constructor(e){this._events=[],this._droppedEventCount=0,this.limit=e??1e3}get events(){return this._events}get reachedLimit(){return this._events.length>=this.limit}get droppedEventCount(){return this._droppedEventCount}push(...e){this.startTime||=new Date;let t=Math.max(0,e.length-this.limit),n=e.slice(t,e.length);if(this._droppedEventCount+=t,this._events.length+n.length>this.limit){let e=this._events.length+n.length-this.limit;this._events.splice(0,e),this._droppedEventCount+=e}return this._events.push(...n)}takeSnapshot(){let e=new Date,t=this.startTime??e,n=this._events.splice(0),r=this._droppedEventCount;return this.startTime=void 0,this._droppedEventCount=0,{startTime:t,endTime:e,events:n,droppedCount:r}}clear(){this._events=[],this.startTime=void 0,this._droppedEventCount=0}},u=class{constructor(e){this.aggregator=new c,this.collectEvents=!0,this.logger=e.logger,this.evaluationEventQueue=new l(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4;let t=e.initialFlushIntervalDelay??5e3;this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),t)}sanitizeValue(t,n){return e(t,n)}async flushAndScheduleNext(){(await this.flush()).fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay)}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=this.evaluationEventQueue.takeSnapshot();return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e)},droppedEvents:{evaluatedConfig:e.droppedCount}})}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout),await this.flush(),this.evaluationEventQueue.clear()}dispose(){this.close()}},d=class extends u{constructor(e){super(e),this.reporter=new s(e)}async updateContext(e){this.cancelScheduledFlush(),await this.flush(),this._context=e,await this.flushAndScheduleNext()}evaluatedConfig(e){this.collectEvents&&this.evaluationEventQueue.push(e)}async forceFlush(){this.cancelScheduledFlush(),await this.flushAndScheduleNext()}};let f=(e,t)=>new URL(e,t?.toString()),p,m=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),h=e=>{try{self.postMessage(e)}catch{self.postMessage(m(e.payload.level,e.payload.message))}},g={debug:function(e,...t){h(m(`debug`,e,t))},info:function(e,...t){h(m(`info`,e,t))},warn:function(e,...t){h(m(`warn`,e,t))},error:function(e,...t){h(m(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!p){g.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(g.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:p=new d({...t.payload,baseUrl:f(t.payload.baseUrl),urlFactory:f,logger:g});break;case`EvaluatedConfigEvent`:p?.evaluatedConfig(t.payload);break;case`UpdateContext`:p?.updateContext(t.payload.context);break;case`Flush`:p?.forceFlush();break;case`Close`:(p?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"], { type: "application/javascript" })));
1074
+ this.worker = new Worker(URL.createObjectURL(new Blob(["(function(){let e=(e,n)=>{if(n===`json`||n==null&&typeof e==`object`)try{return t(JSON.stringify(e))}catch{return e.toString().slice(0,500)}return e.toString().slice(0,500)},t=e=>n(new TextEncoder().encode(e)).toString(16).padStart(8,`0`),n=e=>{let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+(e[n]??0),t>>>=0;return t},r=e=>{let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]?.length??0)>0)return!1;return!0},i=e=>{if(!e)return!0;let t=Object.keys(e);if(t.length==0)return!0;for(let n of t)if((e[n]??0)>0)return!1;return!0},a=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}},o=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var s=class{constructor(e){this.executeRequests=!0,this.sdkKey=e.sdkKey,this.logger=e.logger,this.url=e.urlFactory(`client/telemetry/v1`,e.baseUrl)}async report({context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r}){if(!this.executeRequests)return{success:!1,fatalError:!0};let i={clientSdkKey:this.sdkKey,context:e,discreteEvents:t,aggregatedEvents:n,droppedEvents:r};if(this.isReportEmpty(i))return{success:!0,fatalError:!1};let a=await this.sendReport(i);return a.fatalError&&(this.executeRequests=!1),a}isReportEmpty(e){return r(e.discreteEvents)&&r(e.aggregatedEvents)&&i(e.droppedEvents)}async sendReport(e){try{let t=await a(5e3,this.url,{method:`POST`,body:JSON.stringify(e),keepalive:!0},this.logger),n=this.isStatusFatal(t.status);return n&&this.logger.warn(`[EventReporter] Received a fatal status response (${t.status}) from the telemetry endpoint. No more telemetry data will be sent.`),{success:t.ok,fatalError:n}}catch(e){let t=o(e);return this.logger.warn(`[EventReporter] Error attempting to send telemetry data: ${e}`,{error:e}),{success:!1,fatalError:t}}}isStatusFatal(e){return!!e&&e>=400&&e<500}},c=class{aggregate(e){if(e.events.length==0)return[];let t=new Map;for(let n of e.events){let e=JSON.stringify(n),r=t.get(e)?.count||0;t.set(e,{event:n,count:r+1})}return Array.from(t).map(([,t])=>({startTime:e.startTime,endTime:e.endTime,count:t.count,event:t.event}))}},l=class{constructor(e){this._events=[],this._droppedEventCount=0,this.limit=e??1e3}get events(){return this._events}get reachedLimit(){return this._events.length>=this.limit}get droppedEventCount(){return this._droppedEventCount}push(...e){this.startTime||=new Date;let t=Math.max(0,e.length-this.limit),n=e.slice(t,e.length);if(this._droppedEventCount+=t,this._events.length+n.length>this.limit){let e=this._events.length+n.length-this.limit;this._events.splice(0,e),this._droppedEventCount+=e}return this._events.push(...n)}takeSnapshot(){let e=new Date,t=this.startTime??e,n=this._events.splice(0),r=this._droppedEventCount;return this.startTime=void 0,this._droppedEventCount=0,{startTime:t,endTime:e,events:n,droppedCount:r}}clear(){this._events=[],this.startTime=void 0,this._droppedEventCount=0}},u=class{constructor(e){this.aggregator=new c,this.collectEvents=!0,this.logger=e.logger,this.evaluationEventQueue=new l(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4;let t=e.initialFlushIntervalDelay??5e3;this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),t)}sanitizeValue(t,n){return e(t,n)}async flushAndScheduleNext(){(await this.flush()).fatalError?(this.collectEvents=!1,this.close(),this.logger.warn(`[TelemetryEventCollector] Received a fatal error from telemetry collection. No longer collecting events.`)):this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),this.flushIntervalDelay)}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=this.evaluationEventQueue.takeSnapshot();return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e)},droppedEvents:{evaluatedConfig:e.droppedCount}})}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout),await this.flush(),this.evaluationEventQueue.clear()}dispose(){this.close()}},d=class extends u{constructor(e){super(e),this.reporter=new s(e)}async updateContext(e){this.cancelScheduledFlush(),await this.flush(),this._context=e,await this.flushAndScheduleNext()}evaluatedConfig(e){this.collectEvents&&this.evaluationEventQueue.push(e)}async forceFlush(){this.cancelScheduledFlush(),await this.flushAndScheduleNext()}};let f=(e,t)=>new URL(e,t?.toString()),p,m=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),h=e=>{try{self.postMessage(e)}catch{self.postMessage(m(e.payload.level,e.payload.message))}},g={debug:function(e,...t){h(m(`debug`,e,t))},info:function(e,...t){h(m(`info`,e,t))},warn:function(e,...t){h(m(`warn`,e,t))},error:function(e,...t){h(m(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!p){g.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(g.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:p=new d({...t.payload,baseUrl:f(t.payload.baseUrl),urlFactory:f,logger:g});break;case`EvaluatedConfigEvent`:p?.evaluatedConfig(t.payload);break;case`UpdateContext`:p?.updateContext(t.payload.context);break;case`Flush`:p?.forceFlush();break;case`Close`:(p?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"], { type: "application/javascript" })));
1048
1075
  this.worker.onmessage = (message) => {
1049
1076
  this.handleWorkerEvent(message.data);
1050
1077
  };
@@ -1184,7 +1211,7 @@ var plugin_client_default = defineNuxtPlugin((nuxtApp) => {
1184
1211
  const { clientSdkKey, appName, appVersion, baseUrl } = runtimeConfig.public.configdirector;
1185
1212
  const client = createBrowserClient(clientSdkKey, {
1186
1213
  sdkName: "nuxt-sdk",
1187
- sdkVersion: "0.2.0"
1214
+ sdkVersion: "0.5.0"
1188
1215
  }, {
1189
1216
  metadata: {
1190
1217
  appName,
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorClient } from "../../types-D9MFb76Q.mjs";
1
+ import { t as ConfigDirectorClient } from "../../types-DGQ1B6mZ.mjs";
2
2
 
3
3
  //#region src/runtime/server/composables/useConfigDirectorClient.d.ts
4
4
  declare const useConfigDirectorClient: () => ConfigDirectorClient;
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorClient } from "../../types-D9MFb76Q.mjs";
1
+ import { t as ConfigDirectorClient } from "../../types-DGQ1B6mZ.mjs";
2
2
 
3
3
  //#region src/runtime/server/composables/useConfigDirectorClient.d.ts
4
4
  declare const useConfigDirectorClient: () => ConfigDirectorClient;
@@ -1,8 +1,16 @@
1
1
  //#region ../shared/src/types.d.ts
2
+ declare const ConfigTypeList: readonly ["custom", "boolean", "string", "integer", "float", "enum", "url", "json"];
3
+ type ConfigType = (typeof ConfigTypeList)[number];
2
4
  type ConfigEnumLikeType = {
3
5
  [key: string]: string | number;
4
6
  };
5
7
  type ConfigValueType = string | number | boolean | object | ConfigEnumLikeType;
8
+ type ConfigState = {
9
+ id: string;
10
+ key: string;
11
+ type: ConfigType;
12
+ value: string | undefined | null;
13
+ };
6
14
  /**
7
15
  * The user's context to be sent to ConfigDirector. This context will be used for targeting
8
16
  * rules evaluation.
@@ -31,4 +39,4 @@ type ConfigDirectorContext = {
31
39
  };
32
40
  };
33
41
  //#endregion
34
- export { ConfigValueType as n, ConfigDirectorContext as t };
42
+ export { ConfigState as n, ConfigValueType as r, ConfigDirectorContext as t };
@@ -1,4 +1,4 @@
1
- import { n as ConfigValueType, t as ConfigDirectorContext } from "./types-CQWNx-gI.mjs";
1
+ import { r as ConfigValueType, t as ConfigDirectorContext } from "./types-BWxsGnk2.mjs";
2
2
 
3
3
  //#region ../js-client-core/src/Emitter.d.ts
4
4
  type EventType = string | symbol;
@@ -1,4 +1,4 @@
1
- import { n as ConfigValueType, t as ConfigDirectorContext } from "./types-CQWNx-gI.mjs";
1
+ import { n as ConfigState, r as ConfigValueType, t as ConfigDirectorContext } from "./types-BWxsGnk2.mjs";
2
2
 
3
3
  //#region ../js-server-sdk/src/types.d.ts
4
4
  type ClientEvents = {
@@ -71,6 +71,17 @@ interface ConfigDirectorClient {
71
71
  * Removes all subscribers from all config keys
72
72
  */
73
73
  unwatchAll(): void;
74
+ /**
75
+ * Returns the evaluated {@link ConfigState} for every known config key, or only the keys
76
+ * listed in `configKeys` when provided.
77
+ *
78
+ * Intended for SSR hydration — does NOT record telemetry events. Returns an empty object
79
+ * when the client is not yet ready.
80
+ */
81
+ getAllConfigs(options?: {
82
+ context?: ConfigDirectorContext;
83
+ configKeys?: string[];
84
+ }): Record<string, ConfigState>;
74
85
  on<T extends keyof ClientEvents>(eventName: T, handler: (args: ClientEvents[T]) => void): void;
75
86
  off<T extends keyof ClientEvents>(eventName: T, handler?: (args: ClientEvents[T]) => void): void;
76
87
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configdirector/nuxt-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.5.0",
4
4
  "description": "Nuxt SDK for ConfigDirector. ConfigDirector is a remote configuration and feature flag service.",
5
5
  "license": "MIT",
6
6
  "author": "ConfigDirector",
@@ -64,13 +64,13 @@
64
64
  "changelogen": "^0.6.2",
65
65
  "eslint": "^10.2.1",
66
66
  "nuxt": "^4.4.6",
67
- "playwright": "^1.52.0",
67
+ "playwright": "^1.60.0",
68
68
  "rimraf": "^6.1.3",
69
69
  "tsdown": "^0.21.7",
70
70
  "tslib": "^2.8.1",
71
71
  "typescript": "~6.0.3",
72
72
  "vite": "^8.0.10",
73
- "vitest": "^4.1.4",
73
+ "vitest": "^4.1.8",
74
74
  "vue-tsc": "^3.2.7"
75
75
  }
76
76
  }