@configdirector/nuxt-sdk 1.9.2 → 1.10.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.
Files changed (29) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/app/composables/useConfigDirectorClient.d.mts +1 -1
  3. package/dist/runtime/app/composables/useConfigDirectorClient.d.ts +1 -1
  4. package/dist/runtime/app/composables/useConfigDirectorClientHooks.d.mts +1 -1
  5. package/dist/runtime/app/composables/useConfigDirectorClientHooks.d.ts +1 -1
  6. package/dist/runtime/app/composables/useConfigDirectorContext.d.mts +1 -1
  7. package/dist/runtime/app/composables/useConfigDirectorContext.d.ts +1 -1
  8. package/dist/runtime/app/composables/useConfigDirectorContext.mjs +2 -1
  9. package/dist/runtime/app/composables/useConfigDirectorStatus.d.mts +1 -1
  10. package/dist/runtime/app/composables/useConfigDirectorStatus.d.ts +1 -1
  11. package/dist/runtime/app/composables/useConfigDirectorValue.d.mts +2 -2
  12. package/dist/runtime/app/composables/useConfigDirectorValue.d.ts +2 -2
  13. package/dist/runtime/context-kind-D6YBNij2.mjs +45 -0
  14. package/dist/runtime/nitro/plugin.d.mts +1 -1
  15. package/dist/runtime/nitro/plugin.d.ts +1 -1
  16. package/dist/runtime/nitro/plugin.mjs +98 -10
  17. package/dist/runtime/plugin.client.mjs +218 -38
  18. package/dist/runtime/plugin.server.mjs +50 -6
  19. package/dist/runtime/server/composables/useConfigDirectorClient.d.mts +1 -1
  20. package/dist/runtime/server/composables/useConfigDirectorClient.d.ts +1 -1
  21. package/dist/runtime/server/composables/useConfigDirectorServerHooks.d.mts +1 -1
  22. package/dist/runtime/server/composables/useConfigDirectorServerHooks.d.ts +1 -1
  23. package/dist/runtime/{types-Bgx2-3dY.d.mts → types-B9_4pADA.d.mts} +1 -1
  24. package/dist/runtime/{types-CvmjergQ.d.mts → types-DQhBe4Ei.d.mts} +13 -5
  25. package/dist/runtime/{types-CHmsCChN.d.mts → types-IPLvRsUO.d.mts} +22 -9
  26. package/dist/testing.d.mts +36 -14
  27. package/dist/testing.mjs +144 -36
  28. package/package.json +1 -1
  29. /package/dist/runtime/{types-CkzBXJwA.d.mts → types-F0fKKk6-.d.mts} +0 -0
@@ -22,27 +22,40 @@ type ConfigEvaluation = {
22
22
  context?: ConfigDirectorContext;
23
23
  };
24
24
  /**
25
- * The user's context to be sent to ConfigDirector. This context will be used for targeting
26
- * rules evaluation.
25
+ * The context to be sent to ConfigDirector: the user or other entity, such as a device or an
26
+ * organization, that configs are evaluated for. This context will be used for targeting rules
27
+ * evaluation.
27
28
  */
28
29
  type ConfigDirectorContext = {
29
30
  /**
30
- * The user's identifier. This should be a value that uniquely identifies an application
31
- * user.
31
+ * The context's identifier. This should be a value that uniquely identifies the user or other
32
+ * entity among contexts of the same {@link kind}.
32
33
  * In the case of anonymous users, you could generate a UUID or alternatively not provide
33
34
  * the {@link id} and the SDK will generate a random UUID. However, keep in mind that this
34
- * value is used for segmenting users in percentage rollouts, and changes to the {@link id}
35
- * could result in the user being assigned to a different percentile.
35
+ * value is used for segmenting contexts in percentage rollouts, and changes to the {@link id}
36
+ * could result in the context being assigned to a different percentile.
36
37
  */
37
38
  id?: string;
38
39
  /**
39
- * The user's display name. This will be shown in the ConfigDirector dashboard and may be
40
+ * The kind of entity this context represents, such as `user`, `device`, `organization`,
41
+ * `tenant` or `listing`. You can use any other kind that fits your application. A kind has 1
42
+ * to 64 characters, using only lowercase letters (`a`-`z`), digits, `-` and `_`. It is used
43
+ * exactly as given, without trimming or changing its case.
44
+ *
45
+ * A context with an invalid kind is ignored as a whole: the SDK logs an error and evaluates
46
+ * as if no context had been provided.
47
+ *
48
+ * @default "user"
49
+ */
50
+ kind?: string;
51
+ /**
52
+ * The context's display name. This will be shown in the ConfigDirector dashboard and may be
40
53
  * used for targeting rules.
41
54
  */
42
55
  name?: string;
43
56
  /**
44
- * Any arbitrary traits for the current user. They will be shown in the ConfigDirector
45
- * dashboard and may be used for targeting rules.
57
+ * Any arbitrary traits for the context. They will be shown in the ConfigDirector dashboard
58
+ * and may be used for targeting rules.
46
59
  */
47
60
  traits?: {
48
61
  [key: string]: unknown;
@@ -29,27 +29,40 @@ type ConfigEvaluation = {
29
29
  context?: ConfigDirectorContext;
30
30
  };
31
31
  /**
32
- * The user's context to be sent to ConfigDirector. This context will be used for targeting
33
- * rules evaluation.
32
+ * The context to be sent to ConfigDirector: the user or other entity, such as a device or an
33
+ * organization, that configs are evaluated for. This context will be used for targeting rules
34
+ * evaluation.
34
35
  */
35
36
  type ConfigDirectorContext = {
36
37
  /**
37
- * The user's identifier. This should be a value that uniquely identifies an application
38
- * user.
38
+ * The context's identifier. This should be a value that uniquely identifies the user or other
39
+ * entity among contexts of the same {@link kind}.
39
40
  * In the case of anonymous users, you could generate a UUID or alternatively not provide
40
41
  * the {@link id} and the SDK will generate a random UUID. However, keep in mind that this
41
- * value is used for segmenting users in percentage rollouts, and changes to the {@link id}
42
- * could result in the user being assigned to a different percentile.
42
+ * value is used for segmenting contexts in percentage rollouts, and changes to the {@link id}
43
+ * could result in the context being assigned to a different percentile.
43
44
  */
44
45
  id?: string;
45
46
  /**
46
- * The user's display name. This will be shown in the ConfigDirector dashboard and may be
47
+ * The kind of entity this context represents, such as `user`, `device`, `organization`,
48
+ * `tenant` or `listing`. You can use any other kind that fits your application. A kind has 1
49
+ * to 64 characters, using only lowercase letters (`a`-`z`), digits, `-` and `_`. It is used
50
+ * exactly as given, without trimming or changing its case.
51
+ *
52
+ * A context with an invalid kind is ignored as a whole: the SDK logs an error and evaluates
53
+ * as if no context had been provided.
54
+ *
55
+ * @default "user"
56
+ */
57
+ kind?: string;
58
+ /**
59
+ * The context's display name. This will be shown in the ConfigDirector dashboard and may be
47
60
  * used for targeting rules.
48
61
  */
49
62
  name?: string;
50
63
  /**
51
- * Any arbitrary traits for the current user. They will be shown in the ConfigDirector
52
- * dashboard and may be used for targeting rules.
64
+ * Any arbitrary traits for the context. They will be shown in the ConfigDirector dashboard
65
+ * and may be used for targeting rules.
53
66
  */
54
67
  traits?: {
55
68
  [key: string]: unknown;
@@ -106,17 +119,25 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
106
119
  * not attempt to re-connect and an error will be logged to the console or the provided
107
120
  * logger.
108
121
  *
109
- * @param context The current user's context to be used for evaluating targeting rules (optional).
122
+ * A context whose {@link ConfigDirectorContext.kind} is invalid is ignored as a whole: an error is
123
+ * logged, and the client connects as if no context had been provided.
124
+ *
125
+ * @param context The current context to be used for evaluating targeting rules (optional).
110
126
  */
111
127
  initialize(context?: ConfigDirectorContext): Promise<void>;
112
128
  /**
113
- * Updates the user's context and re-evaluates all config and flag values based on the new context.
129
+ * Updates the context and re-evaluates all config and flag values based on the new context.
130
+ *
131
+ * A context whose {@link ConfigDirectorContext.kind} is invalid is ignored as a whole: an error is
132
+ * logged, the previous context is no longer used, and the client connects as if no context had been
133
+ * provided.
114
134
  *
115
- * @param context The current user's context to be used for evaluating targeting rules (required).
135
+ * @param context The current context to be used for evaluating targeting rules (required).
116
136
  */
117
137
  updateContext(context: ConfigDirectorContext): Promise<void>;
118
138
  /**
119
- * Returns the current context the client is configured with, or undefined if there is no context.
139
+ * Returns the current context the client is configured with, or undefined if there is no context,
140
+ * including after a context with an invalid kind was ignored.
120
141
  *
121
142
  * Note that the value returned does not updated immediately after calling {@link updateContext}. Only
122
143
  * once the underlying connection was successful or timed out, the current context is updated. This is
@@ -287,7 +308,8 @@ interface TestClient {
287
308
  failContextUpdate(): void;
288
309
  /**
289
310
  * The context of every `initialize` and `updateContext` call, in call order. `initialize` without
290
- * a context records an empty context. Resumes are not recorded.
311
+ * a context records an empty context, and so does a call whose context has an invalid kind, since
312
+ * the client connects without it. Resumes are not recorded.
291
313
  */
292
314
  readonly contextUpdates: ConfigDirectorContext[];
293
315
  }
package/dist/testing.mjs CHANGED
@@ -383,6 +383,7 @@ var StreamingTransport = class {
383
383
  eventEmitter = new Emitter();
384
384
  url;
385
385
  timeoutTimer;
386
+ connectionGeneration = 0;
386
387
  constructor(options) {
387
388
  this.options = options;
388
389
  this.options = options;
@@ -390,6 +391,9 @@ var StreamingTransport = class {
390
391
  this.url = options.resolveUrl("client/sse/v1", options.baseUrl);
391
392
  }
392
393
  async connect(context, timeout) {
394
+ const generation = ++this.connectionGeneration;
395
+ const clientSession = await this.options.clientSession;
396
+ if (generation !== this.connectionGeneration) return this;
393
397
  if (this.eventSource) this.close();
394
398
  const eventSourcePromise = new Promise((resolve, reject) => {
395
399
  this.eventSource = createEventSourceClient({
@@ -401,7 +405,8 @@ var StreamingTransport = class {
401
405
  givenContext: context,
402
406
  metaContext: this.options.metaContext,
403
407
  clientSdkKey: this.options.clientSdkKey,
404
- instanceId: this.options.instanceId
408
+ instanceId: clientSession.instanceId,
409
+ ephemeral: clientSession.ephemeral
405
410
  }),
406
411
  onMessage: ({ data }) => {
407
412
  this.dispatchMessage(data);
@@ -466,6 +471,7 @@ var StreamingTransport = class {
466
471
  this.eventEmitter.clear();
467
472
  }
468
473
  close() {
474
+ this.connectionGeneration++;
469
475
  this.eventSource?.close();
470
476
  clearTimeout(this.timeoutTimer);
471
477
  }
@@ -722,10 +728,11 @@ const generateInstanceId = () => {
722
728
  });
723
729
  };
724
730
  //#endregion
725
- //#region ../js-client-core/src/instance-id.ts
731
+ //#region ../js-client-core/src/client-session.ts
726
732
  const STORAGE_KEY = "configdirector-sdk:instance-id";
727
733
  const RECORD_VERSION = 1;
728
734
  const MAX_AGE_MS = 360 * 60 * 1e3;
735
+ const STORAGE_DEADLINE_MS = 1e3;
729
736
  const CHECKSUM_SALT = "configdirector.instanceId.v1";
730
737
  const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
731
738
  const fnv1a = (input, offsetBasis) => {
@@ -741,7 +748,7 @@ const checksumFor = (id, createdAt) => {
741
748
  const low = fnv1a(payload, 2166136261);
742
749
  return fnv1a(`${low}|${payload}`, 16777619).toString(16).padStart(8, "0") + low.toString(16).padStart(8, "0");
743
750
  };
744
- const getLocalStorage = () => {
751
+ const localStorageIfAvailable = () => {
745
752
  try {
746
753
  return globalThis.localStorage ?? void 0;
747
754
  } catch {
@@ -756,34 +763,37 @@ const isUsableRecord = (record) => {
756
763
  if (!UUID_V4_PATTERN.test(id)) return false;
757
764
  return checksum === checksumFor(id, createdAt);
758
765
  };
759
- const readStoredInstanceId = (storage, logger) => {
766
+ const readStoredInstanceId = async (storage, logger) => {
760
767
  let raw;
761
768
  try {
762
- raw = storage.getItem(STORAGE_KEY);
769
+ raw = await storage.getItem(STORAGE_KEY);
763
770
  } catch (error) {
764
- logger?.debug("[ConfigDirectorClient] Could not read the stored instance id, generating a new one", error);
765
- return;
771
+ logger.debug("[ConfigDirectorClient] Could not read the stored instance id, using an ephemeral one", error);
772
+ return { outcome: "failed" };
766
773
  }
767
- if (!raw) return;
774
+ if (typeof raw !== "string" || raw === "") return { outcome: "nothing usable" };
768
775
  let record;
769
776
  try {
770
777
  record = JSON.parse(raw);
771
778
  } catch {
772
- logger?.debug("[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one");
773
- return;
779
+ logger.debug("[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one");
780
+ return { outcome: "nothing usable" };
774
781
  }
775
782
  if (!isUsableRecord(record)) {
776
- logger?.debug("[ConfigDirectorClient] The stored instance id failed validation, generating a new one");
777
- return;
783
+ logger.debug("[ConfigDirectorClient] The stored instance id failed validation, generating a new one");
784
+ return { outcome: "nothing usable" };
778
785
  }
779
786
  const age = Date.now() - record.createdAt;
780
787
  if (age < 0 || age >= MAX_AGE_MS) {
781
- logger?.debug("[ConfigDirectorClient] The stored instance id has expired, generating a new one");
782
- return;
788
+ logger.debug("[ConfigDirectorClient] The stored instance id has expired, generating a new one");
789
+ return { outcome: "nothing usable" };
783
790
  }
784
- return record.id;
791
+ return {
792
+ outcome: "stored",
793
+ instanceId: record.id
794
+ };
785
795
  };
786
- const storeInstanceId = (storage, id, logger) => {
796
+ const persistInstanceId = async (storage, id, logger) => {
787
797
  const createdAt = Date.now();
788
798
  const record = {
789
799
  v: RECORD_VERSION,
@@ -792,19 +802,54 @@ const storeInstanceId = (storage, id, logger) => {
792
802
  checksum: checksumFor(id, createdAt)
793
803
  };
794
804
  try {
795
- storage.setItem(STORAGE_KEY, JSON.stringify(record));
805
+ await storage.setItem(STORAGE_KEY, JSON.stringify(record));
806
+ return true;
796
807
  } catch (error) {
797
- logger?.debug("[ConfigDirectorClient] Could not persist the instance id", error);
808
+ logger.debug("[ConfigDirectorClient] Could not persist the instance id, using it as an ephemeral one", error);
809
+ return false;
810
+ }
811
+ };
812
+ const settleFromStorage = async (storage, provisionalId, deadline, logger) => {
813
+ const read = await readStoredInstanceId(storage, logger);
814
+ switch (read.outcome) {
815
+ case "stored": return { instanceId: read.instanceId };
816
+ case "failed": return {
817
+ instanceId: provisionalId,
818
+ ephemeral: true
819
+ };
820
+ case "nothing usable": break;
798
821
  }
822
+ if (deadline.passed) return {
823
+ instanceId: provisionalId,
824
+ ephemeral: true
825
+ };
826
+ return await persistInstanceId(storage, provisionalId, logger) ? { instanceId: provisionalId } : {
827
+ instanceId: provisionalId,
828
+ ephemeral: true
829
+ };
799
830
  };
800
- const resolveInstanceId = (logger) => {
801
- const storage = getLocalStorage();
802
- if (!storage) return generateInstanceId();
803
- const storedInstanceId = readStoredInstanceId(storage, logger);
804
- if (storedInstanceId) return storedInstanceId;
805
- const instanceId = generateInstanceId();
806
- storeInstanceId(storage, instanceId, logger);
807
- return instanceId;
831
+ const resolveClientSession = (logger, storage = localStorageIfAvailable()) => {
832
+ const provisionalId = generateInstanceId();
833
+ if (!storage) {
834
+ logger.debug("[ConfigDirectorClient] No instance id storage is available, using an ephemeral instance id");
835
+ return Promise.resolve({
836
+ instanceId: provisionalId,
837
+ ephemeral: true
838
+ });
839
+ }
840
+ const deadline = { passed: false };
841
+ let deadlineTimer;
842
+ const fallbackAtDeadline = new Promise((resolve) => {
843
+ deadlineTimer = setTimeout(() => {
844
+ deadline.passed = true;
845
+ logger.warn(`[ConfigDirectorClient] The instance id storage did not respond within ${STORAGE_DEADLINE_MS}ms, using an ephemeral instance id`);
846
+ resolve({
847
+ instanceId: provisionalId,
848
+ ephemeral: true
849
+ });
850
+ }, STORAGE_DEADLINE_MS);
851
+ });
852
+ return Promise.race([settleFromStorage(storage, provisionalId, deadline, logger), fallbackAtDeadline]).finally(() => clearTimeout(deadlineTimer));
808
853
  };
809
854
  //#endregion
810
855
  //#region ../shared/src/transport/AbstractPollingTransport.ts
@@ -885,6 +930,7 @@ var PollingTransport = class extends AbstractPollingTransport {
885
930
  eventEmitter = new Emitter();
886
931
  url;
887
932
  lastUpdateTimestamp;
933
+ connectionGeneration = 0;
888
934
  constructor(options) {
889
935
  super();
890
936
  this.options = options;
@@ -894,19 +940,26 @@ var PollingTransport = class extends AbstractPollingTransport {
894
940
  this.pollingIntervalSeconds = options.pollingInterval ?? 60;
895
941
  }
896
942
  async connect(context, timeout) {
943
+ const generation = ++this.connectionGeneration;
897
944
  this.clearPollingInterval();
945
+ const clientSession = await this.options.clientSession;
946
+ if (generation !== this.connectionGeneration) return this;
898
947
  try {
899
- await this.fetchConfigs(context, timeout);
948
+ await this.fetchConfigs(context, timeout, clientSession);
900
949
  } finally {
901
950
  if (!this.fatalError) this.schedulePollingInterval(() => {
902
- this.fetchConfigs(context, timeout).catch((error) => {
951
+ this.fetchConfigs(context, timeout, clientSession).catch((error) => {
903
952
  this.logger.error("[PollingTransport] Error during polling:", error);
904
953
  });
905
954
  });
906
955
  }
907
956
  return this;
908
957
  }
909
- async fetchConfigs(context, timeout) {
958
+ close() {
959
+ this.connectionGeneration++;
960
+ super.close();
961
+ }
962
+ async fetchConfigs(context, timeout, clientSession) {
910
963
  if (this.fatalError) {
911
964
  this.logger.warn("[PollingTransport] There was a prior unrecoverable error. Ignoring attempt to reconnect.");
912
965
  return;
@@ -919,7 +972,8 @@ var PollingTransport = class extends AbstractPollingTransport {
919
972
  givenContext: context,
920
973
  metaContext: this.options.metaContext,
921
974
  clientSdkKey: this.options.clientSdkKey,
922
- instanceId: this.options.instanceId,
975
+ instanceId: clientSession.instanceId,
976
+ ephemeral: clientSession.ephemeral,
923
977
  lastUpdateTimestamp: this.lastUpdateTimestamp
924
978
  })
925
979
  }, this.logger);
@@ -960,6 +1014,46 @@ const read = (readValue) => {
960
1014
  const readUserAgent = () => read((globals) => globals.navigator?.userAgent);
961
1015
  const readHost = () => read((globals) => globals.location?.host);
962
1016
  //#endregion
1017
+ //#region ../shared/src/context-kind.ts
1018
+ const CONTEXT_KIND_MAXIMUM_LENGTH = 64;
1019
+ const KIND_SAMPLE_MAXIMUM_CHARACTERS = 128;
1020
+ const isContextKindCharacter = (character) => character >= "a" && character <= "z" || character >= "0" && character <= "9" || character === "-" || character === "_";
1021
+ const isValidContextKind = (kind) => {
1022
+ if (kind.length < 1 || kind.length > CONTEXT_KIND_MAXIMUM_LENGTH) return false;
1023
+ for (const character of kind) if (!isContextKindCharacter(character)) return false;
1024
+ return true;
1025
+ };
1026
+ const isAcceptedKind = (kind) => kind === void 0 || kind === null || typeof kind === "string" && isValidContextKind(kind);
1027
+ const stringFormOf = (kind) => {
1028
+ if (typeof kind === "string") return kind;
1029
+ try {
1030
+ return String(kind);
1031
+ } catch {
1032
+ return Object.prototype.toString.call(kind);
1033
+ }
1034
+ };
1035
+ const firstCharactersOf = (text, maximumCharacters) => {
1036
+ let sample = "";
1037
+ let characterCount = 0;
1038
+ for (const character of text) {
1039
+ if (characterCount === maximumCharacters) break;
1040
+ sample += character;
1041
+ characterCount += 1;
1042
+ }
1043
+ return sample;
1044
+ };
1045
+ const admitContext = (context) => {
1046
+ const kind = context?.kind;
1047
+ if (isAcceptedKind(kind)) return {
1048
+ outcome: "admitted",
1049
+ context
1050
+ };
1051
+ return {
1052
+ outcome: "ignored",
1053
+ kindSample: firstCharactersOf(stringFormOf(kind), KIND_SAMPLE_MAXIMUM_CHARACTERS)
1054
+ };
1055
+ };
1056
+ //#endregion
963
1057
  //#region ../js-client-core/src/DefaultConfigDirectorClient.ts
964
1058
  const MAX_EXPONENTIAL_DELAY = 9;
965
1059
  var DefaultConfigDirectorClient = class {
@@ -978,10 +1072,10 @@ var DefaultConfigDirectorClient = class {
978
1072
  readyResolve;
979
1073
  currentContext;
980
1074
  connectionMode;
981
- instanceId;
1075
+ clientSession;
982
1076
  constructor(telemetryClient, clientSdkKey, sdkOptions, clientOptions, internalClientOptions) {
983
1077
  this.logger = clientOptions?.logger ?? createDefaultLogger();
984
- this.instanceId = resolveInstanceId(this.logger);
1078
+ this.clientSession = resolveClientSession(this.logger, internalClientOptions?.instanceIdStorage);
985
1079
  this.timeout = clientOptions?.connection?.timeout ?? 3e3;
986
1080
  this.validateSdkKeyPresence(clientSdkKey);
987
1081
  const urlFactory = internalClientOptions?.urlFactory ?? defaultUrlFactory;
@@ -1036,7 +1130,7 @@ var DefaultConfigDirectorClient = class {
1036
1130
  }
1037
1131
  buildTransport(clientSdkKey, sdkOptions, baseUrl, urlFactory, clientOptions, internalClientOptions) {
1038
1132
  return new (this.getTransportConstructor(this.connectionMode))({
1039
- instanceId: this.instanceId,
1133
+ clientSession: this.clientSession,
1040
1134
  clientSdkKey,
1041
1135
  baseUrl,
1042
1136
  resolveUrl: urlFactory,
@@ -1063,10 +1157,23 @@ var DefaultConfigDirectorClient = class {
1063
1157
  }
1064
1158
  async initialize(context) {
1065
1159
  if (!this.hasReceivedConfigSet) this.initializing = true;
1066
- await this.connectToTransport(context, "initialization");
1160
+ await this.submitContext(context, "initialization");
1067
1161
  }
1068
1162
  async updateContext(context) {
1069
- await this.connectToTransport(context, "context update");
1163
+ await this.submitContext(context, "context update");
1164
+ }
1165
+ async submitContext(context, submission) {
1166
+ await this.connectToTransport(this.contextToConnectWith(context, submission), submission);
1167
+ }
1168
+ contextToConnectWith(suppliedContext, submission) {
1169
+ const admission = admitContext(suppliedContext);
1170
+ switch (admission.outcome) {
1171
+ case "admitted": return admission.context;
1172
+ case "ignored":
1173
+ this.logger.error(`[ConfigDirectorClient] Ignored the context supplied for ${submission} because its kind '${admission.kindSample}' is invalid; connecting as if no context was supplied. A context kind has 1 to 64 characters, using only lowercase letters, digits, '-' and '_'.`);
1174
+ this.telemetryClient.recordInvalidContext(admission.kindSample);
1175
+ return;
1176
+ }
1070
1177
  }
1071
1178
  get context() {
1072
1179
  return this.currentContext;
@@ -1534,6 +1641,7 @@ const TEST_CLIENT_SDK_KEY = "test-client";
1534
1641
  const noopTelemetryClient = {
1535
1642
  updateContext: async () => {},
1536
1643
  evaluatedConfig: () => {},
1644
+ recordInvalidContext: () => {},
1537
1645
  close: async () => {}
1538
1646
  };
1539
1647
  var InMemoryTestClient = class {
@@ -1638,7 +1746,7 @@ const installTestClient = (testClient) => {
1638
1746
  const createTestClient = (options) => {
1639
1747
  return createTestClient$1({
1640
1748
  sdkName: "nuxt-sdk",
1641
- sdkVersion: "1.9.2"
1749
+ sdkVersion: "1.10.0"
1642
1750
  }, options);
1643
1751
  };
1644
1752
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configdirector/nuxt-sdk",
3
- "version": "1.9.2",
3
+ "version": "1.10.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",