@configdirector/nuxt-sdk 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +9 -0
  3. package/dist/runtime/app/composables/useConfigDirectorClient.d.mts +1 -1
  4. package/dist/runtime/app/composables/useConfigDirectorClient.d.ts +1 -1
  5. package/dist/runtime/app/composables/useConfigDirectorClientHooks.d.mts +6 -0
  6. package/dist/runtime/app/composables/useConfigDirectorClientHooks.d.ts +6 -0
  7. package/dist/runtime/app/composables/useConfigDirectorClientHooks.mjs +22 -0
  8. package/dist/runtime/app/composables/useConfigDirectorContext.d.mts +1 -1
  9. package/dist/runtime/app/composables/useConfigDirectorContext.d.ts +1 -1
  10. package/dist/runtime/app/composables/useConfigDirectorValue.d.mts +1 -1
  11. package/dist/runtime/app/composables/useConfigDirectorValue.d.ts +1 -1
  12. package/dist/runtime/nitro/plugin.d.mts +1 -1
  13. package/dist/runtime/nitro/plugin.d.ts +1 -1
  14. package/dist/runtime/nitro/plugin.mjs +39 -13
  15. package/dist/runtime/plugin.client.mjs +73 -10
  16. package/dist/runtime/server/composables/useConfigDirectorClient.d.mts +1 -1
  17. package/dist/runtime/server/composables/useConfigDirectorClient.d.ts +1 -1
  18. package/dist/runtime/server/composables/useConfigDirectorServerHooks.d.mts +6 -0
  19. package/dist/runtime/server/composables/useConfigDirectorServerHooks.d.ts +6 -0
  20. package/dist/runtime/server/composables/useConfigDirectorServerHooks.mjs +14 -0
  21. package/dist/runtime/{types-DE44nrVT.d.mts → types-B4EK1B6g.d.mts} +12 -2
  22. package/dist/runtime/{types-BqdrorBY.d.mts → types-CHmsCChN.d.mts} +10 -1
  23. package/dist/runtime/{types-Ce8HdKnT.d.mts → types-CzmBIfqo.d.mts} +11 -2
  24. package/package.json +2 -2
package/dist/module.json CHANGED
@@ -4,5 +4,5 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.0.0"
6
6
  },
7
- "version": "0.8.0"
7
+ "version": "0.9.1"
8
8
  }
package/dist/module.mjs CHANGED
@@ -37,6 +37,10 @@ var module_default = defineNuxtModule({
37
37
  name: "useConfigDirectorClient",
38
38
  as: "useConfigDirectorClient",
39
39
  from: resolver.resolve("./runtime/server/composables/useConfigDirectorClient")
40
+ }, {
41
+ name: "useConfigDirectorServerHooks",
42
+ as: "useConfigDirectorServerHooks",
43
+ from: resolver.resolve("./runtime/server/composables/useConfigDirectorServerHooks")
40
44
  }]);
41
45
  addPlugin(resolver.resolve("./runtime/plugin.server"));
42
46
  addPlugin(resolver.resolve("./runtime/plugin.client"));
@@ -60,6 +64,11 @@ var module_default = defineNuxtModule({
60
64
  name: "useConfigDirectorValue",
61
65
  as: "useConfigDirectorValue",
62
66
  from: resolver.resolve("./runtime/app/composables/useConfigDirectorValue")
67
+ },
68
+ {
69
+ name: "useConfigDirectorClientHooks",
70
+ as: "useConfigDirectorClientHooks",
71
+ from: resolver.resolve("./runtime/app/composables/useConfigDirectorClientHooks")
63
72
  }
64
73
  ]);
65
74
  }
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorClient } from "../../types-DE44nrVT.mjs";
1
+ import { n as ConfigDirectorClient } from "../../types-B4EK1B6g.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-DE44nrVT.mjs";
1
+ import { n as ConfigDirectorClient } from "../../types-B4EK1B6g.mjs";
2
2
 
3
3
  //#region src/runtime/app/composables/useConfigDirectorClient.d.ts
4
4
  declare const useConfigDirectorClient: () => {
@@ -0,0 +1,6 @@
1
+ import { t as ClientHooks } from "../../types-B4EK1B6g.mjs";
2
+
3
+ //#region src/runtime/app/composables/useConfigDirectorClientHooks.d.ts
4
+ declare const useConfigDirectorClientHooks: (hooks: ClientHooks) => void;
5
+ //#endregion
6
+ export { useConfigDirectorClientHooks };
@@ -0,0 +1,6 @@
1
+ import { t as ClientHooks } from "../../types-B4EK1B6g.mjs";
2
+
3
+ //#region src/runtime/app/composables/useConfigDirectorClientHooks.d.ts
4
+ declare const useConfigDirectorClientHooks: (hooks: ClientHooks) => void;
5
+ //#endregion
6
+ export { useConfigDirectorClientHooks };
@@ -0,0 +1,22 @@
1
+ import { useNuxtApp } from "#app";
2
+ import { getCurrentInstance, onUnmounted } from "vue";
3
+ //#region src/runtime/app/composables/useConfigDirectorClientHooks.ts
4
+ const useConfigDirectorClientHooks = (hooks) => {
5
+ const { $configDirectorClient } = useNuxtApp();
6
+ const client = $configDirectorClient;
7
+ const hookEntries = Object.entries(hooks);
8
+ for (const [event, handler] of hookEntries) {
9
+ if (!handler) continue;
10
+ const handlers = Array.isArray(handler) ? handler : [handler];
11
+ for (const h of handlers) client.on(event, h);
12
+ }
13
+ if (getCurrentInstance()) onUnmounted(() => {
14
+ for (const [event, handler] of hookEntries) {
15
+ if (!handler) continue;
16
+ const handlers = Array.isArray(handler) ? handler : [handler];
17
+ for (const h of handlers) client.off(event, h);
18
+ }
19
+ });
20
+ };
21
+ //#endregion
22
+ export { useConfigDirectorClientHooks };
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorContext } from "../../types-BqdrorBY.mjs";
1
+ import { t as ConfigDirectorContext } from "../../types-CHmsCChN.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-BqdrorBY.mjs";
1
+ import { t as ConfigDirectorContext } from "../../types-CHmsCChN.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 { r as ConfigValueType } from "../../types-BqdrorBY.mjs";
1
+ import { i as ConfigValueType } from "../../types-CHmsCChN.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 { r as ConfigValueType } from "../../types-BqdrorBY.mjs";
1
+ import { i as ConfigValueType } from "../../types-CHmsCChN.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-Ce8HdKnT.mjs";
1
+ import { n as ConfigDirectorClient } from "../types-CzmBIfqo.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-Ce8HdKnT.mjs";
1
+ import { n as ConfigDirectorClient } from "../types-CzmBIfqo.mjs";
2
2
  import * as _$nitropack from "nitropack";
3
3
 
4
4
  //#region src/runtime/nitro/plugin.d.ts
@@ -2,6 +2,7 @@ import EventEmitter, { EventEmitter as EventEmitter$1 } from "node:events";
2
2
  import { findByPointer } from "@jsonjoy.com/json-pointer";
3
3
  import * as semver from "semver";
4
4
  import { rapidhash } from "rapidhash-js";
5
+ import { createHash } from "node:crypto";
5
6
  import { defineNitroPlugin, useRuntimeConfig } from "nitropack/runtime";
6
7
  import { consola } from "consola";
7
8
  //#region ../shared/src/errors.ts
@@ -862,7 +863,7 @@ const parseConfigValue = (configState, defaultValue) => {
862
863
  usedDefault: false,
863
864
  reason: "found-match"
864
865
  };
865
- if (typeof defaultValue === "boolean" && configState.type === "boolean") {
866
+ if (typeof defaultValue === "boolean" && (configState.type === "boolean" || configState.type === "string")) {
866
867
  const boolValue = parseConfigBoolean(value);
867
868
  const hasBoolean = typeof boolValue === "boolean";
868
869
  return {
@@ -884,7 +885,7 @@ const parseConfigValue = (configState, defaultValue) => {
884
885
  reason: hasNumber ? "found-match" : "invalid-number"
885
886
  };
886
887
  }
887
- if (isNumericNativeType(typeof defaultValue) && (configState.type === "float" || configState.type === "enum")) {
888
+ if (isNumericNativeType(typeof defaultValue) && (configState.type === "float" || configState.type === "enum" || configState.type === "string")) {
888
889
  const numValue = parseConfigFloat(value);
889
890
  const hasNumber = typeof numValue === "number";
890
891
  return {
@@ -1360,17 +1361,11 @@ const toBase62 = (buf, length) => {
1360
1361
  }
1361
1362
  return result.padStart(length, "0");
1362
1363
  };
1364
+ const BASE62_LENGTH = Math.ceil(128 / Math.log2(62));
1363
1365
  //#endregion
1364
- //#region ../shared/src/value-id-generator.ts
1365
- const DIGEST_BYTES = 16;
1366
- const BASE62_LENGTH = Math.ceil(DIGEST_BYTES * 8 / Math.log2(62));
1367
- const sha256 = async (value) => {
1368
- const encoded = new TextEncoder().encode(value);
1369
- const hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", encoded);
1370
- return new Uint8Array(hashBuffer).subarray(0, DIGEST_BYTES);
1371
- };
1366
+ //#region ../js-server-sdk/src/telemetry/value-id-generator.ts
1372
1367
  const generateValueId = async (v) => {
1373
- return toBase62(await sha256(v?.toString() ?? ""), BASE62_LENGTH);
1368
+ return toBase62(createHash("sha256").update(v?.toString() ?? "").digest().subarray(0, 16), BASE62_LENGTH);
1374
1369
  };
1375
1370
  //#endregion
1376
1371
  //#region ../js-server-sdk/src/DefaultConfigDirectorClient.ts
@@ -1395,6 +1390,7 @@ var DefaultConfigDirectorClient = class {
1395
1390
  this.logger = clientOptions?.logger ?? createDefaultLogger$1();
1396
1391
  this.timeout = clientOptions?.connection?.timeout ?? 3e3;
1397
1392
  this.metaContext = clientOptions?.metadata ?? {};
1393
+ this.validateSdkKeyPresence(serverSdkKey);
1398
1394
  this.configEvaluator = new ConfigEvaluator(this.logger);
1399
1395
  const baseUrl = this.parseUrl(clientOptions?.connection?.url) ?? defaultBaseUrl;
1400
1396
  this.connectionMode = clientOptions?.connection?.mode ?? "streaming";
@@ -1438,6 +1434,14 @@ var DefaultConfigDirectorClient = class {
1438
1434
  }
1439
1435
  this.logger.debug(`[ConfigDirectorClient] ConfigSet updated from server with ${configKeys.length} key(s)`, { keys: configKeys });
1440
1436
  });
1437
+ this.registerHandler("clientReady", clientOptions?.hooks?.clientReady);
1438
+ this.registerHandler("configEvaluated", clientOptions?.hooks?.configEvaluated);
1439
+ this.registerHandler("configsUpdated", clientOptions?.hooks?.configsUpdated);
1440
+ }
1441
+ registerHandler(event, handler) {
1442
+ if (!handler) return;
1443
+ const handlers = Array.isArray(handler) ? handler : [handler];
1444
+ for (const h of handlers) if (typeof h === "function") this.on(event, h);
1441
1445
  }
1442
1446
  async initialize() {
1443
1447
  try {
@@ -1526,10 +1530,19 @@ var DefaultConfigDirectorClient = class {
1526
1530
  evaluationReason: parseResult.reason
1527
1531
  }
1528
1532
  });
1533
+ this.dispatchEvaluationEvent({
1534
+ key: configKey,
1535
+ value: parseResult.parsedValue,
1536
+ valueId: parseResult.parsedValueId ?? void 0,
1537
+ isDefaultValue: parseResult.usedDefault,
1538
+ reason: parseResult.reason,
1539
+ context
1540
+ });
1529
1541
  this.logger.debug(`[ConfigDirectorClient] Evaluated '${configKey}' to '${parseResult.parsedValue}'`);
1530
1542
  return parseResult.parsedValue;
1531
1543
  } else {
1532
1544
  this.logger.debug(`[ConfigDirectorClient] No config state found for '${configKey}', returning default value '${defaultValue}'`);
1545
+ const reason = this.isReady ? "config-state-missing" : "client-not-ready";
1533
1546
  this.usageEventCollector.evaluatedConfig({
1534
1547
  context,
1535
1548
  evaluation: {
@@ -1538,12 +1551,22 @@ var DefaultConfigDirectorClient = class {
1538
1551
  requestedType: getRequestedType(defaultValue),
1539
1552
  evaluatedValue: defaultValue,
1540
1553
  usedDefault: true,
1541
- evaluationReason: "config-state-missing"
1554
+ evaluationReason: reason
1542
1555
  }
1543
1556
  });
1557
+ this.dispatchEvaluationEvent({
1558
+ key: configKey,
1559
+ value: defaultValue,
1560
+ isDefaultValue: true,
1561
+ reason,
1562
+ context
1563
+ });
1544
1564
  return defaultValue;
1545
1565
  }
1546
1566
  }
1567
+ dispatchEvaluationEvent(event) {
1568
+ setTimeout(() => this.eventEmitter.emit("configEvaluated", { evaluation: event }), 0);
1569
+ }
1547
1570
  parseUrl(url) {
1548
1571
  if (!url) return;
1549
1572
  try {
@@ -1552,6 +1575,9 @@ var DefaultConfigDirectorClient = class {
1552
1575
  throw new ConfigDirectorValidationError(`Invalid base URL '${url}'. Parsing failed: ${error}`);
1553
1576
  }
1554
1577
  }
1578
+ validateSdkKeyPresence(sdkKey) {
1579
+ if (!sdkKey || sdkKey.trim().length == 0) throw new ConfigDirectorValidationError("No server SDK key was provided, the client cannot be instantiated without a valid server SDK key");
1580
+ }
1555
1581
  validateDefaultValue(defaultValue) {
1556
1582
  if (defaultValue === void 0 || defaultValue === null) throw new ConfigDirectorValidationError("Invalid default value. The default value for a config must be defined and non-null.");
1557
1583
  if (typeof defaultValue === "function") throw new ConfigDirectorValidationError("Invalid default value. The default value for a config cannot be a function.");
@@ -1614,7 +1640,7 @@ var plugin_default = defineNitroPlugin((nitroApp) => {
1614
1640
  const { serverSdkKey, baseUrl } = runtimeConfig.configdirector;
1615
1641
  const client = new DefaultConfigDirectorClient(serverSdkKey, {
1616
1642
  sdkName: "nuxt-sdk",
1617
- sdkVersion: "0.8.0"
1643
+ sdkVersion: "0.9.1"
1618
1644
  }, {
1619
1645
  logger,
1620
1646
  ...baseUrl ? { connection: { url: baseUrl } } : {}
@@ -515,7 +515,7 @@ const parseConfigValue = (configState, defaultValue) => {
515
515
  usedDefault: false,
516
516
  reason: "found-match"
517
517
  };
518
- if (typeof defaultValue === "boolean" && configState.type === "boolean") {
518
+ if (typeof defaultValue === "boolean" && (configState.type === "boolean" || configState.type === "string")) {
519
519
  const boolValue = parseConfigBoolean(value);
520
520
  const hasBoolean = typeof boolValue === "boolean";
521
521
  return {
@@ -537,7 +537,7 @@ const parseConfigValue = (configState, defaultValue) => {
537
537
  reason: hasNumber ? "found-match" : "invalid-number"
538
538
  };
539
539
  }
540
- if (isNumericNativeType(typeof defaultValue) && (configState.type === "float" || configState.type === "enum")) {
540
+ if (isNumericNativeType(typeof defaultValue) && (configState.type === "float" || configState.type === "enum" || configState.type === "string")) {
541
541
  const numValue = parseConfigFloat(value);
542
542
  const hasNumber = typeof numValue === "number";
543
543
  return {
@@ -840,6 +840,7 @@ var DefaultConfigDirectorClient = class {
840
840
  this.instanceId = crypto.randomUUID();
841
841
  this.logger = clientOptions?.logger ?? createDefaultLogger$1();
842
842
  this.timeout = clientOptions?.connection?.timeout ?? 3e3;
843
+ this.validateSdkKeyPresence(clientSdkKey);
843
844
  const urlFactory = internalClientOptions?.urlFactory ?? defaultUrlFactory;
844
845
  const baseUrl = this.parseUrl(clientOptions?.connection?.url, urlFactory) ?? "https://client-sdk-api.configdirector.com";
845
846
  this.connectionMode = clientOptions?.connection?.mode ?? "streaming";
@@ -868,18 +869,27 @@ var DefaultConfigDirectorClient = class {
868
869
  const configKeys = Object.keys(configSet.configs);
869
870
  if (!this.configSet || configSet.kind == "full") {
870
871
  this.configSet = configSet;
871
- this.eventEmitter.emit("configsUpdated", { keys: configKeys });
872
+ this.emit("configsUpdated", { keys: configKeys });
872
873
  this.updateWatchers(configSet.configs);
873
874
  } else {
874
875
  this.configSet.configs = {
875
876
  ...this.configSet.configs,
876
877
  ...configSet.configs
877
878
  };
878
- this.eventEmitter.emit("configsUpdated", { keys: configKeys });
879
+ this.emit("configsUpdated", { keys: configKeys });
879
880
  this.updateWatchers(configSet.configs);
880
881
  }
881
882
  this.logger.debug("[ConfigDirectorClient] ConfigSet updated from server:", { keys: configKeys });
882
883
  });
884
+ this.registerHandler("clientReady", clientOptions?.hooks?.clientReady);
885
+ this.registerHandler("configEvaluated", clientOptions?.hooks?.configEvaluated);
886
+ this.registerHandler("configsUpdated", clientOptions?.hooks?.configsUpdated);
887
+ this.registerHandler("contextUpdated", clientOptions?.hooks?.contextUpdated);
888
+ }
889
+ registerHandler(event, handler) {
890
+ if (!handler) return;
891
+ const handlers = Array.isArray(handler) ? handler : [handler];
892
+ for (const h of handlers) if (typeof h === "function") this.on(event, h);
883
893
  }
884
894
  getTransportConstructor(connectionMode) {
885
895
  switch (connectionMode) {
@@ -906,14 +916,14 @@ var DefaultConfigDirectorClient = class {
906
916
  }).then(() => {
907
917
  this.ready = true;
908
918
  this.initializing = false;
909
- this.eventEmitter.emit("clientReady", { action: caller });
919
+ this.emit("clientReady", { action: caller });
910
920
  this.logger.debug("[ConfigDirectorClient] Received initial payload from the server, client is ready");
911
921
  });
912
922
  const startTime = (/* @__PURE__ */ new Date()).getTime();
913
923
  await this.transport.connect(context ?? {}, this.timeout);
914
924
  this.currentContext = context;
915
925
  this.telemetryClient.updateContext(context);
916
- this.eventEmitter.emit("contextUpdated", { context });
926
+ this.emit("contextUpdated", { context });
917
927
  const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - startTime;
918
928
  const remainingTimeout = this.timeout - elapsedTime;
919
929
  clearTimeout(this.timeoutTimer);
@@ -963,6 +973,7 @@ var DefaultConfigDirectorClient = class {
963
973
  getValueFromConfigState(configKey, configState, defaultValue) {
964
974
  if (!configState) {
965
975
  this.logger.debug(`[ConfigDirectorClient] No config state found for '${configKey}', returning default value '${defaultValue}'`);
976
+ const reason = this.isReady ? "config-state-missing" : "client-not-ready";
966
977
  this.telemetryClient.evaluatedConfig({
967
978
  contextId: this.currentContext?.id,
968
979
  key: configKey,
@@ -970,7 +981,14 @@ var DefaultConfigDirectorClient = class {
970
981
  requestedType: getRequestedType(defaultValue),
971
982
  evaluatedValue: defaultValue,
972
983
  usedDefault: true,
973
- evaluationReason: "config-state-missing"
984
+ evaluationReason: reason
985
+ });
986
+ this.dispatchEvaluationEvent({
987
+ key: configKey,
988
+ value: defaultValue,
989
+ isDefaultValue: true,
990
+ reason,
991
+ context: this.context
974
992
  });
975
993
  return defaultValue;
976
994
  }
@@ -986,9 +1004,27 @@ var DefaultConfigDirectorClient = class {
986
1004
  usedDefault: parseResult.usedDefault,
987
1005
  evaluationReason: parseResult.reason
988
1006
  });
1007
+ this.dispatchEvaluationEvent({
1008
+ key: configKey,
1009
+ value: parseResult.parsedValue,
1010
+ valueId: parseResult.parsedValueId ?? void 0,
1011
+ isDefaultValue: parseResult.usedDefault,
1012
+ reason: parseResult.reason,
1013
+ context: this.context
1014
+ });
989
1015
  this.logger.debug(`[ConfigDirectorClient] Evaluated '${configKey}' to '${parseResult.parsedValue}'`);
990
1016
  return parseResult.parsedValue;
991
1017
  }
1018
+ dispatchEvaluationEvent(event) {
1019
+ setTimeout(() => this.emit("configEvaluated", { evaluation: event }), 0);
1020
+ }
1021
+ emit(name, payload) {
1022
+ try {
1023
+ this.eventEmitter.emit(name, payload);
1024
+ } catch (error) {
1025
+ this.logger.error(`[ConfigDirectorClient] Error executing event handlers for '${name}'`, error);
1026
+ }
1027
+ }
992
1028
  parseUrl(url, urlFactory) {
993
1029
  if (!url) return;
994
1030
  try {
@@ -997,6 +1033,9 @@ var DefaultConfigDirectorClient = class {
997
1033
  throw new ConfigDirectorValidationError(`Invalid base URL '${url}'. Parsing failed: ${error}`);
998
1034
  }
999
1035
  }
1036
+ validateSdkKeyPresence(sdkKey) {
1037
+ if (!sdkKey || sdkKey.trim().length == 0) throw new ConfigDirectorValidationError("No client SDK key was provided, the client cannot be instantiated without a valid client SDK key");
1038
+ }
1000
1039
  validateDefaultValue(defaultValue) {
1001
1040
  if (defaultValue === void 0 || defaultValue === null) throw new ConfigDirectorValidationError("Invalid default value. The default value for a config must be defined and non-null.");
1002
1041
  if (typeof defaultValue === "function") throw new ConfigDirectorValidationError("Invalid default value. The default value for a config cannot be a function.");
@@ -1089,7 +1128,7 @@ var WebWorkerTelemetryClient = class {
1089
1128
  flushIntervalDelay: options.flushIntervalDelay ?? 3e4
1090
1129
  }
1091
1130
  };
1092
- this.worker = new Worker(URL.createObjectURL(new Blob(["(function(){let e=async(e,t)=>e.valueId?{valueId:e.valueId}:e.value?e.value.length<=500&&e.type!=`json`?{value:e.value}:{valueId:await t(e.value)}:e,t=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},n=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},r=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}},i=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var a=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 t(e.discreteEvents)&&t(e.aggregatedEvents)&&n(e.droppedEvents)}async sendReport(e){try{let t=await r(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=i(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}},o=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}))}},s=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}},c=class{constructor(e){this.aggregator=new o,this.collectEvents=!0,this.logger=e.logger,this.evaluationEventQueue=new s(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4;let t=e.initialFlushIntervalDelay??5e3;this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),t)}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)}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout),await this.flush(),this.evaluationEventQueue.clear()}dispose(){this.close()}},l=class{constructor(e){this.valueIdGenerator=e,this.valueIdGenerator=e}async process(t){let n=await Promise.all(t.events.map(async t=>({...t,defaultValue:await e(t.defaultValue,this.valueIdGenerator),evaluatedValue:await e(t.evaluatedValue,this.valueIdGenerator)})));return{...t,events:n}}},u=class extends c{constructor(e){super(e),this.reporter=new a(e),this.evaluationEventSnapshotPreprocessor=new l(e.valueIdGenerator)}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()}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e)},droppedEvents:{evaluatedConfig:e.droppedCount}})}};let d=(e,t)=>new URL(e,t?.toString()),f=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},p=Math.ceil(128/Math.log2(62)),m=async e=>{let t=new TextEncoder().encode(e),n=await globalThis.crypto.subtle.digest(`SHA-256`,t);return new Uint8Array(n).subarray(0,16)},h=async e=>f(await m(e?.toString()??``),p),g,_=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),v=e=>{try{self.postMessage(e)}catch{self.postMessage(_(e.payload.level,e.payload.message))}},y={debug:function(e,...t){v(_(`debug`,e,t))},info:function(e,...t){v(_(`info`,e,t))},warn:function(e,...t){v(_(`warn`,e,t))},error:function(e,...t){v(_(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!g){y.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(y.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:g=new u({...t.payload,baseUrl:d(t.payload.baseUrl),urlFactory:d,valueIdGenerator:h,logger:y});break;case`EvaluatedConfigEvent`:g?.evaluatedConfig(t.payload);break;case`UpdateContext`:g?.updateContext(t.payload.context);break;case`Flush`:g?.forceFlush();break;case`Close`:(g?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"], { type: "application/javascript" })));
1131
+ this.worker = new Worker(URL.createObjectURL(new Blob(["(function(){let e=async(e,t)=>e.valueId?{valueId:e.valueId}:e.value?e.value.length<=500&&e.type!=`json`?{value:e.value}:{valueId:await t(e.value)}:e,t=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},n=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},r=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}},i=e=>e?.name===`NotAllowedError`?!0:e instanceof TypeError;var a=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 t(e.discreteEvents)&&t(e.aggregatedEvents)&&n(e.droppedEvents)}async sendReport(e){try{let t=await r(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=i(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}},o=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}))}},s=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}},c=class{constructor(e){this.aggregator=new o,this.collectEvents=!0,this.logger=e.logger,this.evaluationEventQueue=new s(e.evaluationQueueLimit??1e3),this.flushIntervalDelay=e.flushIntervalDelay??3e4;let t=e.initialFlushIntervalDelay??5e3;this.flushTimeout=setTimeout(()=>this.flushAndScheduleNext(),t)}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)}cancelScheduledFlush(){clearTimeout(this.flushTimeout)}async close(){this.collectEvents=!1,clearTimeout(this.flushTimeout),await this.flush(),this.evaluationEventQueue.clear()}dispose(){this.close()}},l=class{constructor(e){this.valueIdGenerator=e,this.valueIdGenerator=e}async process(t){let n=await Promise.all(t.events.map(async t=>({...t,defaultValue:await e(t.defaultValue,this.valueIdGenerator),evaluatedValue:await e(t.evaluatedValue,this.valueIdGenerator)})));return{...t,events:n}}},u=class extends c{constructor(e){super(e),this.reporter=new a(e),this.evaluationEventSnapshotPreprocessor=new l(e.valueIdGenerator)}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()}async flush(){if(!this.reporter)return{success:!1,fatalError:!1};let e=await this.evaluationEventSnapshotPreprocessor.process(this.evaluationEventQueue.takeSnapshot());return await this.reporter?.report({context:this._context,discreteEvents:{},aggregatedEvents:{evaluatedConfig:this.aggregator.aggregate(e)},droppedEvents:{evaluatedConfig:e.droppedCount}})}};let d=(e,t)=>new URL(e,t?.toString()),f=(e,t)=>{let n=BigInt(0),r=BigInt(62),i=Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),a=BigInt(`0x`+i),o=``;for(;a>n;)o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`[Number(a%r)]+o,a/=r;return o.padStart(t,`0`)},p=Math.ceil(128/Math.log2(62)),m=new TextEncoder,h=async e=>{let t=await crypto.subtle.digest(`SHA-256`,m.encode(e?.toString()??``));return f(new Uint8Array(t,0,16),p)},g,_=(e,t,...n)=>({type:`Log`,payload:{level:e,message:t,args:n}}),v=e=>{try{self.postMessage(e)}catch{self.postMessage(_(e.payload.level,e.payload.message))}},y={debug:function(e,...t){v(_(`debug`,e,t))},info:function(e,...t){v(_(`info`,e,t))},warn:function(e,...t){v(_(`warn`,e,t))},error:function(e,...t){v(_(`error`,e,t))}};addEventListener(`message`,e=>{let t=e.data;if(t.type!=`Initialize`&&!g){y.info(`[TelemetryWorker] Ignoring ${t.type} because no collector is configured`);return}switch(y.debug(`[TelemetryWorker] Received '${t.type}' event:`,t),t.type){case`Initialize`:g=new u({...t.payload,baseUrl:d(t.payload.baseUrl),urlFactory:d,valueIdGenerator:h,logger:y});break;case`EvaluatedConfigEvent`:g?.evaluatedConfig(t.payload);break;case`UpdateContext`:g?.updateContext(t.payload.context);break;case`Flush`:g?.forceFlush();break;case`Close`:(g?.close()??Promise.resolve()).then(()=>{self.postMessage({type:`Closed`}),self.close()});break}})})();"], { type: "application/javascript" })));
1093
1132
  this.worker.onmessage = (message) => {
1094
1133
  this.handleWorkerEvent(message.data);
1095
1134
  };
@@ -1170,6 +1209,29 @@ var WebWorkerTelemetryClient = class {
1170
1209
  }
1171
1210
  };
1172
1211
  //#endregion
1212
+ //#region ../shared/src/base62-encoder.ts
1213
+ const BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1214
+ const toBase62 = (buf, length) => {
1215
+ const ZERO = BigInt(0);
1216
+ const BASE = BigInt(62);
1217
+ const hex = Array.from(buf).map((b) => b.toString(16).padStart(2, "0")).join("");
1218
+ let n = BigInt("0x" + hex);
1219
+ let result = "";
1220
+ while (n > ZERO) {
1221
+ result = BASE62[Number(n % BASE)] + result;
1222
+ n /= BASE;
1223
+ }
1224
+ return result.padStart(length, "0");
1225
+ };
1226
+ const BASE62_LENGTH = Math.ceil(128 / Math.log2(62));
1227
+ //#endregion
1228
+ //#region ../js-browser-client/src/telemetry/value-id-generator.ts
1229
+ const encoder = new TextEncoder();
1230
+ const generateValueId = async (v) => {
1231
+ const hashBuffer = await crypto.subtle.digest("SHA-256", encoder.encode(v?.toString() ?? ""));
1232
+ return toBase62(new Uint8Array(hashBuffer, 0, 16), BASE62_LENGTH);
1233
+ };
1234
+ //#endregion
1173
1235
  //#region ../js-browser-client/src/BrowserConfigDirectorClient.ts
1174
1236
  const createBrowserClient = (clientSdkKey, sdkOptions, clientOptions) => {
1175
1237
  const logger = clientOptions?.logger ?? createDefaultLogger$1();
@@ -1177,7 +1239,8 @@ const createBrowserClient = (clientSdkKey, sdkOptions, clientOptions) => {
1177
1239
  sdkKey: clientSdkKey,
1178
1240
  logger,
1179
1241
  baseUrl: parseUrl(clientOptions?.connection?.url) ?? "https://client-sdk-api.configdirector.com",
1180
- urlFactory: defaultUrlFactory
1242
+ urlFactory: defaultUrlFactory,
1243
+ valueIdGenerator: generateValueId
1181
1244
  }), clientSdkKey, sdkOptions, {
1182
1245
  ...clientOptions,
1183
1246
  logger
@@ -1236,7 +1299,7 @@ var plugin_client_default = defineNuxtPlugin((nuxtApp) => {
1236
1299
  const { clientSdkKey, appName, appVersion, baseUrl } = runtimeConfig.public.configdirector;
1237
1300
  const client = createBrowserClient(clientSdkKey, {
1238
1301
  sdkName: "nuxt-sdk",
1239
- sdkVersion: "0.8.0"
1302
+ sdkVersion: "0.9.1"
1240
1303
  }, {
1241
1304
  metadata: {
1242
1305
  appName,
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorClient } from "../../types-Ce8HdKnT.mjs";
1
+ import { n as ConfigDirectorClient } from "../../types-CzmBIfqo.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-Ce8HdKnT.mjs";
1
+ import { n as ConfigDirectorClient } from "../../types-CzmBIfqo.mjs";
2
2
 
3
3
  //#region src/runtime/server/composables/useConfigDirectorClient.d.ts
4
4
  declare const useConfigDirectorClient: () => ConfigDirectorClient;
@@ -0,0 +1,6 @@
1
+ import { t as ClientHooks } from "../../types-CzmBIfqo.mjs";
2
+
3
+ //#region src/runtime/server/composables/useConfigDirectorServerHooks.d.ts
4
+ declare const useConfigDirectorServerHooks: (hooks: ClientHooks) => void;
5
+ //#endregion
6
+ export { useConfigDirectorServerHooks };
@@ -0,0 +1,6 @@
1
+ import { t as ClientHooks } from "../../types-CzmBIfqo.mjs";
2
+
3
+ //#region src/runtime/server/composables/useConfigDirectorServerHooks.d.ts
4
+ declare const useConfigDirectorServerHooks: (hooks: ClientHooks) => void;
5
+ //#endregion
6
+ export { useConfigDirectorServerHooks };
@@ -0,0 +1,14 @@
1
+ import { useNitroApp } from "nitropack/runtime";
2
+ //#region src/runtime/server/composables/useConfigDirectorServerHooks.ts
3
+ const useConfigDirectorServerHooks = (hooks) => {
4
+ const client = useNitroApp().configDirectorClient;
5
+ if (!client) throw new Error("The ConfigDirector Nitro plugin was not initialized");
6
+ const entries = Object.entries(hooks);
7
+ for (const [event, handler] of entries) {
8
+ if (!handler) continue;
9
+ const handlers = Array.isArray(handler) ? handler : [handler];
10
+ for (const h of handlers) client.on(event, h);
11
+ }
12
+ };
13
+ //#endregion
14
+ export { useConfigDirectorServerHooks };
@@ -1,4 +1,4 @@
1
- import { r as ConfigValueType, t as ConfigDirectorContext } from "./types-BqdrorBY.mjs";
1
+ import { i as ConfigValueType, n as ConfigEvaluation, t as ConfigDirectorContext } from "./types-CHmsCChN.mjs";
2
2
 
3
3
  //#region ../js-client-core/src/Emitter.d.ts
4
4
  type EventType = string | symbol;
@@ -11,7 +11,14 @@ interface EventProvider<TEventsRecord extends EventsRecord> {
11
11
  }
12
12
  //#endregion
13
13
  //#region ../js-client-core/src/types.d.ts
14
+ type ClientHooks = {
15
+ clientReady?: HookHandler<"clientReady"> | HookHandler<"clientReady">[];
16
+ configsUpdated?: HookHandler<"configsUpdated"> | HookHandler<"configsUpdated">[];
17
+ contextUpdated?: HookHandler<"contextUpdated"> | HookHandler<"contextUpdated">[];
18
+ configEvaluated?: HookHandler<"configEvaluated"> | HookHandler<"configEvaluated">[];
19
+ };
14
20
  type ClientConnectAction = "initialization" | "context update" | "network resume";
21
+ type HookHandler<TEvent extends keyof ClientEvents> = (payload: ClientEvents[TEvent]) => void;
15
22
  type ClientEvents = {
16
23
  configsUpdated: {
17
24
  keys: string[];
@@ -22,6 +29,9 @@ type ClientEvents = {
22
29
  contextUpdated: {
23
30
  context: ConfigDirectorContext | undefined;
24
31
  };
32
+ configEvaluated: {
33
+ evaluation: ConfigEvaluation;
34
+ };
25
35
  };
26
36
  type WatchHandler<T extends ConfigValueType> = (message: T) => void;
27
37
  /**
@@ -132,4 +142,4 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
132
142
  dispose(): void;
133
143
  }
134
144
  //#endregion
135
- export { ConfigDirectorClient as t };
145
+ export { ConfigDirectorClient as n, ClientHooks as t };
@@ -12,6 +12,15 @@ type ConfigState = {
12
12
  value: string | undefined | null;
13
13
  valueId?: string | undefined | null;
14
14
  };
15
+ type EvaluationReason = "found-match" | "config-state-missing" | "client-not-ready" | "type-mismatch" | "value-missing" | "invalid-number" | "invalid-json" | "invalid-boolean";
16
+ type ConfigEvaluation = {
17
+ key: string;
18
+ value: ConfigValueType;
19
+ valueId?: string;
20
+ isDefaultValue: boolean;
21
+ reason: EvaluationReason;
22
+ context?: ConfigDirectorContext;
23
+ };
15
24
  /**
16
25
  * The user's context to be sent to ConfigDirector. This context will be used for targeting
17
26
  * rules evaluation.
@@ -48,4 +57,4 @@ type ConfigDirectorContext = {
48
57
  anonymous?: boolean;
49
58
  };
50
59
  //#endregion
51
- export { ConfigState as n, ConfigValueType as r, ConfigDirectorContext as t };
60
+ export { ConfigValueType as i, ConfigEvaluation as n, ConfigState as r, ConfigDirectorContext as t };
@@ -1,4 +1,4 @@
1
- import { n as ConfigState, r as ConfigValueType, t as ConfigDirectorContext } from "./types-BqdrorBY.mjs";
1
+ import { i as ConfigValueType, n as ConfigEvaluation, r as ConfigState, t as ConfigDirectorContext } from "./types-CHmsCChN.mjs";
2
2
 
3
3
  //#region ../js-server-sdk/src/types.d.ts
4
4
  type ClientEvents = {
@@ -6,7 +6,16 @@ type ClientEvents = {
6
6
  keys: string[];
7
7
  };
8
8
  clientReady: undefined;
9
+ configEvaluated: {
10
+ evaluation: ConfigEvaluation;
11
+ };
12
+ };
13
+ type ClientHooks = {
14
+ clientReady?: HookHandler<"clientReady"> | HookHandler<"clientReady">[];
15
+ configsUpdated?: HookHandler<"configsUpdated"> | HookHandler<"configsUpdated">[];
16
+ configEvaluated?: HookHandler<"configEvaluated"> | HookHandler<"configEvaluated">[];
9
17
  };
18
+ type HookHandler<TEvent extends keyof ClientEvents> = (payload: ClientEvents[TEvent]) => void;
10
19
  type WatchHandler<T extends ConfigValueType> = (message: T) => void;
11
20
  /**
12
21
  * The ConfigDirector SDK client object.
@@ -93,4 +102,4 @@ interface ConfigDirectorClient {
93
102
  dispose(): void;
94
103
  }
95
104
  //#endregion
96
- export { ConfigDirectorClient as t };
105
+ export { ConfigDirectorClient as n, ClientHooks as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configdirector/nuxt-sdk",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "Nuxt SDK for ConfigDirector. ConfigDirector is a remote configuration and feature flag service.",
5
5
  "license": "MIT",
6
6
  "author": "ConfigDirector",
@@ -62,7 +62,7 @@
62
62
  "@nuxt/test-utils": "^4.0.2",
63
63
  "@types/node": "latest",
64
64
  "changelogen": "^0.6.2",
65
- "eslint": "^10.2.1",
65
+ "eslint": "^10.7.0",
66
66
  "nuxt": "^4.4.8",
67
67
  "playwright": "^1.60.0",
68
68
  "rimraf": "^6.1.3",