@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
package/dist/module.d.mts CHANGED
@@ -2,18 +2,40 @@ import * as _$_nuxt_schema0 from "@nuxt/schema";
2
2
  import { LogLevel } from "consola";
3
3
 
4
4
  //#region ../shared/src/types.d.ts
5
- type ConnectionMode = "streaming" | "polling";
5
+ type ConnectionMode = "streaming" | "polling" | "offline";
6
+ //#endregion
7
+ //#region ../shared/src/native-values.d.ts
8
+ type NativeJsonValue = boolean | number | string | null | NativeJsonValue[] | {
9
+ [key: string]: NativeJsonValue;
10
+ };
11
+ type NativeValue = boolean | number | string | NativeJsonValue[] | {
12
+ [key: string]: NativeJsonValue;
13
+ };
14
+ type NativeValues = Record<string, NativeValue>;
15
+ //#endregion
16
+ //#region ../js-server-sdk/src/types.d.ts
17
+ /**
18
+ * One value an offline client serves for a config key. The config type follows from the value: a
19
+ * boolean, an integral number (`integer`), any other number (`float`), a string, or a plain object
20
+ * or array (`json`).
21
+ */
22
+ type OfflineValue = NativeValue;
23
+ /**
24
+ * The values an offline client serves, keyed by config key. See {@link OfflineValue} for how each
25
+ * value's config type is decided. Every context receives the same value.
26
+ */
27
+ type OfflineValues = NativeValues;
6
28
  //#endregion
7
29
  //#region src/module.d.ts
8
30
  interface ConfigDirectorRuntimeConfig {
9
31
  /**
10
32
  * Your ConfigDirector Server SDK key. You can obtain this key from the ConfigDirector
11
- * dashboard under the project settings.
33
+ * dashboard under the project settings. Not needed when `connection.mode` is `offline`.
12
34
  *
13
35
  * This is a secret value and should not be committed to a source code repository. Alternatively,
14
36
  * it can be provided at runtime via the NUXT_CONFIGDIRECTOR_SERVER_SDK_KEY environment variable.
15
37
  */
16
- serverSdkKey: string;
38
+ serverSdkKey?: string;
17
39
  /**
18
40
  * Log level for the server side of the ConfigDirector Nuxt SDK, using consola's numeric levels.
19
41
  * 0 = error, 1 = warn, 2 = log, 3 = info, 4 = debug, 5 = trace.
@@ -31,14 +53,34 @@ interface ConfigDirectorRuntimeConfig {
31
53
  */
32
54
  connection?: {
33
55
  /**
34
- * The connection mode, one of `streaming` (default) or `polling`. In `streaming` mode the
35
- * connection stays open and receives config updates as they happen. In `polling` mode configs
36
- * are fetched once during initialization and then again on every `pollingInterval`.
56
+ * The connection mode, one of `streaming` (default), `polling` or `offline`. In `streaming` mode
57
+ * the connection stays open and receives config updates as they happen. In `polling` mode configs
58
+ * are fetched once during initialization and then again on every `pollingInterval`. In `offline`
59
+ * mode the server never connects to ConfigDirector and sends nothing: it serves the values of
60
+ * `file` or `values` to every context, or the in-code default values when neither is given, and
61
+ * needs no `serverSdkKey`. The browser follows the server into `offline` mode with the same values
62
+ * unless `runtimeConfig.public.configdirector.connection` sets its own `mode` or `values`.
37
63
  * Can be set via the NUXT_CONFIGDIRECTOR_CONNECTION_MODE environment variable.
38
64
  */
39
65
  mode?: ConnectionMode;
40
66
  /**
41
- * The polling interval in seconds when `mode` is `polling`. Has no effect in `streaming` mode.
67
+ * The path of a JSON file holding the values to serve in `offline` mode, resolved against the
68
+ * server process working directory. The file holds one object with a value per config key. A
69
+ * file that is missing, unreadable, not a JSON object, or holding a value such as `null` makes
70
+ * every request fail with a `ConfigDirectorInitializationError`. Only one of `file` and `values`
71
+ * can be given, and only in `offline` mode.
72
+ * Can be set via the NUXT_CONFIGDIRECTOR_CONNECTION_FILE environment variable.
73
+ */
74
+ file?: string;
75
+ /**
76
+ * The values to serve in `offline` mode, keyed by config key, as an alternative to `file`. The
77
+ * config type of each value follows from the value: a boolean, an integral number (`integer`),
78
+ * any other number (`float`), a string, or a plain object or array (`json`). Only one of `file`
79
+ * and `values` can be given, and only in `offline` mode.
80
+ */
81
+ values?: OfflineValues;
82
+ /**
83
+ * The polling interval in seconds when `mode` is `polling`. Has no effect in the other modes.
42
84
  * When omitted (or `0`), the server SDK default is used.
43
85
  * Can be set via the NUXT_CONFIGDIRECTOR_CONNECTION_POLLING_INTERVAL environment variable.
44
86
  */
@@ -64,12 +106,13 @@ interface ConfigDirectorRuntimeConfig {
64
106
  interface ConfigDirectorPublicRuntimeConfig {
65
107
  /**
66
108
  * Your ConfigDirector Client SDK key. You can obtain this key from the ConfigDirector
67
- * dashboard under the project settings.
109
+ * dashboard under the project settings. Not needed when the browser runs in `offline` mode,
110
+ * whether given here or inherited from the server.
68
111
  *
69
112
  * This value is not a secret. It can alternatively be provided at runtime via the
70
113
  * NUXT_PUBLIC_CONFIGDIRECTOR_CLIENT_SDK_KEY environment variable.
71
114
  */
72
- clientSdkKey: string;
115
+ clientSdkKey?: string;
73
116
  /**
74
117
  * Your app's name. This value can be used in ConfigDirector targeting rules.
75
118
  */
@@ -93,18 +136,30 @@ interface ConfigDirectorPublicRuntimeConfig {
93
136
  */
94
137
  baseUrl?: string;
95
138
  /**
96
- * Connection options for the browser client used on the client side.
139
+ * Connection options for the browser client used on the client side. When neither `mode` nor
140
+ * `values` is given and the server runs in `offline` mode, the browser runs in `offline` mode
141
+ * too, with the server's values.
97
142
  */
98
143
  connection?: {
99
144
  /**
100
- * The connection mode, one of `streaming` (default) or `polling`. In `streaming` mode the
145
+ * The connection mode, one of `streaming`, `polling` or `offline`. In `streaming` mode the
101
146
  * connection stays open and receives config updates as they happen. In `polling` mode configs
102
- * are fetched once during initialization and then again on every `pollingInterval`.
147
+ * are fetched once during initialization and then again on every `pollingInterval`. In `offline`
148
+ * mode the browser never connects to ConfigDirector and sends nothing: it serves `values` to
149
+ * every context, or the in-code default values when none are given, and needs no `clientSdkKey`.
150
+ * Empty when not set; the browser client then uses its default, `streaming`, unless it follows
151
+ * an offline server.
103
152
  * Can be set via the NUXT_PUBLIC_CONFIGDIRECTOR_CONNECTION_MODE environment variable.
104
153
  */
105
- mode?: ConnectionMode;
154
+ mode?: ConnectionMode | "";
155
+ /**
156
+ * The values to serve in `offline` mode, keyed by config key. The config type of each value
157
+ * follows from the value: a boolean, an integral number (`integer`), any other number (`float`),
158
+ * a string, or a plain object or array (`json`). Can be given only in `offline` mode.
159
+ */
160
+ values?: OfflineValues;
106
161
  /**
107
- * The polling interval in seconds when `mode` is `polling`. Has no effect in `streaming` mode.
162
+ * The polling interval in seconds when `mode` is `polling`. Has no effect in the other modes.
108
163
  * When omitted (or `0`), it defaults to 60 seconds. A value below the minimum of 30 seconds is
109
164
  * raised to 30 seconds and a warning is logged.
110
165
  * Can be set via the NUXT_PUBLIC_CONFIGDIRECTOR_CONNECTION_POLLING_INTERVAL environment variable.
@@ -118,6 +173,12 @@ interface ConfigDirectorPublicRuntimeConfig {
118
173
  */
119
174
  timeout?: number;
120
175
  };
176
+ /**
177
+ * The connection mode the server runs in, written by the module on every request so the browser
178
+ * knows whether to follow the server into `offline` mode. Not an option: any value set here is
179
+ * overwritten on every request.
180
+ */
181
+ serverConnectionMode?: ConnectionMode;
121
182
  }
122
183
  declare module "nuxt/schema" {
123
184
  interface RuntimeConfig {
@@ -145,4 +206,4 @@ interface ModuleOptions {
145
206
  }
146
207
  declare const _default: _$_nuxt_schema0.NuxtModule<ModuleOptions, ModuleOptions, false>;
147
208
  //#endregion
148
- export { ModuleOptions, _default as default };
209
+ export { ModuleOptions, type OfflineValue, type OfflineValues, _default as default };
package/dist/module.json CHANGED
@@ -4,5 +4,5 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.0.0"
6
6
  },
7
- "version": "1.9.2"
7
+ "version": "1.11.0"
8
8
  }
package/dist/module.mjs CHANGED
@@ -1,5 +1,8 @@
1
1
  import { addImports, addPlugin, addServerHandler, addServerImports, addServerPlugin, createResolver, defineNuxtModule, useLogger } from "@nuxt/kit";
2
2
  import { defu } from "defu";
3
+ //#region src/runtime/offline-values-route.ts
4
+ const OFFLINE_VALUES_ROUTE = "/_configdirector/offline-values";
5
+ //#endregion
3
6
  //#region src/module.ts
4
7
  var module_default = defineNuxtModule({
5
8
  meta: {
@@ -16,6 +19,7 @@ var module_default = defineNuxtModule({
16
19
  baseUrl: "",
17
20
  connection: {
18
21
  mode: "streaming",
22
+ file: "",
19
23
  pollingInterval: 0,
20
24
  timeout: 0
21
25
  },
@@ -29,7 +33,7 @@ var module_default = defineNuxtModule({
29
33
  clientSdkKey: "",
30
34
  baseUrl: "",
31
35
  connection: {
32
- mode: "streaming",
36
+ mode: "",
33
37
  pollingInterval: 0,
34
38
  timeout: 0
35
39
  }
@@ -44,10 +48,15 @@ var module_default = defineNuxtModule({
44
48
  middleware: true,
45
49
  handler: resolver.resolve("./runtime/nitro/middleware")
46
50
  });
51
+ addServerHandler({
52
+ route: OFFLINE_VALUES_ROUTE,
53
+ method: "get",
54
+ handler: resolver.resolve("./runtime/nitro/offline-values")
55
+ });
47
56
  addServerImports([{
48
- name: "useConfigDirectorClient",
49
- as: "useConfigDirectorClient",
50
- from: resolver.resolve("./runtime/server/composables/useConfigDirectorClient")
57
+ name: "useConfigDirectorServerClient",
58
+ as: "useConfigDirectorServerClient",
59
+ from: resolver.resolve("./runtime/server/composables/useConfigDirectorServerClient")
51
60
  }, {
52
61
  name: "useConfigDirectorServerHooks",
53
62
  as: "useConfigDirectorServerHooks",
@@ -1,4 +1,4 @@
1
- import { n as ConfigDirectorClient } from "../../types-CvmjergQ.mjs";
1
+ import { n as ConfigDirectorClient } from "../../types-Dt3bENKf.mjs";
2
2
 
3
3
  //#region src/runtime/app/composables/useConfigDirectorClient.d.ts
4
4
  declare const useConfigDirectorClient: () => {
@@ -1,4 +1,4 @@
1
- import { n as ConfigDirectorClient } from "../../types-CvmjergQ.mjs";
1
+ import { n as ConfigDirectorClient } from "../../types-Dt3bENKf.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 ClientHooks } from "../../types-CvmjergQ.mjs";
1
+ import { t as ClientHooks } from "../../types-Dt3bENKf.mjs";
2
2
 
3
3
  //#region src/runtime/app/composables/useConfigDirectorClientHooks.d.ts
4
4
  declare const useConfigDirectorClientHooks: (hooks: ClientHooks) => void;
@@ -1,4 +1,4 @@
1
- import { t as ClientHooks } from "../../types-CvmjergQ.mjs";
1
+ import { t as ClientHooks } from "../../types-Dt3bENKf.mjs";
2
2
 
3
3
  //#region src/runtime/app/composables/useConfigDirectorClientHooks.d.ts
4
4
  declare const useConfigDirectorClientHooks: (hooks: ClientHooks) => void;
@@ -1,4 +1,4 @@
1
- import { t as ConfigDirectorContext } from "../../types-CHmsCChN.mjs";
1
+ import { n as ConfigDirectorContext } from "../../native-values-BV2k_xR2.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-CHmsCChN.mjs";
1
+ import { n as ConfigDirectorContext } from "../../native-values-BV2k_xR2.mjs";
2
2
  import { Ref } from "vue";
3
3
 
4
4
  //#region src/runtime/app/composables/useConfigDirectorContext.d.ts
@@ -1,4 +1,5 @@
1
1
  import { useConfigDirectorClient } from "./useConfigDirectorClient.mjs";
2
+ import { n as admittedContextOrNone } from "../../context-kind-D6YBNij2.mjs";
2
3
  import { useState } from "#app";
3
4
  import { readonly, toRaw } from "vue";
4
5
  //#region src/runtime/app/composables/useConfigDirectorContext.ts
@@ -13,7 +14,7 @@ const useConfigDirectorContext = () => {
13
14
  const rawContext = toRaw(context);
14
15
  const oldContext = JSON.stringify(state.value);
15
16
  const newContext = JSON.stringify(rawContext);
16
- state.value = rawContext;
17
+ state.value = admittedContextOrNone(rawContext);
17
18
  if (oldContext != newContext) {
18
19
  const timeout = getEffectiveTimeout(options?.timeoutMilliseconds);
19
20
  let timer;
@@ -1,4 +1,4 @@
1
- import { t as ClientStatus } from "../../types-CkzBXJwA.mjs";
1
+ import { t as ClientStatus } from "../../types-C30VJ25l.mjs";
2
2
  import { Ref, ShallowRef } from "vue";
3
3
 
4
4
  //#region src/runtime/app/composables/useConfigDirectorStatus.d.ts
@@ -1,4 +1,4 @@
1
- import { t as ClientStatus } from "../../types-CkzBXJwA.mjs";
1
+ import { t as ClientStatus } from "../../types-C30VJ25l.mjs";
2
2
  import { Ref, ShallowRef } from "vue";
3
3
 
4
4
  //#region src/runtime/app/composables/useConfigDirectorStatus.d.ts
@@ -1,5 +1,5 @@
1
- import { i as ConfigValueType } from "../../types-CHmsCChN.mjs";
2
- import { t as ClientStatus } from "../../types-CkzBXJwA.mjs";
1
+ import { a as ConfigValueType } from "../../native-values-BV2k_xR2.mjs";
2
+ import { t as ClientStatus } from "../../types-C30VJ25l.mjs";
3
3
  import { DeepReadonly, Ref, ShallowRef } from "vue";
4
4
 
5
5
  //#region src/runtime/app/composables/useConfigDirectorValue.d.ts
@@ -1,5 +1,5 @@
1
- import { i as ConfigValueType } from "../../types-CHmsCChN.mjs";
2
- import { t as ClientStatus } from "../../types-CkzBXJwA.mjs";
1
+ import { a as ConfigValueType } from "../../native-values-BV2k_xR2.mjs";
2
+ import { t as ClientStatus } from "../../types-C30VJ25l.mjs";
3
3
  import { DeepReadonly, Ref, ShallowRef } from "vue";
4
4
 
5
5
  //#region src/runtime/app/composables/useConfigDirectorValue.d.ts
@@ -0,0 +1,45 @@
1
+ //#region ../shared/src/context-kind.ts
2
+ const CONTEXT_KIND_MAXIMUM_LENGTH = 64;
3
+ const KIND_SAMPLE_MAXIMUM_CHARACTERS = 128;
4
+ const isContextKindCharacter = (character) => character >= "a" && character <= "z" || character >= "0" && character <= "9" || character === "-" || character === "_";
5
+ const isValidContextKind = (kind) => {
6
+ if (kind.length < 1 || kind.length > CONTEXT_KIND_MAXIMUM_LENGTH) return false;
7
+ for (const character of kind) if (!isContextKindCharacter(character)) return false;
8
+ return true;
9
+ };
10
+ const isAcceptedKind = (kind) => kind === void 0 || kind === null || typeof kind === "string" && isValidContextKind(kind);
11
+ const stringFormOf = (kind) => {
12
+ if (typeof kind === "string") return kind;
13
+ try {
14
+ return String(kind);
15
+ } catch {
16
+ return Object.prototype.toString.call(kind);
17
+ }
18
+ };
19
+ const firstCharactersOf = (text, maximumCharacters) => {
20
+ let sample = "";
21
+ let characterCount = 0;
22
+ for (const character of text) {
23
+ if (characterCount === maximumCharacters) break;
24
+ sample += character;
25
+ characterCount += 1;
26
+ }
27
+ return sample;
28
+ };
29
+ const admittedContextOrNone = (context) => {
30
+ const admission = admitContext(context);
31
+ return admission.outcome === "admitted" ? admission.context : void 0;
32
+ };
33
+ const admitContext = (context) => {
34
+ const kind = context?.kind;
35
+ if (isAcceptedKind(kind)) return {
36
+ outcome: "admitted",
37
+ context
38
+ };
39
+ return {
40
+ outcome: "ignored",
41
+ kindSample: firstCharactersOf(stringFormOf(kind), KIND_SAMPLE_MAXIMUM_CHARACTERS)
42
+ };
43
+ };
44
+ //#endregion
45
+ export { admittedContextOrNone as n, admitContext as t };
@@ -0,0 +1,83 @@
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];
4
+ type ConfigEnumLikeType = {
5
+ [key: string]: string | number;
6
+ };
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
+ valueId?: string | undefined | null;
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
+ };
24
+ /**
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.
28
+ */
29
+ type ConfigDirectorContext = {
30
+ /**
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}.
33
+ * In the case of anonymous users, you could generate a UUID or alternatively not provide
34
+ * the {@link id} and the SDK will generate a random UUID. However, keep in mind that this
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.
37
+ */
38
+ id?: string;
39
+ /**
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
53
+ * used for targeting rules.
54
+ */
55
+ name?: string;
56
+ /**
57
+ * Any arbitrary traits for the context. They will be shown in the ConfigDirector dashboard
58
+ * and may be used for targeting rules.
59
+ */
60
+ traits?: {
61
+ [key: string]: unknown;
62
+ };
63
+ /**
64
+ * Whether or not to treat the context as anonymous during evaluation. When `true`, the
65
+ * context values will be used for targeting rules evaluation but the context will not be
66
+ * persisted and will not appear in the dashboard.
67
+ *
68
+ * @default false
69
+ */
70
+ anonymous?: boolean;
71
+ };
72
+ type ConnectionMode = "streaming" | "polling" | "offline";
73
+ //#endregion
74
+ //#region ../shared/src/native-values.d.ts
75
+ type NativeJsonValue = boolean | number | string | null | NativeJsonValue[] | {
76
+ [key: string]: NativeJsonValue;
77
+ };
78
+ type NativeValue = boolean | number | string | NativeJsonValue[] | {
79
+ [key: string]: NativeJsonValue;
80
+ };
81
+ type NativeValues = Record<string, NativeValue>;
82
+ //#endregion
83
+ export { ConfigValueType as a, ConfigState as i, ConfigDirectorContext as n, ConnectionMode as o, ConfigEvaluation as r, NativeValues as t };
@@ -0,0 +1,116 @@
1
+ //#region ../shared/src/errors.ts
2
+ var ConfigDirectorConnectionError = class ConfigDirectorConnectionError extends Error {
3
+ name = "ConfigDirectorConnectionError";
4
+ status;
5
+ constructor(message, status) {
6
+ super(message);
7
+ this.status = status;
8
+ Object.setPrototypeOf(this, ConfigDirectorConnectionError.prototype);
9
+ }
10
+ };
11
+ var ConfigDirectorValidationError = class ConfigDirectorValidationError extends Error {
12
+ name = "ConfigDirectorValidationError";
13
+ constructor(message) {
14
+ super(message);
15
+ Object.setPrototypeOf(this, ConfigDirectorValidationError.prototype);
16
+ }
17
+ };
18
+ var ConfigDirectorInitializationError = class ConfigDirectorInitializationError extends Error {
19
+ name = "ConfigDirectorInitializationError";
20
+ constructor(message) {
21
+ super(message);
22
+ Object.setPrototypeOf(this, ConfigDirectorInitializationError.prototype);
23
+ }
24
+ };
25
+ //#endregion
26
+ //#region ../shared/src/native-values.ts
27
+ const encodeNativeValue = (key, value) => {
28
+ if (key.trim().length == 0) throw new ConfigDirectorValidationError("Invalid config key. The key of a value cannot be empty.");
29
+ return encode(key, value);
30
+ };
31
+ const decoders = {
32
+ boolean: (value) => value === "true",
33
+ integer: Number,
34
+ float: Number,
35
+ string: (value) => value,
36
+ enum: (value) => value,
37
+ url: (value) => value,
38
+ custom: (value) => value,
39
+ json: (value) => JSON.parse(value)
40
+ };
41
+ const decodeNativeValue = (type, value) => decoders[type](value);
42
+ const encode = (key, value) => {
43
+ switch (typeof value) {
44
+ case "boolean": return {
45
+ type: "boolean",
46
+ value: value ? "true" : "false"
47
+ };
48
+ case "number": return encodeNumber(key, value);
49
+ case "string": return {
50
+ type: "string",
51
+ value
52
+ };
53
+ case "object": if (value !== null) {
54
+ assertJsonContents(key, value, "");
55
+ return {
56
+ type: "json",
57
+ value: JSON.stringify(value)
58
+ };
59
+ }
60
+ }
61
+ throw new ConfigDirectorValidationError(`Invalid value for '${key}': ${describe(value)}. Use a boolean, a number, a string, a plain object, or an array.`);
62
+ };
63
+ const encodeNumber = (key, value) => {
64
+ if (!Number.isFinite(value)) throw new ConfigDirectorValidationError(`Invalid value for '${key}': ${describe(value)} is not a finite number.`);
65
+ if (Number.isInteger(value)) {
66
+ if (!Number.isSafeInteger(value)) throw new ConfigDirectorValidationError(`Invalid value for '${key}': ${value} is not a safe integer, so the SDK could not read it back exactly.`);
67
+ return {
68
+ type: "integer",
69
+ value: String(value)
70
+ };
71
+ }
72
+ return {
73
+ type: "float",
74
+ value: toPlainDecimal(value)
75
+ };
76
+ };
77
+ const toPlainDecimal = (value) => {
78
+ const text = String(value);
79
+ const exponentIndex = text.indexOf("e-");
80
+ if (exponentIndex < 0) return text;
81
+ const sign = text.startsWith("-") ? "-" : "";
82
+ const [integerDigits = "", fractionDigits = ""] = text.slice(sign.length, exponentIndex).split(".");
83
+ const leadingZeros = Number(text.slice(exponentIndex + 2)) - integerDigits.length;
84
+ return `${sign}0.${"0".repeat(leadingZeros)}${integerDigits}${fractionDigits}`;
85
+ };
86
+ const assertJsonContents = (key, value, path) => {
87
+ if (value === null || typeof value === "boolean" || typeof value === "string") return;
88
+ if (typeof value === "number") {
89
+ if (!Number.isFinite(value)) throw invalidJsonContents(key, path, `${describe(value)} is not a finite number`);
90
+ return;
91
+ }
92
+ if (Array.isArray(value)) {
93
+ value.forEach((item, index) => assertJsonContents(key, item, `${path}[${index}]`));
94
+ return;
95
+ }
96
+ if (isPlainObject(value)) {
97
+ for (const [property, item] of Object.entries(value)) assertJsonContents(key, item, path ? `${path}.${property}` : property);
98
+ return;
99
+ }
100
+ throw invalidJsonContents(key, path, `${describe(value)} cannot be encoded as JSON`);
101
+ };
102
+ const invalidJsonContents = (key, path, problem) => new ConfigDirectorValidationError(`Invalid value for '${key}'${path ? ` at '${path}'` : ""}: ${problem}. JSON contents can hold booleans, finite numbers, strings, null, arrays, and plain objects.`);
103
+ const isPlainObject = (value) => {
104
+ if (typeof value !== "object" || value === null) return false;
105
+ const prototype = Object.getPrototypeOf(value);
106
+ return prototype === Object.prototype || prototype === null;
107
+ };
108
+ const describe = (value) => {
109
+ if (value === null) return "null";
110
+ if (typeof value === "function") return "a function";
111
+ if (typeof value === "object") return `a ${value.constructor?.name ?? "object"} instance`;
112
+ if (typeof value === "symbol") return "a symbol";
113
+ return String(value);
114
+ };
115
+ //#endregion
116
+ export { ConfigDirectorValidationError as a, ConfigDirectorInitializationError as i, encodeNativeValue as n, ConfigDirectorConnectionError as r, decodeNativeValue as t };
@@ -3,8 +3,12 @@ import { defineEventHandler } from "h3";
3
3
  //#region src/runtime/nitro/middleware.ts
4
4
  var middleware_default = defineEventHandler(async (event) => {
5
5
  const nitroApp = useNitroApp();
6
- if (useRuntimeConfig(event).configdirector.waitForInitialization) await nitroApp.configDirectorInitialization;
6
+ if (decideRequestHold(useRuntimeConfig(event).configdirector.waitForInitialization, nitroApp.configDirectorConnectionMode) === "hold-until-initialized") await nitroApp.configDirectorInitialization;
7
7
  event.context.configDirectorClient = nitroApp.configDirectorClient;
8
8
  });
9
+ const decideRequestHold = (waitForInitialization, connectionMode) => {
10
+ if (connectionMode === "offline") return "hold-until-initialized";
11
+ return waitForInitialization ? "hold-until-initialized" : "pass-through";
12
+ };
9
13
  //#endregion
10
14
  export { middleware_default as default };
@@ -0,0 +1,7 @@
1
+ import { t as NativeValues } from "../native-values-BV2k_xR2.mjs";
2
+ import * as _$h3 from "h3";
3
+
4
+ //#region src/runtime/nitro/offline-values.d.ts
5
+ declare const _default: _$h3.EventHandler<_$h3.EventHandlerRequest, NativeValues>;
6
+ //#endregion
7
+ export { _default as default };
@@ -0,0 +1,7 @@
1
+ import { t as NativeValues } from "../native-values-BV2k_xR2.mjs";
2
+ import * as _$h3 from "h3";
3
+
4
+ //#region src/runtime/nitro/offline-values.d.ts
5
+ declare const _default: _$h3.EventHandler<_$h3.EventHandlerRequest, NativeValues>;
6
+ //#endregion
7
+ export { _default as default };
@@ -0,0 +1,15 @@
1
+ import { t as decodeNativeValue } from "../native-values-DZJjFBvk.mjs";
2
+ import { useNitroApp } from "nitropack/runtime";
3
+ import { createError, defineEventHandler } from "h3";
4
+ //#region ../shared/src/browser-half.ts
5
+ const holdsAValue = (config) => typeof config.value === "string";
6
+ const offlineValuesOf = (configs) => Object.fromEntries(Object.values(configs).filter(holdsAValue).map((config) => [config.key, decodeNativeValue(config.type, config.value)]));
7
+ //#endregion
8
+ //#region src/runtime/nitro/offline-values.ts
9
+ var offline_values_default = defineEventHandler(() => {
10
+ const nitroApp = useNitroApp();
11
+ if (nitroApp.configDirectorConnectionMode !== "offline") throw createError({ statusCode: 404 });
12
+ return offlineValuesOf(nitroApp.configDirectorClient.getAllConfigs());
13
+ });
14
+ //#endregion
15
+ export { offline_values_default as default };
@@ -1,4 +1,5 @@
1
- import { n as ConfigDirectorClient } from "../types-Bgx2-3dY.mjs";
1
+ import { o as ConnectionMode } from "../native-values-BV2k_xR2.mjs";
2
+ import { n as ConfigDirectorClient } from "../types-CS7AMNWe.mjs";
2
3
  import * as _$nitropack from "nitropack";
3
4
 
4
5
  //#region src/runtime/nitro/plugin.d.ts
@@ -6,6 +7,7 @@ declare const _default: _$nitropack.NitroAppPlugin;
6
7
  declare module "nitropack" {
7
8
  interface NitroApp {
8
9
  configDirectorClient: ConfigDirectorClient;
10
+ configDirectorConnectionMode: ConnectionMode;
9
11
  configDirectorInitialization: Promise<void>;
10
12
  }
11
13
  }
@@ -1,4 +1,5 @@
1
- import { n as ConfigDirectorClient } from "../types-Bgx2-3dY.mjs";
1
+ import { o as ConnectionMode } from "../native-values-BV2k_xR2.mjs";
2
+ import { n as ConfigDirectorClient } from "../types-CS7AMNWe.mjs";
2
3
  import * as _$nitropack from "nitropack";
3
4
 
4
5
  //#region src/runtime/nitro/plugin.d.ts
@@ -6,6 +7,7 @@ declare const _default: _$nitropack.NitroAppPlugin;
6
7
  declare module "nitropack" {
7
8
  interface NitroApp {
8
9
  configDirectorClient: ConfigDirectorClient;
10
+ configDirectorConnectionMode: ConnectionMode;
9
11
  configDirectorInitialization: Promise<void>;
10
12
  }
11
13
  }