@lorion-org/runtime-config-node 1.0.0-beta.0 → 1.0.0-beta.5
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 +27 -27
- package/dist/index.cjs +106 -14
- package/dist/index.d.cts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +107 -15
- package/package.json +9 -4
- package/src/index.ts +1063 -0
- package/examples/env-assignments.ts +0 -21
- package/examples/load-runtime-config-tree.ts +0 -17
- package/examples/query-runtime-config-tree.ts +0 -53
- package/examples/source-and-scope-files.ts +0 -24
package/dist/index.js
CHANGED
|
@@ -8,7 +8,10 @@ import {
|
|
|
8
8
|
resolveRuntimeConfigValueFromRuntimeConfig,
|
|
9
9
|
projectRuntimeConfigEnvVars,
|
|
10
10
|
toRuntimeConfigFragment,
|
|
11
|
-
runtimeEnvVarsToShellAssignments
|
|
11
|
+
runtimeEnvVarsToShellAssignments,
|
|
12
|
+
resolveRuntimeConfigValidationMode,
|
|
13
|
+
shouldRegisterRuntimeConfigValidationSchema,
|
|
14
|
+
shouldRequireRuntimeConfigAtStartup
|
|
12
15
|
} from "@lorion-org/runtime-config";
|
|
13
16
|
var defaultRuntimeConfigFileName = "runtime.config.json";
|
|
14
17
|
var defaultRuntimeConfigDirName = "runtime-config";
|
|
@@ -103,6 +106,35 @@ function getRuntimeConfigPathOptions(source) {
|
|
|
103
106
|
function getSchemaFileName(options) {
|
|
104
107
|
return options.schemaFileName ?? defaultRuntimeConfigSchemaFileName;
|
|
105
108
|
}
|
|
109
|
+
function formatMissingRuntimeConfigValidationError(skipped) {
|
|
110
|
+
if (skipped.reason === "missing-schema") {
|
|
111
|
+
return new Error(
|
|
112
|
+
[
|
|
113
|
+
`RuntimeConfig schema file missing for scope "${skipped.scopeId}".`,
|
|
114
|
+
...skipped.schemaPath ? [`missing schema file: ${skipped.schemaPath}`] : [],
|
|
115
|
+
...skipped.configPath ? [`runtime config file: ${skipped.configPath}`] : []
|
|
116
|
+
].join(" ")
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
if (skipped.reason === "missing-config") {
|
|
120
|
+
return new Error(
|
|
121
|
+
[
|
|
122
|
+
`RuntimeConfig file missing for scope "${skipped.scopeId}".`,
|
|
123
|
+
...skipped.configPath ? [`expected runtime config file: ${skipped.configPath}`] : [],
|
|
124
|
+
...skipped.schemaPath ? [`schema file: ${skipped.schemaPath}`] : []
|
|
125
|
+
].join(" ")
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const details = [
|
|
129
|
+
`RuntimeConfig validation target has no schema directory for scope "${skipped.scopeId}".`
|
|
130
|
+
];
|
|
131
|
+
if (skipped.configPath) details.push(`runtime config file: ${skipped.configPath}`);
|
|
132
|
+
if (skipped.schemaPath) details.push(`schema file: ${skipped.schemaPath}`);
|
|
133
|
+
return new Error(details.join(" "));
|
|
134
|
+
}
|
|
135
|
+
function shouldReportMissingRuntimeConfig(mode) {
|
|
136
|
+
return mode !== "optional";
|
|
137
|
+
}
|
|
106
138
|
function stripJsonBom(text) {
|
|
107
139
|
return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
108
140
|
}
|
|
@@ -279,12 +311,19 @@ function formatRuntimeConfigSchemaValidationError(target, validationError) {
|
|
|
279
311
|
);
|
|
280
312
|
}
|
|
281
313
|
function validateRuntimeConfigSchemaTargets(targets, options = {}) {
|
|
314
|
+
const invalid = collectRuntimeConfigSchemaTargetValidationErrors(targets, options);
|
|
315
|
+
if (invalid[0]) {
|
|
316
|
+
throw invalid[0].error;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function collectRuntimeConfigSchemaTargetValidationErrors(targets, options = {}) {
|
|
282
320
|
const ajv = new Ajv({
|
|
283
321
|
strict: false,
|
|
284
322
|
allErrors: false,
|
|
285
323
|
...options.ajvOptions
|
|
286
324
|
});
|
|
287
325
|
const formatError = options.formatError ?? formatRuntimeConfigSchemaValidationError;
|
|
326
|
+
const invalid = [];
|
|
288
327
|
for (const target of targets) {
|
|
289
328
|
if (!existsSync(target.schemaPath) || !existsSync(target.configPath)) {
|
|
290
329
|
continue;
|
|
@@ -296,13 +335,21 @@ function validateRuntimeConfigSchemaTargets(targets, options = {}) {
|
|
|
296
335
|
if (!isValid) {
|
|
297
336
|
const validationError = validate.errors?.[0];
|
|
298
337
|
if (validationError) {
|
|
299
|
-
|
|
338
|
+
invalid.push({
|
|
339
|
+
...target,
|
|
340
|
+
error: formatError(target, validationError)
|
|
341
|
+
});
|
|
342
|
+
continue;
|
|
300
343
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
344
|
+
invalid.push({
|
|
345
|
+
...target,
|
|
346
|
+
error: new Error(
|
|
347
|
+
`RuntimeConfig schema validation failed for "${target.scopeId}" (${target.configPath})`
|
|
348
|
+
)
|
|
349
|
+
});
|
|
304
350
|
}
|
|
305
351
|
}
|
|
352
|
+
return invalid;
|
|
306
353
|
}
|
|
307
354
|
function loadRuntimeConfigTree(varDir, options = {}) {
|
|
308
355
|
const runtimeConfigDir = path.join(varDir, getRuntimeConfigDirName(options));
|
|
@@ -421,21 +468,28 @@ function validateRuntimeConfigScopes(varDir, targets, options = {}) {
|
|
|
421
468
|
const schemaFileName = getSchemaFileName(options);
|
|
422
469
|
const result = {
|
|
423
470
|
fileName: getFileName(options),
|
|
471
|
+
invalid: [],
|
|
424
472
|
skipped: [],
|
|
425
473
|
validated: [],
|
|
426
474
|
varDir
|
|
427
475
|
};
|
|
428
476
|
for (const target of targets) {
|
|
477
|
+
if (!shouldRegisterRuntimeConfigValidationSchema(target.policy)) continue;
|
|
429
478
|
const scopeId = target.scopeId.trim();
|
|
430
479
|
if (!scopeId) continue;
|
|
480
|
+
const mode = resolveRuntimeConfigValidationMode(target.policy);
|
|
431
481
|
const configPath = resolveRuntimeConfigPaths(varDir, scopeId, options).filePath;
|
|
432
482
|
const schemaPath = target.cwd ? path.resolve(target.cwd, schemaFileName) : void 0;
|
|
433
483
|
if (!target.cwd || !schemaPath) {
|
|
434
|
-
|
|
484
|
+
if (shouldReportMissingRuntimeConfig(mode)) {
|
|
485
|
+
result.skipped.push({ configPath, reason: "missing-scope-dir", scopeId });
|
|
486
|
+
}
|
|
435
487
|
continue;
|
|
436
488
|
}
|
|
437
489
|
if (!existsSync(configPath)) {
|
|
438
|
-
|
|
490
|
+
if (shouldReportMissingRuntimeConfig(mode)) {
|
|
491
|
+
result.skipped.push({ configPath, reason: "missing-config", schemaPath, scopeId });
|
|
492
|
+
}
|
|
439
493
|
continue;
|
|
440
494
|
}
|
|
441
495
|
if (!existsSync(schemaPath)) {
|
|
@@ -444,16 +498,45 @@ function validateRuntimeConfigScopes(varDir, targets, options = {}) {
|
|
|
444
498
|
}
|
|
445
499
|
result.validated.push({ configPath, schemaPath, scopeId });
|
|
446
500
|
}
|
|
447
|
-
|
|
501
|
+
result.invalid = collectRuntimeConfigSchemaTargetValidationErrors(result.validated, {
|
|
448
502
|
...options.formatError ? { formatError: options.formatError } : {}
|
|
449
503
|
});
|
|
450
504
|
return result;
|
|
451
505
|
}
|
|
506
|
+
function readRuntimeConfigSchemaRegistry(targets, options = {}) {
|
|
507
|
+
const schemaFileName = options.schemaFileName ?? defaultRuntimeConfigSchemaFileName;
|
|
508
|
+
const entries = targets.filter((target) => shouldRegisterRuntimeConfigValidationSchema(target.policy)).flatMap((target) => {
|
|
509
|
+
const scopeId = target.scopeId.trim();
|
|
510
|
+
if (!scopeId || !target.cwd) return [];
|
|
511
|
+
const schemaPath = path.resolve(target.cwd, schemaFileName);
|
|
512
|
+
if (!existsSync(schemaPath)) return [];
|
|
513
|
+
return [[scopeId, readRequiredJsonFile(schemaPath)]];
|
|
514
|
+
});
|
|
515
|
+
return Object.fromEntries(entries);
|
|
516
|
+
}
|
|
517
|
+
function assertRequiredRuntimeConfigValidationTargets(result, targets) {
|
|
518
|
+
const requiredScopeIds = new Set(
|
|
519
|
+
targets.filter((target) => shouldRequireRuntimeConfigAtStartup(target.policy)).map((target) => target.scopeId.trim()).filter(Boolean)
|
|
520
|
+
);
|
|
521
|
+
const requiredFailures = [
|
|
522
|
+
...result.skipped.filter((entry) => requiredScopeIds.has(entry.scopeId)).map(formatMissingRuntimeConfigValidationError),
|
|
523
|
+
...result.invalid.filter((entry) => requiredScopeIds.has(entry.scopeId)).map((entry) => entry.error)
|
|
524
|
+
];
|
|
525
|
+
if (requiredFailures.length) {
|
|
526
|
+
throw new Error(
|
|
527
|
+
[
|
|
528
|
+
"RuntimeConfig startup validation failed.",
|
|
529
|
+
...requiredFailures.map((error) => error.message)
|
|
530
|
+
].join("\n\n")
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
452
534
|
function validateRuntimeConfigSourceScopes(source, targets, options = {}) {
|
|
453
535
|
const schemaFileName = getSchemaFileName(options);
|
|
454
536
|
const filesByScope = /* @__PURE__ */ new Map();
|
|
455
537
|
const result = {
|
|
456
538
|
fileName: source.paths[0] ?? "",
|
|
539
|
+
invalid: [],
|
|
457
540
|
skipped: [],
|
|
458
541
|
validated: [],
|
|
459
542
|
varDir: ""
|
|
@@ -462,20 +545,26 @@ function validateRuntimeConfigSourceScopes(source, targets, options = {}) {
|
|
|
462
545
|
filesByScope.set(file.scopeId, file.configPath);
|
|
463
546
|
}
|
|
464
547
|
for (const target of targets) {
|
|
548
|
+
if (!shouldRegisterRuntimeConfigValidationSchema(target.policy)) continue;
|
|
465
549
|
const scopeId = target.scopeId.trim();
|
|
466
550
|
if (!scopeId) continue;
|
|
551
|
+
const mode = resolveRuntimeConfigValidationMode(target.policy);
|
|
467
552
|
const configPath = filesByScope.get(scopeId);
|
|
468
553
|
const schemaPath = target.cwd ? path.resolve(target.cwd, schemaFileName) : void 0;
|
|
469
554
|
if (!target.cwd || !schemaPath) {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
555
|
+
if (shouldReportMissingRuntimeConfig(mode)) {
|
|
556
|
+
result.skipped.push({
|
|
557
|
+
...configPath ? { configPath } : {},
|
|
558
|
+
reason: "missing-scope-dir",
|
|
559
|
+
scopeId
|
|
560
|
+
});
|
|
561
|
+
}
|
|
475
562
|
continue;
|
|
476
563
|
}
|
|
477
564
|
if (!configPath) {
|
|
478
|
-
|
|
565
|
+
if (shouldReportMissingRuntimeConfig(mode)) {
|
|
566
|
+
result.skipped.push({ reason: "missing-config", schemaPath, scopeId });
|
|
567
|
+
}
|
|
479
568
|
continue;
|
|
480
569
|
}
|
|
481
570
|
if (!existsSync(schemaPath)) {
|
|
@@ -484,13 +573,15 @@ function validateRuntimeConfigSourceScopes(source, targets, options = {}) {
|
|
|
484
573
|
}
|
|
485
574
|
result.validated.push({ configPath, schemaPath, scopeId });
|
|
486
575
|
}
|
|
487
|
-
|
|
576
|
+
result.invalid = collectRuntimeConfigSchemaTargetValidationErrors(result.validated, {
|
|
488
577
|
...options.formatError ? { formatError: options.formatError } : {}
|
|
489
578
|
});
|
|
490
579
|
return result;
|
|
491
580
|
}
|
|
492
581
|
export {
|
|
582
|
+
assertRequiredRuntimeConfigValidationTargets,
|
|
493
583
|
collectRuntimeConfigFragmentFiles,
|
|
584
|
+
collectRuntimeConfigSchemaTargetValidationErrors,
|
|
494
585
|
ensureParentDir,
|
|
495
586
|
getRuntimeConfigScopeView,
|
|
496
587
|
getRuntimeConfigValue,
|
|
@@ -505,6 +596,7 @@ export {
|
|
|
505
596
|
projectRuntimeConfigTree,
|
|
506
597
|
readJsonFile,
|
|
507
598
|
readRequiredJsonFile,
|
|
599
|
+
readRuntimeConfigSchemaRegistry,
|
|
508
600
|
readRuntimeConfigScopeJson,
|
|
509
601
|
readTextFile,
|
|
510
602
|
resolveRuntimeConfigFilePath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lorion-org/runtime-config-node",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
4
|
"description": "Node file-system helpers for runtime-config directories and files.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"types": "./dist/index.d.ts",
|
|
23
23
|
"exports": {
|
|
24
24
|
".": {
|
|
25
|
+
"lorion-source": {
|
|
26
|
+
"types": "./src/index.ts",
|
|
27
|
+
"default": "./src/index.ts"
|
|
28
|
+
},
|
|
25
29
|
"import": {
|
|
26
30
|
"types": "./dist/index.d.ts",
|
|
27
31
|
"default": "./dist/index.js"
|
|
@@ -34,8 +38,9 @@
|
|
|
34
38
|
},
|
|
35
39
|
"files": [
|
|
36
40
|
"dist",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
41
|
+
"LICENSE",
|
|
42
|
+
"src/**/*.ts",
|
|
43
|
+
"!src/**/*.spec.ts"
|
|
39
44
|
],
|
|
40
45
|
"keywords": [
|
|
41
46
|
"runtime-config",
|
|
@@ -48,7 +53,7 @@
|
|
|
48
53
|
},
|
|
49
54
|
"dependencies": {
|
|
50
55
|
"ajv": "^8.17.1",
|
|
51
|
-
"@lorion-org/runtime-config": "^1.0.0-beta.
|
|
56
|
+
"@lorion-org/runtime-config": "^1.0.0-beta.5"
|
|
52
57
|
},
|
|
53
58
|
"scripts": {
|
|
54
59
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|