@lorion-org/runtime-config 1.0.0-beta.0 → 1.0.0-beta.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.
- package/LICENSE +21 -21
- package/README.md +60 -65
- package/dist/index.cjs +85 -0
- package/dist/index.d.cts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +68 -0
- package/examples/context-input-key.ts +15 -15
- package/examples/env-vars.ts +6 -6
- package/examples/namespaced-runtime-config.ts +18 -18
- package/examples/scope-view.ts +13 -13
- package/examples/sectioned-runtime-config.ts +23 -18
- package/package.json +11 -2
- package/src/env.ts +91 -0
- package/src/fragment.ts +28 -0
- package/src/index.ts +8 -0
- package/src/key.ts +54 -0
- package/src/project.ts +208 -0
- package/src/resolve.ts +51 -0
- package/src/scope.ts +129 -0
- package/src/types.ts +34 -0
- package/src/validation.ts +126 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the 'Software'), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the 'Software'), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ The intended adapter shape is:
|
|
|
45
45
|
- application-specific names, file names, and defaults stay in the consuming adapter
|
|
46
46
|
|
|
47
47
|
Adapters may accept existing fragment field names and map them to generic
|
|
48
|
-
contexts with `contextInputKey`. For example, a project can read `
|
|
48
|
+
contexts with `contextInputKey`. For example, a project can read `stores`
|
|
49
49
|
from its files while this package still works with the generic `contexts`
|
|
50
50
|
model internally.
|
|
51
51
|
|
|
@@ -59,13 +59,13 @@ Fragments are written in local scope vocabulary. The scope id is not repeated in
|
|
|
59
59
|
the keys.
|
|
60
60
|
|
|
61
61
|
```ts
|
|
62
|
-
const
|
|
62
|
+
const checkoutFragment = {
|
|
63
63
|
public: {
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
currency: 'EUR',
|
|
65
|
+
successPath: '/orders/confirmed',
|
|
66
66
|
},
|
|
67
67
|
private: {
|
|
68
|
-
|
|
68
|
+
signingSecret: 'checkout_signing_secret_demo',
|
|
69
69
|
},
|
|
70
70
|
};
|
|
71
71
|
```
|
|
@@ -78,15 +78,15 @@ Some runtimes need one shared `public` and `private` object. The scope id become
|
|
|
78
78
|
a transport prefix so many fragments can coexist without key collisions.
|
|
79
79
|
|
|
80
80
|
```ts
|
|
81
|
-
const runtimeConfig = projectSectionedRuntimeConfig(new Map([['
|
|
81
|
+
const runtimeConfig = projectSectionedRuntimeConfig(new Map([['checkout', checkoutFragment]]));
|
|
82
82
|
|
|
83
83
|
// For a single fragment, use:
|
|
84
|
-
projectRuntimeConfigFragment('
|
|
84
|
+
projectRuntimeConfigFragment('checkout', checkoutFragment);
|
|
85
85
|
|
|
86
|
-
runtimeConfig.public.
|
|
87
|
-
// => '
|
|
88
|
-
runtimeConfig.private.
|
|
89
|
-
// => '
|
|
86
|
+
runtimeConfig.public.checkoutCurrency;
|
|
87
|
+
// => 'EUR'
|
|
88
|
+
runtimeConfig.private.checkoutSigningSecret;
|
|
89
|
+
// => 'checkout_signing_secret_demo'
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
### 3. Environment variable shape
|
|
@@ -96,19 +96,19 @@ Environment variables keep the same transport prefix and add visibility.
|
|
|
96
96
|
```ts
|
|
97
97
|
toRuntimeEnvVars(runtimeConfig, 'APP');
|
|
98
98
|
// => {
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
99
|
+
// APP_PUBLIC_CHECKOUT_CURRENCY: 'EUR',
|
|
100
|
+
// APP_PUBLIC_CHECKOUT_SUCCESS_PATH: '/orders/confirmed',
|
|
101
|
+
// APP_PRIVATE_CHECKOUT_SIGNING_SECRET: 'checkout_signing_secret_demo'
|
|
102
102
|
// }
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
Usage code can read the flat runtime shape back through local keys:
|
|
106
106
|
|
|
107
107
|
```ts
|
|
108
|
-
const
|
|
108
|
+
const checkout = getPublicRuntimeConfigScope(runtimeConfig, 'checkout');
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
// => '
|
|
110
|
+
checkout.successPath;
|
|
111
|
+
// => '/orders/confirmed'
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
## Basic example
|
|
@@ -122,18 +122,18 @@ import {
|
|
|
122
122
|
|
|
123
123
|
const fragments = new Map([
|
|
124
124
|
[
|
|
125
|
-
'
|
|
125
|
+
'checkout',
|
|
126
126
|
{
|
|
127
127
|
public: {
|
|
128
|
-
|
|
128
|
+
successPath: '/orders/confirmed',
|
|
129
129
|
},
|
|
130
130
|
private: {
|
|
131
|
-
|
|
131
|
+
signingSecret: 'checkout_signing_secret_demo',
|
|
132
132
|
},
|
|
133
133
|
contexts: {
|
|
134
|
-
|
|
134
|
+
'eu-store': {
|
|
135
135
|
public: {
|
|
136
|
-
|
|
136
|
+
successPath: '/eu-store/orders/confirmed',
|
|
137
137
|
},
|
|
138
138
|
},
|
|
139
139
|
},
|
|
@@ -143,16 +143,16 @@ const fragments = new Map([
|
|
|
143
143
|
|
|
144
144
|
const runtimeConfig = projectSectionedRuntimeConfig(fragments);
|
|
145
145
|
|
|
146
|
-
runtimeConfig.public.
|
|
147
|
-
// => '/
|
|
146
|
+
runtimeConfig.public.checkoutSuccessPath;
|
|
147
|
+
// => '/orders/confirmed'
|
|
148
148
|
|
|
149
|
-
resolveRuntimeConfigValue(runtimeConfig.public, '
|
|
150
|
-
contextId: '
|
|
149
|
+
resolveRuntimeConfigValue(runtimeConfig.public, 'checkout', 'successPath', {
|
|
150
|
+
contextId: 'eu-store',
|
|
151
151
|
});
|
|
152
|
-
// => '/
|
|
152
|
+
// => '/eu-store/orders/confirmed'
|
|
153
153
|
|
|
154
|
-
getPublicRuntimeConfigScope(runtimeConfig, '
|
|
155
|
-
// => {
|
|
154
|
+
getPublicRuntimeConfigScope(runtimeConfig, 'checkout');
|
|
155
|
+
// => { successPath: '/orders/confirmed' }
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
## Example: custom context input key
|
|
@@ -163,15 +163,15 @@ import { projectSectionedRuntimeConfig } from '@lorion-org/runtime-config';
|
|
|
163
163
|
projectSectionedRuntimeConfig(
|
|
164
164
|
[
|
|
165
165
|
{
|
|
166
|
-
scopeId: '
|
|
166
|
+
scopeId: 'checkout',
|
|
167
167
|
config: {
|
|
168
168
|
public: {
|
|
169
|
-
|
|
169
|
+
successPath: '/orders/confirmed',
|
|
170
170
|
},
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
stores: {
|
|
172
|
+
'eu-store': {
|
|
173
173
|
public: {
|
|
174
|
-
|
|
174
|
+
successPath: '/eu-store/orders/confirmed',
|
|
175
175
|
},
|
|
176
176
|
},
|
|
177
177
|
},
|
|
@@ -179,16 +179,16 @@ projectSectionedRuntimeConfig(
|
|
|
179
179
|
},
|
|
180
180
|
],
|
|
181
181
|
{
|
|
182
|
-
contextInputKey: '
|
|
183
|
-
contextOutputKey: '
|
|
182
|
+
contextInputKey: 'stores',
|
|
183
|
+
contextOutputKey: '__stores',
|
|
184
184
|
},
|
|
185
185
|
);
|
|
186
186
|
// => {
|
|
187
187
|
// public: {
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
188
|
+
// checkoutSuccessPath: '/orders/confirmed',
|
|
189
|
+
// __stores: {
|
|
190
|
+
// 'eu-store': {
|
|
191
|
+
// checkoutSuccessPath: '/eu-store/orders/confirmed'
|
|
192
192
|
// }
|
|
193
193
|
// }
|
|
194
194
|
// },
|
|
@@ -209,38 +209,33 @@ import {
|
|
|
209
209
|
projectRuntimeConfigNamespaces,
|
|
210
210
|
} from '@lorion-org/runtime-config';
|
|
211
211
|
|
|
212
|
-
const runtimeConfig = projectRuntimeConfigNamespace('
|
|
212
|
+
const runtimeConfig = projectRuntimeConfigNamespace('checkout', {
|
|
213
213
|
public: {
|
|
214
|
-
|
|
214
|
+
successPath: '/orders/confirmed',
|
|
215
215
|
},
|
|
216
216
|
private: {
|
|
217
|
-
|
|
217
|
+
signingSecret: 'checkout_signing_secret_demo',
|
|
218
218
|
},
|
|
219
219
|
});
|
|
220
220
|
|
|
221
|
-
runtimeConfig.public.
|
|
222
|
-
// => {
|
|
223
|
-
runtimeConfig.
|
|
224
|
-
// => {
|
|
221
|
+
runtimeConfig.public.checkout;
|
|
222
|
+
// => { successPath: '/orders/confirmed' }
|
|
223
|
+
runtimeConfig.checkout;
|
|
224
|
+
// => { signingSecret: 'checkout_signing_secret_demo' }
|
|
225
225
|
|
|
226
226
|
const combinedRuntimeConfig = projectRuntimeConfigNamespaces([
|
|
227
227
|
{
|
|
228
|
-
scopeId: '
|
|
228
|
+
scopeId: 'payments',
|
|
229
229
|
config: {
|
|
230
230
|
public: {
|
|
231
|
-
|
|
232
|
-
},
|
|
233
|
-
private: {
|
|
234
|
-
token: 'mail-token',
|
|
231
|
+
configuredProvider: 'payment-provider-stripe',
|
|
235
232
|
},
|
|
236
233
|
},
|
|
237
234
|
},
|
|
238
235
|
]);
|
|
239
236
|
|
|
240
|
-
combinedRuntimeConfig.public.
|
|
241
|
-
// => {
|
|
242
|
-
combinedRuntimeConfig.mail;
|
|
243
|
-
// => { token: 'mail-token' }
|
|
237
|
+
combinedRuntimeConfig.public.payments;
|
|
238
|
+
// => { configuredProvider: 'payment-provider-stripe' }
|
|
244
239
|
```
|
|
245
240
|
|
|
246
241
|
## Example: environment variables
|
|
@@ -258,30 +253,30 @@ import {
|
|
|
258
253
|
const envVars = toRuntimeEnvVars(
|
|
259
254
|
{
|
|
260
255
|
public: {
|
|
261
|
-
|
|
256
|
+
checkoutSuccessPath: '/orders/confirmed',
|
|
262
257
|
},
|
|
263
258
|
private: {
|
|
264
|
-
|
|
259
|
+
checkoutSigningSecret: 'checkout_signing_secret_demo',
|
|
265
260
|
},
|
|
266
261
|
},
|
|
267
262
|
'APP',
|
|
268
263
|
);
|
|
269
264
|
|
|
270
265
|
runtimeEnvVarsToString(envVars);
|
|
271
|
-
// =>
|
|
272
|
-
// =>
|
|
266
|
+
// => APP_PUBLIC_CHECKOUT_SUCCESS_PATH=/orders/confirmed
|
|
267
|
+
// => APP_PRIVATE_CHECKOUT_SIGNING_SECRET=checkout_signing_secret_demo
|
|
273
268
|
|
|
274
269
|
runtimeEnvVarsToShellAssignments(envVars);
|
|
275
|
-
// =>
|
|
276
|
-
// =>
|
|
270
|
+
// => APP_PUBLIC_CHECKOUT_SUCCESS_PATH='"/orders/confirmed"'
|
|
271
|
+
// => APP_PRIVATE_CHECKOUT_SIGNING_SECRET='"checkout_signing_secret_demo"'
|
|
277
272
|
|
|
278
273
|
projectRuntimeConfigEnvVars(
|
|
279
274
|
new Map([
|
|
280
275
|
[
|
|
281
|
-
'
|
|
276
|
+
'payments',
|
|
282
277
|
{
|
|
283
278
|
public: {
|
|
284
|
-
|
|
279
|
+
configuredProvider: 'payment-provider-stripe',
|
|
285
280
|
},
|
|
286
281
|
},
|
|
287
282
|
],
|
|
@@ -291,7 +286,7 @@ projectRuntimeConfigEnvVars(
|
|
|
291
286
|
},
|
|
292
287
|
);
|
|
293
288
|
// => {
|
|
294
|
-
//
|
|
289
|
+
// APP_PUBLIC_PAYMENTS_CONFIGURED_PROVIDER: 'payment-provider-stripe'
|
|
295
290
|
// }
|
|
296
291
|
```
|
|
297
292
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,13 +17,24 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
33
|
+
RuntimeConfigValidatorRegistry: () => RuntimeConfigValidatorRegistry,
|
|
23
34
|
createRuntimeConfigEnvKey: () => createRuntimeConfigEnvKey,
|
|
24
35
|
createRuntimeConfigKey: () => createRuntimeConfigKey,
|
|
36
|
+
createRuntimeConfigValidatorRegistry: () => createRuntimeConfigValidatorRegistry,
|
|
37
|
+
defaultRuntimeConfigValidationMode: () => defaultRuntimeConfigValidationMode,
|
|
25
38
|
getPrivateRuntimeConfigScope: () => getPrivateRuntimeConfigScope,
|
|
26
39
|
getPublicRuntimeConfigScope: () => getPublicRuntimeConfigScope,
|
|
27
40
|
getRuntimeConfigFragment: () => getRuntimeConfigFragment,
|
|
@@ -33,12 +46,16 @@ __export(index_exports, {
|
|
|
33
46
|
projectRuntimeConfigNamespace: () => projectRuntimeConfigNamespace,
|
|
34
47
|
projectRuntimeConfigNamespaces: () => projectRuntimeConfigNamespaces,
|
|
35
48
|
projectSectionedRuntimeConfig: () => projectSectionedRuntimeConfig,
|
|
49
|
+
resolveRuntimeConfigValidationMode: () => resolveRuntimeConfigValidationMode,
|
|
36
50
|
resolveRuntimeConfigValue: () => resolveRuntimeConfigValue,
|
|
37
51
|
resolveRuntimeConfigValueFromRuntimeConfig: () => resolveRuntimeConfigValueFromRuntimeConfig,
|
|
38
52
|
runtimeConfigVisibilities: () => runtimeConfigVisibilities,
|
|
39
53
|
runtimeEnvValueToShellLiteral: () => runtimeEnvValueToShellLiteral,
|
|
40
54
|
runtimeEnvVarsToShellAssignments: () => runtimeEnvVarsToShellAssignments,
|
|
41
55
|
runtimeEnvVarsToString: () => runtimeEnvVarsToString,
|
|
56
|
+
shouldRegisterRuntimeConfigValidationSchema: () => shouldRegisterRuntimeConfigValidationSchema,
|
|
57
|
+
shouldRequireRuntimeConfigAtStartup: () => shouldRequireRuntimeConfigAtStartup,
|
|
58
|
+
shouldValidateRuntimeConfigAtStartup: () => shouldValidateRuntimeConfigAtStartup,
|
|
42
59
|
stripRuntimeConfigScopePrefix: () => stripRuntimeConfigScopePrefix,
|
|
43
60
|
toRuntimeConfigFragment: () => toRuntimeConfigFragment,
|
|
44
61
|
toRuntimeEnvVars: () => toRuntimeEnvVars,
|
|
@@ -340,10 +357,74 @@ function getRuntimeConfigFragment(runtimeConfig, scopeId, options = {}) {
|
|
|
340
357
|
private: getPrivateRuntimeConfigScope(runtimeConfig, scopeId, privateOptions)
|
|
341
358
|
};
|
|
342
359
|
}
|
|
360
|
+
|
|
361
|
+
// src/validation.ts
|
|
362
|
+
var import_ajv = __toESM(require("ajv"), 1);
|
|
363
|
+
var defaultRuntimeConfigValidationMode = "optional";
|
|
364
|
+
function resolveRuntimeConfigValidationMode(input) {
|
|
365
|
+
return typeof input === "string" ? input : input?.validation ?? defaultRuntimeConfigValidationMode;
|
|
366
|
+
}
|
|
367
|
+
function shouldRegisterRuntimeConfigValidationSchema(input) {
|
|
368
|
+
return resolveRuntimeConfigValidationMode(input) !== "none";
|
|
369
|
+
}
|
|
370
|
+
function shouldValidateRuntimeConfigAtStartup(input) {
|
|
371
|
+
const mode = resolveRuntimeConfigValidationMode(input);
|
|
372
|
+
return mode !== "none" && mode !== "onUse";
|
|
373
|
+
}
|
|
374
|
+
function shouldRequireRuntimeConfigAtStartup(input) {
|
|
375
|
+
return resolveRuntimeConfigValidationMode(input) === "startup";
|
|
376
|
+
}
|
|
377
|
+
function formatDefaultRuntimeConfigValidationError(target, validationError) {
|
|
378
|
+
const jsonPath = validationError.instancePath || "/";
|
|
379
|
+
const schemaError = `${validationError.keyword}${validationError.message ? `: ${validationError.message}` : ""}`;
|
|
380
|
+
return new Error(
|
|
381
|
+
[
|
|
382
|
+
"RuntimeConfig schema validation failed.",
|
|
383
|
+
`Scope: ${target.scopeId}`,
|
|
384
|
+
`JSON path: ${jsonPath}`,
|
|
385
|
+
`Schema error: ${schemaError}`
|
|
386
|
+
].join("\n")
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
var RuntimeConfigValidatorRegistry = class {
|
|
390
|
+
#cache = /* @__PURE__ */ new Map();
|
|
391
|
+
#formatError;
|
|
392
|
+
#schemas;
|
|
393
|
+
constructor(schemas, options = {}) {
|
|
394
|
+
this.#formatError = options.formatError ?? formatDefaultRuntimeConfigValidationError;
|
|
395
|
+
this.#schemas = schemas;
|
|
396
|
+
}
|
|
397
|
+
get(scopeId) {
|
|
398
|
+
const schema = this.#schemas[scopeId];
|
|
399
|
+
if (!schema) {
|
|
400
|
+
throw new Error(`RuntimeConfig validation schema not registered for scope "${scopeId}".`);
|
|
401
|
+
}
|
|
402
|
+
const cached = this.#cache.get(scopeId);
|
|
403
|
+
if (cached) return cached;
|
|
404
|
+
const validate = new import_ajv.default({ strict: false, allErrors: false }).compile(schema);
|
|
405
|
+
this.#cache.set(scopeId, validate);
|
|
406
|
+
return validate;
|
|
407
|
+
}
|
|
408
|
+
assert(scopeId, fragment) {
|
|
409
|
+
const validate = this.get(scopeId);
|
|
410
|
+
if (validate(fragment)) return;
|
|
411
|
+
const validationError = validate.errors?.[0];
|
|
412
|
+
if (!validationError) {
|
|
413
|
+
throw new Error(`RuntimeConfig schema validation failed for scope "${scopeId}".`);
|
|
414
|
+
}
|
|
415
|
+
throw this.#formatError({ scopeId }, validationError);
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
function createRuntimeConfigValidatorRegistry(schemas, options = {}) {
|
|
419
|
+
return new RuntimeConfigValidatorRegistry(schemas, options);
|
|
420
|
+
}
|
|
343
421
|
// Annotate the CommonJS export names for ESM import in node:
|
|
344
422
|
0 && (module.exports = {
|
|
423
|
+
RuntimeConfigValidatorRegistry,
|
|
345
424
|
createRuntimeConfigEnvKey,
|
|
346
425
|
createRuntimeConfigKey,
|
|
426
|
+
createRuntimeConfigValidatorRegistry,
|
|
427
|
+
defaultRuntimeConfigValidationMode,
|
|
347
428
|
getPrivateRuntimeConfigScope,
|
|
348
429
|
getPublicRuntimeConfigScope,
|
|
349
430
|
getRuntimeConfigFragment,
|
|
@@ -355,12 +436,16 @@ function getRuntimeConfigFragment(runtimeConfig, scopeId, options = {}) {
|
|
|
355
436
|
projectRuntimeConfigNamespace,
|
|
356
437
|
projectRuntimeConfigNamespaces,
|
|
357
438
|
projectSectionedRuntimeConfig,
|
|
439
|
+
resolveRuntimeConfigValidationMode,
|
|
358
440
|
resolveRuntimeConfigValue,
|
|
359
441
|
resolveRuntimeConfigValueFromRuntimeConfig,
|
|
360
442
|
runtimeConfigVisibilities,
|
|
361
443
|
runtimeEnvValueToShellLiteral,
|
|
362
444
|
runtimeEnvVarsToShellAssignments,
|
|
363
445
|
runtimeEnvVarsToString,
|
|
446
|
+
shouldRegisterRuntimeConfigValidationSchema,
|
|
447
|
+
shouldRequireRuntimeConfigAtStartup,
|
|
448
|
+
shouldValidateRuntimeConfigAtStartup,
|
|
364
449
|
stripRuntimeConfigScopePrefix,
|
|
365
450
|
toRuntimeConfigFragment,
|
|
366
451
|
toRuntimeEnvVars,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ErrorObject, ValidateFunction } from 'ajv';
|
|
2
|
+
|
|
1
3
|
type RuntimeConfigKeyStrategy = (scopeId: string, key: string) => string;
|
|
2
4
|
type RuntimeConfigKeyOptions = {
|
|
3
5
|
keyStrategy?: RuntimeConfigKeyStrategy;
|
|
@@ -98,4 +100,31 @@ declare function getPublicRuntimeConfigScope<T extends RuntimeConfigSection = Ru
|
|
|
98
100
|
declare function getPrivateRuntimeConfigScope<T extends RuntimeConfigSection = RuntimeConfigSection>(runtimeConfig: Partial<Record<ConfigVisibility, RuntimeConfigSection | undefined>>, scopeId: string, options?: Omit<GetRuntimeConfigScopeOptions, 'visibility'>): T;
|
|
99
101
|
declare function getRuntimeConfigFragment(runtimeConfig: Partial<Record<ConfigVisibility, RuntimeConfigSection | undefined>>, scopeId: string, options?: GetRuntimeConfigFragmentOptions): RuntimeConfigContext;
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
type RuntimeConfigValidationMode = 'none' | 'optional' | 'startup' | 'onUse';
|
|
104
|
+
type RuntimeConfigValidationPolicy = {
|
|
105
|
+
validation?: RuntimeConfigValidationMode;
|
|
106
|
+
};
|
|
107
|
+
type RuntimeConfigValidationSchemaRegistry = Record<string, object>;
|
|
108
|
+
type RuntimeConfigValidationErrorTarget = {
|
|
109
|
+
scopeId: string;
|
|
110
|
+
};
|
|
111
|
+
type RuntimeConfigValidationErrorFormatter = (target: RuntimeConfigValidationErrorTarget, validationError: ErrorObject) => Error;
|
|
112
|
+
type RuntimeConfigValidationPolicyInput = RuntimeConfigValidationMode | RuntimeConfigValidationPolicy | undefined;
|
|
113
|
+
declare const defaultRuntimeConfigValidationMode: RuntimeConfigValidationMode;
|
|
114
|
+
declare function resolveRuntimeConfigValidationMode(input: RuntimeConfigValidationPolicyInput): RuntimeConfigValidationMode;
|
|
115
|
+
declare function shouldRegisterRuntimeConfigValidationSchema(input: RuntimeConfigValidationPolicyInput): boolean;
|
|
116
|
+
declare function shouldValidateRuntimeConfigAtStartup(input: RuntimeConfigValidationPolicyInput): boolean;
|
|
117
|
+
declare function shouldRequireRuntimeConfigAtStartup(input: RuntimeConfigValidationPolicyInput): boolean;
|
|
118
|
+
declare class RuntimeConfigValidatorRegistry {
|
|
119
|
+
#private;
|
|
120
|
+
constructor(schemas: RuntimeConfigValidationSchemaRegistry, options?: {
|
|
121
|
+
formatError?: RuntimeConfigValidationErrorFormatter;
|
|
122
|
+
});
|
|
123
|
+
get(scopeId: string): ValidateFunction;
|
|
124
|
+
assert(scopeId: string, fragment: RuntimeConfigContext): void;
|
|
125
|
+
}
|
|
126
|
+
declare function createRuntimeConfigValidatorRegistry(schemas: RuntimeConfigValidationSchemaRegistry, options?: {
|
|
127
|
+
formatError?: RuntimeConfigValidationErrorFormatter;
|
|
128
|
+
}): RuntimeConfigValidatorRegistry;
|
|
129
|
+
|
|
130
|
+
export { type ConfigVisibility, type GetRuntimeConfigFragmentOptions, type GetRuntimeConfigScopeOptions, type NamedRuntimeConfigFragment, type NormalizeRuntimeConfigFragmentOptions, type ProjectRuntimeConfigEnvVarsOptions, type ProjectRuntimeConfigFragmentOptions, type ProjectRuntimeConfigNamespaceOptions, type ProjectRuntimeConfigNamespacesOptions, type ProjectSectionedRuntimeConfigOptions, type ResolveRuntimeConfigValueFromRuntimeConfigOptions, type ResolveRuntimeConfigValueOptions, type RuntimeConfigContext, type RuntimeConfigFragment, type RuntimeConfigFragmentInput, type RuntimeConfigFragmentMap, type RuntimeConfigKeyOptions, type RuntimeConfigKeyStrategy, type RuntimeConfigNamespaceProjection, type RuntimeConfigSection, type RuntimeConfigValidationErrorFormatter, type RuntimeConfigValidationErrorTarget, type RuntimeConfigValidationMode, type RuntimeConfigValidationPolicy, type RuntimeConfigValidationPolicyInput, type RuntimeConfigValidationSchemaRegistry, RuntimeConfigValidatorRegistry, type RuntimeEnvVars, type SectionedRuntimeConfig, createRuntimeConfigEnvKey, createRuntimeConfigKey, createRuntimeConfigValidatorRegistry, defaultRuntimeConfigValidationMode, getPrivateRuntimeConfigScope, getPublicRuntimeConfigScope, getRuntimeConfigFragment, getRuntimeConfigScope, injectRuntimeEnvVars, normalizeRuntimeConfigFragments, projectRuntimeConfigEnvVars, projectRuntimeConfigFragment, projectRuntimeConfigNamespace, projectRuntimeConfigNamespaces, projectSectionedRuntimeConfig, resolveRuntimeConfigValidationMode, resolveRuntimeConfigValue, resolveRuntimeConfigValueFromRuntimeConfig, runtimeConfigVisibilities, runtimeEnvValueToShellLiteral, runtimeEnvVarsToShellAssignments, runtimeEnvVarsToString, shouldRegisterRuntimeConfigValidationSchema, shouldRequireRuntimeConfigAtStartup, shouldValidateRuntimeConfigAtStartup, stripRuntimeConfigScopePrefix, toRuntimeConfigFragment, toRuntimeEnvVars, toSnakeUpperCase };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ErrorObject, ValidateFunction } from 'ajv';
|
|
2
|
+
|
|
1
3
|
type RuntimeConfigKeyStrategy = (scopeId: string, key: string) => string;
|
|
2
4
|
type RuntimeConfigKeyOptions = {
|
|
3
5
|
keyStrategy?: RuntimeConfigKeyStrategy;
|
|
@@ -98,4 +100,31 @@ declare function getPublicRuntimeConfigScope<T extends RuntimeConfigSection = Ru
|
|
|
98
100
|
declare function getPrivateRuntimeConfigScope<T extends RuntimeConfigSection = RuntimeConfigSection>(runtimeConfig: Partial<Record<ConfigVisibility, RuntimeConfigSection | undefined>>, scopeId: string, options?: Omit<GetRuntimeConfigScopeOptions, 'visibility'>): T;
|
|
99
101
|
declare function getRuntimeConfigFragment(runtimeConfig: Partial<Record<ConfigVisibility, RuntimeConfigSection | undefined>>, scopeId: string, options?: GetRuntimeConfigFragmentOptions): RuntimeConfigContext;
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
type RuntimeConfigValidationMode = 'none' | 'optional' | 'startup' | 'onUse';
|
|
104
|
+
type RuntimeConfigValidationPolicy = {
|
|
105
|
+
validation?: RuntimeConfigValidationMode;
|
|
106
|
+
};
|
|
107
|
+
type RuntimeConfigValidationSchemaRegistry = Record<string, object>;
|
|
108
|
+
type RuntimeConfigValidationErrorTarget = {
|
|
109
|
+
scopeId: string;
|
|
110
|
+
};
|
|
111
|
+
type RuntimeConfigValidationErrorFormatter = (target: RuntimeConfigValidationErrorTarget, validationError: ErrorObject) => Error;
|
|
112
|
+
type RuntimeConfigValidationPolicyInput = RuntimeConfigValidationMode | RuntimeConfigValidationPolicy | undefined;
|
|
113
|
+
declare const defaultRuntimeConfigValidationMode: RuntimeConfigValidationMode;
|
|
114
|
+
declare function resolveRuntimeConfigValidationMode(input: RuntimeConfigValidationPolicyInput): RuntimeConfigValidationMode;
|
|
115
|
+
declare function shouldRegisterRuntimeConfigValidationSchema(input: RuntimeConfigValidationPolicyInput): boolean;
|
|
116
|
+
declare function shouldValidateRuntimeConfigAtStartup(input: RuntimeConfigValidationPolicyInput): boolean;
|
|
117
|
+
declare function shouldRequireRuntimeConfigAtStartup(input: RuntimeConfigValidationPolicyInput): boolean;
|
|
118
|
+
declare class RuntimeConfigValidatorRegistry {
|
|
119
|
+
#private;
|
|
120
|
+
constructor(schemas: RuntimeConfigValidationSchemaRegistry, options?: {
|
|
121
|
+
formatError?: RuntimeConfigValidationErrorFormatter;
|
|
122
|
+
});
|
|
123
|
+
get(scopeId: string): ValidateFunction;
|
|
124
|
+
assert(scopeId: string, fragment: RuntimeConfigContext): void;
|
|
125
|
+
}
|
|
126
|
+
declare function createRuntimeConfigValidatorRegistry(schemas: RuntimeConfigValidationSchemaRegistry, options?: {
|
|
127
|
+
formatError?: RuntimeConfigValidationErrorFormatter;
|
|
128
|
+
}): RuntimeConfigValidatorRegistry;
|
|
129
|
+
|
|
130
|
+
export { type ConfigVisibility, type GetRuntimeConfigFragmentOptions, type GetRuntimeConfigScopeOptions, type NamedRuntimeConfigFragment, type NormalizeRuntimeConfigFragmentOptions, type ProjectRuntimeConfigEnvVarsOptions, type ProjectRuntimeConfigFragmentOptions, type ProjectRuntimeConfigNamespaceOptions, type ProjectRuntimeConfigNamespacesOptions, type ProjectSectionedRuntimeConfigOptions, type ResolveRuntimeConfigValueFromRuntimeConfigOptions, type ResolveRuntimeConfigValueOptions, type RuntimeConfigContext, type RuntimeConfigFragment, type RuntimeConfigFragmentInput, type RuntimeConfigFragmentMap, type RuntimeConfigKeyOptions, type RuntimeConfigKeyStrategy, type RuntimeConfigNamespaceProjection, type RuntimeConfigSection, type RuntimeConfigValidationErrorFormatter, type RuntimeConfigValidationErrorTarget, type RuntimeConfigValidationMode, type RuntimeConfigValidationPolicy, type RuntimeConfigValidationPolicyInput, type RuntimeConfigValidationSchemaRegistry, RuntimeConfigValidatorRegistry, type RuntimeEnvVars, type SectionedRuntimeConfig, createRuntimeConfigEnvKey, createRuntimeConfigKey, createRuntimeConfigValidatorRegistry, defaultRuntimeConfigValidationMode, getPrivateRuntimeConfigScope, getPublicRuntimeConfigScope, getRuntimeConfigFragment, getRuntimeConfigScope, injectRuntimeEnvVars, normalizeRuntimeConfigFragments, projectRuntimeConfigEnvVars, projectRuntimeConfigFragment, projectRuntimeConfigNamespace, projectRuntimeConfigNamespaces, projectSectionedRuntimeConfig, resolveRuntimeConfigValidationMode, resolveRuntimeConfigValue, resolveRuntimeConfigValueFromRuntimeConfig, runtimeConfigVisibilities, runtimeEnvValueToShellLiteral, runtimeEnvVarsToShellAssignments, runtimeEnvVarsToString, shouldRegisterRuntimeConfigValidationSchema, shouldRequireRuntimeConfigAtStartup, shouldValidateRuntimeConfigAtStartup, stripRuntimeConfigScopePrefix, toRuntimeConfigFragment, toRuntimeEnvVars, toSnakeUpperCase };
|
package/dist/index.js
CHANGED
|
@@ -292,9 +292,73 @@ function getRuntimeConfigFragment(runtimeConfig, scopeId, options = {}) {
|
|
|
292
292
|
private: getPrivateRuntimeConfigScope(runtimeConfig, scopeId, privateOptions)
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
|
+
|
|
296
|
+
// src/validation.ts
|
|
297
|
+
import Ajv from "ajv";
|
|
298
|
+
var defaultRuntimeConfigValidationMode = "optional";
|
|
299
|
+
function resolveRuntimeConfigValidationMode(input) {
|
|
300
|
+
return typeof input === "string" ? input : input?.validation ?? defaultRuntimeConfigValidationMode;
|
|
301
|
+
}
|
|
302
|
+
function shouldRegisterRuntimeConfigValidationSchema(input) {
|
|
303
|
+
return resolveRuntimeConfigValidationMode(input) !== "none";
|
|
304
|
+
}
|
|
305
|
+
function shouldValidateRuntimeConfigAtStartup(input) {
|
|
306
|
+
const mode = resolveRuntimeConfigValidationMode(input);
|
|
307
|
+
return mode !== "none" && mode !== "onUse";
|
|
308
|
+
}
|
|
309
|
+
function shouldRequireRuntimeConfigAtStartup(input) {
|
|
310
|
+
return resolveRuntimeConfigValidationMode(input) === "startup";
|
|
311
|
+
}
|
|
312
|
+
function formatDefaultRuntimeConfigValidationError(target, validationError) {
|
|
313
|
+
const jsonPath = validationError.instancePath || "/";
|
|
314
|
+
const schemaError = `${validationError.keyword}${validationError.message ? `: ${validationError.message}` : ""}`;
|
|
315
|
+
return new Error(
|
|
316
|
+
[
|
|
317
|
+
"RuntimeConfig schema validation failed.",
|
|
318
|
+
`Scope: ${target.scopeId}`,
|
|
319
|
+
`JSON path: ${jsonPath}`,
|
|
320
|
+
`Schema error: ${schemaError}`
|
|
321
|
+
].join("\n")
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
var RuntimeConfigValidatorRegistry = class {
|
|
325
|
+
#cache = /* @__PURE__ */ new Map();
|
|
326
|
+
#formatError;
|
|
327
|
+
#schemas;
|
|
328
|
+
constructor(schemas, options = {}) {
|
|
329
|
+
this.#formatError = options.formatError ?? formatDefaultRuntimeConfigValidationError;
|
|
330
|
+
this.#schemas = schemas;
|
|
331
|
+
}
|
|
332
|
+
get(scopeId) {
|
|
333
|
+
const schema = this.#schemas[scopeId];
|
|
334
|
+
if (!schema) {
|
|
335
|
+
throw new Error(`RuntimeConfig validation schema not registered for scope "${scopeId}".`);
|
|
336
|
+
}
|
|
337
|
+
const cached = this.#cache.get(scopeId);
|
|
338
|
+
if (cached) return cached;
|
|
339
|
+
const validate = new Ajv({ strict: false, allErrors: false }).compile(schema);
|
|
340
|
+
this.#cache.set(scopeId, validate);
|
|
341
|
+
return validate;
|
|
342
|
+
}
|
|
343
|
+
assert(scopeId, fragment) {
|
|
344
|
+
const validate = this.get(scopeId);
|
|
345
|
+
if (validate(fragment)) return;
|
|
346
|
+
const validationError = validate.errors?.[0];
|
|
347
|
+
if (!validationError) {
|
|
348
|
+
throw new Error(`RuntimeConfig schema validation failed for scope "${scopeId}".`);
|
|
349
|
+
}
|
|
350
|
+
throw this.#formatError({ scopeId }, validationError);
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
function createRuntimeConfigValidatorRegistry(schemas, options = {}) {
|
|
354
|
+
return new RuntimeConfigValidatorRegistry(schemas, options);
|
|
355
|
+
}
|
|
295
356
|
export {
|
|
357
|
+
RuntimeConfigValidatorRegistry,
|
|
296
358
|
createRuntimeConfigEnvKey,
|
|
297
359
|
createRuntimeConfigKey,
|
|
360
|
+
createRuntimeConfigValidatorRegistry,
|
|
361
|
+
defaultRuntimeConfigValidationMode,
|
|
298
362
|
getPrivateRuntimeConfigScope,
|
|
299
363
|
getPublicRuntimeConfigScope,
|
|
300
364
|
getRuntimeConfigFragment,
|
|
@@ -306,12 +370,16 @@ export {
|
|
|
306
370
|
projectRuntimeConfigNamespace,
|
|
307
371
|
projectRuntimeConfigNamespaces,
|
|
308
372
|
projectSectionedRuntimeConfig,
|
|
373
|
+
resolveRuntimeConfigValidationMode,
|
|
309
374
|
resolveRuntimeConfigValue,
|
|
310
375
|
resolveRuntimeConfigValueFromRuntimeConfig,
|
|
311
376
|
runtimeConfigVisibilities,
|
|
312
377
|
runtimeEnvValueToShellLiteral,
|
|
313
378
|
runtimeEnvVarsToShellAssignments,
|
|
314
379
|
runtimeEnvVarsToString,
|
|
380
|
+
shouldRegisterRuntimeConfigValidationSchema,
|
|
381
|
+
shouldRequireRuntimeConfigAtStartup,
|
|
382
|
+
shouldValidateRuntimeConfigAtStartup,
|
|
315
383
|
stripRuntimeConfigScopePrefix,
|
|
316
384
|
toRuntimeConfigFragment,
|
|
317
385
|
toRuntimeEnvVars,
|