@configdirector/nuxt-sdk 1.9.2 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/module.d.mts +76 -15
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +13 -4
  4. package/dist/runtime/app/composables/useConfigDirectorClient.d.mts +1 -1
  5. package/dist/runtime/app/composables/useConfigDirectorClient.d.ts +1 -1
  6. package/dist/runtime/app/composables/useConfigDirectorClientHooks.d.mts +1 -1
  7. package/dist/runtime/app/composables/useConfigDirectorClientHooks.d.ts +1 -1
  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/useConfigDirectorContext.mjs +2 -1
  11. package/dist/runtime/app/composables/useConfigDirectorStatus.d.mts +1 -1
  12. package/dist/runtime/app/composables/useConfigDirectorStatus.d.ts +1 -1
  13. package/dist/runtime/app/composables/useConfigDirectorValue.d.mts +2 -2
  14. package/dist/runtime/app/composables/useConfigDirectorValue.d.ts +2 -2
  15. package/dist/runtime/context-kind-D6YBNij2.mjs +45 -0
  16. package/dist/runtime/native-values-BV2k_xR2.d.mts +83 -0
  17. package/dist/runtime/native-values-DZJjFBvk.mjs +116 -0
  18. package/dist/runtime/nitro/middleware.mjs +5 -1
  19. package/dist/runtime/nitro/offline-values.d.mts +7 -0
  20. package/dist/runtime/nitro/offline-values.d.ts +7 -0
  21. package/dist/runtime/nitro/offline-values.mjs +15 -0
  22. package/dist/runtime/nitro/plugin.d.mts +3 -1
  23. package/dist/runtime/nitro/plugin.d.ts +3 -1
  24. package/dist/runtime/nitro/plugin.mjs +329 -92
  25. package/dist/runtime/plugin.client.mjs +553 -118
  26. package/dist/runtime/plugin.server.mjs +50 -6
  27. package/dist/runtime/server/composables/useConfigDirectorServerClient.d.mts +6 -0
  28. package/dist/runtime/server/composables/useConfigDirectorServerClient.d.ts +6 -0
  29. package/dist/runtime/server/composables/{useConfigDirectorClient.mjs → useConfigDirectorServerClient.mjs} +3 -3
  30. package/dist/runtime/server/composables/useConfigDirectorServerHooks.d.mts +1 -1
  31. package/dist/runtime/server/composables/useConfigDirectorServerHooks.d.ts +1 -1
  32. package/dist/runtime/{types-Bgx2-3dY.d.mts → types-CS7AMNWe.d.mts} +1 -1
  33. package/dist/runtime/{types-CvmjergQ.d.mts → types-Dt3bENKf.d.mts} +13 -5
  34. package/dist/testing.d.mts +49 -27
  35. package/dist/testing.mjs +429 -185
  36. package/package.json +1 -1
  37. package/dist/runtime/server/composables/useConfigDirectorClient.d.mts +0 -6
  38. package/dist/runtime/server/composables/useConfigDirectorClient.d.ts +0 -6
  39. package/dist/runtime/types-CHmsCChN.d.mts +0 -60
  40. /package/dist/runtime/{types-CkzBXJwA.d.mts → types-C30VJ25l.d.mts} +0 -0
@@ -14,6 +14,50 @@ const useConfigDirectorClient = () => {
14
14
  return { client: $configDirectorClient };
15
15
  };
16
16
  //#endregion
17
+ //#region ../shared/src/context-kind.ts
18
+ const CONTEXT_KIND_MAXIMUM_LENGTH = 64;
19
+ const KIND_SAMPLE_MAXIMUM_CHARACTERS = 128;
20
+ const isContextKindCharacter = (character) => character >= "a" && character <= "z" || character >= "0" && character <= "9" || character === "-" || character === "_";
21
+ const isValidContextKind = (kind) => {
22
+ if (kind.length < 1 || kind.length > CONTEXT_KIND_MAXIMUM_LENGTH) return false;
23
+ for (const character of kind) if (!isContextKindCharacter(character)) return false;
24
+ return true;
25
+ };
26
+ const isAcceptedKind = (kind) => kind === void 0 || kind === null || typeof kind === "string" && isValidContextKind(kind);
27
+ const stringFormOf = (kind) => {
28
+ if (typeof kind === "string") return kind;
29
+ try {
30
+ return String(kind);
31
+ } catch {
32
+ return Object.prototype.toString.call(kind);
33
+ }
34
+ };
35
+ const firstCharactersOf = (text, maximumCharacters) => {
36
+ let sample = "";
37
+ let characterCount = 0;
38
+ for (const character of text) {
39
+ if (characterCount === maximumCharacters) break;
40
+ sample += character;
41
+ characterCount += 1;
42
+ }
43
+ return sample;
44
+ };
45
+ const admittedContextOrNone = (context) => {
46
+ const admission = admitContext(context);
47
+ return admission.outcome === "admitted" ? admission.context : void 0;
48
+ };
49
+ const admitContext = (context) => {
50
+ const kind = context?.kind;
51
+ if (isAcceptedKind(kind)) return {
52
+ outcome: "admitted",
53
+ context
54
+ };
55
+ return {
56
+ outcome: "ignored",
57
+ kindSample: firstCharactersOf(stringFormOf(kind), KIND_SAMPLE_MAXIMUM_CHARACTERS)
58
+ };
59
+ };
60
+ //#endregion
17
61
  //#region src/runtime/app/composables/useConfigDirectorContext.ts
18
62
  const DEFAULT_TIMEOUT = 3e3;
19
63
  const getEffectiveTimeout = (option) => {
@@ -26,7 +70,7 @@ const useConfigDirectorContext = () => {
26
70
  const rawContext = toRaw(context);
27
71
  const oldContext = JSON.stringify(state.value);
28
72
  const newContext = JSON.stringify(rawContext);
29
- state.value = rawContext;
73
+ state.value = admittedContextOrNone(rawContext);
30
74
  if (oldContext != newContext) {
31
75
  const timeout = getEffectiveTimeout(options?.timeoutMilliseconds);
32
76
  let timer;
@@ -65,19 +109,19 @@ var plugin_server_default = defineNuxtPlugin((nuxtApp) => {
65
109
  } };
66
110
  });
67
111
  var SsrClient = class {
68
- currentContext;
112
+ suppliedContext;
69
113
  constructor(serverClient) {
70
114
  this.serverClient = serverClient;
71
115
  this.serverClient = serverClient;
72
116
  }
73
117
  async initialize(context) {
74
- this.currentContext = context;
118
+ this.suppliedContext = context;
75
119
  }
76
120
  async updateContext(context) {
77
- this.currentContext = context;
121
+ this.suppliedContext = context;
78
122
  }
79
123
  get context() {
80
- return this.currentContext;
124
+ return admittedContextOrNone(this.suppliedContext);
81
125
  }
82
126
  get isReady() {
83
127
  return this.serverClient.isReady;
@@ -86,7 +130,7 @@ var SsrClient = class {
86
130
  return false;
87
131
  }
88
132
  getValue(configKey, defaultValue) {
89
- return this.serverClient.getValue(configKey, defaultValue, this.currentContext);
133
+ return this.serverClient.getValue(configKey, defaultValue, this.suppliedContext);
90
134
  }
91
135
  watch() {
92
136
  return () => {};
@@ -0,0 +1,6 @@
1
+ import { n as ConfigDirectorClient } from "../../types-CS7AMNWe.mjs";
2
+
3
+ //#region src/runtime/server/composables/useConfigDirectorServerClient.d.ts
4
+ declare const useConfigDirectorServerClient: () => ConfigDirectorClient;
5
+ //#endregion
6
+ export { useConfigDirectorServerClient };
@@ -0,0 +1,6 @@
1
+ import { n as ConfigDirectorClient } from "../../types-CS7AMNWe.mjs";
2
+
3
+ //#region src/runtime/server/composables/useConfigDirectorServerClient.d.ts
4
+ declare const useConfigDirectorServerClient: () => ConfigDirectorClient;
5
+ //#endregion
6
+ export { useConfigDirectorServerClient };
@@ -1,9 +1,9 @@
1
1
  import { useNitroApp } from "nitropack/runtime";
2
- //#region src/runtime/server/composables/useConfigDirectorClient.ts
3
- const useConfigDirectorClient = () => {
2
+ //#region src/runtime/server/composables/useConfigDirectorServerClient.ts
3
+ const useConfigDirectorServerClient = () => {
4
4
  const serverSdkClient = useNitroApp().configDirectorClient;
5
5
  if (!serverSdkClient) throw "The nitro ConfigDirector plugin was not initialized";
6
6
  return serverSdkClient;
7
7
  };
8
8
  //#endregion
9
- export { useConfigDirectorClient };
9
+ export { useConfigDirectorServerClient };
@@ -1,4 +1,4 @@
1
- import { t as ClientHooks } from "../../types-Bgx2-3dY.mjs";
1
+ import { t as ClientHooks } from "../../types-CS7AMNWe.mjs";
2
2
 
3
3
  //#region src/runtime/server/composables/useConfigDirectorServerHooks.d.ts
4
4
  declare const useConfigDirectorServerHooks: (hooks: ClientHooks) => void;
@@ -1,4 +1,4 @@
1
- import { t as ClientHooks } from "../../types-Bgx2-3dY.mjs";
1
+ import { t as ClientHooks } from "../../types-CS7AMNWe.mjs";
2
2
 
3
3
  //#region src/runtime/server/composables/useConfigDirectorServerHooks.d.ts
4
4
  declare const useConfigDirectorServerHooks: (hooks: ClientHooks) => void;
@@ -1,4 +1,4 @@
1
- import { i as ConfigValueType, n as ConfigEvaluation, r as ConfigState, t as ConfigDirectorContext } from "./types-CHmsCChN.mjs";
1
+ import { a as ConfigValueType, i as ConfigState, n as ConfigDirectorContext, r as ConfigEvaluation } from "./native-values-BV2k_xR2.mjs";
2
2
 
3
3
  //#region ../js-server-sdk/src/types.d.ts
4
4
  type ClientEvents = {
@@ -1,4 +1,4 @@
1
- import { i as ConfigValueType, n as ConfigEvaluation, t as ConfigDirectorContext } from "./types-CHmsCChN.mjs";
1
+ import { a as ConfigValueType, n as ConfigDirectorContext, r as ConfigEvaluation } from "./native-values-BV2k_xR2.mjs";
2
2
 
3
3
  //#region ../js-client-core/src/Emitter.d.ts
4
4
  type EventType = string | symbol;
@@ -60,17 +60,25 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
60
60
  * not attempt to re-connect and an error will be logged to the console or the provided
61
61
  * logger.
62
62
  *
63
- * @param context The current user's context to be used for evaluating targeting rules (optional).
63
+ * A context whose {@link ConfigDirectorContext.kind} is invalid is ignored as a whole: an error is
64
+ * logged, and the client connects as if no context had been provided.
65
+ *
66
+ * @param context The current context to be used for evaluating targeting rules (optional).
64
67
  */
65
68
  initialize(context?: ConfigDirectorContext): Promise<void>;
66
69
  /**
67
- * Updates the user's context and re-evaluates all config and flag values based on the new context.
70
+ * Updates the context and re-evaluates all config and flag values based on the new context.
71
+ *
72
+ * A context whose {@link ConfigDirectorContext.kind} is invalid is ignored as a whole: an error is
73
+ * logged, the previous context is no longer used, and the client connects as if no context had been
74
+ * provided.
68
75
  *
69
- * @param context The current user's context to be used for evaluating targeting rules (required).
76
+ * @param context The current context to be used for evaluating targeting rules (required).
70
77
  */
71
78
  updateContext(context: ConfigDirectorContext): Promise<void>;
72
79
  /**
73
- * Returns the current context the client is configured with, or undefined if there is no context.
80
+ * Returns the current context the client is configured with, or undefined if there is no context,
81
+ * including after a context with an invalid kind was ignored.
74
82
  *
75
83
  * Note that the value returned does not updated immediately after calling {@link updateContext}. Only
76
84
  * once the underlying connection was successful or timed out, the current context is updated. This is
@@ -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;
@@ -64,6 +77,15 @@ type ConfigDirectorContext = {
64
77
  anonymous?: boolean;
65
78
  };
66
79
  //#endregion
80
+ //#region ../shared/src/native-values.d.ts
81
+ type NativeJsonValue = boolean | number | string | null | NativeJsonValue[] | {
82
+ [key: string]: NativeJsonValue;
83
+ };
84
+ type NativeValue = boolean | number | string | NativeJsonValue[] | {
85
+ [key: string]: NativeJsonValue;
86
+ };
87
+ type NativeValues = Record<string, NativeValue>;
88
+ //#endregion
67
89
  //#region ../js-client-core/src/types.d.ts
68
90
  type ClientConnectAction = "initialization" | "context update" | "network resume";
69
91
  type ClientEvents = {
@@ -106,17 +128,25 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
106
128
  * not attempt to re-connect and an error will be logged to the console or the provided
107
129
  * logger.
108
130
  *
109
- * @param context The current user's context to be used for evaluating targeting rules (optional).
131
+ * A context whose {@link ConfigDirectorContext.kind} is invalid is ignored as a whole: an error is
132
+ * logged, and the client connects as if no context had been provided.
133
+ *
134
+ * @param context The current context to be used for evaluating targeting rules (optional).
110
135
  */
111
136
  initialize(context?: ConfigDirectorContext): Promise<void>;
112
137
  /**
113
- * Updates the user's context and re-evaluates all config and flag values based on the new context.
138
+ * Updates the context and re-evaluates all config and flag values based on the new context.
139
+ *
140
+ * A context whose {@link ConfigDirectorContext.kind} is invalid is ignored as a whole: an error is
141
+ * logged, the previous context is no longer used, and the client connects as if no context had been
142
+ * provided.
114
143
  *
115
- * @param context The current user's context to be used for evaluating targeting rules (required).
144
+ * @param context The current context to be used for evaluating targeting rules (required).
116
145
  */
117
146
  updateContext(context: ConfigDirectorContext): Promise<void>;
118
147
  /**
119
- * Returns the current context the client is configured with, or undefined if there is no context.
148
+ * Returns the current context the client is configured with, or undefined if there is no context,
149
+ * including after a context with an invalid kind was ignored.
120
150
  *
121
151
  * Note that the value returned does not updated immediately after calling {@link updateContext}. Only
122
152
  * once the underlying connection was successful or timed out, the current context is updated. This is
@@ -196,15 +226,6 @@ interface ConfigDirectorClient extends EventProvider<ClientEvents> {
196
226
  dispose(): void;
197
227
  }
198
228
  //#endregion
199
- //#region ../shared/src/testing/values.d.ts
200
- type TestJsonValue = boolean | number | string | null | TestJsonValue[] | {
201
- [key: string]: TestJsonValue;
202
- };
203
- type TestValue = boolean | number | string | TestJsonValue[] | {
204
- [key: string]: TestJsonValue;
205
- };
206
- type TestValues = Record<string, TestValue>;
207
- //#endregion
208
229
  //#region ../js-client-core/src/testing/TestClient.d.ts
209
230
  /**
210
231
  * Options for {@link createTestClient}. Every option is optional.
@@ -215,7 +236,7 @@ type TestClientOptions = {
215
236
  * config type follows from each value: a boolean, an integral number (`integer`), any other
216
237
  * number (`float`), a string, or a plain object or array (`json`).
217
238
  */
218
- values?: TestValues;
239
+ values?: NativeValues;
219
240
  /**
220
241
  * The connection timeout of the SDK client, in milliseconds. It bounds how long a held
221
242
  * `initialize` or `updateContext` waits. Defaults to the SDK's production timeout.
@@ -244,7 +265,7 @@ interface TestClient {
244
265
  * Stores `value` under `key` and, when the client is connected, delivers it as an update, so
245
266
  * reads, watchers, and `configsUpdated` handlers see it.
246
267
  */
247
- setValue(key: string, value: TestValue): void;
268
+ setValue(key: string, value: NativeValue): void;
248
269
  /**
249
270
  * Removes `key` and, when the client is connected, delivers a full update without it, so reads
250
271
  * fall back to the in-code default value and watchers of `key` receive that default.
@@ -254,7 +275,7 @@ interface TestClient {
254
275
  * Replaces every stored value with `values`, disarms any armed hold or failure, and, when the
255
276
  * client is connected, delivers the new values as a full update.
256
277
  */
257
- replaceValues(values: TestValues): void;
278
+ replaceValues(values: NativeValues): void;
258
279
  /**
259
280
  * Makes the next `initialize` wait until {@link completeInitialization} or
260
281
  * {@link failInitialization} is called, or until the client's timeout elapses.
@@ -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
  }
@@ -349,4 +371,4 @@ declare class ConfigDirectorValidationError extends Error {
349
371
  */
350
372
  declare const createTestClient: (options?: TestClientOptions) => TestClient;
351
373
  //#endregion
352
- export { ConfigDirectorConnectionError, ConfigDirectorValidationError, type TestClient, type TestClientOptions, type TestJsonValue, type TestValue, type TestValues, createTestClient, installTestClient };
374
+ export { ConfigDirectorConnectionError, ConfigDirectorValidationError, type TestClient, type TestClientOptions, type NativeJsonValue as TestJsonValue, type NativeValue as TestValue, type NativeValues as TestValues, createTestClient, installTestClient };