@kitsy/cnos 1.6.1 → 1.8.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 (63) hide show
  1. package/dist/build/index.cjs +1332 -156
  2. package/dist/build/index.d.cts +1 -1
  3. package/dist/build/index.d.ts +1 -1
  4. package/dist/build/index.js +36 -14
  5. package/dist/{chunk-JYWQFMW5.js → chunk-2DGT7N7E.js} +1 -1
  6. package/dist/{chunk-S7H2UULC.js → chunk-2TL42I6M.js} +1323 -139
  7. package/dist/{chunk-MW4OVAT3.js → chunk-5KIQCYFH.js} +1 -1
  8. package/dist/{chunk-6FAX2VKQ.js → chunk-CW7SNVIQ.js} +195 -28
  9. package/dist/{chunk-XSUP7JKH.js → chunk-GHGJFRDL.js} +6 -2
  10. package/dist/{chunk-BMAD24KC.js → chunk-OA7FQGAG.js} +1 -1
  11. package/dist/{chunk-VGZREX5D.js → chunk-RYIARE4M.js} +1 -1
  12. package/dist/{chunk-UR7CHHNN.js → chunk-TT4NV56Z.js} +3 -2
  13. package/dist/{chunk-UJBQS7CJ.js → chunk-UL63DFLS.js} +1 -1
  14. package/dist/{chunk-N32UN66E.js → chunk-ZD4YX6VC.js} +8 -8
  15. package/dist/configure/index.cjs +1309 -155
  16. package/dist/configure/index.d.cts +3 -3
  17. package/dist/configure/index.d.ts +3 -3
  18. package/dist/configure/index.js +8 -8
  19. package/dist/{plugin-CKrBlWGI.d.cts → core-BJ8xewez.d.cts} +142 -60
  20. package/dist/{plugin-CKrBlWGI.d.ts → core-BJ8xewez.d.ts} +142 -60
  21. package/dist/{envNaming-B7Mztkcf.d.ts → envNaming-BRyiuPoI.d.ts} +1 -1
  22. package/dist/{envNaming-gMVnPOfe.d.cts → envNaming-rx71gpi0.d.cts} +1 -1
  23. package/dist/index.cjs +1548 -227
  24. package/dist/index.d.cts +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.js +10 -10
  27. package/dist/internal.cjs +831 -122
  28. package/dist/internal.d.cts +56 -3
  29. package/dist/internal.d.ts +56 -3
  30. package/dist/internal.js +30 -3
  31. package/dist/plugin/basic-schema.cjs +49 -23
  32. package/dist/plugin/basic-schema.d.cts +1 -1
  33. package/dist/plugin/basic-schema.d.ts +1 -1
  34. package/dist/plugin/basic-schema.js +2 -2
  35. package/dist/plugin/cli-args.cjs +38 -23
  36. package/dist/plugin/cli-args.d.cts +1 -1
  37. package/dist/plugin/cli-args.d.ts +1 -1
  38. package/dist/plugin/cli-args.js +2 -2
  39. package/dist/plugin/dotenv.cjs +46 -31
  40. package/dist/plugin/dotenv.d.cts +2 -2
  41. package/dist/plugin/dotenv.d.ts +2 -2
  42. package/dist/plugin/dotenv.js +2 -2
  43. package/dist/plugin/env-export.cjs +56 -27
  44. package/dist/plugin/env-export.d.cts +2 -2
  45. package/dist/plugin/env-export.d.ts +2 -2
  46. package/dist/plugin/env-export.js +2 -2
  47. package/dist/plugin/filesystem.cjs +61 -39
  48. package/dist/plugin/filesystem.d.cts +1 -1
  49. package/dist/plugin/filesystem.d.ts +1 -1
  50. package/dist/plugin/filesystem.js +2 -2
  51. package/dist/plugin/process-env.cjs +40 -25
  52. package/dist/plugin/process-env.d.cts +2 -2
  53. package/dist/plugin/process-env.d.ts +2 -2
  54. package/dist/plugin/process-env.js +2 -2
  55. package/dist/runtime/index.cjs +1548 -227
  56. package/dist/runtime/index.d.cts +3 -1
  57. package/dist/runtime/index.d.ts +3 -1
  58. package/dist/runtime/index.js +10 -10
  59. package/dist/toPublicEnv-CCSgdvI9.d.ts +13 -0
  60. package/dist/toPublicEnv-ivRtLjcw.d.cts +13 -0
  61. package/package.json +1 -1
  62. package/dist/toPublicEnv-CmBsy53P.d.cts +0 -7
  63. package/dist/toPublicEnv-q6VwWxXZ.d.ts +0 -7
@@ -73,16 +73,673 @@ var CnosKeyNotFoundError = class extends CnosError {
73
73
  }
74
74
  key;
75
75
  };
76
+ var CnosDerivedExpressionError = class extends CnosError {
77
+ constructor(message, expression) {
78
+ super(expression ? `${message} (${expression})` : message);
79
+ this.expression = expression;
80
+ }
81
+ expression;
82
+ };
83
+ var CnosDerivedCycleError = class extends CnosError {
84
+ constructor(message) {
85
+ super(message);
86
+ }
87
+ };
88
+ var CnosDerivedResolutionError = class extends CnosError {
89
+ constructor(key, message) {
90
+ super(message);
91
+ this.key = key;
92
+ }
93
+ key;
94
+ };
95
+ var CnosRuntimeProviderError = class extends CnosError {
96
+ constructor(message) {
97
+ super(message);
98
+ }
99
+ };
100
+
101
+ // ../core/src/derive/builtins.ts
102
+ function stringify(value) {
103
+ if (value === void 0 || value === null) {
104
+ return "";
105
+ }
106
+ if (typeof value === "string") {
107
+ return value;
108
+ }
109
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
110
+ return String(value);
111
+ }
112
+ return JSON.stringify(value);
113
+ }
114
+ var DERIVE_BUILTINS = {
115
+ concat: (...args) => args.map((value) => stringify(value)).join(""),
116
+ coalesce: (...args) => args.find((value) => value !== void 0 && value !== null),
117
+ when: (condition, whenTrue, whenFalse) => condition ? whenTrue : whenFalse,
118
+ exists: (value) => value !== void 0 && value !== null,
119
+ eq: (left, right) => left === right,
120
+ ne: (left, right) => left !== right
121
+ };
122
+
123
+ // ../core/src/derive/depGraph.ts
124
+ function detectDerivationCycles(dependencyMap) {
125
+ const visiting = /* @__PURE__ */ new Set();
126
+ const visited = /* @__PURE__ */ new Set();
127
+ const stack = [];
128
+ const visit = (key) => {
129
+ if (visited.has(key)) {
130
+ return;
131
+ }
132
+ if (visiting.has(key)) {
133
+ const start = stack.indexOf(key);
134
+ const cycle = [...stack.slice(start), key].join(" -> ");
135
+ throw new CnosDerivedCycleError(`Derivation cycle detected: ${cycle}`);
136
+ }
137
+ visiting.add(key);
138
+ stack.push(key);
139
+ for (const dependency of dependencyMap.get(key) ?? []) {
140
+ visit(dependency);
141
+ }
142
+ stack.pop();
143
+ visiting.delete(key);
144
+ visited.add(key);
145
+ };
146
+ for (const key of dependencyMap.keys()) {
147
+ visit(key);
148
+ }
149
+ }
150
+
151
+ // ../core/src/derive/parser.ts
152
+ function isWhitespace(value) {
153
+ return value === " " || value === "\n" || value === "\r" || value === " ";
154
+ }
155
+ function skipWhitespace(state) {
156
+ while (isWhitespace(state.source[state.index])) {
157
+ state.index += 1;
158
+ }
159
+ }
160
+ function isIdentifierStart(value) {
161
+ return typeof value === "string" && /[A-Za-z_]/.test(value);
162
+ }
163
+ function isIdentifierPart(value) {
164
+ return typeof value === "string" && /[A-Za-z0-9_.-]/.test(value);
165
+ }
166
+ function errorAt(state, message) {
167
+ throw new CnosDerivedExpressionError(`${message} at position ${state.index + 1}`, state.source);
168
+ }
169
+ function parseStringLiteral(state) {
170
+ const quote = state.source[state.index];
171
+ if (quote !== "'") {
172
+ errorAt(state, "Expected string literal");
173
+ }
174
+ state.index += 1;
175
+ let value = "";
176
+ while (state.index < state.source.length) {
177
+ const current = state.source[state.index];
178
+ if (current === "\\") {
179
+ const next = state.source[state.index + 1];
180
+ if (next === void 0) {
181
+ errorAt(state, "Unterminated escape sequence");
182
+ }
183
+ value += next;
184
+ state.index += 2;
185
+ continue;
186
+ }
187
+ if (current === "'") {
188
+ state.index += 1;
189
+ return {
190
+ type: "literal",
191
+ value
192
+ };
193
+ }
194
+ value += current;
195
+ state.index += 1;
196
+ }
197
+ errorAt(state, "Unterminated string literal");
198
+ }
199
+ function parseNumberLiteral(state) {
200
+ const start = state.index;
201
+ while (/[0-9]/.test(state.source[state.index] ?? "")) {
202
+ state.index += 1;
203
+ }
204
+ if (state.source[state.index] === ".") {
205
+ state.index += 1;
206
+ while (/[0-9]/.test(state.source[state.index] ?? "")) {
207
+ state.index += 1;
208
+ }
209
+ }
210
+ return {
211
+ type: "literal",
212
+ value: Number(state.source.slice(start, state.index))
213
+ };
214
+ }
215
+ function parseIdentifier(state) {
216
+ if (!isIdentifierStart(state.source[state.index])) {
217
+ errorAt(state, "Expected identifier");
218
+ }
219
+ const start = state.index;
220
+ state.index += 1;
221
+ while (isIdentifierPart(state.source[state.index])) {
222
+ state.index += 1;
223
+ }
224
+ return state.source.slice(start, state.index);
225
+ }
226
+ function parseArguments(state) {
227
+ const args = [];
228
+ skipWhitespace(state);
229
+ if (state.source[state.index] === ")") {
230
+ state.index += 1;
231
+ return args;
232
+ }
233
+ while (state.index < state.source.length) {
234
+ args.push(parseExpressionNode(state));
235
+ skipWhitespace(state);
236
+ const current = state.source[state.index];
237
+ if (current === ",") {
238
+ state.index += 1;
239
+ skipWhitespace(state);
240
+ continue;
241
+ }
242
+ if (current === ")") {
243
+ state.index += 1;
244
+ return args;
245
+ }
246
+ errorAt(state, 'Expected "," or ")"');
247
+ }
248
+ errorAt(state, "Unterminated function call");
249
+ }
250
+ function parseIdentifierOrCall(state) {
251
+ const identifier = parseIdentifier(state);
252
+ skipWhitespace(state);
253
+ if (state.source[state.index] === "(") {
254
+ if (!(identifier in DERIVE_BUILTINS)) {
255
+ throw new CnosDerivedExpressionError(`Unknown derive function: ${identifier}`, state.source);
256
+ }
257
+ state.index += 1;
258
+ return {
259
+ type: "call",
260
+ name: identifier,
261
+ args: parseArguments(state)
262
+ };
263
+ }
264
+ if (identifier === "true" || identifier === "false") {
265
+ return {
266
+ type: "literal",
267
+ value: identifier === "true"
268
+ };
269
+ }
270
+ if (identifier === "null") {
271
+ return {
272
+ type: "literal",
273
+ value: null
274
+ };
275
+ }
276
+ return {
277
+ type: "ref",
278
+ path: identifier
279
+ };
280
+ }
281
+ function parseExpressionNode(state) {
282
+ skipWhitespace(state);
283
+ const current = state.source[state.index];
284
+ if (current === "'") {
285
+ return parseStringLiteral(state);
286
+ }
287
+ if (/[0-9]/.test(current ?? "")) {
288
+ return parseNumberLiteral(state);
289
+ }
290
+ if (isIdentifierStart(current)) {
291
+ return parseIdentifierOrCall(state);
292
+ }
293
+ errorAt(state, "Unexpected token");
294
+ }
295
+ function parseExpression(source) {
296
+ const state = {
297
+ source,
298
+ index: 0
299
+ };
300
+ const ast = parseExpressionNode(state);
301
+ skipWhitespace(state);
302
+ if (state.index !== source.length) {
303
+ errorAt(state, "Unexpected trailing input");
304
+ }
305
+ return ast;
306
+ }
307
+
308
+ // ../core/src/derive/templateParser.ts
309
+ function toLiteral(value) {
310
+ return {
311
+ type: "literal",
312
+ value
313
+ };
314
+ }
315
+ function toRef(path16) {
316
+ return {
317
+ type: "ref",
318
+ path: path16
319
+ };
320
+ }
321
+ function parseTemplate(source) {
322
+ const parts = [];
323
+ let cursor = 0;
324
+ while (cursor < source.length) {
325
+ const start = source.indexOf("${", cursor);
326
+ if (start < 0) {
327
+ if (cursor < source.length) {
328
+ parts.push(toLiteral(source.slice(cursor)));
329
+ }
330
+ break;
331
+ }
332
+ if (start > cursor) {
333
+ parts.push(toLiteral(source.slice(cursor, start)));
334
+ }
335
+ const end = source.indexOf("}", start + 2);
336
+ if (end < 0) {
337
+ throw new CnosDerivedExpressionError(`Invalid derivation template: unclosed \${...} at position ${start + 1}`, source);
338
+ }
339
+ const ref = source.slice(start + 2, end).trim();
340
+ if (!ref) {
341
+ throw new CnosDerivedExpressionError(`Invalid derivation template: empty reference at position ${start + 1}`, source);
342
+ }
343
+ if (!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(ref)) {
344
+ throw new CnosDerivedExpressionError(`Invalid derivation template reference "${ref}"`, source);
345
+ }
346
+ parts.push(toRef(ref));
347
+ cursor = end + 1;
348
+ }
349
+ if (parts.length === 0) {
350
+ return toLiteral("");
351
+ }
352
+ if (parts.length === 1) {
353
+ return parts[0];
354
+ }
355
+ return {
356
+ type: "call",
357
+ name: "concat",
358
+ args: parts
359
+ };
360
+ }
361
+
362
+ // ../core/src/derive/evaluator.ts
363
+ function isDerivedValue(value) {
364
+ return Boolean(
365
+ value && typeof value === "object" && !Array.isArray(value) && "$derive" in value
366
+ );
367
+ }
368
+ function extractRefs(node, refs = /* @__PURE__ */ new Set()) {
369
+ if (node.type === "ref") {
370
+ refs.add(node.path);
371
+ return refs;
372
+ }
373
+ if (node.type === "call") {
374
+ for (const arg of node.args) {
375
+ extractRefs(arg, refs);
376
+ }
377
+ }
378
+ return refs;
379
+ }
380
+ function parseDerivation(value) {
381
+ const source = typeof value.$derive === "string" ? value.$derive : value.$derive?.expr;
382
+ if (typeof source !== "string") {
383
+ throw new CnosDerivedExpressionError("Derived value requires either a template string or { expr } object");
384
+ }
385
+ const type = typeof value.$derive === "string" ? "template" : "expression";
386
+ const ast = type === "template" ? parseTemplate(source) : parseExpression(source);
387
+ const refs = Array.from(extractRefs(ast)).sort((left, right) => left.localeCompare(right));
388
+ return {
389
+ type,
390
+ raw: source,
391
+ ast,
392
+ refs,
393
+ runtimeRefs: [],
394
+ isRuntimeDependent: false
395
+ };
396
+ }
397
+ function normalizeConcatValue(value) {
398
+ if (value === void 0 || value === null) {
399
+ return "";
400
+ }
401
+ if (typeof value === "string") {
402
+ return value;
403
+ }
404
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
405
+ return String(value);
406
+ }
407
+ return JSON.stringify(value);
408
+ }
409
+ function evaluateNode(node, resolveRef) {
410
+ switch (node.type) {
411
+ case "literal":
412
+ return node.value;
413
+ case "ref":
414
+ return resolveRef(node.path);
415
+ case "call": {
416
+ const args = node.args.map((arg) => evaluateNode(arg, resolveRef));
417
+ switch (node.name) {
418
+ case "concat":
419
+ return args.map((value) => normalizeConcatValue(value)).join("");
420
+ case "coalesce":
421
+ return DERIVE_BUILTINS.coalesce(...args);
422
+ case "when":
423
+ return DERIVE_BUILTINS.when(args[0], args[1], args[2]);
424
+ case "exists":
425
+ return DERIVE_BUILTINS.exists(args[0]);
426
+ case "eq":
427
+ return DERIVE_BUILTINS.eq(args[0], args[1]);
428
+ case "ne":
429
+ return DERIVE_BUILTINS.ne(args[0], args[1]);
430
+ default:
431
+ throw new CnosDerivedExpressionError(`Unknown derive function: ${String(node.name)}`);
432
+ }
433
+ }
434
+ default:
435
+ throw new CnosDerivedExpressionError(`Unsupported derive AST node ${node.type ?? "unknown"}`);
436
+ }
437
+ }
438
+ function evaluateDerivation(options) {
439
+ const missingRefs = /* @__PURE__ */ new Set();
440
+ const value = evaluateNode(options.parsed.ast, (ref) => {
441
+ const resolved = options.resolveRef(ref);
442
+ if (resolved === void 0) {
443
+ missingRefs.add(ref);
444
+ options.onMissing?.(ref);
445
+ }
446
+ return resolved;
447
+ });
448
+ if (missingRefs.size > 0 && options.parsed.ast.type === "ref") {
449
+ throw new CnosDerivedResolutionError(
450
+ options.key,
451
+ `Unable to resolve derived config key ${options.key} because ${Array.from(missingRefs).join(", ")} is missing.`
452
+ );
453
+ }
454
+ return value;
455
+ }
456
+
457
+ // ../core/src/derive/validate.ts
458
+ var FORBIDDEN_TARGET_NAMESPACES = /* @__PURE__ */ new Set(["public", "meta", "secret"]);
459
+ var FORBIDDEN_REF_NAMESPACES = /* @__PURE__ */ new Set(["public", "secret"]);
460
+ function validateDerivedTargetNamespace(manifest, namespace) {
461
+ if (FORBIDDEN_TARGET_NAMESPACES.has(namespace)) {
462
+ throw new CnosManifestError(`Cannot define derived values under namespace "${namespace}".`);
463
+ }
464
+ if (manifest.runtimeNamespaces[namespace]) {
465
+ throw new CnosManifestError(`Cannot define derived values under runtime namespace "${namespace}".`);
466
+ }
467
+ }
468
+ function validateParsedDerivation(manifest, parsed) {
469
+ for (const ref of parsed.refs) {
470
+ const namespace = ref.split(".")[0] ?? "";
471
+ if (FORBIDDEN_REF_NAMESPACES.has(namespace)) {
472
+ throw new CnosDerivedExpressionError(`Derived expressions cannot reference ${namespace}.* keys.`, parsed.raw);
473
+ }
474
+ if (manifest.runtimeNamespaces[namespace]) {
475
+ continue;
476
+ }
477
+ if (!manifest.namespaces[namespace] && namespace !== "value" && namespace !== "meta") {
478
+ throw new CnosDerivedExpressionError(`Unknown derive reference namespace: ${namespace}`, parsed.raw);
479
+ }
480
+ }
481
+ }
482
+
483
+ // ../core/src/derive/runtime.ts
484
+ function namespaceForKey(key) {
485
+ return key.split(".")[0] ?? "";
486
+ }
487
+ function dependencyNamespaces(key, entries, memo) {
488
+ if (memo.has(key)) {
489
+ return memo.get(key);
490
+ }
491
+ const entry = entries.get(key);
492
+ if (!entry) {
493
+ memo.set(key, []);
494
+ return [];
495
+ }
496
+ const namespaces = /* @__PURE__ */ new Set();
497
+ for (const ref of entry.parsed.refs) {
498
+ const namespace = namespaceForKey(ref);
499
+ if (!entries.has(ref)) {
500
+ namespaces.add(namespace);
501
+ continue;
502
+ }
503
+ for (const dependencyNamespace of dependencyNamespaces(ref, entries, memo)) {
504
+ namespaces.add(dependencyNamespace);
505
+ }
506
+ }
507
+ const result = Array.from(namespaces).sort((left, right) => left.localeCompare(right));
508
+ memo.set(key, result);
509
+ return result;
510
+ }
511
+ function isRuntimeDependentKey(key, entries, manifest, memo) {
512
+ if (memo.has(key)) {
513
+ return memo.get(key);
514
+ }
515
+ const entry = entries.get(key);
516
+ if (!entry) {
517
+ memo.set(key, false);
518
+ return false;
519
+ }
520
+ for (const ref of entry.parsed.refs) {
521
+ const namespace = namespaceForKey(ref);
522
+ if (manifest.runtimeNamespaces[namespace]) {
523
+ memo.set(key, true);
524
+ return true;
525
+ }
526
+ if (entries.has(ref) && isRuntimeDependentKey(ref, entries, manifest, memo)) {
527
+ memo.set(key, true);
528
+ return true;
529
+ }
530
+ }
531
+ memo.set(key, false);
532
+ return false;
533
+ }
534
+ function prepareEntries(graph, manifest) {
535
+ const entries = /* @__PURE__ */ new Map();
536
+ for (const [key, entry] of graph.entries) {
537
+ if (!isDerivedValue(entry.value)) {
538
+ continue;
539
+ }
540
+ const namespaceDefinition = manifest.namespaces[entry.namespace];
541
+ if (!namespaceDefinition || namespaceDefinition.kind === "data") {
542
+ validateDerivedTargetNamespace(manifest, entry.namespace);
543
+ }
544
+ const parsed = parseDerivation(entry.value);
545
+ validateParsedDerivation(manifest, parsed);
546
+ entries.set(key, {
547
+ key,
548
+ namespace: entry.namespace,
549
+ value: entry.value,
550
+ parsed
551
+ });
552
+ }
553
+ detectDerivationCycles(
554
+ new Map(
555
+ Array.from(entries.values()).map((entry) => [
556
+ entry.key,
557
+ entry.parsed.refs.filter((ref) => entries.has(ref))
558
+ ])
559
+ )
560
+ );
561
+ const runtimeMemo = /* @__PURE__ */ new Map();
562
+ const namespaceMemo = /* @__PURE__ */ new Map();
563
+ for (const entry of entries.values()) {
564
+ entry.parsed.isRuntimeDependent = isRuntimeDependentKey(entry.key, entries, manifest, runtimeMemo);
565
+ entry.parsed.runtimeRefs = entry.parsed.refs.filter((ref) => manifest.runtimeNamespaces[namespaceForKey(ref)]);
566
+ if (entry.parsed.runtimeRefs.length === 0 && entry.parsed.isRuntimeDependent) {
567
+ entry.parsed.runtimeRefs = dependencyNamespaces(entry.key, entries, namespaceMemo).filter((namespace) => manifest.runtimeNamespaces[namespace]).map((namespace) => `${namespace}.*`);
568
+ }
569
+ }
570
+ return entries;
571
+ }
572
+ function createDerivedRuntimeSupport(graph, manifest, runtimeProviders) {
573
+ const entries = prepareEntries(graph, manifest);
574
+ const configCache = /* @__PURE__ */ new Map();
575
+ const runtimeDependencyMemo = /* @__PURE__ */ new Map();
576
+ const support = {};
577
+ Object.assign(support, {
578
+ runtimeProviders,
579
+ read(key, readBase) {
580
+ const namespace = namespaceForKey(key);
581
+ if (runtimeProviders.has(namespace)) {
582
+ const provider = runtimeProviders.get(namespace);
583
+ return provider(key.slice(namespace.length + 1));
584
+ }
585
+ if (entries.has(key)) {
586
+ return readDerived(key, readBase);
587
+ }
588
+ return readBase(key);
589
+ },
590
+ describe(key, readBase) {
591
+ const entry = entries.get(key);
592
+ if (!entry) {
593
+ return void 0;
594
+ }
595
+ const runtimeNamespaces = Array.from(
596
+ new Set(
597
+ entry.parsed.refs.map((ref) => namespaceForKey(ref)).filter((namespace) => manifest.runtimeNamespaces[namespace])
598
+ )
599
+ ).sort((left, right) => left.localeCompare(right));
600
+ return {
601
+ key,
602
+ type: entry.parsed.type,
603
+ expression: entry.parsed.raw,
604
+ dependencies: entry.parsed.refs.map((ref) => {
605
+ const namespace = namespaceForKey(ref);
606
+ return {
607
+ key: ref,
608
+ value: support.read(ref, readBase),
609
+ ...manifest.runtimeNamespaces[namespace] ? {
610
+ runtimeNamespace: namespace
611
+ } : {}
612
+ };
613
+ }),
614
+ runtimeDependent: entry.parsed.isRuntimeDependent,
615
+ runtimeNamespaces,
616
+ ...entry.parsed.isRuntimeDependent ? {
617
+ promotionWarning: "Cannot be promoted to browser/public."
618
+ } : {}
619
+ };
620
+ },
621
+ isDerivedKey(key) {
622
+ return entries.has(key);
623
+ },
624
+ isRuntimeDependentKey(key) {
625
+ if (runtimeDependencyMemo.has(key)) {
626
+ return runtimeDependencyMemo.get(key);
627
+ }
628
+ const value = entries.get(key)?.parsed.isRuntimeDependent ?? false;
629
+ runtimeDependencyMemo.set(key, value);
630
+ return value;
631
+ },
632
+ toConcreteValue(key, readBase, mode) {
633
+ const entry = entries.get(key);
634
+ if (!entry) {
635
+ return support.read(key, readBase);
636
+ }
637
+ if (!entry.parsed.isRuntimeDependent) {
638
+ return support.read(key, readBase);
639
+ }
640
+ if (mode === "server" || mode === "runtime") {
641
+ return support.read(key, readBase);
642
+ }
643
+ for (const ref of entry.parsed.refs) {
644
+ const namespace = namespaceForKey(ref);
645
+ const runtimeNamespace = manifest.runtimeNamespaces[namespace];
646
+ if (!runtimeNamespace) {
647
+ continue;
648
+ }
649
+ if (runtimeNamespace.serverOnly) {
650
+ throw new CnosDerivedResolutionError(
651
+ key,
652
+ `Cannot resolve ${key} for ${mode} output because it depends on runtime namespace ${namespace}.`
653
+ );
654
+ }
655
+ if (!runtimeProviders.has(namespace)) {
656
+ if (mode === "env") {
657
+ return void 0;
658
+ }
659
+ throw new CnosDerivedResolutionError(
660
+ key,
661
+ `Cannot resolve ${key} for ${mode} output because runtime namespace ${namespace} has no registered provider.`
662
+ );
663
+ }
664
+ }
665
+ return support.read(key, readBase);
666
+ },
667
+ toServerFormula(key) {
668
+ const entry = entries.get(key);
669
+ if (!entry || !entry.parsed.isRuntimeDependent) {
670
+ return void 0;
671
+ }
672
+ return {
673
+ expr: entry.parsed.raw,
674
+ deps: entry.parsed.refs.filter((ref) => !manifest.runtimeNamespaces[namespaceForKey(ref)]),
675
+ runtimeRefs: entry.parsed.refs.filter((ref) => manifest.runtimeNamespaces[namespaceForKey(ref)])
676
+ };
677
+ },
678
+ derivedKeys: Array.from(entries.keys()).sort((left, right) => left.localeCompare(right))
679
+ });
680
+ const readDerived = (key, readBase, evaluationStack = /* @__PURE__ */ new Set()) => {
681
+ const entry = entries.get(key);
682
+ if (!entry) {
683
+ return readBase(key);
684
+ }
685
+ if (!entry.parsed.isRuntimeDependent && configCache.has(key)) {
686
+ return configCache.get(key);
687
+ }
688
+ const value = evaluateDerivation({
689
+ key,
690
+ parsed: entry.parsed,
691
+ resolveRef: (ref) => {
692
+ const namespace = namespaceForKey(ref);
693
+ if (runtimeProviders.has(namespace)) {
694
+ const provider = runtimeProviders.get(namespace);
695
+ return provider(ref.slice(namespace.length + 1));
696
+ }
697
+ if (entries.has(ref)) {
698
+ if (evaluationStack.has(ref)) {
699
+ throw new CnosDerivedResolutionError(key, `Unable to resolve derived config key ${key} because of a recursive dependency on ${ref}.`);
700
+ }
701
+ evaluationStack.add(ref);
702
+ const resolved = readDerived(ref, readBase, evaluationStack);
703
+ evaluationStack.delete(ref);
704
+ return resolved;
705
+ }
706
+ return readBase(ref);
707
+ }
708
+ });
709
+ if (!entry.parsed.isRuntimeDependent) {
710
+ configCache.set(key, value);
711
+ }
712
+ return value;
713
+ };
714
+ for (const key of Array.from(entries.keys()).sort((left, right) => left.localeCompare(right))) {
715
+ const entry = entries.get(key);
716
+ if (!entry.parsed.isRuntimeDependent) {
717
+ readDerived(key, (ref) => graph.entries.get(ref)?.value);
718
+ }
719
+ }
720
+ return support;
721
+ }
722
+ function registerRuntimeProvider(manifest, runtimeProviders, namespace, provider) {
723
+ const definition = manifest.runtimeNamespaces[namespace];
724
+ if (!definition) {
725
+ throw new CnosRuntimeProviderError(`Cannot register runtime provider for undeclared namespace "${namespace}".`);
726
+ }
727
+ if (definition.builtIn) {
728
+ throw new CnosRuntimeProviderError(`Cannot override built-in runtime namespace "${namespace}".`);
729
+ }
730
+ runtimeProviders.set(namespace, provider);
731
+ }
76
732
 
77
733
  // ../core/src/runtime/inspect.ts
78
- function inspectValue(graph, key) {
734
+ function inspectValue(graph, key, helpers = {}) {
79
735
  const entry = graph.entries.get(key);
80
736
  if (!entry) {
81
737
  throw new CnosKeyNotFoundError(key);
82
738
  }
739
+ const derived = helpers.describeDerived?.(key);
83
740
  return {
84
741
  key: entry.key,
85
- value: entry.value,
742
+ value: helpers.read ? helpers.read(entry.key) : entry.value,
86
743
  namespace: entry.namespace,
87
744
  profile: graph.profile,
88
745
  profileSource: graph.profileSource,
@@ -103,7 +760,10 @@ function inspectValue(graph, key) {
103
760
  workspaceId: override.workspaceId,
104
761
  value: override.value,
105
762
  ...override.origin ? { origin: override.origin } : {}
106
- }))
763
+ })),
764
+ ...derived ? {
765
+ derived
766
+ } : {}
107
767
  };
108
768
  }
109
769
 
@@ -181,17 +841,17 @@ async function readKeychain(entry) {
181
841
  }
182
842
 
183
843
  // ../core/src/manifest/loadManifest.ts
184
- var import_promises3 = require("fs/promises");
185
- var import_node_path3 = __toESM(require("path"), 1);
844
+ var import_promises5 = require("fs/promises");
845
+ var import_node_path6 = __toESM(require("path"), 1);
186
846
 
187
847
  // ../core/src/utils/path.ts
188
- var import_promises2 = require("fs/promises");
189
- var import_node_os = __toESM(require("os"), 1);
190
- var import_node_path2 = __toESM(require("path"), 1);
848
+ var import_promises4 = require("fs/promises");
849
+ var import_node_os3 = __toESM(require("os"), 1);
850
+ var import_node_path5 = __toESM(require("path"), 1);
191
851
 
192
852
  // ../core/src/discovery/findCnosrc.ts
193
- var import_promises = require("fs/promises");
194
- var import_node_path = __toESM(require("path"), 1);
853
+ var import_promises3 = require("fs/promises");
854
+ var import_node_path4 = __toESM(require("path"), 1);
195
855
 
196
856
  // ../core/src/utils/yaml.ts
197
857
  var import_yaml = require("yaml");
@@ -202,10 +862,315 @@ function stringifyYaml(value) {
202
862
  return (0, import_yaml.stringify)(value);
203
863
  }
204
864
 
865
+ // ../core/src/discovery/resolveRoot.ts
866
+ var import_promises2 = require("fs/promises");
867
+ var import_node_path3 = __toESM(require("path"), 1);
868
+ var import_node_child_process4 = require("child_process");
869
+ var import_node_os2 = __toESM(require("os"), 1);
870
+
871
+ // ../core/src/discovery/parseGitUri.ts
872
+ function isGitRootUri(uri) {
873
+ return /^git\+[a-z]+:\/\//i.test(uri);
874
+ }
875
+ function parseGitUri(uri) {
876
+ if (!isGitRootUri(uri)) {
877
+ throw new CnosDiscoveryError(`Unsupported git root URI: ${uri}`);
878
+ }
879
+ const withoutPrefix = uri.slice("git+".length);
880
+ const hashIndex = withoutPrefix.indexOf("#");
881
+ if (hashIndex < 0) {
882
+ throw new CnosDiscoveryError(
883
+ `Git root URI must include a #ref (tag, branch, or commit). Got: ${uri}`
884
+ );
885
+ }
886
+ const cloneUrl = withoutPrefix.slice(0, hashIndex);
887
+ const fragment = withoutPrefix.slice(hashIndex + 1);
888
+ const separatorIndex = fragment.indexOf(":");
889
+ const ref = (separatorIndex >= 0 ? fragment.slice(0, separatorIndex) : fragment).trim();
890
+ const subpath = (separatorIndex >= 0 ? fragment.slice(separatorIndex + 1) : ".cnos").trim() || ".cnos";
891
+ const protocol = cloneUrl.slice(0, cloneUrl.indexOf("://"));
892
+ if (!cloneUrl || !ref) {
893
+ throw new CnosDiscoveryError(
894
+ `Git root URI must include both a clone URL and #ref. Got: ${uri}`
895
+ );
896
+ }
897
+ return {
898
+ uri,
899
+ cloneUrl,
900
+ ref,
901
+ subpath,
902
+ transport: protocol === "https" ? "https" : protocol === "ssh" ? "ssh" : protocol === "file" ? "file" : "custom"
903
+ };
904
+ }
905
+
906
+ // ../core/src/discovery/cache/cacheManager.ts
907
+ var SEMVER_TAG_RE = /^v?\d+\.\d+(?:\.\d+)?(?:[-+][A-Za-z0-9.-]+)?$/;
908
+ var COMMIT_SHA_RE = /^[0-9a-f]{40}$/i;
909
+ function isImmutableGitRef(ref) {
910
+ return SEMVER_TAG_RE.test(ref) || COMMIT_SHA_RE.test(ref);
911
+ }
912
+ function resolveRemoteRootCacheTtlSeconds(mode = "runtime", processEnv = process.env, override) {
913
+ if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
914
+ return override;
915
+ }
916
+ const fromEnv = Number(processEnv.CNOS_CACHE_TTL ?? "");
917
+ if (Number.isFinite(fromEnv) && fromEnv >= 0) {
918
+ return fromEnv;
919
+ }
920
+ switch (mode) {
921
+ case "build":
922
+ return 0;
923
+ case "dev":
924
+ return 30;
925
+ case "runtime":
926
+ default:
927
+ return 300;
928
+ }
929
+ }
930
+ function isRemoteRootCacheFresh(metadata, options) {
931
+ if (!metadata || options.forceRefresh) {
932
+ return false;
933
+ }
934
+ if (metadata.uri !== options.uri || metadata.ref !== options.ref) {
935
+ return false;
936
+ }
937
+ if (metadata.isImmutable) {
938
+ return true;
939
+ }
940
+ const ttlSeconds = resolveRemoteRootCacheTtlSeconds(
941
+ options.mode,
942
+ options.processEnv,
943
+ options.ttlSeconds
944
+ );
945
+ if (ttlSeconds <= 0) {
946
+ return false;
947
+ }
948
+ const cachedAtMs = Date.parse(metadata.cachedAt);
949
+ if (Number.isNaN(cachedAtMs)) {
950
+ return false;
951
+ }
952
+ return Date.now() - cachedAtMs <= ttlSeconds * 1e3;
953
+ }
954
+
955
+ // ../core/src/discovery/cache/cacheMetadata.ts
956
+ var import_promises = require("fs/promises");
957
+ var import_node_path = __toESM(require("path"), 1);
958
+ async function readRemoteRootCacheMetadata(metaPath) {
959
+ try {
960
+ const source = await (0, import_promises.readFile)(metaPath, "utf8");
961
+ const parsed = JSON.parse(source);
962
+ if (!parsed || typeof parsed.uri !== "string" || typeof parsed.cloneUrl !== "string" || typeof parsed.ref !== "string" || typeof parsed.subpath !== "string" || typeof parsed.resolvedCommit !== "string" || typeof parsed.cachedAt !== "string" || typeof parsed.isImmutable !== "boolean") {
963
+ return void 0;
964
+ }
965
+ return parsed;
966
+ } catch {
967
+ return void 0;
968
+ }
969
+ }
970
+ async function writeRemoteRootCacheMetadata(metaPath, metadata) {
971
+ await (0, import_promises.mkdir)(import_node_path.default.dirname(metaPath), { recursive: true });
972
+ await (0, import_promises.writeFile)(metaPath, `${JSON.stringify(metadata, null, 2)}
973
+ `, "utf8");
974
+ }
975
+
976
+ // ../core/src/discovery/cache/cachePaths.ts
977
+ var import_node_crypto = require("crypto");
978
+ var import_node_os = __toESM(require("os"), 1);
979
+ var import_node_path2 = __toESM(require("path"), 1);
980
+ function resolveCnosCacheRoot(processEnv = process.env) {
981
+ return import_node_path2.default.resolve(
982
+ expandHomePath(processEnv.CNOS_CACHE_DIR ?? import_node_path2.default.join(import_node_os.default.homedir(), ".cnos", "cache"))
983
+ );
984
+ }
985
+ function createRemoteRootCacheKey(uri) {
986
+ return (0, import_node_crypto.createHash)("sha256").update(uri).digest("hex");
987
+ }
988
+ function resolveRemoteRootCachePaths(uri, processEnv = process.env) {
989
+ const cacheRoot = resolveCnosCacheRoot(processEnv);
990
+ const cacheDir = import_node_path2.default.join(cacheRoot, "roots", createRemoteRootCacheKey(uri));
991
+ return {
992
+ cacheRoot,
993
+ cacheDir,
994
+ repoDir: import_node_path2.default.join(cacheDir, "repo"),
995
+ metaPath: import_node_path2.default.join(cacheDir, ".cnos-cache-meta.json")
996
+ };
997
+ }
998
+
999
+ // ../core/src/discovery/resolveRoot.ts
1000
+ async function pathExists(targetPath) {
1001
+ try {
1002
+ await (0, import_promises2.access)(targetPath);
1003
+ return true;
1004
+ } catch {
1005
+ return false;
1006
+ }
1007
+ }
1008
+ function expandHomePath2(targetPath) {
1009
+ if (targetPath === "~") {
1010
+ return import_node_os2.default.homedir();
1011
+ }
1012
+ if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
1013
+ return import_node_path3.default.join(import_node_os2.default.homedir(), targetPath.slice(2));
1014
+ }
1015
+ return targetPath;
1016
+ }
1017
+ function isLocalRootUri(rootUri) {
1018
+ return !isGitRootUri2(rootUri) && !isCnosHostedRootUri(rootUri);
1019
+ }
1020
+ function isCnosHostedRootUri(rootUri) {
1021
+ return rootUri.startsWith("cnos://");
1022
+ }
1023
+ function isGitRootUri2(rootUri) {
1024
+ return rootUri.startsWith("git+");
1025
+ }
1026
+ async function runGitCommand(args, options = {}) {
1027
+ return new Promise((resolve, reject) => {
1028
+ const child = (0, import_node_child_process4.spawn)("git", args, {
1029
+ cwd: options.cwd,
1030
+ env: options.processEnv ?? process.env,
1031
+ shell: process.platform === "win32",
1032
+ stdio: ["ignore", "pipe", "pipe"]
1033
+ });
1034
+ let stdout = "";
1035
+ let stderr = "";
1036
+ child.stdout.on("data", (chunk) => {
1037
+ stdout += chunk.toString();
1038
+ });
1039
+ child.stderr.on("data", (chunk) => {
1040
+ stderr += chunk.toString();
1041
+ });
1042
+ child.on("error", (error) => {
1043
+ reject(
1044
+ new CnosDiscoveryError(
1045
+ `Failed to run git. Make sure git is installed and available on PATH. ${error.message}`
1046
+ )
1047
+ );
1048
+ });
1049
+ child.on("close", (code) => {
1050
+ if (code === 0) {
1051
+ resolve(stdout.trim());
1052
+ return;
1053
+ }
1054
+ const details = stderr.trim() || stdout.trim();
1055
+ reject(
1056
+ new CnosDiscoveryError(
1057
+ details ? `Git command failed: ${details}` : `Git command failed with exit code ${code ?? 1}`
1058
+ )
1059
+ );
1060
+ });
1061
+ });
1062
+ }
1063
+ async function resolveLocalRoot(rootUri, cnosrcDir) {
1064
+ const candidateRoot = rootUri.startsWith("~") ? expandHomePath2(rootUri) : rootUri;
1065
+ const manifestRoot = import_node_path3.default.resolve(cnosrcDir, candidateRoot);
1066
+ const manifestPath = import_node_path3.default.join(manifestRoot, "cnos.yml");
1067
+ if (!await pathExists(manifestPath)) {
1068
+ throw new CnosDiscoveryError(`.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`);
1069
+ }
1070
+ return {
1071
+ manifestRoot,
1072
+ resolution: {
1073
+ rootUri,
1074
+ protocol: "local",
1075
+ remote: false,
1076
+ readOnly: false
1077
+ }
1078
+ };
1079
+ }
1080
+ async function ensureGitCheckout(parsed, repoDir, processEnv) {
1081
+ const hasRepo = await pathExists(import_node_path3.default.join(repoDir, ".git"));
1082
+ if (!hasRepo) {
1083
+ await (0, import_promises2.mkdir)(import_node_path3.default.dirname(repoDir), { recursive: true });
1084
+ await runGitCommand(["clone", "--no-checkout", parsed.cloneUrl, repoDir], { processEnv });
1085
+ } else {
1086
+ await runGitCommand(["-C", repoDir, "remote", "set-url", "origin", parsed.cloneUrl], {
1087
+ processEnv
1088
+ });
1089
+ }
1090
+ await runGitCommand(["-C", repoDir, "fetch", "--tags", "--force", "origin"], { processEnv });
1091
+ await runGitCommand(["-C", repoDir, "checkout", "--force", parsed.ref], { processEnv });
1092
+ await runGitCommand(["-C", repoDir, "clean", "-fdx"], { processEnv });
1093
+ }
1094
+ async function resolveGitRoot(rootUri, options = {}) {
1095
+ const processEnv = options.processEnv ?? process.env;
1096
+ const parsed = parseGitUri(rootUri);
1097
+ const cachePaths = resolveRemoteRootCachePaths(rootUri, processEnv);
1098
+ const metadata = await readRemoteRootCacheMetadata(cachePaths.metaPath);
1099
+ const immutable = isImmutableGitRef(parsed.ref);
1100
+ const cacheFresh = isRemoteRootCacheFresh(metadata, {
1101
+ uri: rootUri,
1102
+ ref: parsed.ref,
1103
+ ...options.cacheMode ? { mode: options.cacheMode } : {},
1104
+ processEnv,
1105
+ ...typeof options.cacheTtlSeconds === "number" ? { ttlSeconds: options.cacheTtlSeconds } : {},
1106
+ ...options.forceRefresh ? { forceRefresh: true } : {}
1107
+ });
1108
+ if (!cacheFresh) {
1109
+ try {
1110
+ await ensureGitCheckout(parsed, cachePaths.repoDir, processEnv);
1111
+ } catch (error) {
1112
+ const message = error instanceof Error ? error.message : String(error);
1113
+ const authHint = parsed.transport === "ssh" ? " Check your SSH key and git access." : " Check the URL and your git credential helper or token setup.";
1114
+ throw new CnosDiscoveryError(`Failed to resolve remote git root ${rootUri}. ${message}${authHint}`);
1115
+ }
1116
+ const resolvedCommit = await runGitCommand(["-C", cachePaths.repoDir, "rev-parse", "HEAD"], {
1117
+ processEnv
1118
+ });
1119
+ await writeRemoteRootCacheMetadata(cachePaths.metaPath, {
1120
+ uri: rootUri,
1121
+ cloneUrl: parsed.cloneUrl,
1122
+ ref: parsed.ref,
1123
+ subpath: parsed.subpath,
1124
+ resolvedCommit,
1125
+ cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
1126
+ isImmutable: immutable
1127
+ });
1128
+ }
1129
+ const nextMetadata = metadata && cacheFresh ? metadata : await readRemoteRootCacheMetadata(cachePaths.metaPath);
1130
+ const manifestRoot = import_node_path3.default.join(cachePaths.repoDir, parsed.subpath);
1131
+ if (!await pathExists(import_node_path3.default.join(manifestRoot, "cnos.yml"))) {
1132
+ throw new CnosDiscoveryError(
1133
+ `Git root ${rootUri} resolved to ${manifestRoot} but no cnos.yml was found there. Check the :subpath segment.`
1134
+ );
1135
+ }
1136
+ return {
1137
+ manifestRoot,
1138
+ resolution: {
1139
+ rootUri,
1140
+ protocol: "git",
1141
+ remote: true,
1142
+ readOnly: true,
1143
+ cacheDir: cachePaths.cacheDir,
1144
+ cacheMetaPath: cachePaths.metaPath,
1145
+ ref: parsed.ref,
1146
+ subpath: parsed.subpath,
1147
+ immutable,
1148
+ ...nextMetadata?.resolvedCommit ? { resolvedCommit: nextMetadata.resolvedCommit } : {},
1149
+ ...nextMetadata?.cachedAt ? { cachedAt: nextMetadata.cachedAt } : {}
1150
+ }
1151
+ };
1152
+ }
1153
+ async function resolveRootUri(rootUri, cnosrcDir, options = {}) {
1154
+ if (isLocalRootUri(rootUri)) {
1155
+ return resolveLocalRoot(rootUri, cnosrcDir);
1156
+ }
1157
+ if (isGitRootUri2(rootUri)) {
1158
+ return resolveGitRoot(rootUri, options);
1159
+ }
1160
+ if (isCnosHostedRootUri(rootUri)) {
1161
+ throw new CnosDiscoveryError(
1162
+ `The cnos:// remote root protocol is reserved but not implemented yet. Use git+https:// or git+ssh:// for now.`
1163
+ );
1164
+ }
1165
+ throw new CnosDiscoveryError(
1166
+ `Unknown root protocol: ${rootUri}. Supported root protocols are local paths, git+https://..., and git+ssh://....`
1167
+ );
1168
+ }
1169
+
205
1170
  // ../core/src/discovery/findCnosrc.ts
206
1171
  async function exists(targetPath) {
207
1172
  try {
208
- await (0, import_promises.access)(targetPath);
1173
+ await (0, import_promises3.access)(targetPath);
209
1174
  return true;
210
1175
  } catch {
211
1176
  return false;
@@ -226,13 +1191,13 @@ function validateCnosrc(value, filePath) {
226
1191
  };
227
1192
  }
228
1193
  async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
229
- let current = import_node_path.default.resolve(startDir);
1194
+ let current = import_node_path4.default.resolve(startDir);
230
1195
  for (let depth = 0; depth <= maxLevels; depth += 1) {
231
- const candidate = import_node_path.default.join(current, ".cnosrc.yml");
1196
+ const candidate = import_node_path4.default.join(current, ".cnosrc.yml");
232
1197
  if (await exists(candidate)) {
233
1198
  return candidate;
234
1199
  }
235
- const parent = import_node_path.default.dirname(current);
1200
+ const parent = import_node_path4.default.dirname(current);
236
1201
  if (parent === current) {
237
1202
  break;
238
1203
  }
@@ -240,27 +1205,22 @@ async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
240
1205
  }
241
1206
  return void 0;
242
1207
  }
243
- async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3) {
1208
+ async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3, options = {}) {
244
1209
  const anchorPath = await findCnosrc(startDir, maxLevels);
245
1210
  if (!anchorPath) {
246
1211
  throw new CnosDiscoveryError(
247
1212
  "No .cnosrc.yml found. Run cnos init or create .cnosrc.yml in your package root."
248
1213
  );
249
1214
  }
250
- const source = await (0, import_promises.readFile)(anchorPath, "utf8");
1215
+ const source = await (0, import_promises3.readFile)(anchorPath, "utf8");
251
1216
  const parsed = validateCnosrc(parseYaml(source), anchorPath);
252
- const consumerRoot = import_node_path.default.dirname(anchorPath);
253
- const manifestRoot = import_node_path.default.resolve(consumerRoot, parsed.root);
254
- const manifestPath = import_node_path.default.join(manifestRoot, "cnos.yml");
255
- if (!await exists(manifestPath)) {
256
- throw new CnosDiscoveryError(
257
- `.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`
258
- );
259
- }
1217
+ const consumerRoot = import_node_path4.default.dirname(anchorPath);
1218
+ const resolvedRoot = await resolveRootUri(parsed.root, consumerRoot, options);
260
1219
  return {
261
1220
  anchorPath,
262
1221
  consumerRoot,
263
- manifestRoot,
1222
+ manifestRoot: resolvedRoot.manifestRoot,
1223
+ rootResolution: resolvedRoot.resolution,
264
1224
  ...parsed.workspace ? { workspace: parsed.workspace } : {}
265
1225
  };
266
1226
  }
@@ -270,21 +1230,21 @@ var PRIMARY_CNOS_DIR = ".cnos";
270
1230
  var LEGACY_CNOS_DIR = "cnos";
271
1231
  async function exists2(filePath) {
272
1232
  try {
273
- await (0, import_promises2.access)(filePath);
1233
+ await (0, import_promises4.access)(filePath);
274
1234
  return true;
275
1235
  } catch {
276
1236
  return false;
277
1237
  }
278
1238
  }
279
1239
  async function resolveCnosRoot(root = process.cwd()) {
280
- const basePath = import_node_path2.default.resolve(root);
1240
+ const basePath = import_node_path5.default.resolve(root);
281
1241
  const candidates = [
282
- import_node_path2.default.join(basePath, PRIMARY_CNOS_DIR),
283
- import_node_path2.default.join(basePath, LEGACY_CNOS_DIR),
1242
+ import_node_path5.default.join(basePath, PRIMARY_CNOS_DIR),
1243
+ import_node_path5.default.join(basePath, LEGACY_CNOS_DIR),
284
1244
  basePath
285
1245
  ];
286
1246
  for (const candidate of candidates) {
287
- if (await exists2(import_node_path2.default.join(candidate, "cnos.yml"))) {
1247
+ if (await exists2(import_node_path5.default.join(candidate, "cnos.yml"))) {
288
1248
  return candidate;
289
1249
  }
290
1250
  }
@@ -294,18 +1254,44 @@ async function resolveCnosRoot(root = process.cwd()) {
294
1254
  }
295
1255
  async function resolveManifestRoot(options = {}) {
296
1256
  if (options.root) {
1257
+ if (options.root.startsWith("git+") || options.root.startsWith("cnos://")) {
1258
+ const consumerRoot2 = import_node_path5.default.resolve(options.cwd ?? process.cwd());
1259
+ const resolvedRoot2 = await resolveRootUri(options.root, consumerRoot2, {
1260
+ ...options.processEnv ? { processEnv: options.processEnv } : {},
1261
+ ...options.cacheMode ? { cacheMode: options.cacheMode } : {},
1262
+ ...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
1263
+ ...options.forceRefresh ? { forceRefresh: true } : {}
1264
+ });
1265
+ return {
1266
+ manifestRoot: resolvedRoot2.manifestRoot,
1267
+ consumerRoot: consumerRoot2,
1268
+ rootResolution: resolvedRoot2.resolution
1269
+ };
1270
+ }
297
1271
  const manifestRoot = await resolveCnosRoot(options.root);
298
- const resolvedRoot = import_node_path2.default.resolve(options.root);
299
- const consumerRoot = import_node_path2.default.basename(manifestRoot) === PRIMARY_CNOS_DIR || import_node_path2.default.basename(manifestRoot) === LEGACY_CNOS_DIR ? import_node_path2.default.dirname(manifestRoot) : resolvedRoot;
1272
+ const resolvedRoot = import_node_path5.default.resolve(options.root);
1273
+ const consumerRoot = import_node_path5.default.basename(manifestRoot) === PRIMARY_CNOS_DIR || import_node_path5.default.basename(manifestRoot) === LEGACY_CNOS_DIR ? import_node_path5.default.dirname(manifestRoot) : resolvedRoot;
300
1274
  return {
301
1275
  manifestRoot,
302
- consumerRoot
1276
+ consumerRoot,
1277
+ rootResolution: {
1278
+ rootUri: manifestRoot,
1279
+ protocol: "local",
1280
+ remote: false,
1281
+ readOnly: false
1282
+ }
303
1283
  };
304
1284
  }
305
- const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd());
1285
+ const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd(), 3, {
1286
+ ...options.processEnv ? { processEnv: options.processEnv } : {},
1287
+ ...options.cacheMode ? { cacheMode: options.cacheMode } : {},
1288
+ ...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
1289
+ ...options.forceRefresh ? { forceRefresh: true } : {}
1290
+ });
306
1291
  return {
307
1292
  manifestRoot: discovered.manifestRoot,
308
1293
  consumerRoot: discovered.consumerRoot,
1294
+ rootResolution: discovered.rootResolution,
309
1295
  anchorPath: discovered.anchorPath,
310
1296
  ...discovered.workspace ? { workspace: discovered.workspace } : {}
311
1297
  };
@@ -318,10 +1304,10 @@ function interpolatePathTemplate(template, tokens) {
318
1304
  }
319
1305
  function expandHomePath(targetPath) {
320
1306
  if (targetPath === "~") {
321
- return import_node_os.default.homedir();
1307
+ return import_node_os3.default.homedir();
322
1308
  }
323
1309
  if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
324
- return import_node_path2.default.join(import_node_os.default.homedir(), targetPath.slice(2));
1310
+ return import_node_path5.default.join(import_node_os3.default.homedir(), targetPath.slice(2));
325
1311
  }
326
1312
  return targetPath;
327
1313
  }
@@ -339,7 +1325,7 @@ function stripWorkspaceTemplatePrefix(template) {
339
1325
  function resolveWorkspaceScopedPath(workspaceRoot, template, tokens) {
340
1326
  const relativeTemplate = stripWorkspaceTemplatePrefix(template);
341
1327
  const interpolated = interpolatePathTemplate(relativeTemplate, tokens);
342
- return import_node_path2.default.resolve(workspaceRoot, interpolated);
1328
+ return import_node_path5.default.resolve(workspaceRoot, interpolated);
343
1329
  }
344
1330
  function toPortablePath(targetPath) {
345
1331
  return targetPath.replace(/\\/g, "/");
@@ -405,6 +1391,13 @@ var DEFAULT_NAMESPACES = {
405
1391
  readonly: true
406
1392
  }
407
1393
  };
1394
+ var DEFAULT_RUNTIME_NAMESPACES = {
1395
+ process: {
1396
+ description: "Live process runtime values.",
1397
+ serverOnly: true,
1398
+ builtIn: true
1399
+ }
1400
+ };
408
1401
  function validateResolveFrom(resolveFrom) {
409
1402
  const validValues = ["cli.profile", "env.CNOS_PROFILE", "default"];
410
1403
  for (const entry of resolveFrom) {
@@ -427,7 +1420,7 @@ function normalizeWorkspaceItems(items) {
427
1420
  }
428
1421
  function normalizeNamespaces(namespaces) {
429
1422
  const normalized = Object.fromEntries(
430
- Object.entries(namespaces ?? {}).map(([namespace, definition]) => [
1423
+ Object.entries(namespaces ?? {}).filter(([namespace]) => namespace !== "runtime").map(([namespace, definition]) => [
431
1424
  namespace,
432
1425
  {
433
1426
  kind: definition.kind ?? "data",
@@ -443,6 +1436,29 @@ function normalizeNamespaces(namespaces) {
443
1436
  ...normalized
444
1437
  };
445
1438
  }
1439
+ function normalizeRuntimeNamespaces(namespaces) {
1440
+ const runtimeEntries = namespaces?.runtime ?? {};
1441
+ const normalized = Object.fromEntries(
1442
+ Object.entries(runtimeEntries).map(([namespace, definition]) => [
1443
+ namespace,
1444
+ {
1445
+ ...definition.description?.trim() ? {
1446
+ description: definition.description.trim()
1447
+ } : {},
1448
+ serverOnly: definition.server_only ?? true
1449
+ }
1450
+ ])
1451
+ );
1452
+ for (const namespace of Object.keys(normalized)) {
1453
+ if (DEFAULT_NAMESPACES[namespace] || namespace === "runtime") {
1454
+ throw new CnosManifestError(`Runtime namespace "${namespace}" conflicts with a built-in or reserved namespace.`);
1455
+ }
1456
+ }
1457
+ return {
1458
+ ...DEFAULT_RUNTIME_NAMESPACES,
1459
+ ...normalized
1460
+ };
1461
+ }
446
1462
  function normalizeVaults(vaults) {
447
1463
  return Object.fromEntries(
448
1464
  Object.entries(vaults ?? {}).map(([name, definition]) => {
@@ -534,6 +1550,7 @@ function normalizeManifest(manifest) {
534
1550
  const defaultProfile = manifest.profiles?.default?.trim() || "base";
535
1551
  const workspaceItems = normalizeWorkspaceItems(manifest.workspaces?.items);
536
1552
  const resolveFrom = validateResolveFrom(manifest.profiles?.resolveFrom ?? DEFAULT_RESOLVE_FROM);
1553
+ const runtimeNamespaces = normalizeRuntimeNamespaces(manifest.namespaces);
537
1554
  const filesystemValues = {
538
1555
  root: "./",
539
1556
  format: "yaml",
@@ -607,6 +1624,7 @@ function normalizeManifest(manifest) {
607
1624
  }
608
1625
  },
609
1626
  namespaces: normalizeNamespaces(manifest.namespaces),
1627
+ runtimeNamespaces,
610
1628
  vaults: normalizeVaults(manifest.vaults),
611
1629
  writePolicy: {
612
1630
  define: {
@@ -625,13 +1643,17 @@ function normalizeManifest(manifest) {
625
1643
  async function loadManifest(options = {}) {
626
1644
  const resolved = await resolveManifestRoot({
627
1645
  ...options.root ? { root: options.root } : {},
628
- ...options.cwd ? { cwd: options.cwd } : {}
1646
+ ...options.cwd ? { cwd: options.cwd } : {},
1647
+ ...options.processEnv ? { processEnv: options.processEnv } : {},
1648
+ ...options.cacheMode ? { cacheMode: options.cacheMode } : {},
1649
+ ...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
1650
+ ...options.forceRefresh ? { forceRefresh: true } : {}
629
1651
  });
630
1652
  const manifestRoot = resolved.manifestRoot;
631
- const manifestPath = import_node_path3.default.join(manifestRoot, "cnos.yml");
1653
+ const manifestPath = import_node_path6.default.join(manifestRoot, "cnos.yml");
632
1654
  let source;
633
1655
  try {
634
- source = await (0, import_promises3.readFile)(manifestPath, "utf8");
1656
+ source = await (0, import_promises5.readFile)(manifestPath, "utf8");
635
1657
  } catch {
636
1658
  throw new CnosManifestError("Unable to read CNOS manifest", manifestPath);
637
1659
  }
@@ -641,10 +1663,11 @@ async function loadManifest(options = {}) {
641
1663
  }
642
1664
  return {
643
1665
  manifestRoot,
644
- repoRoot: import_node_path3.default.dirname(manifestRoot),
1666
+ repoRoot: import_node_path6.default.dirname(manifestRoot),
645
1667
  consumerRoot: resolved.consumerRoot,
646
1668
  ...resolved.anchorPath ? { anchorPath: resolved.anchorPath } : {},
647
1669
  ...resolved.workspace ? { anchoredWorkspace: resolved.workspace } : {},
1670
+ rootResolution: resolved.rootResolution,
648
1671
  manifestPath,
649
1672
  manifest: normalizeManifest(rawManifest),
650
1673
  rawManifest
@@ -652,12 +1675,12 @@ async function loadManifest(options = {}) {
652
1675
  }
653
1676
 
654
1677
  // ../core/src/manifest/loadWorkspaceFile.ts
655
- var import_promises4 = require("fs/promises");
656
- var import_node_path4 = __toESM(require("path"), 1);
1678
+ var import_promises6 = require("fs/promises");
1679
+ var import_node_path7 = __toESM(require("path"), 1);
657
1680
  async function loadWorkspaceFile(repoRoot) {
658
- const workspaceFilePath = import_node_path4.default.join(repoRoot, ".cnos-workspace.yml");
1681
+ const workspaceFilePath = import_node_path7.default.join(repoRoot, ".cnos-workspace.yml");
659
1682
  try {
660
- const source = await (0, import_promises4.readFile)(workspaceFilePath, "utf8");
1683
+ const source = await (0, import_promises6.readFile)(workspaceFilePath, "utf8");
661
1684
  const parsed = parseYaml(source);
662
1685
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
663
1686
  throw new CnosManifestError(".cnos-workspace.yml must be a YAML object", workspaceFilePath);
@@ -680,11 +1703,11 @@ async function loadWorkspaceFile(repoRoot) {
680
1703
  }
681
1704
 
682
1705
  // ../core/src/profiles/expandProfileChain.ts
683
- var import_promises5 = require("fs/promises");
684
- var import_node_path5 = __toESM(require("path"), 1);
1706
+ var import_promises7 = require("fs/promises");
1707
+ var import_node_path8 = __toESM(require("path"), 1);
685
1708
  async function fileExists(targetPath) {
686
1709
  try {
687
- await (0, import_promises5.access)(targetPath);
1710
+ await (0, import_promises7.access)(targetPath);
688
1711
  return true;
689
1712
  } catch {
690
1713
  return false;
@@ -718,11 +1741,11 @@ async function loadProfileDefinition(profileName, options) {
718
1741
  return normalizeProfileDefinition(profileName, void 0);
719
1742
  }
720
1743
  for (const workspaceRoot of [...workspaceRoots].reverse()) {
721
- const profilePath = import_node_path5.default.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
1744
+ const profilePath = import_node_path8.default.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
722
1745
  if (!await fileExists(profilePath)) {
723
1746
  continue;
724
1747
  }
725
- const document = await (0, import_promises5.readFile)(profilePath, "utf8");
1748
+ const document = await (0, import_promises7.readFile)(profilePath, "utf8");
726
1749
  const parsed = parseYaml(document);
727
1750
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
728
1751
  throw new CnosManifestError("Profile definition must be a YAML object", profilePath);
@@ -730,7 +1753,7 @@ async function loadProfileDefinition(profileName, options) {
730
1753
  const definition = normalizeProfileDefinition(
731
1754
  profileName,
732
1755
  parsed,
733
- options.manifestRoot ? toPortablePath(import_node_path5.default.relative(import_node_path5.default.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
1756
+ options.manifestRoot ? toPortablePath(import_node_path8.default.relative(import_node_path8.default.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
734
1757
  );
735
1758
  if (definition.name !== profileName) {
736
1759
  throw new CnosManifestError(
@@ -1012,8 +2035,8 @@ function createProfileAwareResolver() {
1012
2035
  }
1013
2036
 
1014
2037
  // ../core/src/workspaces/resolveWorkspaceContext.ts
1015
- var import_promises6 = require("fs/promises");
1016
- var import_node_path6 = __toESM(require("path"), 1);
2038
+ var import_promises8 = require("fs/promises");
2039
+ var import_node_path9 = __toESM(require("path"), 1);
1017
2040
 
1018
2041
  // ../core/src/workspaces/expandWorkspaceChain.ts
1019
2042
  function expandWorkspaceChain(workspaceId, items) {
@@ -1052,14 +2075,14 @@ function expandWorkspaceChain(workspaceId, items) {
1052
2075
  // ../core/src/workspaces/resolveWorkspaceContext.ts
1053
2076
  async function exists3(targetPath) {
1054
2077
  try {
1055
- await (0, import_promises6.access)(targetPath);
2078
+ await (0, import_promises8.access)(targetPath);
1056
2079
  return true;
1057
2080
  } catch {
1058
2081
  return false;
1059
2082
  }
1060
2083
  }
1061
2084
  async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
1062
- const workspaceRoot = import_node_path6.default.join(manifestRoot, "workspaces", workspaceId);
2085
+ const workspaceRoot = import_node_path9.default.join(manifestRoot, "workspaces", workspaceId);
1063
2086
  if (await exists3(workspaceRoot)) {
1064
2087
  return workspaceRoot;
1065
2088
  }
@@ -1067,7 +2090,7 @@ async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
1067
2090
  ([namespace, definition]) => namespace !== "value" && namespace !== "secret" && definition.kind === "data" && !definition.sensitive
1068
2091
  ).map(([namespace]) => namespace);
1069
2092
  const legacyMarkers = ["values", "secrets", "env", "profiles", ...customDataNamespaceRoots].map(
1070
- (segment) => import_node_path6.default.join(manifestRoot, segment)
2093
+ (segment) => import_node_path9.default.join(manifestRoot, segment)
1071
2094
  );
1072
2095
  if ((await Promise.all(legacyMarkers.map((marker) => exists3(marker)))).some(Boolean)) {
1073
2096
  return manifestRoot;
@@ -1115,26 +2138,26 @@ function resolveGlobalRoot(manifest, workspaceFile, options) {
1115
2138
  }
1116
2139
  if (options.globalRoot) {
1117
2140
  return {
1118
- value: import_node_path6.default.resolve(expandHomePath(options.globalRoot)),
2141
+ value: import_node_path9.default.resolve(expandHomePath(options.globalRoot)),
1119
2142
  source: "cli"
1120
2143
  };
1121
2144
  }
1122
2145
  if (workspaceFile?.globalRoot) {
1123
2146
  return {
1124
- value: import_node_path6.default.resolve(expandHomePath(workspaceFile.globalRoot)),
2147
+ value: import_node_path9.default.resolve(expandHomePath(workspaceFile.globalRoot)),
1125
2148
  source: "workspace-file"
1126
2149
  };
1127
2150
  }
1128
2151
  if (manifest.workspaces.global.root) {
1129
2152
  return {
1130
- value: import_node_path6.default.resolve(expandHomePath(manifest.workspaces.global.root)),
2153
+ value: import_node_path9.default.resolve(expandHomePath(manifest.workspaces.global.root)),
1131
2154
  source: "manifest"
1132
2155
  };
1133
2156
  }
1134
2157
  const cnosHome = options.processEnv?.CNOS_HOME;
1135
2158
  if (cnosHome) {
1136
2159
  return {
1137
- value: import_node_path6.default.resolve(expandHomePath(cnosHome)),
2160
+ value: import_node_path9.default.resolve(expandHomePath(cnosHome)),
1138
2161
  source: "CNOS_HOME"
1139
2162
  };
1140
2163
  }
@@ -1156,7 +2179,7 @@ async function resolveWorkspaceContext(manifest, options) {
1156
2179
  workspaceRoots.push({
1157
2180
  scope: "global",
1158
2181
  workspaceId: chainWorkspaceId,
1159
- path: import_node_path6.default.join(globalRoot.value, "workspaces", globalWorkspaceId)
2182
+ path: import_node_path9.default.join(globalRoot.value, "workspaces", globalWorkspaceId)
1160
2183
  });
1161
2184
  }
1162
2185
  }
@@ -1279,6 +2302,10 @@ function applySchemaRules(graph, schema) {
1279
2302
  }
1280
2303
  continue;
1281
2304
  }
2305
+ if (isDerivedValue(resolvedEntry.value)) {
2306
+ nextEntries.set(key, resolvedEntry);
2307
+ continue;
2308
+ }
1282
2309
  const coercedValue = coerceValue(resolvedEntry.value, rule);
1283
2310
  const nextResolvedEntry = coercedValue === resolvedEntry.value ? resolvedEntry : {
1284
2311
  ...resolvedEntry,
@@ -1348,26 +2375,26 @@ async function runPipeline(options) {
1348
2375
  }
1349
2376
 
1350
2377
  // ../core/src/secrets/auditLog.ts
1351
- var import_promises9 = require("fs/promises");
1352
- var import_node_path9 = __toESM(require("path"), 1);
2378
+ var import_promises11 = require("fs/promises");
2379
+ var import_node_path12 = __toESM(require("path"), 1);
1353
2380
 
1354
2381
  // ../core/src/utils/secretStore.ts
1355
- var import_node_crypto = require("crypto");
1356
- var import_promises8 = require("fs/promises");
1357
- var import_node_path8 = __toESM(require("path"), 1);
2382
+ var import_node_crypto2 = require("crypto");
2383
+ var import_promises10 = require("fs/promises");
2384
+ var import_node_path11 = __toESM(require("path"), 1);
1358
2385
 
1359
2386
  // ../core/src/secrets/sessionStore.ts
1360
- var import_promises7 = require("fs/promises");
1361
- var import_node_path7 = __toESM(require("path"), 1);
2387
+ var import_promises9 = require("fs/promises");
2388
+ var import_node_path10 = __toESM(require("path"), 1);
1362
2389
  function buildSessionRoot(processEnv = process.env) {
1363
- return import_node_path7.default.join(import_node_path7.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
2390
+ return import_node_path10.default.join(import_node_path10.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
1364
2391
  }
1365
2392
  function buildSessionPath(vault, processEnv) {
1366
- return import_node_path7.default.join(buildSessionRoot(processEnv), `${vault}.json`);
2393
+ return import_node_path10.default.join(buildSessionRoot(processEnv), `${vault}.json`);
1367
2394
  }
1368
2395
  async function readVaultSessionKey(vault, processEnv) {
1369
2396
  try {
1370
- const source = await (0, import_promises7.readFile)(buildSessionPath(vault, processEnv), "utf8");
2397
+ const source = await (0, import_promises9.readFile)(buildSessionPath(vault, processEnv), "utf8");
1371
2398
  const document = JSON.parse(source);
1372
2399
  if (document.version !== 1 || typeof document.derivedKey !== "string") {
1373
2400
  return void 0;
@@ -1396,7 +2423,7 @@ function isSecretReference(value) {
1396
2423
  return isObject(value) && typeof value.provider === "string" && value.provider.trim().length > 0 && typeof value.ref === "string" && value.ref.trim().length > 0 && (value.vault === void 0 && true || typeof value.vault === "string" && value.vault.trim().length > 0) && Object.keys(value).every((key) => ["provider", "ref", "vault"].includes(key));
1397
2424
  }
1398
2425
  function resolveSecretStoreRoot(processEnv = process.env) {
1399
- return import_node_path8.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
2426
+ return import_node_path11.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
1400
2427
  }
1401
2428
  function normalizeVaultToken(vault = "default") {
1402
2429
  return vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
@@ -1425,19 +2452,19 @@ function resolveVaultSessionKey(vault = "default", processEnv = process.env) {
1425
2452
  }
1426
2453
  }
1427
2454
  function deriveVaultKey(passphrase, salt, iterations = PBKDF2_ITERATIONS) {
1428
- return (0, import_node_crypto.pbkdf2Sync)(passphrase, salt, iterations, KEY_LENGTH, "sha512");
2455
+ return (0, import_node_crypto2.pbkdf2Sync)(passphrase, salt, iterations, KEY_LENGTH, "sha512");
1429
2456
  }
1430
2457
  function buildMetaPath(storeRoot, vault = "default") {
1431
- return import_node_path8.default.join(storeRoot, "vaults", vault, META_FILENAME);
2458
+ return import_node_path11.default.join(storeRoot, "vaults", vault, META_FILENAME);
1432
2459
  }
1433
2460
  function buildKeystorePath(storeRoot, vault = "default") {
1434
- return import_node_path8.default.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
2461
+ return import_node_path11.default.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
1435
2462
  }
1436
2463
  function buildLegacyVaultFile(storeRoot, vault = "default") {
1437
- return import_node_path8.default.join(storeRoot, "vaults", `${vault}.json`);
2464
+ return import_node_path11.default.join(storeRoot, "vaults", `${vault}.json`);
1438
2465
  }
1439
2466
  function buildLegacyVaultStoreRoot(storeRoot, vault = "default") {
1440
- return import_node_path8.default.join(storeRoot, "vaults", vault, "store");
2467
+ return import_node_path11.default.join(storeRoot, "vaults", vault, "store");
1441
2468
  }
1442
2469
  function assertVaultMetadata(value, filePath) {
1443
2470
  if (!isObject(value)) {
@@ -1450,7 +2477,7 @@ function assertVaultMetadata(value, filePath) {
1450
2477
  }
1451
2478
  async function exists4(targetPath) {
1452
2479
  try {
1453
- await (0, import_promises8.stat)(targetPath);
2480
+ await (0, import_promises10.stat)(targetPath);
1454
2481
  return true;
1455
2482
  } catch {
1456
2483
  return false;
@@ -1477,8 +2504,8 @@ async function assertNoLegacyVaultFormat(storeRoot, vault = "default") {
1477
2504
  );
1478
2505
  }
1479
2506
  function encryptPayload(payload, key) {
1480
- const iv = (0, import_node_crypto.randomBytes)(IV_LENGTH);
1481
- const cipher = (0, import_node_crypto.createCipheriv)("aes-256-gcm", key, iv);
2507
+ const iv = (0, import_node_crypto2.randomBytes)(IV_LENGTH);
2508
+ const cipher = (0, import_node_crypto2.createCipheriv)("aes-256-gcm", key, iv);
1482
2509
  const plaintext = Buffer.from(JSON.stringify(payload), "utf8");
1483
2510
  const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
1484
2511
  const tag = cipher.getAuthTag();
@@ -1503,7 +2530,7 @@ function decryptPayload(buffer, key) {
1503
2530
  const iv = buffer.subarray(ivOffset, tagOffset);
1504
2531
  const tag = buffer.subarray(tagOffset, cipherOffset);
1505
2532
  const ciphertext = buffer.subarray(cipherOffset);
1506
- const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-gcm", key, iv);
2533
+ const decipher = (0, import_node_crypto2.createDecipheriv)("aes-256-gcm", key, iv);
1507
2534
  decipher.setAuthTag(tag);
1508
2535
  try {
1509
2536
  const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
@@ -1534,15 +2561,15 @@ function buildInitialPayload() {
1534
2561
  async function writeVaultFiles(storeRoot, vault, meta, payload, key) {
1535
2562
  const metaPath = buildMetaPath(storeRoot, vault);
1536
2563
  const keystorePath = buildKeystorePath(storeRoot, vault);
1537
- await (0, import_promises8.mkdir)(import_node_path8.default.dirname(metaPath), { recursive: true });
1538
- await (0, import_promises8.writeFile)(metaPath, stringifyYaml(meta), "utf8");
1539
- await (0, import_promises8.writeFile)(keystorePath, encryptPayload(payload, key));
2564
+ await (0, import_promises10.mkdir)(import_node_path11.default.dirname(metaPath), { recursive: true });
2565
+ await (0, import_promises10.writeFile)(metaPath, stringifyYaml(meta), "utf8");
2566
+ await (0, import_promises10.writeFile)(keystorePath, encryptPayload(payload, key));
1540
2567
  }
1541
2568
  async function readVaultMetadata(storeRoot, vault = "default") {
1542
2569
  await assertNoLegacyVaultFormat(storeRoot, vault);
1543
2570
  const metaPath = buildMetaPath(storeRoot, vault);
1544
2571
  try {
1545
- const source = await (0, import_promises8.readFile)(metaPath, "utf8");
2572
+ const source = await (0, import_promises10.readFile)(metaPath, "utf8");
1546
2573
  return assertVaultMetadata(parseYaml(source), metaPath);
1547
2574
  } catch (error) {
1548
2575
  if (error.code === "ENOENT") {
@@ -1554,7 +2581,7 @@ async function readVaultMetadata(storeRoot, vault = "default") {
1554
2581
  async function createSecretVault(storeRoot, vault, passphrase) {
1555
2582
  const normalizedVault = vault.trim() || "default";
1556
2583
  await assertNoLegacyVaultFormat(storeRoot, normalizedVault);
1557
- const salt = (0, import_node_crypto.randomBytes)(SALT_LENGTH);
2584
+ const salt = (0, import_node_crypto2.randomBytes)(SALT_LENGTH);
1558
2585
  const key = deriveVaultKey(passphrase, salt, PBKDF2_ITERATIONS);
1559
2586
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
1560
2587
  const meta = {
@@ -1633,7 +2660,7 @@ async function loadVaultPayload(storeRoot, vault, auth) {
1633
2660
  if (!key) {
1634
2661
  throw new CnosAuthenticationError(`Vault "${vault}" requires authentication before access.`);
1635
2662
  }
1636
- const buffer = await (0, import_promises8.readFile)(buildKeystorePath(storeRoot, vault));
2663
+ const buffer = await (0, import_promises10.readFile)(buildKeystorePath(storeRoot, vault));
1637
2664
  return {
1638
2665
  meta,
1639
2666
  payload: decryptPayload(buffer, key),
@@ -1708,9 +2735,9 @@ function resolveVaultDefinition(vaults, vault = "default") {
1708
2735
 
1709
2736
  // ../core/src/secrets/auditLog.ts
1710
2737
  async function appendAuditEvent(event, processEnv = process.env) {
1711
- const auditFile = processEnv.CNOS_AUDIT_FILE ?? import_node_path9.default.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
1712
- await (0, import_promises9.mkdir)(import_node_path9.default.dirname(auditFile), { recursive: true });
1713
- await (0, import_promises9.appendFile)(
2738
+ const auditFile = processEnv.CNOS_AUDIT_FILE ?? import_node_path12.default.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
2739
+ await (0, import_promises11.mkdir)(import_node_path12.default.dirname(auditFile), { recursive: true });
2740
+ await (0, import_promises11.appendFile)(
1714
2741
  auditFile,
1715
2742
  `${JSON.stringify({
1716
2743
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -2068,7 +3095,7 @@ function setNestedValue(target, pathSegments, value) {
2068
3095
  target[head] = nextTarget;
2069
3096
  setNestedValue(nextTarget, tail, value);
2070
3097
  }
2071
- function toNamespaceObject(graph, namespace) {
3098
+ function toNamespaceObject(graph, namespace, readValueForKey = (key) => graph.entries.get(key)?.value) {
2072
3099
  const output = {};
2073
3100
  const resolvedEntries = Array.from(graph.entries.values()).sort(
2074
3101
  (left, right) => left.key.localeCompare(right.key)
@@ -2078,7 +3105,11 @@ function toNamespaceObject(graph, namespace) {
2078
3105
  continue;
2079
3106
  }
2080
3107
  const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
2081
- setNestedValue(output, valuePath.split("."), entry.value);
3108
+ const value = readValueForKey(entry.key);
3109
+ if (value === void 0) {
3110
+ continue;
3111
+ }
3112
+ setNestedValue(output, valuePath.split("."), value);
2082
3113
  }
2083
3114
  return output;
2084
3115
  }
@@ -2088,12 +3119,6 @@ function readValue(graph, key) {
2088
3119
  return graph.entries.get(key)?.value;
2089
3120
  }
2090
3121
 
2091
- // ../core/src/runtime/readOr.ts
2092
- function readOrValue(graph, key, fallback) {
2093
- const value = readValue(graph, key);
2094
- return value === void 0 ? fallback : value;
2095
- }
2096
-
2097
3122
  // ../core/src/runtime/require.ts
2098
3123
  function requireValue(graph, key) {
2099
3124
  const value = readValue(graph, key);
@@ -2103,8 +3128,38 @@ function requireValue(graph, key) {
2103
3128
  return value;
2104
3129
  }
2105
3130
 
3131
+ // ../core/src/runtime/runtimeProviders.ts
3132
+ function createDefaultRuntimeProviders(manifest, processEnv) {
3133
+ const providers = /* @__PURE__ */ new Map();
3134
+ if (manifest.runtimeNamespaces.process) {
3135
+ providers.set("process", (key) => {
3136
+ const segments = key.split(".");
3137
+ if (segments[0] === "env") {
3138
+ return processEnv[segments.slice(1).join(".")];
3139
+ }
3140
+ if (key === "cwd") {
3141
+ return process.cwd();
3142
+ }
3143
+ if (key === "platform") {
3144
+ return process.platform;
3145
+ }
3146
+ if (key === "arch") {
3147
+ return process.arch;
3148
+ }
3149
+ if (key === "pid") {
3150
+ return process.pid;
3151
+ }
3152
+ if (key === "node.version") {
3153
+ return process.version;
3154
+ }
3155
+ return void 0;
3156
+ });
3157
+ }
3158
+ return providers;
3159
+ }
3160
+
2106
3161
  // ../core/src/runtime/toServerProjection.ts
2107
- var import_node_crypto2 = require("crypto");
3162
+ var import_node_crypto3 = require("crypto");
2108
3163
  function stableSortObject(value) {
2109
3164
  return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
2110
3165
  }
@@ -2113,12 +3168,14 @@ function stripValuePrefix(key) {
2113
3168
  }
2114
3169
  function configHash(values) {
2115
3170
  const serialized = JSON.stringify(stableSortObject(values));
2116
- return (0, import_node_crypto2.createHash)("sha256").update(serialized).digest("hex");
3171
+ return (0, import_node_crypto3.createHash)("sha256").update(serialized).digest("hex");
2117
3172
  }
2118
- function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
3173
+ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
2119
3174
  const values = {};
3175
+ const derived = {};
2120
3176
  const secretRefs = {};
2121
3177
  const namespaces = /* @__PURE__ */ new Set();
3178
+ const runtimeNamespaces = /* @__PURE__ */ new Set();
2122
3179
  const publicKeys = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").map((entry) => entry.key.slice("public.".length)).sort((left, right) => left.localeCompare(right));
2123
3180
  for (const [key, entry] of graph.entries) {
2124
3181
  if (entry.namespace === "secret" && isSecretReference(entry.value)) {
@@ -2130,12 +3187,33 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
2130
3187
  continue;
2131
3188
  }
2132
3189
  if (entry.namespace === "value") {
2133
- values[stripValuePrefix(key)] = entry.value;
3190
+ if (helpers.isRuntimeDependent?.(key)) {
3191
+ const formula = helpers.toServerFormula?.(key);
3192
+ if (formula) {
3193
+ derived[stripValuePrefix(key)] = formula;
3194
+ for (const ref of formula.runtimeRefs) {
3195
+ runtimeNamespaces.add(ref.split(".")[0] ?? "");
3196
+ }
3197
+ }
3198
+ continue;
3199
+ }
3200
+ const value = helpers.read ? helpers.read(key) : entry.value;
3201
+ values[stripValuePrefix(key)] = value;
2134
3202
  continue;
2135
3203
  }
2136
3204
  const namespaceDefinition = manifest.namespaces[entry.namespace];
2137
3205
  if (namespaceDefinition && namespaceDefinition.kind === "data" && !namespaceDefinition.sensitive && entry.namespace !== "public") {
2138
- values[key] = entry.value;
3206
+ if (helpers.isRuntimeDependent?.(key)) {
3207
+ const formula = helpers.toServerFormula?.(key);
3208
+ if (formula) {
3209
+ derived[key] = formula;
3210
+ for (const ref of formula.runtimeRefs) {
3211
+ runtimeNamespaces.add(ref.split(".")[0] ?? "");
3212
+ }
3213
+ }
3214
+ continue;
3215
+ }
3216
+ values[key] = helpers.read ? helpers.read(key) : entry.value;
2139
3217
  namespaces.add(entry.namespace);
2140
3218
  }
2141
3219
  }
@@ -2146,8 +3224,10 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
2146
3224
  resolvedAt: graph.resolvedAt,
2147
3225
  configHash: configHash(values),
2148
3226
  values: stableSortObject(values),
3227
+ derived: stableSortObject(derived),
2149
3228
  secretRefs: stableSortObject(secretRefs),
2150
3229
  publicKeys,
3230
+ runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
2151
3231
  meta: {
2152
3232
  workspace: graph.workspace.workspaceId,
2153
3233
  profile: graph.profile,
@@ -2170,7 +3250,7 @@ function normalizeEnvValue(value) {
2170
3250
  }
2171
3251
  return JSON.stringify(value);
2172
3252
  }
2173
- function toEnv(graph, manifest, options = {}) {
3253
+ function toEnv(graph, manifest, options = {}, helpers = {}) {
2174
3254
  const includeSecrets = options.includeSecrets ?? true;
2175
3255
  const output = {};
2176
3256
  const mappedEntries = Object.entries(manifest.envMapping.explicit).sort(
@@ -2191,7 +3271,11 @@ function toEnv(graph, manifest, options = {}) {
2191
3271
  if (isSecretReference(entry.value)) {
2192
3272
  continue;
2193
3273
  }
2194
- output[envVar] = normalizeEnvValue(entry.value);
3274
+ const value = helpers.read ? helpers.read(logicalKey) : entry.value;
3275
+ if (value === void 0) {
3276
+ continue;
3277
+ }
3278
+ output[envVar] = normalizeEnvValue(value);
2195
3279
  }
2196
3280
  return output;
2197
3281
  }
@@ -2228,20 +3312,43 @@ function resolvePublicPrefix(manifest, options) {
2228
3312
  }
2229
3313
  return manifest.public.frameworks[options.framework] ?? "";
2230
3314
  }
2231
- function toPublicEnv(graph, manifest, options = {}) {
3315
+ function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
2232
3316
  const prefix = resolvePublicPrefix(manifest, options);
2233
3317
  const output = {};
2234
3318
  const promotions = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").sort((left, right) => left.key.localeCompare(right.key));
2235
3319
  for (const resolved of promotions) {
3320
+ if (helpers.isRuntimeDependent?.(resolved.key)) {
3321
+ const value2 = helpers.read?.(resolved.key);
3322
+ if (value2 === void 0) {
3323
+ throw new CnosManifestError(`Cannot build public output for ${resolved.key} because it depends on runtime-only values.`);
3324
+ }
3325
+ }
2236
3326
  const baseEnvVar = fallbackPublicEnvVar(stripNamespace(resolved.key));
2237
3327
  const envVar = prefix && !baseEnvVar.startsWith(prefix) ? `${prefix}${baseEnvVar}` : baseEnvVar;
2238
- output[envVar] = normalizeEnvValue2(resolved.value);
3328
+ const value = helpers.read ? helpers.read(resolved.key) : resolved.value;
3329
+ if (value === void 0) {
3330
+ continue;
3331
+ }
3332
+ output[envVar] = normalizeEnvValue2(value);
2239
3333
  }
2240
3334
  return output;
2241
3335
  }
2242
3336
 
2243
3337
  // ../core/src/orchestrator/runtime.ts
2244
3338
  function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
3339
+ const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
3340
+ const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
3341
+ function resolveProjectedSourceKey(key) {
3342
+ if (!key.startsWith("public.")) {
3343
+ return key;
3344
+ }
3345
+ const promotedFrom = graph.entries.get(key)?.winner.metadata?.promotedFrom;
3346
+ if (typeof promotedFrom === "string") {
3347
+ return promotedFrom;
3348
+ }
3349
+ const fallback = `value.${key.slice("public.".length)}`;
3350
+ return graph.entries.has(fallback) ? fallback : key;
3351
+ }
2245
3352
  async function refreshSecretEntry(key) {
2246
3353
  const entry = graph.entries.get(key);
2247
3354
  if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
@@ -2273,6 +3380,19 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
2273
3380
  }
2274
3381
  }
2275
3382
  function readLogicalKey(key) {
3383
+ const resolved = derivedSupport.read(key, (ref) => {
3384
+ const entry2 = graph.entries.get(ref);
3385
+ if (!entry2) {
3386
+ return void 0;
3387
+ }
3388
+ if (!secretCache) {
3389
+ return entry2.value;
3390
+ }
3391
+ return resolveSecretEntryValue(ref, entry2.value, secretCache);
3392
+ });
3393
+ if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
3394
+ return resolved;
3395
+ }
2276
3396
  const entry = graph.entries.get(key);
2277
3397
  if (!entry) {
2278
3398
  return void 0;
@@ -2297,34 +3417,64 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
2297
3417
  return value;
2298
3418
  },
2299
3419
  readOr(key, fallback) {
2300
- return readOrValue(graph, key, fallback);
3420
+ const value = readLogicalKey(key);
3421
+ return value === void 0 ? fallback : value;
2301
3422
  },
2302
- value(path13) {
2303
- return readLogicalKey(toLogicalKey("value", path13));
3423
+ value(path16) {
3424
+ return readLogicalKey(toLogicalKey("value", path16));
2304
3425
  },
2305
- secret(path13) {
2306
- return readLogicalKey(toLogicalKey("secret", path13));
3426
+ secret(path16) {
3427
+ return readLogicalKey(toLogicalKey("secret", path16));
2307
3428
  },
2308
- meta(path13) {
2309
- return readLogicalKey(toLogicalKey("meta", path13));
3429
+ meta(path16) {
3430
+ return readLogicalKey(toLogicalKey("meta", path16));
2310
3431
  },
2311
3432
  inspect(key) {
2312
- return inspectValue(graph, key);
3433
+ return inspectValue(graph, key, {
3434
+ read: (ref) => readLogicalKey(ref),
3435
+ describeDerived: (ref) => derivedSupport.describe(ref, (candidate) => {
3436
+ const entry = graph.entries.get(candidate);
3437
+ if (!entry) {
3438
+ return void 0;
3439
+ }
3440
+ if (!secretCache) {
3441
+ return entry.value;
3442
+ }
3443
+ return resolveSecretEntryValue(candidate, entry.value, secretCache);
3444
+ })
3445
+ });
2313
3446
  },
2314
3447
  toObject() {
2315
- return toNamespaceObject(graph);
3448
+ return toNamespaceObject(graph, void 0, (key) => readLogicalKey(key));
2316
3449
  },
2317
3450
  toNamespace(namespace) {
2318
- return toNamespaceObject(graph, namespace);
3451
+ return toNamespaceObject(graph, namespace, (key) => readLogicalKey(key));
2319
3452
  },
2320
3453
  toEnv(options) {
2321
- return toEnv(graph, manifest, options);
3454
+ return toEnv(graph, manifest, options, {
3455
+ read: (key) => readLogicalKey(key),
3456
+ isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
3457
+ });
2322
3458
  },
2323
3459
  toPublicEnv(options) {
2324
- return toPublicEnv(graph, manifest, options);
3460
+ return toPublicEnv(graph, manifest, options, {
3461
+ read: (key) => derivedSupport.toConcreteValue(
3462
+ resolveProjectedSourceKey(key),
3463
+ (candidate) => readLogicalKey(candidate),
3464
+ "public"
3465
+ ),
3466
+ isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(resolveProjectedSourceKey(key))
3467
+ });
2325
3468
  },
2326
3469
  toServerProjection() {
2327
- return toServerProjection(graph, manifest, cnosVersion);
3470
+ return toServerProjection(graph, manifest, cnosVersion, {
3471
+ read: (key) => derivedSupport.toConcreteValue(key, (candidate) => readLogicalKey(candidate), "server"),
3472
+ isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key),
3473
+ toServerFormula: (key) => derivedSupport.toServerFormula(key)
3474
+ });
3475
+ },
3476
+ registerRuntimeProvider(namespace, provider) {
3477
+ registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
2328
3478
  },
2329
3479
  async refreshSecrets() {
2330
3480
  await refreshAllSecrets();
@@ -2431,7 +3581,11 @@ function appendMetaEntries(graph, cnosVersion) {
2431
3581
  async function createCnos(options = {}) {
2432
3582
  const loadedManifest = await loadManifest({
2433
3583
  ...options.root ? { root: options.root } : {},
2434
- ...options.cwd ? { cwd: options.cwd } : {}
3584
+ ...options.cwd ? { cwd: options.cwd } : {},
3585
+ ...options.processEnv ? { processEnv: options.processEnv } : {},
3586
+ ...options.cacheMode ? { cacheMode: options.cacheMode } : {},
3587
+ ...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
3588
+ ...options.forceRefresh ? { forceRefresh: true } : {}
2435
3589
  });
2436
3590
  for (const key of loadedManifest.manifest.public.promote) {
2437
3591
  ensureProjectionAllowed(loadedManifest.manifest, key, "public");
@@ -2492,8 +3646,8 @@ async function createCnos(options = {}) {
2492
3646
  }
2493
3647
 
2494
3648
  // ../core/src/runtime/dump.ts
2495
- var import_promises10 = require("fs/promises");
2496
- var import_node_path10 = __toESM(require("path"), 1);
3649
+ var import_promises12 = require("fs/promises");
3650
+ var import_node_path13 = __toESM(require("path"), 1);
2497
3651
 
2498
3652
  // ../core/src/utils/envNaming.ts
2499
3653
  function normalizeMappingConfig(config = {}) {
@@ -2502,8 +3656,8 @@ function normalizeMappingConfig(config = {}) {
2502
3656
  explicit: config.explicit ?? {}
2503
3657
  };
2504
3658
  }
2505
- function fromScreamingSnake(path13) {
2506
- return path13.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
3659
+ function fromScreamingSnake(path16) {
3660
+ return path16.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
2507
3661
  }
2508
3662
  function envVarToLogicalKey(envVar, config = {}) {
2509
3663
  const normalized = normalizeMappingConfig(config);
@@ -2530,7 +3684,7 @@ function envVarToLogicalKey(envVar, config = {}) {
2530
3684
  // package.json
2531
3685
  var package_default = {
2532
3686
  name: "@kitsy/cnos",
2533
- version: "1.6.1",
3687
+ version: "1.8.0",
2534
3688
  description: "Batteries-included CNOS runtime package wired with the official plugins.",
2535
3689
  type: "module",
2536
3690
  main: "./dist/index.cjs",
@@ -2729,8 +3883,8 @@ function createCliArgsPlugin() {
2729
3883
  }
2730
3884
 
2731
3885
  // ../../plugins/dotenv/src/index.ts
2732
- var import_promises11 = require("fs/promises");
2733
- var import_node_path11 = __toESM(require("path"), 1);
3886
+ var import_promises13 = require("fs/promises");
3887
+ var import_node_path14 = __toESM(require("path"), 1);
2734
3888
  var DOTENV_PLUGIN_ID = "@kitsy/cnos/plugins/dotenv";
2735
3889
  function parseDoubleQuoted(value) {
2736
3890
  return value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
@@ -2787,7 +3941,7 @@ function dotenvEntriesFromObject(values, mapping = {}, originFile, workspaceId =
2787
3941
  }
2788
3942
  async function readIfPresent(filePath) {
2789
3943
  try {
2790
- return await (0, import_promises11.readFile)(filePath, "utf8");
3944
+ return await (0, import_promises13.readFile)(filePath, "utf8");
2791
3945
  } catch {
2792
3946
  return void 0;
2793
3947
  }
@@ -2806,7 +3960,7 @@ function createDotenvPlugin() {
2806
3960
  workspace: workspaceRoot.workspaceId
2807
3961
  });
2808
3962
  for (const fileName of fileNames) {
2809
- const absolutePath = import_node_path11.default.join(envRoot, fileName);
3963
+ const absolutePath = import_node_path14.default.join(envRoot, fileName);
2810
3964
  const document = await readIfPresent(absolutePath);
2811
3965
  if (!document) {
2812
3966
  continue;
@@ -2815,7 +3969,7 @@ function createDotenvPlugin() {
2815
3969
  ...dotenvEntriesFromObject(
2816
3970
  parseDotenv(document),
2817
3971
  config.envMapping,
2818
- toPortablePath(import_node_path11.default.relative(import_node_path11.default.dirname(context.manifestRoot), absolutePath)),
3972
+ toPortablePath(import_node_path14.default.relative(import_node_path14.default.dirname(context.manifestRoot), absolutePath)),
2819
3973
  workspaceRoot.workspaceId
2820
3974
  )
2821
3975
  );
@@ -2853,16 +4007,16 @@ function createPublicEnvExportPlugin() {
2853
4007
  }
2854
4008
 
2855
4009
  // ../../plugins/filesystem/src/filesystemSecretsReader.ts
2856
- var import_promises13 = require("fs/promises");
4010
+ var import_promises15 = require("fs/promises");
2857
4011
 
2858
4012
  // ../../plugins/filesystem/src/helpers.ts
2859
- var import_promises12 = require("fs/promises");
2860
- var import_node_path12 = __toESM(require("path"), 1);
4013
+ var import_promises14 = require("fs/promises");
4014
+ var import_node_path15 = __toESM(require("path"), 1);
2861
4015
  var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
2862
4016
  var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
2863
4017
  async function existsDirectory(targetPath) {
2864
4018
  try {
2865
- const stat2 = await (0, import_promises12.readdir)(targetPath);
4019
+ const stat2 = await (0, import_promises14.readdir)(targetPath);
2866
4020
  void stat2;
2867
4021
  return true;
2868
4022
  } catch {
@@ -2870,15 +4024,15 @@ async function existsDirectory(targetPath) {
2870
4024
  }
2871
4025
  }
2872
4026
  async function collectYamlFiles(root) {
2873
- const entries = await (0, import_promises12.readdir)(root, { withFileTypes: true });
4027
+ const entries = await (0, import_promises14.readdir)(root, { withFileTypes: true });
2874
4028
  const results = [];
2875
4029
  for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
2876
- const absolutePath = import_node_path12.default.join(root, entry.name);
4030
+ const absolutePath = import_node_path15.default.join(root, entry.name);
2877
4031
  if (entry.isDirectory()) {
2878
4032
  results.push(...await collectYamlFiles(absolutePath));
2879
4033
  continue;
2880
4034
  }
2881
- if (entry.isFile() && YAML_EXTENSIONS.has(import_node_path12.default.extname(entry.name).toLowerCase())) {
4035
+ if (entry.isFile() && YAML_EXTENSIONS.has(import_node_path15.default.extname(entry.name).toLowerCase())) {
2882
4036
  results.push(absolutePath);
2883
4037
  }
2884
4038
  }
@@ -2886,16 +4040,16 @@ async function collectYamlFiles(root) {
2886
4040
  }
2887
4041
  async function collectFilesystemLayerFiles(manifestRoot, workspaceRoots, sourceRoot, activeLayers) {
2888
4042
  const files = [];
2889
- const repoRoot = import_node_path12.default.dirname(manifestRoot);
4043
+ const repoRoot = import_node_path15.default.dirname(manifestRoot);
2890
4044
  for (const workspaceRoot of workspaceRoots) {
2891
- const resolvedRoot = import_node_path12.default.resolve(workspaceRoot.path, sourceRoot);
4045
+ const resolvedRoot = import_node_path15.default.resolve(workspaceRoot.path, sourceRoot);
2892
4046
  for (const layer of activeLayers) {
2893
- const layerRoot = import_node_path12.default.join(resolvedRoot, layer);
4047
+ const layerRoot = import_node_path15.default.join(resolvedRoot, layer);
2894
4048
  if (!await existsDirectory(layerRoot)) {
2895
4049
  continue;
2896
4050
  }
2897
4051
  for (const absolutePath of await collectYamlFiles(layerRoot)) {
2898
- const relativePath = import_node_path12.default.relative(repoRoot, absolutePath);
4052
+ const relativePath = import_node_path15.default.relative(repoRoot, absolutePath);
2899
4053
  files.push({
2900
4054
  absolutePath,
2901
4055
  relativePath: toPortablePath(relativePath.startsWith("..") ? absolutePath : relativePath),
@@ -2915,7 +4069,7 @@ function assertObjectDocument(value, filePath) {
2915
4069
  function flattenConfigObject(value, options = {}, prefix = "") {
2916
4070
  return Object.entries(value).reduce((accumulator, [key, nestedValue]) => {
2917
4071
  const nextKey = prefix ? `${prefix}.${key}` : key;
2918
- if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue) && !options.stopAtLeaf?.(nestedValue)) {
4072
+ if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue) && !isDerivedValue(nestedValue) && !options.stopAtLeaf?.(nestedValue)) {
2919
4073
  Object.assign(
2920
4074
  accumulator,
2921
4075
  flattenConfigObject(nestedValue, options, nextKey)
@@ -2972,7 +4126,7 @@ function createFilesystemSecretsPlugin() {
2972
4126
  );
2973
4127
  const entries = [];
2974
4128
  for (const file of files) {
2975
- const document = await (0, import_promises13.readFile)(file.absolutePath, "utf8");
4129
+ const document = await (0, import_promises15.readFile)(file.absolutePath, "utf8");
2976
4130
  const fileEntries = filesystemSecretsReader(file.relativePath, document, file.workspaceId);
2977
4131
  for (const entry of fileEntries) {
2978
4132
  const metadata = toSecretReferenceMetadata(entry.value);
@@ -2988,7 +4142,7 @@ function createFilesystemSecretsPlugin() {
2988
4142
  }
2989
4143
 
2990
4144
  // ../../plugins/filesystem/src/filesystemValuesReader.ts
2991
- var import_promises14 = require("fs/promises");
4145
+ var import_promises16 = require("fs/promises");
2992
4146
  function filesystemValuesReader(filePath, document, workspaceId = "default") {
2993
4147
  return yamlObjectToEntries(document, filePath, "value", "filesystem-values", workspaceId);
2994
4148
  }
@@ -3009,7 +4163,7 @@ function createFilesystemValuesPlugin() {
3009
4163
  ).map(([namespace]) => namespace);
3010
4164
  const entries = [];
3011
4165
  for (const file of files) {
3012
- const document = await (0, import_promises14.readFile)(file.absolutePath, "utf8");
4166
+ const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
3013
4167
  entries.push(...filesystemValuesReader(file.relativePath, document, file.workspaceId));
3014
4168
  }
3015
4169
  for (const namespace of customNamespaces) {
@@ -3024,7 +4178,7 @@ function createFilesystemValuesPlugin() {
3024
4178
  layers
3025
4179
  );
3026
4180
  for (const file of namespaceFiles) {
3027
- const document = await (0, import_promises14.readFile)(file.absolutePath, "utf8");
4181
+ const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
3028
4182
  entries.push(...yamlObjectToEntries(document, file.relativePath, namespace, "filesystem-values", file.workspaceId));
3029
4183
  }
3030
4184
  }
@@ -3179,21 +4333,34 @@ async function createCnos2(options = {}) {
3179
4333
 
3180
4334
  // src/build/index.ts
3181
4335
  async function resolveBrowserData(options = {}) {
3182
- const runtime = await createCnos2(options);
4336
+ const runtime = await createCnos2({
4337
+ ...options,
4338
+ cacheMode: options.cacheMode ?? "build"
4339
+ });
3183
4340
  const browserData = {};
3184
- for (const [key, entry] of runtime.graph.entries) {
4341
+ for (const [key] of runtime.graph.entries) {
3185
4342
  if (!key.startsWith("public.")) {
3186
4343
  continue;
3187
4344
  }
3188
- browserData[key] = entry.value;
4345
+ const inspect = runtime.inspect(key);
4346
+ if (inspect.derived?.runtimeDependent) {
4347
+ throw new Error(
4348
+ `Cannot build browser projection: ${key} depends on runtime namespaces ${inspect.derived.runtimeNamespaces.join(", ") || "runtime"}.`
4349
+ );
4350
+ }
4351
+ const value = runtime.read(key);
4352
+ if (value === void 0) {
4353
+ continue;
4354
+ }
4355
+ browserData[key] = value;
3189
4356
  }
3190
4357
  return browserData;
3191
4358
  }
3192
4359
  function toScreamingSnakeSegment(segment) {
3193
4360
  return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
3194
4361
  }
3195
- function toScreamingSnake(path13) {
3196
- return path13.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
4362
+ function toScreamingSnake(path16) {
4363
+ return path16.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
3197
4364
  }
3198
4365
  function stripPublicNamespace(key) {
3199
4366
  return key.startsWith("public.") ? key.slice("public.".length) : key;
@@ -3225,17 +4392,26 @@ function toFrameworkEnv(browserData, framework = "generic", options = {}) {
3225
4392
  }
3226
4393
  async function resolveFrameworkEnv(options = {}, framework = "generic", envOptions = {}) {
3227
4394
  if (framework === "generic") {
3228
- const browserData = await resolveBrowserData(options);
4395
+ const browserData = await resolveBrowserData({
4396
+ ...options,
4397
+ cacheMode: options.cacheMode ?? "build"
4398
+ });
3229
4399
  return toFrameworkEnv(browserData, framework, envOptions);
3230
4400
  }
3231
- const runtime = await createCnos2(options);
4401
+ const runtime = await createCnos2({
4402
+ ...options,
4403
+ cacheMode: options.cacheMode ?? "build"
4404
+ });
3232
4405
  return runtime.toPublicEnv({
3233
4406
  framework,
3234
4407
  ...envOptions.prefix ? { prefix: envOptions.prefix } : {}
3235
4408
  });
3236
4409
  }
3237
4410
  async function resolveServerProjection(options = {}) {
3238
- const runtime = await createCnos2(options);
4411
+ const runtime = await createCnos2({
4412
+ ...options,
4413
+ cacheMode: options.cacheMode ?? "build"
4414
+ });
3239
4415
  return runtime.toServerProjection();
3240
4416
  }
3241
4417
  // Annotate the CommonJS export names for ESM import in node: