@kitsy/cnos 1.6.0 → 1.7.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.
- package/dist/build/index.cjs +1332 -156
- package/dist/build/index.d.cts +1 -1
- package/dist/build/index.d.ts +1 -1
- package/dist/build/index.js +36 -14
- package/dist/{chunk-JYWQFMW5.js → chunk-2DGT7N7E.js} +1 -1
- package/dist/{chunk-S7H2UULC.js → chunk-2TL42I6M.js} +1323 -139
- package/dist/{chunk-MW4OVAT3.js → chunk-5KIQCYFH.js} +1 -1
- package/dist/{chunk-UOKVLCFL.js → chunk-CV3SLBYZ.js} +10 -10
- package/dist/{chunk-XSUP7JKH.js → chunk-GHGJFRDL.js} +6 -2
- package/dist/{chunk-BMAD24KC.js → chunk-OA7FQGAG.js} +1 -1
- package/dist/{chunk-QU5CXL47.js → chunk-PFT56ID2.js} +195 -28
- package/dist/{chunk-VGZREX5D.js → chunk-RYIARE4M.js} +1 -1
- package/dist/{chunk-UR7CHHNN.js → chunk-TT4NV56Z.js} +3 -2
- package/dist/{chunk-UJBQS7CJ.js → chunk-UL63DFLS.js} +1 -1
- package/dist/configure/index.cjs +1309 -155
- package/dist/configure/index.d.cts +3 -3
- package/dist/configure/index.d.ts +3 -3
- package/dist/configure/index.js +8 -8
- package/dist/{plugin-CKrBlWGI.d.cts → core-BJ8xewez.d.cts} +142 -60
- package/dist/{plugin-CKrBlWGI.d.ts → core-BJ8xewez.d.ts} +142 -60
- package/dist/{envNaming-B7Mztkcf.d.ts → envNaming-BRyiuPoI.d.ts} +1 -1
- package/dist/{envNaming-gMVnPOfe.d.cts → envNaming-rx71gpi0.d.cts} +1 -1
- package/dist/index.cjs +1548 -227
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -10
- package/dist/internal.cjs +831 -122
- package/dist/internal.d.cts +56 -3
- package/dist/internal.d.ts +56 -3
- package/dist/internal.js +30 -3
- package/dist/plugin/basic-schema.cjs +49 -23
- package/dist/plugin/basic-schema.d.cts +1 -1
- package/dist/plugin/basic-schema.d.ts +1 -1
- package/dist/plugin/basic-schema.js +2 -2
- package/dist/plugin/cli-args.cjs +38 -23
- package/dist/plugin/cli-args.d.cts +1 -1
- package/dist/plugin/cli-args.d.ts +1 -1
- package/dist/plugin/cli-args.js +2 -2
- package/dist/plugin/dotenv.cjs +46 -31
- package/dist/plugin/dotenv.d.cts +2 -2
- package/dist/plugin/dotenv.d.ts +2 -2
- package/dist/plugin/dotenv.js +2 -2
- package/dist/plugin/env-export.cjs +56 -27
- package/dist/plugin/env-export.d.cts +2 -2
- package/dist/plugin/env-export.d.ts +2 -2
- package/dist/plugin/env-export.js +2 -2
- package/dist/plugin/filesystem.cjs +61 -39
- package/dist/plugin/filesystem.d.cts +1 -1
- package/dist/plugin/filesystem.d.ts +1 -1
- package/dist/plugin/filesystem.js +2 -2
- package/dist/plugin/process-env.cjs +40 -25
- package/dist/plugin/process-env.d.cts +2 -2
- package/dist/plugin/process-env.d.ts +2 -2
- package/dist/plugin/process-env.js +2 -2
- package/dist/runtime/index.cjs +1548 -227
- package/dist/runtime/index.d.cts +3 -1
- package/dist/runtime/index.d.ts +3 -1
- package/dist/runtime/index.js +10 -10
- package/dist/toPublicEnv-CCSgdvI9.d.ts +13 -0
- package/dist/toPublicEnv-ivRtLjcw.d.cts +13 -0
- package/package.json +1 -1
- package/dist/toPublicEnv-CmBsy53P.d.cts +0 -7
- package/dist/toPublicEnv-q6VwWxXZ.d.ts +0 -7
|
@@ -34,16 +34,682 @@ var CnosKeyNotFoundError = class extends CnosError {
|
|
|
34
34
|
}
|
|
35
35
|
key;
|
|
36
36
|
};
|
|
37
|
+
var CnosDerivedExpressionError = class extends CnosError {
|
|
38
|
+
constructor(message, expression) {
|
|
39
|
+
super(expression ? `${message} (${expression})` : message);
|
|
40
|
+
this.expression = expression;
|
|
41
|
+
}
|
|
42
|
+
expression;
|
|
43
|
+
};
|
|
44
|
+
var CnosDerivedCycleError = class extends CnosError {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var CnosDerivedResolutionError = class extends CnosError {
|
|
50
|
+
constructor(key, message) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.key = key;
|
|
53
|
+
}
|
|
54
|
+
key;
|
|
55
|
+
};
|
|
56
|
+
var CnosRuntimeProviderError = class extends CnosError {
|
|
57
|
+
constructor(message) {
|
|
58
|
+
super(message);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// ../core/src/derive/builtins.ts
|
|
63
|
+
function stringify(value) {
|
|
64
|
+
if (value === void 0 || value === null) {
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
67
|
+
if (typeof value === "string") {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
71
|
+
return String(value);
|
|
72
|
+
}
|
|
73
|
+
return JSON.stringify(value);
|
|
74
|
+
}
|
|
75
|
+
var DERIVE_BUILTINS = {
|
|
76
|
+
concat: (...args) => args.map((value) => stringify(value)).join(""),
|
|
77
|
+
coalesce: (...args) => args.find((value) => value !== void 0 && value !== null),
|
|
78
|
+
when: (condition, whenTrue, whenFalse) => condition ? whenTrue : whenFalse,
|
|
79
|
+
exists: (value) => value !== void 0 && value !== null,
|
|
80
|
+
eq: (left, right) => left === right,
|
|
81
|
+
ne: (left, right) => left !== right
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// ../core/src/derive/parser.ts
|
|
85
|
+
function isWhitespace(value) {
|
|
86
|
+
return value === " " || value === "\n" || value === "\r" || value === " ";
|
|
87
|
+
}
|
|
88
|
+
function skipWhitespace(state) {
|
|
89
|
+
while (isWhitespace(state.source[state.index])) {
|
|
90
|
+
state.index += 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function isIdentifierStart(value) {
|
|
94
|
+
return typeof value === "string" && /[A-Za-z_]/.test(value);
|
|
95
|
+
}
|
|
96
|
+
function isIdentifierPart(value) {
|
|
97
|
+
return typeof value === "string" && /[A-Za-z0-9_.-]/.test(value);
|
|
98
|
+
}
|
|
99
|
+
function errorAt(state, message) {
|
|
100
|
+
throw new CnosDerivedExpressionError(`${message} at position ${state.index + 1}`, state.source);
|
|
101
|
+
}
|
|
102
|
+
function parseStringLiteral(state) {
|
|
103
|
+
const quote = state.source[state.index];
|
|
104
|
+
if (quote !== "'") {
|
|
105
|
+
errorAt(state, "Expected string literal");
|
|
106
|
+
}
|
|
107
|
+
state.index += 1;
|
|
108
|
+
let value = "";
|
|
109
|
+
while (state.index < state.source.length) {
|
|
110
|
+
const current = state.source[state.index];
|
|
111
|
+
if (current === "\\") {
|
|
112
|
+
const next = state.source[state.index + 1];
|
|
113
|
+
if (next === void 0) {
|
|
114
|
+
errorAt(state, "Unterminated escape sequence");
|
|
115
|
+
}
|
|
116
|
+
value += next;
|
|
117
|
+
state.index += 2;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (current === "'") {
|
|
121
|
+
state.index += 1;
|
|
122
|
+
return {
|
|
123
|
+
type: "literal",
|
|
124
|
+
value
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
value += current;
|
|
128
|
+
state.index += 1;
|
|
129
|
+
}
|
|
130
|
+
errorAt(state, "Unterminated string literal");
|
|
131
|
+
}
|
|
132
|
+
function parseNumberLiteral(state) {
|
|
133
|
+
const start = state.index;
|
|
134
|
+
while (/[0-9]/.test(state.source[state.index] ?? "")) {
|
|
135
|
+
state.index += 1;
|
|
136
|
+
}
|
|
137
|
+
if (state.source[state.index] === ".") {
|
|
138
|
+
state.index += 1;
|
|
139
|
+
while (/[0-9]/.test(state.source[state.index] ?? "")) {
|
|
140
|
+
state.index += 1;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
type: "literal",
|
|
145
|
+
value: Number(state.source.slice(start, state.index))
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function parseIdentifier(state) {
|
|
149
|
+
if (!isIdentifierStart(state.source[state.index])) {
|
|
150
|
+
errorAt(state, "Expected identifier");
|
|
151
|
+
}
|
|
152
|
+
const start = state.index;
|
|
153
|
+
state.index += 1;
|
|
154
|
+
while (isIdentifierPart(state.source[state.index])) {
|
|
155
|
+
state.index += 1;
|
|
156
|
+
}
|
|
157
|
+
return state.source.slice(start, state.index);
|
|
158
|
+
}
|
|
159
|
+
function parseArguments(state) {
|
|
160
|
+
const args = [];
|
|
161
|
+
skipWhitespace(state);
|
|
162
|
+
if (state.source[state.index] === ")") {
|
|
163
|
+
state.index += 1;
|
|
164
|
+
return args;
|
|
165
|
+
}
|
|
166
|
+
while (state.index < state.source.length) {
|
|
167
|
+
args.push(parseExpressionNode(state));
|
|
168
|
+
skipWhitespace(state);
|
|
169
|
+
const current = state.source[state.index];
|
|
170
|
+
if (current === ",") {
|
|
171
|
+
state.index += 1;
|
|
172
|
+
skipWhitespace(state);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (current === ")") {
|
|
176
|
+
state.index += 1;
|
|
177
|
+
return args;
|
|
178
|
+
}
|
|
179
|
+
errorAt(state, 'Expected "," or ")"');
|
|
180
|
+
}
|
|
181
|
+
errorAt(state, "Unterminated function call");
|
|
182
|
+
}
|
|
183
|
+
function parseIdentifierOrCall(state) {
|
|
184
|
+
const identifier = parseIdentifier(state);
|
|
185
|
+
skipWhitespace(state);
|
|
186
|
+
if (state.source[state.index] === "(") {
|
|
187
|
+
if (!(identifier in DERIVE_BUILTINS)) {
|
|
188
|
+
throw new CnosDerivedExpressionError(`Unknown derive function: ${identifier}`, state.source);
|
|
189
|
+
}
|
|
190
|
+
state.index += 1;
|
|
191
|
+
return {
|
|
192
|
+
type: "call",
|
|
193
|
+
name: identifier,
|
|
194
|
+
args: parseArguments(state)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (identifier === "true" || identifier === "false") {
|
|
198
|
+
return {
|
|
199
|
+
type: "literal",
|
|
200
|
+
value: identifier === "true"
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (identifier === "null") {
|
|
204
|
+
return {
|
|
205
|
+
type: "literal",
|
|
206
|
+
value: null
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
type: "ref",
|
|
211
|
+
path: identifier
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function parseExpressionNode(state) {
|
|
215
|
+
skipWhitespace(state);
|
|
216
|
+
const current = state.source[state.index];
|
|
217
|
+
if (current === "'") {
|
|
218
|
+
return parseStringLiteral(state);
|
|
219
|
+
}
|
|
220
|
+
if (/[0-9]/.test(current ?? "")) {
|
|
221
|
+
return parseNumberLiteral(state);
|
|
222
|
+
}
|
|
223
|
+
if (isIdentifierStart(current)) {
|
|
224
|
+
return parseIdentifierOrCall(state);
|
|
225
|
+
}
|
|
226
|
+
errorAt(state, "Unexpected token");
|
|
227
|
+
}
|
|
228
|
+
function parseExpression(source) {
|
|
229
|
+
const state = {
|
|
230
|
+
source,
|
|
231
|
+
index: 0
|
|
232
|
+
};
|
|
233
|
+
const ast = parseExpressionNode(state);
|
|
234
|
+
skipWhitespace(state);
|
|
235
|
+
if (state.index !== source.length) {
|
|
236
|
+
errorAt(state, "Unexpected trailing input");
|
|
237
|
+
}
|
|
238
|
+
return ast;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ../core/src/derive/templateParser.ts
|
|
242
|
+
function toLiteral(value) {
|
|
243
|
+
return {
|
|
244
|
+
type: "literal",
|
|
245
|
+
value
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function toRef(path14) {
|
|
249
|
+
return {
|
|
250
|
+
type: "ref",
|
|
251
|
+
path: path14
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function parseTemplate(source) {
|
|
255
|
+
const parts = [];
|
|
256
|
+
let cursor = 0;
|
|
257
|
+
while (cursor < source.length) {
|
|
258
|
+
const start = source.indexOf("${", cursor);
|
|
259
|
+
if (start < 0) {
|
|
260
|
+
if (cursor < source.length) {
|
|
261
|
+
parts.push(toLiteral(source.slice(cursor)));
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
if (start > cursor) {
|
|
266
|
+
parts.push(toLiteral(source.slice(cursor, start)));
|
|
267
|
+
}
|
|
268
|
+
const end = source.indexOf("}", start + 2);
|
|
269
|
+
if (end < 0) {
|
|
270
|
+
throw new CnosDerivedExpressionError(`Invalid derivation template: unclosed \${...} at position ${start + 1}`, source);
|
|
271
|
+
}
|
|
272
|
+
const ref = source.slice(start + 2, end).trim();
|
|
273
|
+
if (!ref) {
|
|
274
|
+
throw new CnosDerivedExpressionError(`Invalid derivation template: empty reference at position ${start + 1}`, source);
|
|
275
|
+
}
|
|
276
|
+
if (!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(ref)) {
|
|
277
|
+
throw new CnosDerivedExpressionError(`Invalid derivation template reference "${ref}"`, source);
|
|
278
|
+
}
|
|
279
|
+
parts.push(toRef(ref));
|
|
280
|
+
cursor = end + 1;
|
|
281
|
+
}
|
|
282
|
+
if (parts.length === 0) {
|
|
283
|
+
return toLiteral("");
|
|
284
|
+
}
|
|
285
|
+
if (parts.length === 1) {
|
|
286
|
+
return parts[0];
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
type: "call",
|
|
290
|
+
name: "concat",
|
|
291
|
+
args: parts
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ../core/src/derive/evaluator.ts
|
|
296
|
+
function isDerivedValue(value) {
|
|
297
|
+
return Boolean(
|
|
298
|
+
value && typeof value === "object" && !Array.isArray(value) && "$derive" in value
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
function extractRefs(node, refs = /* @__PURE__ */ new Set()) {
|
|
302
|
+
if (node.type === "ref") {
|
|
303
|
+
refs.add(node.path);
|
|
304
|
+
return refs;
|
|
305
|
+
}
|
|
306
|
+
if (node.type === "call") {
|
|
307
|
+
for (const arg of node.args) {
|
|
308
|
+
extractRefs(arg, refs);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return refs;
|
|
312
|
+
}
|
|
313
|
+
function parseDerivation(value) {
|
|
314
|
+
const source = typeof value.$derive === "string" ? value.$derive : value.$derive?.expr;
|
|
315
|
+
if (typeof source !== "string") {
|
|
316
|
+
throw new CnosDerivedExpressionError("Derived value requires either a template string or { expr } object");
|
|
317
|
+
}
|
|
318
|
+
const type = typeof value.$derive === "string" ? "template" : "expression";
|
|
319
|
+
const ast = type === "template" ? parseTemplate(source) : parseExpression(source);
|
|
320
|
+
const refs = Array.from(extractRefs(ast)).sort((left, right) => left.localeCompare(right));
|
|
321
|
+
return {
|
|
322
|
+
type,
|
|
323
|
+
raw: source,
|
|
324
|
+
ast,
|
|
325
|
+
refs,
|
|
326
|
+
runtimeRefs: [],
|
|
327
|
+
isRuntimeDependent: false
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
function normalizeConcatValue(value) {
|
|
331
|
+
if (value === void 0 || value === null) {
|
|
332
|
+
return "";
|
|
333
|
+
}
|
|
334
|
+
if (typeof value === "string") {
|
|
335
|
+
return value;
|
|
336
|
+
}
|
|
337
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
338
|
+
return String(value);
|
|
339
|
+
}
|
|
340
|
+
return JSON.stringify(value);
|
|
341
|
+
}
|
|
342
|
+
function evaluateNode(node, resolveRef) {
|
|
343
|
+
switch (node.type) {
|
|
344
|
+
case "literal":
|
|
345
|
+
return node.value;
|
|
346
|
+
case "ref":
|
|
347
|
+
return resolveRef(node.path);
|
|
348
|
+
case "call": {
|
|
349
|
+
const args = node.args.map((arg) => evaluateNode(arg, resolveRef));
|
|
350
|
+
switch (node.name) {
|
|
351
|
+
case "concat":
|
|
352
|
+
return args.map((value) => normalizeConcatValue(value)).join("");
|
|
353
|
+
case "coalesce":
|
|
354
|
+
return DERIVE_BUILTINS.coalesce(...args);
|
|
355
|
+
case "when":
|
|
356
|
+
return DERIVE_BUILTINS.when(args[0], args[1], args[2]);
|
|
357
|
+
case "exists":
|
|
358
|
+
return DERIVE_BUILTINS.exists(args[0]);
|
|
359
|
+
case "eq":
|
|
360
|
+
return DERIVE_BUILTINS.eq(args[0], args[1]);
|
|
361
|
+
case "ne":
|
|
362
|
+
return DERIVE_BUILTINS.ne(args[0], args[1]);
|
|
363
|
+
default:
|
|
364
|
+
throw new CnosDerivedExpressionError(`Unknown derive function: ${String(node.name)}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
default:
|
|
368
|
+
throw new CnosDerivedExpressionError(`Unsupported derive AST node ${node.type ?? "unknown"}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function evaluateDerivation(options) {
|
|
372
|
+
const missingRefs = /* @__PURE__ */ new Set();
|
|
373
|
+
const value = evaluateNode(options.parsed.ast, (ref) => {
|
|
374
|
+
const resolved = options.resolveRef(ref);
|
|
375
|
+
if (resolved === void 0) {
|
|
376
|
+
missingRefs.add(ref);
|
|
377
|
+
options.onMissing?.(ref);
|
|
378
|
+
}
|
|
379
|
+
return resolved;
|
|
380
|
+
});
|
|
381
|
+
if (missingRefs.size > 0 && options.parsed.ast.type === "ref") {
|
|
382
|
+
throw new CnosDerivedResolutionError(
|
|
383
|
+
options.key,
|
|
384
|
+
`Unable to resolve derived config key ${options.key} because ${Array.from(missingRefs).join(", ")} is missing.`
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
return value;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ../core/src/derive/validate.ts
|
|
391
|
+
var FORBIDDEN_TARGET_NAMESPACES = /* @__PURE__ */ new Set(["public", "meta", "secret"]);
|
|
392
|
+
var FORBIDDEN_REF_NAMESPACES = /* @__PURE__ */ new Set(["public", "secret"]);
|
|
393
|
+
function validateDerivedTargetNamespace(manifest, namespace) {
|
|
394
|
+
if (FORBIDDEN_TARGET_NAMESPACES.has(namespace)) {
|
|
395
|
+
throw new CnosManifestError(`Cannot define derived values under namespace "${namespace}".`);
|
|
396
|
+
}
|
|
397
|
+
if (manifest.runtimeNamespaces[namespace]) {
|
|
398
|
+
throw new CnosManifestError(`Cannot define derived values under runtime namespace "${namespace}".`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function validateParsedDerivation(manifest, parsed) {
|
|
402
|
+
for (const ref of parsed.refs) {
|
|
403
|
+
const namespace = ref.split(".")[0] ?? "";
|
|
404
|
+
if (FORBIDDEN_REF_NAMESPACES.has(namespace)) {
|
|
405
|
+
throw new CnosDerivedExpressionError(`Derived expressions cannot reference ${namespace}.* keys.`, parsed.raw);
|
|
406
|
+
}
|
|
407
|
+
if (manifest.runtimeNamespaces[namespace]) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
if (!manifest.namespaces[namespace] && namespace !== "value" && namespace !== "meta") {
|
|
411
|
+
throw new CnosDerivedExpressionError(`Unknown derive reference namespace: ${namespace}`, parsed.raw);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function normalizeDerivedValue(templateOrExpr, expr = false) {
|
|
416
|
+
return expr ? {
|
|
417
|
+
$derive: {
|
|
418
|
+
expr: templateOrExpr
|
|
419
|
+
}
|
|
420
|
+
} : {
|
|
421
|
+
$derive: templateOrExpr
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// ../core/src/derive/depGraph.ts
|
|
426
|
+
function detectDerivationCycles(dependencyMap) {
|
|
427
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
428
|
+
const visited = /* @__PURE__ */ new Set();
|
|
429
|
+
const stack = [];
|
|
430
|
+
const visit = (key) => {
|
|
431
|
+
if (visited.has(key)) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (visiting.has(key)) {
|
|
435
|
+
const start = stack.indexOf(key);
|
|
436
|
+
const cycle = [...stack.slice(start), key].join(" -> ");
|
|
437
|
+
throw new CnosDerivedCycleError(`Derivation cycle detected: ${cycle}`);
|
|
438
|
+
}
|
|
439
|
+
visiting.add(key);
|
|
440
|
+
stack.push(key);
|
|
441
|
+
for (const dependency of dependencyMap.get(key) ?? []) {
|
|
442
|
+
visit(dependency);
|
|
443
|
+
}
|
|
444
|
+
stack.pop();
|
|
445
|
+
visiting.delete(key);
|
|
446
|
+
visited.add(key);
|
|
447
|
+
};
|
|
448
|
+
for (const key of dependencyMap.keys()) {
|
|
449
|
+
visit(key);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// ../core/src/derive/runtime.ts
|
|
454
|
+
function namespaceForKey(key) {
|
|
455
|
+
return key.split(".")[0] ?? "";
|
|
456
|
+
}
|
|
457
|
+
function dependencyNamespaces(key, entries, memo) {
|
|
458
|
+
if (memo.has(key)) {
|
|
459
|
+
return memo.get(key);
|
|
460
|
+
}
|
|
461
|
+
const entry = entries.get(key);
|
|
462
|
+
if (!entry) {
|
|
463
|
+
memo.set(key, []);
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
467
|
+
for (const ref of entry.parsed.refs) {
|
|
468
|
+
const namespace = namespaceForKey(ref);
|
|
469
|
+
if (!entries.has(ref)) {
|
|
470
|
+
namespaces.add(namespace);
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
for (const dependencyNamespace of dependencyNamespaces(ref, entries, memo)) {
|
|
474
|
+
namespaces.add(dependencyNamespace);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const result = Array.from(namespaces).sort((left, right) => left.localeCompare(right));
|
|
478
|
+
memo.set(key, result);
|
|
479
|
+
return result;
|
|
480
|
+
}
|
|
481
|
+
function isRuntimeDependentKey(key, entries, manifest, memo) {
|
|
482
|
+
if (memo.has(key)) {
|
|
483
|
+
return memo.get(key);
|
|
484
|
+
}
|
|
485
|
+
const entry = entries.get(key);
|
|
486
|
+
if (!entry) {
|
|
487
|
+
memo.set(key, false);
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
for (const ref of entry.parsed.refs) {
|
|
491
|
+
const namespace = namespaceForKey(ref);
|
|
492
|
+
if (manifest.runtimeNamespaces[namespace]) {
|
|
493
|
+
memo.set(key, true);
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
if (entries.has(ref) && isRuntimeDependentKey(ref, entries, manifest, memo)) {
|
|
497
|
+
memo.set(key, true);
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
memo.set(key, false);
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
function prepareEntries(graph, manifest) {
|
|
505
|
+
const entries = /* @__PURE__ */ new Map();
|
|
506
|
+
for (const [key, entry] of graph.entries) {
|
|
507
|
+
if (!isDerivedValue(entry.value)) {
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
const namespaceDefinition = manifest.namespaces[entry.namespace];
|
|
511
|
+
if (!namespaceDefinition || namespaceDefinition.kind === "data") {
|
|
512
|
+
validateDerivedTargetNamespace(manifest, entry.namespace);
|
|
513
|
+
}
|
|
514
|
+
const parsed = parseDerivation(entry.value);
|
|
515
|
+
validateParsedDerivation(manifest, parsed);
|
|
516
|
+
entries.set(key, {
|
|
517
|
+
key,
|
|
518
|
+
namespace: entry.namespace,
|
|
519
|
+
value: entry.value,
|
|
520
|
+
parsed
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
detectDerivationCycles(
|
|
524
|
+
new Map(
|
|
525
|
+
Array.from(entries.values()).map((entry) => [
|
|
526
|
+
entry.key,
|
|
527
|
+
entry.parsed.refs.filter((ref) => entries.has(ref))
|
|
528
|
+
])
|
|
529
|
+
)
|
|
530
|
+
);
|
|
531
|
+
const runtimeMemo = /* @__PURE__ */ new Map();
|
|
532
|
+
const namespaceMemo = /* @__PURE__ */ new Map();
|
|
533
|
+
for (const entry of entries.values()) {
|
|
534
|
+
entry.parsed.isRuntimeDependent = isRuntimeDependentKey(entry.key, entries, manifest, runtimeMemo);
|
|
535
|
+
entry.parsed.runtimeRefs = entry.parsed.refs.filter((ref) => manifest.runtimeNamespaces[namespaceForKey(ref)]);
|
|
536
|
+
if (entry.parsed.runtimeRefs.length === 0 && entry.parsed.isRuntimeDependent) {
|
|
537
|
+
entry.parsed.runtimeRefs = dependencyNamespaces(entry.key, entries, namespaceMemo).filter((namespace) => manifest.runtimeNamespaces[namespace]).map((namespace) => `${namespace}.*`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return entries;
|
|
541
|
+
}
|
|
542
|
+
function createDerivedRuntimeSupport(graph, manifest, runtimeProviders) {
|
|
543
|
+
const entries = prepareEntries(graph, manifest);
|
|
544
|
+
const configCache = /* @__PURE__ */ new Map();
|
|
545
|
+
const runtimeDependencyMemo = /* @__PURE__ */ new Map();
|
|
546
|
+
const support = {};
|
|
547
|
+
Object.assign(support, {
|
|
548
|
+
runtimeProviders,
|
|
549
|
+
read(key, readBase) {
|
|
550
|
+
const namespace = namespaceForKey(key);
|
|
551
|
+
if (runtimeProviders.has(namespace)) {
|
|
552
|
+
const provider = runtimeProviders.get(namespace);
|
|
553
|
+
return provider(key.slice(namespace.length + 1));
|
|
554
|
+
}
|
|
555
|
+
if (entries.has(key)) {
|
|
556
|
+
return readDerived(key, readBase);
|
|
557
|
+
}
|
|
558
|
+
return readBase(key);
|
|
559
|
+
},
|
|
560
|
+
describe(key, readBase) {
|
|
561
|
+
const entry = entries.get(key);
|
|
562
|
+
if (!entry) {
|
|
563
|
+
return void 0;
|
|
564
|
+
}
|
|
565
|
+
const runtimeNamespaces = Array.from(
|
|
566
|
+
new Set(
|
|
567
|
+
entry.parsed.refs.map((ref) => namespaceForKey(ref)).filter((namespace) => manifest.runtimeNamespaces[namespace])
|
|
568
|
+
)
|
|
569
|
+
).sort((left, right) => left.localeCompare(right));
|
|
570
|
+
return {
|
|
571
|
+
key,
|
|
572
|
+
type: entry.parsed.type,
|
|
573
|
+
expression: entry.parsed.raw,
|
|
574
|
+
dependencies: entry.parsed.refs.map((ref) => {
|
|
575
|
+
const namespace = namespaceForKey(ref);
|
|
576
|
+
return {
|
|
577
|
+
key: ref,
|
|
578
|
+
value: support.read(ref, readBase),
|
|
579
|
+
...manifest.runtimeNamespaces[namespace] ? {
|
|
580
|
+
runtimeNamespace: namespace
|
|
581
|
+
} : {}
|
|
582
|
+
};
|
|
583
|
+
}),
|
|
584
|
+
runtimeDependent: entry.parsed.isRuntimeDependent,
|
|
585
|
+
runtimeNamespaces,
|
|
586
|
+
...entry.parsed.isRuntimeDependent ? {
|
|
587
|
+
promotionWarning: "Cannot be promoted to browser/public."
|
|
588
|
+
} : {}
|
|
589
|
+
};
|
|
590
|
+
},
|
|
591
|
+
isDerivedKey(key) {
|
|
592
|
+
return entries.has(key);
|
|
593
|
+
},
|
|
594
|
+
isRuntimeDependentKey(key) {
|
|
595
|
+
if (runtimeDependencyMemo.has(key)) {
|
|
596
|
+
return runtimeDependencyMemo.get(key);
|
|
597
|
+
}
|
|
598
|
+
const value = entries.get(key)?.parsed.isRuntimeDependent ?? false;
|
|
599
|
+
runtimeDependencyMemo.set(key, value);
|
|
600
|
+
return value;
|
|
601
|
+
},
|
|
602
|
+
toConcreteValue(key, readBase, mode) {
|
|
603
|
+
const entry = entries.get(key);
|
|
604
|
+
if (!entry) {
|
|
605
|
+
return support.read(key, readBase);
|
|
606
|
+
}
|
|
607
|
+
if (!entry.parsed.isRuntimeDependent) {
|
|
608
|
+
return support.read(key, readBase);
|
|
609
|
+
}
|
|
610
|
+
if (mode === "server" || mode === "runtime") {
|
|
611
|
+
return support.read(key, readBase);
|
|
612
|
+
}
|
|
613
|
+
for (const ref of entry.parsed.refs) {
|
|
614
|
+
const namespace = namespaceForKey(ref);
|
|
615
|
+
const runtimeNamespace = manifest.runtimeNamespaces[namespace];
|
|
616
|
+
if (!runtimeNamespace) {
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
if (runtimeNamespace.serverOnly) {
|
|
620
|
+
throw new CnosDerivedResolutionError(
|
|
621
|
+
key,
|
|
622
|
+
`Cannot resolve ${key} for ${mode} output because it depends on runtime namespace ${namespace}.`
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
if (!runtimeProviders.has(namespace)) {
|
|
626
|
+
if (mode === "env") {
|
|
627
|
+
return void 0;
|
|
628
|
+
}
|
|
629
|
+
throw new CnosDerivedResolutionError(
|
|
630
|
+
key,
|
|
631
|
+
`Cannot resolve ${key} for ${mode} output because runtime namespace ${namespace} has no registered provider.`
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
return support.read(key, readBase);
|
|
636
|
+
},
|
|
637
|
+
toServerFormula(key) {
|
|
638
|
+
const entry = entries.get(key);
|
|
639
|
+
if (!entry || !entry.parsed.isRuntimeDependent) {
|
|
640
|
+
return void 0;
|
|
641
|
+
}
|
|
642
|
+
return {
|
|
643
|
+
expr: entry.parsed.raw,
|
|
644
|
+
deps: entry.parsed.refs.filter((ref) => !manifest.runtimeNamespaces[namespaceForKey(ref)]),
|
|
645
|
+
runtimeRefs: entry.parsed.refs.filter((ref) => manifest.runtimeNamespaces[namespaceForKey(ref)])
|
|
646
|
+
};
|
|
647
|
+
},
|
|
648
|
+
derivedKeys: Array.from(entries.keys()).sort((left, right) => left.localeCompare(right))
|
|
649
|
+
});
|
|
650
|
+
const readDerived = (key, readBase, evaluationStack = /* @__PURE__ */ new Set()) => {
|
|
651
|
+
const entry = entries.get(key);
|
|
652
|
+
if (!entry) {
|
|
653
|
+
return readBase(key);
|
|
654
|
+
}
|
|
655
|
+
if (!entry.parsed.isRuntimeDependent && configCache.has(key)) {
|
|
656
|
+
return configCache.get(key);
|
|
657
|
+
}
|
|
658
|
+
const value = evaluateDerivation({
|
|
659
|
+
key,
|
|
660
|
+
parsed: entry.parsed,
|
|
661
|
+
resolveRef: (ref) => {
|
|
662
|
+
const namespace = namespaceForKey(ref);
|
|
663
|
+
if (runtimeProviders.has(namespace)) {
|
|
664
|
+
const provider = runtimeProviders.get(namespace);
|
|
665
|
+
return provider(ref.slice(namespace.length + 1));
|
|
666
|
+
}
|
|
667
|
+
if (entries.has(ref)) {
|
|
668
|
+
if (evaluationStack.has(ref)) {
|
|
669
|
+
throw new CnosDerivedResolutionError(key, `Unable to resolve derived config key ${key} because of a recursive dependency on ${ref}.`);
|
|
670
|
+
}
|
|
671
|
+
evaluationStack.add(ref);
|
|
672
|
+
const resolved = readDerived(ref, readBase, evaluationStack);
|
|
673
|
+
evaluationStack.delete(ref);
|
|
674
|
+
return resolved;
|
|
675
|
+
}
|
|
676
|
+
return readBase(ref);
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
if (!entry.parsed.isRuntimeDependent) {
|
|
680
|
+
configCache.set(key, value);
|
|
681
|
+
}
|
|
682
|
+
return value;
|
|
683
|
+
};
|
|
684
|
+
for (const key of Array.from(entries.keys()).sort((left, right) => left.localeCompare(right))) {
|
|
685
|
+
const entry = entries.get(key);
|
|
686
|
+
if (!entry.parsed.isRuntimeDependent) {
|
|
687
|
+
readDerived(key, (ref) => graph.entries.get(ref)?.value);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return support;
|
|
691
|
+
}
|
|
692
|
+
function registerRuntimeProvider(manifest, runtimeProviders, namespace, provider) {
|
|
693
|
+
const definition = manifest.runtimeNamespaces[namespace];
|
|
694
|
+
if (!definition) {
|
|
695
|
+
throw new CnosRuntimeProviderError(`Cannot register runtime provider for undeclared namespace "${namespace}".`);
|
|
696
|
+
}
|
|
697
|
+
if (definition.builtIn) {
|
|
698
|
+
throw new CnosRuntimeProviderError(`Cannot override built-in runtime namespace "${namespace}".`);
|
|
699
|
+
}
|
|
700
|
+
runtimeProviders.set(namespace, provider);
|
|
701
|
+
}
|
|
37
702
|
|
|
38
703
|
// ../core/src/runtime/inspect.ts
|
|
39
|
-
function inspectValue(graph, key) {
|
|
704
|
+
function inspectValue(graph, key, helpers = {}) {
|
|
40
705
|
const entry = graph.entries.get(key);
|
|
41
706
|
if (!entry) {
|
|
42
707
|
throw new CnosKeyNotFoundError(key);
|
|
43
708
|
}
|
|
709
|
+
const derived = helpers.describeDerived?.(key);
|
|
44
710
|
return {
|
|
45
711
|
key: entry.key,
|
|
46
|
-
value: entry.value,
|
|
712
|
+
value: helpers.read ? helpers.read(entry.key) : entry.value,
|
|
47
713
|
namespace: entry.namespace,
|
|
48
714
|
profile: graph.profile,
|
|
49
715
|
profileSource: graph.profileSource,
|
|
@@ -64,7 +730,10 @@ function inspectValue(graph, key) {
|
|
|
64
730
|
workspaceId: override.workspaceId,
|
|
65
731
|
value: override.value,
|
|
66
732
|
...override.origin ? { origin: override.origin } : {}
|
|
67
|
-
}))
|
|
733
|
+
})),
|
|
734
|
+
...derived ? {
|
|
735
|
+
derived
|
|
736
|
+
} : {}
|
|
68
737
|
};
|
|
69
738
|
}
|
|
70
739
|
|
|
@@ -175,25 +844,312 @@ async function writeKeychain(entry, value) {
|
|
|
175
844
|
}
|
|
176
845
|
|
|
177
846
|
// ../core/src/utils/yaml.ts
|
|
178
|
-
import { parse, stringify } from "yaml";
|
|
847
|
+
import { parse, stringify as stringify2 } from "yaml";
|
|
179
848
|
function parseYaml(source) {
|
|
180
849
|
return parse(source);
|
|
181
850
|
}
|
|
182
851
|
function stringifyYaml(value) {
|
|
183
|
-
return
|
|
852
|
+
return stringify2(value);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// ../core/src/discovery/parseGitUri.ts
|
|
856
|
+
function isGitRootUri(uri) {
|
|
857
|
+
return /^git\+[a-z]+:\/\//i.test(uri);
|
|
858
|
+
}
|
|
859
|
+
function parseGitUri(uri) {
|
|
860
|
+
if (!isGitRootUri(uri)) {
|
|
861
|
+
throw new CnosDiscoveryError(`Unsupported git root URI: ${uri}`);
|
|
862
|
+
}
|
|
863
|
+
const withoutPrefix = uri.slice("git+".length);
|
|
864
|
+
const hashIndex = withoutPrefix.indexOf("#");
|
|
865
|
+
if (hashIndex < 0) {
|
|
866
|
+
throw new CnosDiscoveryError(
|
|
867
|
+
`Git root URI must include a #ref (tag, branch, or commit). Got: ${uri}`
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
const cloneUrl = withoutPrefix.slice(0, hashIndex);
|
|
871
|
+
const fragment = withoutPrefix.slice(hashIndex + 1);
|
|
872
|
+
const separatorIndex = fragment.indexOf(":");
|
|
873
|
+
const ref = (separatorIndex >= 0 ? fragment.slice(0, separatorIndex) : fragment).trim();
|
|
874
|
+
const subpath = (separatorIndex >= 0 ? fragment.slice(separatorIndex + 1) : ".cnos").trim() || ".cnos";
|
|
875
|
+
const protocol = cloneUrl.slice(0, cloneUrl.indexOf("://"));
|
|
876
|
+
if (!cloneUrl || !ref) {
|
|
877
|
+
throw new CnosDiscoveryError(
|
|
878
|
+
`Git root URI must include both a clone URL and #ref. Got: ${uri}`
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
uri,
|
|
883
|
+
cloneUrl,
|
|
884
|
+
ref,
|
|
885
|
+
subpath,
|
|
886
|
+
transport: protocol === "https" ? "https" : protocol === "ssh" ? "ssh" : protocol === "file" ? "file" : "custom"
|
|
887
|
+
};
|
|
184
888
|
}
|
|
185
889
|
|
|
890
|
+
// ../core/src/discovery/cache/cacheManager.ts
|
|
891
|
+
var SEMVER_TAG_RE = /^v?\d+\.\d+(?:\.\d+)?(?:[-+][A-Za-z0-9.-]+)?$/;
|
|
892
|
+
var COMMIT_SHA_RE = /^[0-9a-f]{40}$/i;
|
|
893
|
+
function isImmutableGitRef(ref) {
|
|
894
|
+
return SEMVER_TAG_RE.test(ref) || COMMIT_SHA_RE.test(ref);
|
|
895
|
+
}
|
|
896
|
+
function resolveRemoteRootCacheTtlSeconds(mode = "runtime", processEnv = process.env, override) {
|
|
897
|
+
if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
|
|
898
|
+
return override;
|
|
899
|
+
}
|
|
900
|
+
const fromEnv = Number(processEnv.CNOS_CACHE_TTL ?? "");
|
|
901
|
+
if (Number.isFinite(fromEnv) && fromEnv >= 0) {
|
|
902
|
+
return fromEnv;
|
|
903
|
+
}
|
|
904
|
+
switch (mode) {
|
|
905
|
+
case "build":
|
|
906
|
+
return 0;
|
|
907
|
+
case "dev":
|
|
908
|
+
return 30;
|
|
909
|
+
case "runtime":
|
|
910
|
+
default:
|
|
911
|
+
return 300;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
function isRemoteRootCacheFresh(metadata, options) {
|
|
915
|
+
if (!metadata || options.forceRefresh) {
|
|
916
|
+
return false;
|
|
917
|
+
}
|
|
918
|
+
if (metadata.uri !== options.uri || metadata.ref !== options.ref) {
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
if (metadata.isImmutable) {
|
|
922
|
+
return true;
|
|
923
|
+
}
|
|
924
|
+
const ttlSeconds = resolveRemoteRootCacheTtlSeconds(
|
|
925
|
+
options.mode,
|
|
926
|
+
options.processEnv,
|
|
927
|
+
options.ttlSeconds
|
|
928
|
+
);
|
|
929
|
+
if (ttlSeconds <= 0) {
|
|
930
|
+
return false;
|
|
931
|
+
}
|
|
932
|
+
const cachedAtMs = Date.parse(metadata.cachedAt);
|
|
933
|
+
if (Number.isNaN(cachedAtMs)) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
return Date.now() - cachedAtMs <= ttlSeconds * 1e3;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// ../core/src/discovery/cache/cacheMetadata.ts
|
|
940
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
941
|
+
import path from "path";
|
|
942
|
+
async function readRemoteRootCacheMetadata(metaPath) {
|
|
943
|
+
try {
|
|
944
|
+
const source = await readFile(metaPath, "utf8");
|
|
945
|
+
const parsed = JSON.parse(source);
|
|
946
|
+
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") {
|
|
947
|
+
return void 0;
|
|
948
|
+
}
|
|
949
|
+
return parsed;
|
|
950
|
+
} catch {
|
|
951
|
+
return void 0;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
async function writeRemoteRootCacheMetadata(metaPath, metadata) {
|
|
955
|
+
await mkdir(path.dirname(metaPath), { recursive: true });
|
|
956
|
+
await writeFile(metaPath, `${JSON.stringify(metadata, null, 2)}
|
|
957
|
+
`, "utf8");
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// ../core/src/discovery/cache/cachePaths.ts
|
|
961
|
+
import { createHash } from "crypto";
|
|
962
|
+
import os3 from "os";
|
|
963
|
+
import path5 from "path";
|
|
964
|
+
|
|
186
965
|
// ../core/src/utils/path.ts
|
|
187
|
-
import { access as
|
|
188
|
-
import
|
|
966
|
+
import { access as access3 } from "fs/promises";
|
|
967
|
+
import os2 from "os";
|
|
968
|
+
import path4 from "path";
|
|
969
|
+
|
|
970
|
+
// ../core/src/discovery/findCnosrc.ts
|
|
971
|
+
import { access as access2, readFile as readFile2 } from "fs/promises";
|
|
972
|
+
import path3 from "path";
|
|
973
|
+
|
|
974
|
+
// ../core/src/discovery/resolveRoot.ts
|
|
975
|
+
import { access, mkdir as mkdir2 } from "fs/promises";
|
|
189
976
|
import path2 from "path";
|
|
977
|
+
import { spawn as spawn2 } from "child_process";
|
|
978
|
+
import os from "os";
|
|
979
|
+
async function pathExists(targetPath) {
|
|
980
|
+
try {
|
|
981
|
+
await access(targetPath);
|
|
982
|
+
return true;
|
|
983
|
+
} catch {
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
function expandHomePath(targetPath) {
|
|
988
|
+
if (targetPath === "~") {
|
|
989
|
+
return os.homedir();
|
|
990
|
+
}
|
|
991
|
+
if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
|
|
992
|
+
return path2.join(os.homedir(), targetPath.slice(2));
|
|
993
|
+
}
|
|
994
|
+
return targetPath;
|
|
995
|
+
}
|
|
996
|
+
function isLocalRootUri(rootUri) {
|
|
997
|
+
return !isGitRootUri2(rootUri) && !isCnosHostedRootUri(rootUri);
|
|
998
|
+
}
|
|
999
|
+
function isCnosHostedRootUri(rootUri) {
|
|
1000
|
+
return rootUri.startsWith("cnos://");
|
|
1001
|
+
}
|
|
1002
|
+
function isGitRootUri2(rootUri) {
|
|
1003
|
+
return rootUri.startsWith("git+");
|
|
1004
|
+
}
|
|
1005
|
+
async function runGitCommand(args, options = {}) {
|
|
1006
|
+
return new Promise((resolve, reject) => {
|
|
1007
|
+
const child = spawn2("git", args, {
|
|
1008
|
+
cwd: options.cwd,
|
|
1009
|
+
env: options.processEnv ?? process.env,
|
|
1010
|
+
shell: process.platform === "win32",
|
|
1011
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1012
|
+
});
|
|
1013
|
+
let stdout = "";
|
|
1014
|
+
let stderr = "";
|
|
1015
|
+
child.stdout.on("data", (chunk) => {
|
|
1016
|
+
stdout += chunk.toString();
|
|
1017
|
+
});
|
|
1018
|
+
child.stderr.on("data", (chunk) => {
|
|
1019
|
+
stderr += chunk.toString();
|
|
1020
|
+
});
|
|
1021
|
+
child.on("error", (error) => {
|
|
1022
|
+
reject(
|
|
1023
|
+
new CnosDiscoveryError(
|
|
1024
|
+
`Failed to run git. Make sure git is installed and available on PATH. ${error.message}`
|
|
1025
|
+
)
|
|
1026
|
+
);
|
|
1027
|
+
});
|
|
1028
|
+
child.on("close", (code) => {
|
|
1029
|
+
if (code === 0) {
|
|
1030
|
+
resolve(stdout.trim());
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
const details = stderr.trim() || stdout.trim();
|
|
1034
|
+
reject(
|
|
1035
|
+
new CnosDiscoveryError(
|
|
1036
|
+
details ? `Git command failed: ${details}` : `Git command failed with exit code ${code ?? 1}`
|
|
1037
|
+
)
|
|
1038
|
+
);
|
|
1039
|
+
});
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
async function resolveLocalRoot(rootUri, cnosrcDir) {
|
|
1043
|
+
const candidateRoot = rootUri.startsWith("~") ? expandHomePath(rootUri) : rootUri;
|
|
1044
|
+
const manifestRoot = path2.resolve(cnosrcDir, candidateRoot);
|
|
1045
|
+
const manifestPath = path2.join(manifestRoot, "cnos.yml");
|
|
1046
|
+
if (!await pathExists(manifestPath)) {
|
|
1047
|
+
throw new CnosDiscoveryError(`.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`);
|
|
1048
|
+
}
|
|
1049
|
+
return {
|
|
1050
|
+
manifestRoot,
|
|
1051
|
+
resolution: {
|
|
1052
|
+
rootUri,
|
|
1053
|
+
protocol: "local",
|
|
1054
|
+
remote: false,
|
|
1055
|
+
readOnly: false
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
async function ensureGitCheckout(parsed, repoDir, processEnv) {
|
|
1060
|
+
const hasRepo = await pathExists(path2.join(repoDir, ".git"));
|
|
1061
|
+
if (!hasRepo) {
|
|
1062
|
+
await mkdir2(path2.dirname(repoDir), { recursive: true });
|
|
1063
|
+
await runGitCommand(["clone", "--no-checkout", parsed.cloneUrl, repoDir], { processEnv });
|
|
1064
|
+
} else {
|
|
1065
|
+
await runGitCommand(["-C", repoDir, "remote", "set-url", "origin", parsed.cloneUrl], {
|
|
1066
|
+
processEnv
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
await runGitCommand(["-C", repoDir, "fetch", "--tags", "--force", "origin"], { processEnv });
|
|
1070
|
+
await runGitCommand(["-C", repoDir, "checkout", "--force", parsed.ref], { processEnv });
|
|
1071
|
+
await runGitCommand(["-C", repoDir, "clean", "-fdx"], { processEnv });
|
|
1072
|
+
}
|
|
1073
|
+
async function resolveGitRoot(rootUri, options = {}) {
|
|
1074
|
+
const processEnv = options.processEnv ?? process.env;
|
|
1075
|
+
const parsed = parseGitUri(rootUri);
|
|
1076
|
+
const cachePaths = resolveRemoteRootCachePaths(rootUri, processEnv);
|
|
1077
|
+
const metadata = await readRemoteRootCacheMetadata(cachePaths.metaPath);
|
|
1078
|
+
const immutable = isImmutableGitRef(parsed.ref);
|
|
1079
|
+
const cacheFresh = isRemoteRootCacheFresh(metadata, {
|
|
1080
|
+
uri: rootUri,
|
|
1081
|
+
ref: parsed.ref,
|
|
1082
|
+
...options.cacheMode ? { mode: options.cacheMode } : {},
|
|
1083
|
+
processEnv,
|
|
1084
|
+
...typeof options.cacheTtlSeconds === "number" ? { ttlSeconds: options.cacheTtlSeconds } : {},
|
|
1085
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
1086
|
+
});
|
|
1087
|
+
if (!cacheFresh) {
|
|
1088
|
+
try {
|
|
1089
|
+
await ensureGitCheckout(parsed, cachePaths.repoDir, processEnv);
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1092
|
+
const authHint = parsed.transport === "ssh" ? " Check your SSH key and git access." : " Check the URL and your git credential helper or token setup.";
|
|
1093
|
+
throw new CnosDiscoveryError(`Failed to resolve remote git root ${rootUri}. ${message}${authHint}`);
|
|
1094
|
+
}
|
|
1095
|
+
const resolvedCommit = await runGitCommand(["-C", cachePaths.repoDir, "rev-parse", "HEAD"], {
|
|
1096
|
+
processEnv
|
|
1097
|
+
});
|
|
1098
|
+
await writeRemoteRootCacheMetadata(cachePaths.metaPath, {
|
|
1099
|
+
uri: rootUri,
|
|
1100
|
+
cloneUrl: parsed.cloneUrl,
|
|
1101
|
+
ref: parsed.ref,
|
|
1102
|
+
subpath: parsed.subpath,
|
|
1103
|
+
resolvedCommit,
|
|
1104
|
+
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1105
|
+
isImmutable: immutable
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
const nextMetadata = metadata && cacheFresh ? metadata : await readRemoteRootCacheMetadata(cachePaths.metaPath);
|
|
1109
|
+
const manifestRoot = path2.join(cachePaths.repoDir, parsed.subpath);
|
|
1110
|
+
if (!await pathExists(path2.join(manifestRoot, "cnos.yml"))) {
|
|
1111
|
+
throw new CnosDiscoveryError(
|
|
1112
|
+
`Git root ${rootUri} resolved to ${manifestRoot} but no cnos.yml was found there. Check the :subpath segment.`
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
return {
|
|
1116
|
+
manifestRoot,
|
|
1117
|
+
resolution: {
|
|
1118
|
+
rootUri,
|
|
1119
|
+
protocol: "git",
|
|
1120
|
+
remote: true,
|
|
1121
|
+
readOnly: true,
|
|
1122
|
+
cacheDir: cachePaths.cacheDir,
|
|
1123
|
+
cacheMetaPath: cachePaths.metaPath,
|
|
1124
|
+
ref: parsed.ref,
|
|
1125
|
+
subpath: parsed.subpath,
|
|
1126
|
+
immutable,
|
|
1127
|
+
...nextMetadata?.resolvedCommit ? { resolvedCommit: nextMetadata.resolvedCommit } : {},
|
|
1128
|
+
...nextMetadata?.cachedAt ? { cachedAt: nextMetadata.cachedAt } : {}
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
async function resolveRootUri(rootUri, cnosrcDir, options = {}) {
|
|
1133
|
+
if (isLocalRootUri(rootUri)) {
|
|
1134
|
+
return resolveLocalRoot(rootUri, cnosrcDir);
|
|
1135
|
+
}
|
|
1136
|
+
if (isGitRootUri2(rootUri)) {
|
|
1137
|
+
return resolveGitRoot(rootUri, options);
|
|
1138
|
+
}
|
|
1139
|
+
if (isCnosHostedRootUri(rootUri)) {
|
|
1140
|
+
throw new CnosDiscoveryError(
|
|
1141
|
+
`The cnos:// remote root protocol is reserved but not implemented yet. Use git+https:// or git+ssh:// for now.`
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
throw new CnosDiscoveryError(
|
|
1145
|
+
`Unknown root protocol: ${rootUri}. Supported root protocols are local paths, git+https://..., and git+ssh://....`
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
190
1148
|
|
|
191
1149
|
// ../core/src/discovery/findCnosrc.ts
|
|
192
|
-
import { access, readFile } from "fs/promises";
|
|
193
|
-
import path from "path";
|
|
194
1150
|
async function exists(targetPath) {
|
|
195
1151
|
try {
|
|
196
|
-
await
|
|
1152
|
+
await access2(targetPath);
|
|
197
1153
|
return true;
|
|
198
1154
|
} catch {
|
|
199
1155
|
return false;
|
|
@@ -214,13 +1170,13 @@ function validateCnosrc(value, filePath) {
|
|
|
214
1170
|
};
|
|
215
1171
|
}
|
|
216
1172
|
async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
|
|
217
|
-
let current =
|
|
1173
|
+
let current = path3.resolve(startDir);
|
|
218
1174
|
for (let depth = 0; depth <= maxLevels; depth += 1) {
|
|
219
|
-
const candidate =
|
|
1175
|
+
const candidate = path3.join(current, ".cnosrc.yml");
|
|
220
1176
|
if (await exists(candidate)) {
|
|
221
1177
|
return candidate;
|
|
222
1178
|
}
|
|
223
|
-
const parent =
|
|
1179
|
+
const parent = path3.dirname(current);
|
|
224
1180
|
if (parent === current) {
|
|
225
1181
|
break;
|
|
226
1182
|
}
|
|
@@ -228,27 +1184,22 @@ async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
|
|
|
228
1184
|
}
|
|
229
1185
|
return void 0;
|
|
230
1186
|
}
|
|
231
|
-
async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3) {
|
|
1187
|
+
async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3, options = {}) {
|
|
232
1188
|
const anchorPath = await findCnosrc(startDir, maxLevels);
|
|
233
1189
|
if (!anchorPath) {
|
|
234
1190
|
throw new CnosDiscoveryError(
|
|
235
1191
|
"No .cnosrc.yml found. Run cnos init or create .cnosrc.yml in your package root."
|
|
236
1192
|
);
|
|
237
1193
|
}
|
|
238
|
-
const source = await
|
|
1194
|
+
const source = await readFile2(anchorPath, "utf8");
|
|
239
1195
|
const parsed = validateCnosrc(parseYaml(source), anchorPath);
|
|
240
|
-
const consumerRoot =
|
|
241
|
-
const
|
|
242
|
-
const manifestPath = path.join(manifestRoot, "cnos.yml");
|
|
243
|
-
if (!await exists(manifestPath)) {
|
|
244
|
-
throw new CnosDiscoveryError(
|
|
245
|
-
`.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`
|
|
246
|
-
);
|
|
247
|
-
}
|
|
1196
|
+
const consumerRoot = path3.dirname(anchorPath);
|
|
1197
|
+
const resolvedRoot = await resolveRootUri(parsed.root, consumerRoot, options);
|
|
248
1198
|
return {
|
|
249
1199
|
anchorPath,
|
|
250
1200
|
consumerRoot,
|
|
251
|
-
manifestRoot,
|
|
1201
|
+
manifestRoot: resolvedRoot.manifestRoot,
|
|
1202
|
+
rootResolution: resolvedRoot.resolution,
|
|
252
1203
|
...parsed.workspace ? { workspace: parsed.workspace } : {}
|
|
253
1204
|
};
|
|
254
1205
|
}
|
|
@@ -258,21 +1209,21 @@ var PRIMARY_CNOS_DIR = ".cnos";
|
|
|
258
1209
|
var LEGACY_CNOS_DIR = "cnos";
|
|
259
1210
|
async function exists2(filePath) {
|
|
260
1211
|
try {
|
|
261
|
-
await
|
|
1212
|
+
await access3(filePath);
|
|
262
1213
|
return true;
|
|
263
1214
|
} catch {
|
|
264
1215
|
return false;
|
|
265
1216
|
}
|
|
266
1217
|
}
|
|
267
1218
|
async function resolveCnosRoot(root = process.cwd()) {
|
|
268
|
-
const basePath =
|
|
1219
|
+
const basePath = path4.resolve(root);
|
|
269
1220
|
const candidates = [
|
|
270
|
-
|
|
271
|
-
|
|
1221
|
+
path4.join(basePath, PRIMARY_CNOS_DIR),
|
|
1222
|
+
path4.join(basePath, LEGACY_CNOS_DIR),
|
|
272
1223
|
basePath
|
|
273
1224
|
];
|
|
274
1225
|
for (const candidate of candidates) {
|
|
275
|
-
if (await exists2(
|
|
1226
|
+
if (await exists2(path4.join(candidate, "cnos.yml"))) {
|
|
276
1227
|
return candidate;
|
|
277
1228
|
}
|
|
278
1229
|
}
|
|
@@ -282,18 +1233,44 @@ async function resolveCnosRoot(root = process.cwd()) {
|
|
|
282
1233
|
}
|
|
283
1234
|
async function resolveManifestRoot(options = {}) {
|
|
284
1235
|
if (options.root) {
|
|
1236
|
+
if (options.root.startsWith("git+") || options.root.startsWith("cnos://")) {
|
|
1237
|
+
const consumerRoot2 = path4.resolve(options.cwd ?? process.cwd());
|
|
1238
|
+
const resolvedRoot2 = await resolveRootUri(options.root, consumerRoot2, {
|
|
1239
|
+
...options.processEnv ? { processEnv: options.processEnv } : {},
|
|
1240
|
+
...options.cacheMode ? { cacheMode: options.cacheMode } : {},
|
|
1241
|
+
...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
|
|
1242
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
1243
|
+
});
|
|
1244
|
+
return {
|
|
1245
|
+
manifestRoot: resolvedRoot2.manifestRoot,
|
|
1246
|
+
consumerRoot: consumerRoot2,
|
|
1247
|
+
rootResolution: resolvedRoot2.resolution
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
285
1250
|
const manifestRoot = await resolveCnosRoot(options.root);
|
|
286
|
-
const resolvedRoot =
|
|
287
|
-
const consumerRoot =
|
|
1251
|
+
const resolvedRoot = path4.resolve(options.root);
|
|
1252
|
+
const consumerRoot = path4.basename(manifestRoot) === PRIMARY_CNOS_DIR || path4.basename(manifestRoot) === LEGACY_CNOS_DIR ? path4.dirname(manifestRoot) : resolvedRoot;
|
|
288
1253
|
return {
|
|
289
1254
|
manifestRoot,
|
|
290
|
-
consumerRoot
|
|
1255
|
+
consumerRoot,
|
|
1256
|
+
rootResolution: {
|
|
1257
|
+
rootUri: manifestRoot,
|
|
1258
|
+
protocol: "local",
|
|
1259
|
+
remote: false,
|
|
1260
|
+
readOnly: false
|
|
1261
|
+
}
|
|
291
1262
|
};
|
|
292
1263
|
}
|
|
293
|
-
const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd()
|
|
1264
|
+
const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd(), 3, {
|
|
1265
|
+
...options.processEnv ? { processEnv: options.processEnv } : {},
|
|
1266
|
+
...options.cacheMode ? { cacheMode: options.cacheMode } : {},
|
|
1267
|
+
...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
|
|
1268
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
1269
|
+
});
|
|
294
1270
|
return {
|
|
295
1271
|
manifestRoot: discovered.manifestRoot,
|
|
296
1272
|
consumerRoot: discovered.consumerRoot,
|
|
1273
|
+
rootResolution: discovered.rootResolution,
|
|
297
1274
|
anchorPath: discovered.anchorPath,
|
|
298
1275
|
...discovered.workspace ? { workspace: discovered.workspace } : {}
|
|
299
1276
|
};
|
|
@@ -304,12 +1281,12 @@ function interpolatePathTemplate(template, tokens) {
|
|
|
304
1281
|
template
|
|
305
1282
|
);
|
|
306
1283
|
}
|
|
307
|
-
function
|
|
1284
|
+
function expandHomePath2(targetPath) {
|
|
308
1285
|
if (targetPath === "~") {
|
|
309
|
-
return
|
|
1286
|
+
return os2.homedir();
|
|
310
1287
|
}
|
|
311
1288
|
if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
|
|
312
|
-
return
|
|
1289
|
+
return path4.join(os2.homedir(), targetPath.slice(2));
|
|
313
1290
|
}
|
|
314
1291
|
return targetPath;
|
|
315
1292
|
}
|
|
@@ -327,19 +1304,19 @@ function stripWorkspaceTemplatePrefix(template) {
|
|
|
327
1304
|
function resolveWorkspaceScopedPath(workspaceRoot, template, tokens) {
|
|
328
1305
|
const relativeTemplate = stripWorkspaceTemplatePrefix(template);
|
|
329
1306
|
const interpolated = interpolatePathTemplate(relativeTemplate, tokens);
|
|
330
|
-
return
|
|
1307
|
+
return path4.resolve(workspaceRoot, interpolated);
|
|
331
1308
|
}
|
|
332
1309
|
function resolveNamespaceDirectory(workspaceRoot, namespace, profile) {
|
|
333
1310
|
const rootFolder = namespace === "value" ? "values" : namespace === "secret" ? "secrets" : namespace;
|
|
334
1311
|
if (profile && profile !== "base") {
|
|
335
|
-
return
|
|
1312
|
+
return path4.resolve(workspaceRoot, "profiles", profile, rootFolder);
|
|
336
1313
|
}
|
|
337
|
-
return
|
|
1314
|
+
return path4.resolve(workspaceRoot, rootFolder);
|
|
338
1315
|
}
|
|
339
1316
|
function resolveConfigDocumentPath(workspaceRoot, namespace, configPath, profile) {
|
|
340
1317
|
const namespaceRoot = resolveNamespaceDirectory(workspaceRoot, namespace, profile);
|
|
341
1318
|
const fileName = `${configPath.split(".").shift() ?? "app"}.yml`;
|
|
342
|
-
return
|
|
1319
|
+
return path4.resolve(namespaceRoot, fileName);
|
|
343
1320
|
}
|
|
344
1321
|
function toPortablePath(targetPath) {
|
|
345
1322
|
return targetPath.replace(/\\/g, "/");
|
|
@@ -354,9 +1331,29 @@ function stripNamespace(key) {
|
|
|
354
1331
|
return key.split(".").slice(1).join(".");
|
|
355
1332
|
}
|
|
356
1333
|
|
|
1334
|
+
// ../core/src/discovery/cache/cachePaths.ts
|
|
1335
|
+
function resolveCnosCacheRoot(processEnv = process.env) {
|
|
1336
|
+
return path5.resolve(
|
|
1337
|
+
expandHomePath2(processEnv.CNOS_CACHE_DIR ?? path5.join(os3.homedir(), ".cnos", "cache"))
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
function createRemoteRootCacheKey(uri) {
|
|
1341
|
+
return createHash("sha256").update(uri).digest("hex");
|
|
1342
|
+
}
|
|
1343
|
+
function resolveRemoteRootCachePaths(uri, processEnv = process.env) {
|
|
1344
|
+
const cacheRoot = resolveCnosCacheRoot(processEnv);
|
|
1345
|
+
const cacheDir = path5.join(cacheRoot, "roots", createRemoteRootCacheKey(uri));
|
|
1346
|
+
return {
|
|
1347
|
+
cacheRoot,
|
|
1348
|
+
cacheDir,
|
|
1349
|
+
repoDir: path5.join(cacheDir, "repo"),
|
|
1350
|
+
metaPath: path5.join(cacheDir, ".cnos-cache-meta.json")
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
|
|
357
1354
|
// ../core/src/manifest/loadManifest.ts
|
|
358
|
-
import { readFile as
|
|
359
|
-
import
|
|
1355
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1356
|
+
import path6 from "path";
|
|
360
1357
|
|
|
361
1358
|
// ../core/src/manifest/normalizeManifest.ts
|
|
362
1359
|
var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
|
|
@@ -409,6 +1406,13 @@ var DEFAULT_NAMESPACES = {
|
|
|
409
1406
|
readonly: true
|
|
410
1407
|
}
|
|
411
1408
|
};
|
|
1409
|
+
var DEFAULT_RUNTIME_NAMESPACES = {
|
|
1410
|
+
process: {
|
|
1411
|
+
description: "Live process runtime values.",
|
|
1412
|
+
serverOnly: true,
|
|
1413
|
+
builtIn: true
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
412
1416
|
function validateResolveFrom(resolveFrom) {
|
|
413
1417
|
const validValues = ["cli.profile", "env.CNOS_PROFILE", "default"];
|
|
414
1418
|
for (const entry of resolveFrom) {
|
|
@@ -431,7 +1435,7 @@ function normalizeWorkspaceItems(items) {
|
|
|
431
1435
|
}
|
|
432
1436
|
function normalizeNamespaces(namespaces) {
|
|
433
1437
|
const normalized = Object.fromEntries(
|
|
434
|
-
Object.entries(namespaces ?? {}).map(([namespace, definition]) => [
|
|
1438
|
+
Object.entries(namespaces ?? {}).filter(([namespace]) => namespace !== "runtime").map(([namespace, definition]) => [
|
|
435
1439
|
namespace,
|
|
436
1440
|
{
|
|
437
1441
|
kind: definition.kind ?? "data",
|
|
@@ -447,6 +1451,29 @@ function normalizeNamespaces(namespaces) {
|
|
|
447
1451
|
...normalized
|
|
448
1452
|
};
|
|
449
1453
|
}
|
|
1454
|
+
function normalizeRuntimeNamespaces(namespaces) {
|
|
1455
|
+
const runtimeEntries = namespaces?.runtime ?? {};
|
|
1456
|
+
const normalized = Object.fromEntries(
|
|
1457
|
+
Object.entries(runtimeEntries).map(([namespace, definition]) => [
|
|
1458
|
+
namespace,
|
|
1459
|
+
{
|
|
1460
|
+
...definition.description?.trim() ? {
|
|
1461
|
+
description: definition.description.trim()
|
|
1462
|
+
} : {},
|
|
1463
|
+
serverOnly: definition.server_only ?? true
|
|
1464
|
+
}
|
|
1465
|
+
])
|
|
1466
|
+
);
|
|
1467
|
+
for (const namespace of Object.keys(normalized)) {
|
|
1468
|
+
if (DEFAULT_NAMESPACES[namespace] || namespace === "runtime") {
|
|
1469
|
+
throw new CnosManifestError(`Runtime namespace "${namespace}" conflicts with a built-in or reserved namespace.`);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return {
|
|
1473
|
+
...DEFAULT_RUNTIME_NAMESPACES,
|
|
1474
|
+
...normalized
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
450
1477
|
function normalizeVaults(vaults) {
|
|
451
1478
|
return Object.fromEntries(
|
|
452
1479
|
Object.entries(vaults ?? {}).map(([name, definition]) => {
|
|
@@ -538,6 +1565,7 @@ function normalizeManifest(manifest) {
|
|
|
538
1565
|
const defaultProfile = manifest.profiles?.default?.trim() || "base";
|
|
539
1566
|
const workspaceItems = normalizeWorkspaceItems(manifest.workspaces?.items);
|
|
540
1567
|
const resolveFrom = validateResolveFrom(manifest.profiles?.resolveFrom ?? DEFAULT_RESOLVE_FROM);
|
|
1568
|
+
const runtimeNamespaces = normalizeRuntimeNamespaces(manifest.namespaces);
|
|
541
1569
|
const filesystemValues = {
|
|
542
1570
|
root: "./",
|
|
543
1571
|
format: "yaml",
|
|
@@ -611,6 +1639,7 @@ function normalizeManifest(manifest) {
|
|
|
611
1639
|
}
|
|
612
1640
|
},
|
|
613
1641
|
namespaces: normalizeNamespaces(manifest.namespaces),
|
|
1642
|
+
runtimeNamespaces,
|
|
614
1643
|
vaults: normalizeVaults(manifest.vaults),
|
|
615
1644
|
writePolicy: {
|
|
616
1645
|
define: {
|
|
@@ -629,13 +1658,17 @@ function normalizeManifest(manifest) {
|
|
|
629
1658
|
async function loadManifest(options = {}) {
|
|
630
1659
|
const resolved = await resolveManifestRoot({
|
|
631
1660
|
...options.root ? { root: options.root } : {},
|
|
632
|
-
...options.cwd ? { cwd: options.cwd } : {}
|
|
1661
|
+
...options.cwd ? { cwd: options.cwd } : {},
|
|
1662
|
+
...options.processEnv ? { processEnv: options.processEnv } : {},
|
|
1663
|
+
...options.cacheMode ? { cacheMode: options.cacheMode } : {},
|
|
1664
|
+
...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
|
|
1665
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
633
1666
|
});
|
|
634
1667
|
const manifestRoot = resolved.manifestRoot;
|
|
635
|
-
const manifestPath =
|
|
1668
|
+
const manifestPath = path6.join(manifestRoot, "cnos.yml");
|
|
636
1669
|
let source;
|
|
637
1670
|
try {
|
|
638
|
-
source = await
|
|
1671
|
+
source = await readFile3(manifestPath, "utf8");
|
|
639
1672
|
} catch {
|
|
640
1673
|
throw new CnosManifestError("Unable to read CNOS manifest", manifestPath);
|
|
641
1674
|
}
|
|
@@ -645,10 +1678,11 @@ async function loadManifest(options = {}) {
|
|
|
645
1678
|
}
|
|
646
1679
|
return {
|
|
647
1680
|
manifestRoot,
|
|
648
|
-
repoRoot:
|
|
1681
|
+
repoRoot: path6.dirname(manifestRoot),
|
|
649
1682
|
consumerRoot: resolved.consumerRoot,
|
|
650
1683
|
...resolved.anchorPath ? { anchorPath: resolved.anchorPath } : {},
|
|
651
1684
|
...resolved.workspace ? { anchoredWorkspace: resolved.workspace } : {},
|
|
1685
|
+
rootResolution: resolved.rootResolution,
|
|
652
1686
|
manifestPath,
|
|
653
1687
|
manifest: normalizeManifest(rawManifest),
|
|
654
1688
|
rawManifest
|
|
@@ -704,29 +1738,29 @@ function validateProjectionIssue(manifest, key, target) {
|
|
|
704
1738
|
}
|
|
705
1739
|
|
|
706
1740
|
// ../core/src/secrets/sessionStore.ts
|
|
707
|
-
import { mkdir, readFile as
|
|
708
|
-
import
|
|
1741
|
+
import { mkdir as mkdir3, readFile as readFile4, readdir, rm, writeFile as writeFile2 } from "fs/promises";
|
|
1742
|
+
import path7 from "path";
|
|
709
1743
|
function buildSessionRoot(processEnv = process.env) {
|
|
710
|
-
return
|
|
1744
|
+
return path7.join(path7.resolve(expandHomePath2(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
|
|
711
1745
|
}
|
|
712
1746
|
function buildSessionPath(vault, processEnv) {
|
|
713
|
-
return
|
|
1747
|
+
return path7.join(buildSessionRoot(processEnv), `${vault}.json`);
|
|
714
1748
|
}
|
|
715
1749
|
async function writeVaultSessionKey(vault, derivedKey, processEnv) {
|
|
716
1750
|
const filePath = buildSessionPath(vault, processEnv);
|
|
717
|
-
await
|
|
1751
|
+
await mkdir3(path7.dirname(filePath), { recursive: true });
|
|
718
1752
|
const document = {
|
|
719
1753
|
version: 1,
|
|
720
1754
|
vault,
|
|
721
1755
|
derivedKey: derivedKey.toString("hex"),
|
|
722
1756
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
723
1757
|
};
|
|
724
|
-
await
|
|
1758
|
+
await writeFile2(filePath, JSON.stringify(document, null, 2), "utf8");
|
|
725
1759
|
return filePath;
|
|
726
1760
|
}
|
|
727
1761
|
async function readVaultSessionKey(vault, processEnv) {
|
|
728
1762
|
try {
|
|
729
|
-
const source = await
|
|
1763
|
+
const source = await readFile4(buildSessionPath(vault, processEnv), "utf8");
|
|
730
1764
|
const document = JSON.parse(source);
|
|
731
1765
|
if (document.version !== 1 || typeof document.derivedKey !== "string") {
|
|
732
1766
|
return void 0;
|
|
@@ -744,15 +1778,15 @@ async function clearAllVaultSessionKeys(processEnv) {
|
|
|
744
1778
|
const root = buildSessionRoot(processEnv);
|
|
745
1779
|
try {
|
|
746
1780
|
const entries = await readdir(root);
|
|
747
|
-
await Promise.all(entries.map((entry) => rm(
|
|
1781
|
+
await Promise.all(entries.map((entry) => rm(path7.join(root, entry), { force: true })));
|
|
748
1782
|
} catch {
|
|
749
1783
|
}
|
|
750
1784
|
}
|
|
751
1785
|
|
|
752
1786
|
// ../core/src/utils/secretStore.ts
|
|
753
1787
|
import { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from "crypto";
|
|
754
|
-
import { mkdir as
|
|
755
|
-
import
|
|
1788
|
+
import { mkdir as mkdir4, readdir as readdir2, readFile as readFile5, rm as rm2, stat, writeFile as writeFile3 } from "fs/promises";
|
|
1789
|
+
import path8 from "path";
|
|
756
1790
|
var KEY_LENGTH = 32;
|
|
757
1791
|
var SALT_LENGTH = 32;
|
|
758
1792
|
var IV_LENGTH = 12;
|
|
@@ -769,7 +1803,7 @@ function isSecretReference(value) {
|
|
|
769
1803
|
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));
|
|
770
1804
|
}
|
|
771
1805
|
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
772
|
-
return
|
|
1806
|
+
return path8.resolve(expandHomePath2(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
773
1807
|
}
|
|
774
1808
|
function normalizeVaultToken(vault = "default") {
|
|
775
1809
|
return vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
@@ -804,19 +1838,19 @@ function deriveVaultKey(passphrase, salt, iterations = PBKDF2_ITERATIONS) {
|
|
|
804
1838
|
return pbkdf2Sync(passphrase, salt, iterations, KEY_LENGTH, "sha512");
|
|
805
1839
|
}
|
|
806
1840
|
function buildMetaPath(storeRoot, vault = "default") {
|
|
807
|
-
return
|
|
1841
|
+
return path8.join(storeRoot, "vaults", vault, META_FILENAME);
|
|
808
1842
|
}
|
|
809
1843
|
function resolveSecretVaultFile(storeRoot, vault = "default") {
|
|
810
1844
|
return buildMetaPath(storeRoot, vault);
|
|
811
1845
|
}
|
|
812
1846
|
function buildKeystorePath(storeRoot, vault = "default") {
|
|
813
|
-
return
|
|
1847
|
+
return path8.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
|
|
814
1848
|
}
|
|
815
1849
|
function buildLegacyVaultFile(storeRoot, vault = "default") {
|
|
816
|
-
return
|
|
1850
|
+
return path8.join(storeRoot, "vaults", `${vault}.json`);
|
|
817
1851
|
}
|
|
818
1852
|
function buildLegacyVaultStoreRoot(storeRoot, vault = "default") {
|
|
819
|
-
return
|
|
1853
|
+
return path8.join(storeRoot, "vaults", vault, "store");
|
|
820
1854
|
}
|
|
821
1855
|
function assertVaultMetadata(value, filePath) {
|
|
822
1856
|
if (!isObject(value)) {
|
|
@@ -913,15 +1947,15 @@ function buildInitialPayload() {
|
|
|
913
1947
|
async function writeVaultFiles(storeRoot, vault, meta, payload, key) {
|
|
914
1948
|
const metaPath = buildMetaPath(storeRoot, vault);
|
|
915
1949
|
const keystorePath = buildKeystorePath(storeRoot, vault);
|
|
916
|
-
await
|
|
917
|
-
await
|
|
918
|
-
await
|
|
1950
|
+
await mkdir4(path8.dirname(metaPath), { recursive: true });
|
|
1951
|
+
await writeFile3(metaPath, stringifyYaml(meta), "utf8");
|
|
1952
|
+
await writeFile3(keystorePath, encryptPayload(payload, key));
|
|
919
1953
|
}
|
|
920
1954
|
async function readVaultMetadata(storeRoot, vault = "default") {
|
|
921
1955
|
await assertNoLegacyVaultFormat(storeRoot, vault);
|
|
922
1956
|
const metaPath = buildMetaPath(storeRoot, vault);
|
|
923
1957
|
try {
|
|
924
|
-
const source = await
|
|
1958
|
+
const source = await readFile5(metaPath, "utf8");
|
|
925
1959
|
return assertVaultMetadata(parseYaml(source), metaPath);
|
|
926
1960
|
} catch (error) {
|
|
927
1961
|
if (error.code === "ENOENT") {
|
|
@@ -931,11 +1965,11 @@ async function readVaultMetadata(storeRoot, vault = "default") {
|
|
|
931
1965
|
}
|
|
932
1966
|
}
|
|
933
1967
|
async function listSecretVaults(storeRoot) {
|
|
934
|
-
const vaultRoot =
|
|
1968
|
+
const vaultRoot = path8.join(storeRoot, "vaults");
|
|
935
1969
|
try {
|
|
936
1970
|
const entries = await readdir2(vaultRoot, { withFileTypes: true });
|
|
937
1971
|
const vaults = await Promise.all(
|
|
938
|
-
entries.filter((entry) => entry.isDirectory()).map(async (entry) => await exists3(
|
|
1972
|
+
entries.filter((entry) => entry.isDirectory()).map(async (entry) => await exists3(path8.join(vaultRoot, entry.name, META_FILENAME)) ? entry.name : void 0)
|
|
939
1973
|
);
|
|
940
1974
|
return vaults.filter((value) => Boolean(value)).sort((left, right) => left.localeCompare(right));
|
|
941
1975
|
} catch {
|
|
@@ -1024,7 +2058,7 @@ async function loadVaultPayload(storeRoot, vault, auth) {
|
|
|
1024
2058
|
if (!key) {
|
|
1025
2059
|
throw new CnosAuthenticationError(`Vault "${vault}" requires authentication before access.`);
|
|
1026
2060
|
}
|
|
1027
|
-
const buffer = await
|
|
2061
|
+
const buffer = await readFile5(buildKeystorePath(storeRoot, vault));
|
|
1028
2062
|
return {
|
|
1029
2063
|
meta,
|
|
1030
2064
|
payload: decryptPayload(buffer, key),
|
|
@@ -1097,7 +2131,7 @@ function resolveVaultDefinition(vaults, vault = "default") {
|
|
|
1097
2131
|
};
|
|
1098
2132
|
}
|
|
1099
2133
|
async function removeLocalVaultFiles(storeRoot, vault = "default") {
|
|
1100
|
-
await rm2(
|
|
2134
|
+
await rm2(path8.join(storeRoot, "vaults", vault), { recursive: true, force: true });
|
|
1101
2135
|
}
|
|
1102
2136
|
|
|
1103
2137
|
// ../core/src/secrets/providers/github.ts
|
|
@@ -1156,11 +2190,11 @@ var GithubSecretsVaultProvider = class {
|
|
|
1156
2190
|
};
|
|
1157
2191
|
|
|
1158
2192
|
// ../core/src/secrets/auditLog.ts
|
|
1159
|
-
import { appendFile, mkdir as
|
|
1160
|
-
import
|
|
2193
|
+
import { appendFile, mkdir as mkdir5 } from "fs/promises";
|
|
2194
|
+
import path9 from "path";
|
|
1161
2195
|
async function appendAuditEvent(event, processEnv = process.env) {
|
|
1162
|
-
const auditFile = processEnv.CNOS_AUDIT_FILE ??
|
|
1163
|
-
await
|
|
2196
|
+
const auditFile = processEnv.CNOS_AUDIT_FILE ?? path9.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
|
|
2197
|
+
await mkdir5(path9.dirname(auditFile), { recursive: true });
|
|
1164
2198
|
await appendFile(
|
|
1165
2199
|
auditFile,
|
|
1166
2200
|
`${JSON.stringify({
|
|
@@ -1387,7 +2421,7 @@ function setNestedValue(target, pathSegments, value) {
|
|
|
1387
2421
|
target[head] = nextTarget;
|
|
1388
2422
|
setNestedValue(nextTarget, tail, value);
|
|
1389
2423
|
}
|
|
1390
|
-
function toNamespaceObject(graph, namespace) {
|
|
2424
|
+
function toNamespaceObject(graph, namespace, readValueForKey = (key) => graph.entries.get(key)?.value) {
|
|
1391
2425
|
const output = {};
|
|
1392
2426
|
const resolvedEntries = Array.from(graph.entries.values()).sort(
|
|
1393
2427
|
(left, right) => left.key.localeCompare(right.key)
|
|
@@ -1397,7 +2431,11 @@ function toNamespaceObject(graph, namespace) {
|
|
|
1397
2431
|
continue;
|
|
1398
2432
|
}
|
|
1399
2433
|
const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
|
|
1400
|
-
|
|
2434
|
+
const value = readValueForKey(entry.key);
|
|
2435
|
+
if (value === void 0) {
|
|
2436
|
+
continue;
|
|
2437
|
+
}
|
|
2438
|
+
setNestedValue(output, valuePath.split("."), value);
|
|
1401
2439
|
}
|
|
1402
2440
|
return output;
|
|
1403
2441
|
}
|
|
@@ -1407,12 +2445,6 @@ function readValue(graph, key) {
|
|
|
1407
2445
|
return graph.entries.get(key)?.value;
|
|
1408
2446
|
}
|
|
1409
2447
|
|
|
1410
|
-
// ../core/src/runtime/readOr.ts
|
|
1411
|
-
function readOrValue(graph, key, fallback) {
|
|
1412
|
-
const value = readValue(graph, key);
|
|
1413
|
-
return value === void 0 ? fallback : value;
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
2448
|
// ../core/src/runtime/require.ts
|
|
1417
2449
|
function requireValue(graph, key) {
|
|
1418
2450
|
const value = readValue(graph, key);
|
|
@@ -1422,6 +2454,36 @@ function requireValue(graph, key) {
|
|
|
1422
2454
|
return value;
|
|
1423
2455
|
}
|
|
1424
2456
|
|
|
2457
|
+
// ../core/src/runtime/runtimeProviders.ts
|
|
2458
|
+
function createDefaultRuntimeProviders(manifest, processEnv) {
|
|
2459
|
+
const providers = /* @__PURE__ */ new Map();
|
|
2460
|
+
if (manifest.runtimeNamespaces.process) {
|
|
2461
|
+
providers.set("process", (key) => {
|
|
2462
|
+
const segments = key.split(".");
|
|
2463
|
+
if (segments[0] === "env") {
|
|
2464
|
+
return processEnv[segments.slice(1).join(".")];
|
|
2465
|
+
}
|
|
2466
|
+
if (key === "cwd") {
|
|
2467
|
+
return process.cwd();
|
|
2468
|
+
}
|
|
2469
|
+
if (key === "platform") {
|
|
2470
|
+
return process.platform;
|
|
2471
|
+
}
|
|
2472
|
+
if (key === "arch") {
|
|
2473
|
+
return process.arch;
|
|
2474
|
+
}
|
|
2475
|
+
if (key === "pid") {
|
|
2476
|
+
return process.pid;
|
|
2477
|
+
}
|
|
2478
|
+
if (key === "node.version") {
|
|
2479
|
+
return process.version;
|
|
2480
|
+
}
|
|
2481
|
+
return void 0;
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
return providers;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
1425
2487
|
// ../core/src/runtime/toEnv.ts
|
|
1426
2488
|
function normalizeEnvValue(value) {
|
|
1427
2489
|
if (value === void 0 || value === null) {
|
|
@@ -1435,7 +2497,7 @@ function normalizeEnvValue(value) {
|
|
|
1435
2497
|
}
|
|
1436
2498
|
return JSON.stringify(value);
|
|
1437
2499
|
}
|
|
1438
|
-
function toEnv(graph, manifest, options = {}) {
|
|
2500
|
+
function toEnv(graph, manifest, options = {}, helpers = {}) {
|
|
1439
2501
|
const includeSecrets = options.includeSecrets ?? true;
|
|
1440
2502
|
const output = {};
|
|
1441
2503
|
const mappedEntries = Object.entries(manifest.envMapping.explicit).sort(
|
|
@@ -1456,7 +2518,11 @@ function toEnv(graph, manifest, options = {}) {
|
|
|
1456
2518
|
if (isSecretReference(entry.value)) {
|
|
1457
2519
|
continue;
|
|
1458
2520
|
}
|
|
1459
|
-
|
|
2521
|
+
const value = helpers.read ? helpers.read(logicalKey) : entry.value;
|
|
2522
|
+
if (value === void 0) {
|
|
2523
|
+
continue;
|
|
2524
|
+
}
|
|
2525
|
+
output[envVar] = normalizeEnvValue(value);
|
|
1460
2526
|
}
|
|
1461
2527
|
return output;
|
|
1462
2528
|
}
|
|
@@ -1493,36 +2559,46 @@ function resolvePublicPrefix(manifest, options) {
|
|
|
1493
2559
|
}
|
|
1494
2560
|
return manifest.public.frameworks[options.framework] ?? "";
|
|
1495
2561
|
}
|
|
1496
|
-
function toPublicEnv(graph, manifest, options = {}) {
|
|
2562
|
+
function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
|
|
1497
2563
|
const prefix = resolvePublicPrefix(manifest, options);
|
|
1498
2564
|
const output = {};
|
|
1499
2565
|
const promotions = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").sort((left, right) => left.key.localeCompare(right.key));
|
|
1500
2566
|
for (const resolved of promotions) {
|
|
2567
|
+
if (helpers.isRuntimeDependent?.(resolved.key)) {
|
|
2568
|
+
const value2 = helpers.read?.(resolved.key);
|
|
2569
|
+
if (value2 === void 0) {
|
|
2570
|
+
throw new CnosManifestError(`Cannot build public output for ${resolved.key} because it depends on runtime-only values.`);
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
1501
2573
|
const baseEnvVar = fallbackPublicEnvVar(stripNamespace(resolved.key));
|
|
1502
2574
|
const envVar = prefix && !baseEnvVar.startsWith(prefix) ? `${prefix}${baseEnvVar}` : baseEnvVar;
|
|
1503
|
-
|
|
2575
|
+
const value = helpers.read ? helpers.read(resolved.key) : resolved.value;
|
|
2576
|
+
if (value === void 0) {
|
|
2577
|
+
continue;
|
|
2578
|
+
}
|
|
2579
|
+
output[envVar] = normalizeEnvValue2(value);
|
|
1504
2580
|
}
|
|
1505
2581
|
return output;
|
|
1506
2582
|
}
|
|
1507
2583
|
|
|
1508
2584
|
// ../core/src/runtime/dump.ts
|
|
1509
|
-
import { mkdir as
|
|
1510
|
-
import
|
|
2585
|
+
import { mkdir as mkdir6, writeFile as writeFile4 } from "fs/promises";
|
|
2586
|
+
import path10 from "path";
|
|
1511
2587
|
function buildDumpFiles(graph, options = {}) {
|
|
1512
|
-
const basePath = options.flatten ? "" :
|
|
2588
|
+
const basePath = options.flatten ? "" : path10.posix.join("workspaces", graph.workspace.workspaceId);
|
|
1513
2589
|
const values = toNamespaceObject(graph, "value");
|
|
1514
2590
|
const secrets = toNamespaceObject(graph, "secret");
|
|
1515
2591
|
const files = [];
|
|
1516
2592
|
if (Object.keys(values).length > 0) {
|
|
1517
2593
|
files.push({
|
|
1518
|
-
path:
|
|
2594
|
+
path: path10.posix.join(basePath, "values", graph.profile, "app.yml"),
|
|
1519
2595
|
namespace: "value",
|
|
1520
2596
|
content: stringifyYaml(values)
|
|
1521
2597
|
});
|
|
1522
2598
|
}
|
|
1523
2599
|
if (Object.keys(secrets).length > 0) {
|
|
1524
2600
|
files.push({
|
|
1525
|
-
path:
|
|
2601
|
+
path: path10.posix.join(basePath, "secrets", graph.profile, "app.yml"),
|
|
1526
2602
|
namespace: "secret",
|
|
1527
2603
|
content: stringifyYaml(secrets)
|
|
1528
2604
|
});
|
|
@@ -1538,12 +2614,12 @@ function planDump(graph, options = {}) {
|
|
|
1538
2614
|
};
|
|
1539
2615
|
}
|
|
1540
2616
|
async function writeDump(graph, options) {
|
|
1541
|
-
const root =
|
|
2617
|
+
const root = path10.resolve(options.to);
|
|
1542
2618
|
const plan = planDump(graph, options);
|
|
1543
2619
|
for (const file of plan.files) {
|
|
1544
|
-
const destination =
|
|
1545
|
-
await
|
|
1546
|
-
await
|
|
2620
|
+
const destination = path10.join(root, file.path);
|
|
2621
|
+
await mkdir6(path10.dirname(destination), { recursive: true });
|
|
2622
|
+
await writeFile4(destination, file.content, "utf8");
|
|
1547
2623
|
}
|
|
1548
2624
|
return {
|
|
1549
2625
|
...plan,
|
|
@@ -1555,6 +2631,10 @@ async function writeDump(graph, options) {
|
|
|
1555
2631
|
function flattenObject(value, prefix = "") {
|
|
1556
2632
|
return Object.entries(value).reduce((accumulator, [key, nestedValue]) => {
|
|
1557
2633
|
const nextKey = prefix ? `${prefix}.${key}` : key;
|
|
2634
|
+
if (isDerivedValue(nestedValue) || isSecretReference(nestedValue)) {
|
|
2635
|
+
accumulator[nextKey] = nestedValue;
|
|
2636
|
+
return accumulator;
|
|
2637
|
+
}
|
|
1558
2638
|
if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue)) {
|
|
1559
2639
|
Object.assign(accumulator, flattenObject(nestedValue, nextKey));
|
|
1560
2640
|
return accumulator;
|
|
@@ -1574,11 +2654,11 @@ function normalizeMappingConfig(config = {}) {
|
|
|
1574
2654
|
function toScreamingSnakeSegment(segment) {
|
|
1575
2655
|
return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
1576
2656
|
}
|
|
1577
|
-
function toScreamingSnake(
|
|
1578
|
-
return
|
|
2657
|
+
function toScreamingSnake(path14) {
|
|
2658
|
+
return path14.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
|
|
1579
2659
|
}
|
|
1580
|
-
function fromScreamingSnake(
|
|
1581
|
-
return
|
|
2660
|
+
function fromScreamingSnake(path14) {
|
|
2661
|
+
return path14.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
|
|
1582
2662
|
}
|
|
1583
2663
|
function logicalKeyToEnvVar(key, config = {}) {
|
|
1584
2664
|
const normalized = normalizeMappingConfig(config);
|
|
@@ -1730,12 +2810,12 @@ function createProvenanceInspector() {
|
|
|
1730
2810
|
}
|
|
1731
2811
|
|
|
1732
2812
|
// ../core/src/manifest/loadWorkspaceFile.ts
|
|
1733
|
-
import { readFile as
|
|
1734
|
-
import
|
|
2813
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
2814
|
+
import path11 from "path";
|
|
1735
2815
|
async function loadWorkspaceFile(repoRoot) {
|
|
1736
|
-
const workspaceFilePath =
|
|
2816
|
+
const workspaceFilePath = path11.join(repoRoot, ".cnos-workspace.yml");
|
|
1737
2817
|
try {
|
|
1738
|
-
const source = await
|
|
2818
|
+
const source = await readFile6(workspaceFilePath, "utf8");
|
|
1739
2819
|
const parsed = parseYaml(source);
|
|
1740
2820
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1741
2821
|
throw new CnosManifestError(".cnos-workspace.yml must be a YAML object", workspaceFilePath);
|
|
@@ -1758,11 +2838,11 @@ async function loadWorkspaceFile(repoRoot) {
|
|
|
1758
2838
|
}
|
|
1759
2839
|
|
|
1760
2840
|
// ../core/src/profiles/expandProfileChain.ts
|
|
1761
|
-
import { access as
|
|
1762
|
-
import
|
|
2841
|
+
import { access as access4, readFile as readFile7 } from "fs/promises";
|
|
2842
|
+
import path12 from "path";
|
|
1763
2843
|
async function fileExists(targetPath) {
|
|
1764
2844
|
try {
|
|
1765
|
-
await
|
|
2845
|
+
await access4(targetPath);
|
|
1766
2846
|
return true;
|
|
1767
2847
|
} catch {
|
|
1768
2848
|
return false;
|
|
@@ -1796,11 +2876,11 @@ async function loadProfileDefinition(profileName, options) {
|
|
|
1796
2876
|
return normalizeProfileDefinition(profileName, void 0);
|
|
1797
2877
|
}
|
|
1798
2878
|
for (const workspaceRoot of [...workspaceRoots].reverse()) {
|
|
1799
|
-
const profilePath =
|
|
2879
|
+
const profilePath = path12.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
|
|
1800
2880
|
if (!await fileExists(profilePath)) {
|
|
1801
2881
|
continue;
|
|
1802
2882
|
}
|
|
1803
|
-
const document = await
|
|
2883
|
+
const document = await readFile7(profilePath, "utf8");
|
|
1804
2884
|
const parsed = parseYaml(document);
|
|
1805
2885
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1806
2886
|
throw new CnosManifestError("Profile definition must be a YAML object", profilePath);
|
|
@@ -1808,7 +2888,7 @@ async function loadProfileDefinition(profileName, options) {
|
|
|
1808
2888
|
const definition = normalizeProfileDefinition(
|
|
1809
2889
|
profileName,
|
|
1810
2890
|
parsed,
|
|
1811
|
-
options.manifestRoot ? toPortablePath(
|
|
2891
|
+
options.manifestRoot ? toPortablePath(path12.relative(path12.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
|
|
1812
2892
|
);
|
|
1813
2893
|
if (definition.name !== profileName) {
|
|
1814
2894
|
throw new CnosManifestError(
|
|
@@ -2054,8 +3134,8 @@ function createProfileAwareResolver() {
|
|
|
2054
3134
|
}
|
|
2055
3135
|
|
|
2056
3136
|
// ../core/src/workspaces/resolveWorkspaceContext.ts
|
|
2057
|
-
import { access as
|
|
2058
|
-
import
|
|
3137
|
+
import { access as access5 } from "fs/promises";
|
|
3138
|
+
import path13 from "path";
|
|
2059
3139
|
|
|
2060
3140
|
// ../core/src/workspaces/expandWorkspaceChain.ts
|
|
2061
3141
|
function expandWorkspaceChain(workspaceId, items) {
|
|
@@ -2094,14 +3174,14 @@ function expandWorkspaceChain(workspaceId, items) {
|
|
|
2094
3174
|
// ../core/src/workspaces/resolveWorkspaceContext.ts
|
|
2095
3175
|
async function exists4(targetPath) {
|
|
2096
3176
|
try {
|
|
2097
|
-
await
|
|
3177
|
+
await access5(targetPath);
|
|
2098
3178
|
return true;
|
|
2099
3179
|
} catch {
|
|
2100
3180
|
return false;
|
|
2101
3181
|
}
|
|
2102
3182
|
}
|
|
2103
3183
|
async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
|
|
2104
|
-
const workspaceRoot =
|
|
3184
|
+
const workspaceRoot = path13.join(manifestRoot, "workspaces", workspaceId);
|
|
2105
3185
|
if (await exists4(workspaceRoot)) {
|
|
2106
3186
|
return workspaceRoot;
|
|
2107
3187
|
}
|
|
@@ -2109,7 +3189,7 @@ async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
|
|
|
2109
3189
|
([namespace, definition]) => namespace !== "value" && namespace !== "secret" && definition.kind === "data" && !definition.sensitive
|
|
2110
3190
|
).map(([namespace]) => namespace);
|
|
2111
3191
|
const legacyMarkers = ["values", "secrets", "env", "profiles", ...customDataNamespaceRoots].map(
|
|
2112
|
-
(segment) =>
|
|
3192
|
+
(segment) => path13.join(manifestRoot, segment)
|
|
2113
3193
|
);
|
|
2114
3194
|
if ((await Promise.all(legacyMarkers.map((marker) => exists4(marker)))).some(Boolean)) {
|
|
2115
3195
|
return manifestRoot;
|
|
@@ -2157,26 +3237,26 @@ function resolveGlobalRoot(manifest, workspaceFile, options) {
|
|
|
2157
3237
|
}
|
|
2158
3238
|
if (options.globalRoot) {
|
|
2159
3239
|
return {
|
|
2160
|
-
value:
|
|
3240
|
+
value: path13.resolve(expandHomePath2(options.globalRoot)),
|
|
2161
3241
|
source: "cli"
|
|
2162
3242
|
};
|
|
2163
3243
|
}
|
|
2164
3244
|
if (workspaceFile?.globalRoot) {
|
|
2165
3245
|
return {
|
|
2166
|
-
value:
|
|
3246
|
+
value: path13.resolve(expandHomePath2(workspaceFile.globalRoot)),
|
|
2167
3247
|
source: "workspace-file"
|
|
2168
3248
|
};
|
|
2169
3249
|
}
|
|
2170
3250
|
if (manifest.workspaces.global.root) {
|
|
2171
3251
|
return {
|
|
2172
|
-
value:
|
|
3252
|
+
value: path13.resolve(expandHomePath2(manifest.workspaces.global.root)),
|
|
2173
3253
|
source: "manifest"
|
|
2174
3254
|
};
|
|
2175
3255
|
}
|
|
2176
3256
|
const cnosHome = options.processEnv?.CNOS_HOME;
|
|
2177
3257
|
if (cnosHome) {
|
|
2178
3258
|
return {
|
|
2179
|
-
value:
|
|
3259
|
+
value: path13.resolve(expandHomePath2(cnosHome)),
|
|
2180
3260
|
source: "CNOS_HOME"
|
|
2181
3261
|
};
|
|
2182
3262
|
}
|
|
@@ -2198,7 +3278,7 @@ async function resolveWorkspaceContext(manifest, options) {
|
|
|
2198
3278
|
workspaceRoots.push({
|
|
2199
3279
|
scope: "global",
|
|
2200
3280
|
workspaceId: chainWorkspaceId,
|
|
2201
|
-
path:
|
|
3281
|
+
path: path13.join(globalRoot.value, "workspaces", globalWorkspaceId)
|
|
2202
3282
|
});
|
|
2203
3283
|
}
|
|
2204
3284
|
}
|
|
@@ -2321,6 +3401,10 @@ function applySchemaRules(graph, schema) {
|
|
|
2321
3401
|
}
|
|
2322
3402
|
continue;
|
|
2323
3403
|
}
|
|
3404
|
+
if (isDerivedValue(resolvedEntry.value)) {
|
|
3405
|
+
nextEntries.set(key, resolvedEntry);
|
|
3406
|
+
continue;
|
|
3407
|
+
}
|
|
2324
3408
|
const coercedValue = coerceValue(resolvedEntry.value, rule);
|
|
2325
3409
|
const nextResolvedEntry = coercedValue === resolvedEntry.value ? resolvedEntry : {
|
|
2326
3410
|
...resolvedEntry,
|
|
@@ -2467,7 +3551,7 @@ function resolveSecretEntryValue(key, value, cache) {
|
|
|
2467
3551
|
}
|
|
2468
3552
|
|
|
2469
3553
|
// ../core/src/runtime/toServerProjection.ts
|
|
2470
|
-
import { createHash } from "crypto";
|
|
3554
|
+
import { createHash as createHash2 } from "crypto";
|
|
2471
3555
|
function stableSortObject(value) {
|
|
2472
3556
|
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
|
|
2473
3557
|
}
|
|
@@ -2476,12 +3560,14 @@ function stripValuePrefix(key) {
|
|
|
2476
3560
|
}
|
|
2477
3561
|
function configHash(values) {
|
|
2478
3562
|
const serialized = JSON.stringify(stableSortObject(values));
|
|
2479
|
-
return
|
|
3563
|
+
return createHash2("sha256").update(serialized).digest("hex");
|
|
2480
3564
|
}
|
|
2481
|
-
function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
|
|
3565
|
+
function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
|
|
2482
3566
|
const values = {};
|
|
3567
|
+
const derived = {};
|
|
2483
3568
|
const secretRefs = {};
|
|
2484
3569
|
const namespaces = /* @__PURE__ */ new Set();
|
|
3570
|
+
const runtimeNamespaces = /* @__PURE__ */ new Set();
|
|
2485
3571
|
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));
|
|
2486
3572
|
for (const [key, entry] of graph.entries) {
|
|
2487
3573
|
if (entry.namespace === "secret" && isSecretReference(entry.value)) {
|
|
@@ -2493,12 +3579,33 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
|
|
|
2493
3579
|
continue;
|
|
2494
3580
|
}
|
|
2495
3581
|
if (entry.namespace === "value") {
|
|
2496
|
-
|
|
3582
|
+
if (helpers.isRuntimeDependent?.(key)) {
|
|
3583
|
+
const formula = helpers.toServerFormula?.(key);
|
|
3584
|
+
if (formula) {
|
|
3585
|
+
derived[stripValuePrefix(key)] = formula;
|
|
3586
|
+
for (const ref of formula.runtimeRefs) {
|
|
3587
|
+
runtimeNamespaces.add(ref.split(".")[0] ?? "");
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
continue;
|
|
3591
|
+
}
|
|
3592
|
+
const value = helpers.read ? helpers.read(key) : entry.value;
|
|
3593
|
+
values[stripValuePrefix(key)] = value;
|
|
2497
3594
|
continue;
|
|
2498
3595
|
}
|
|
2499
3596
|
const namespaceDefinition = manifest.namespaces[entry.namespace];
|
|
2500
3597
|
if (namespaceDefinition && namespaceDefinition.kind === "data" && !namespaceDefinition.sensitive && entry.namespace !== "public") {
|
|
2501
|
-
|
|
3598
|
+
if (helpers.isRuntimeDependent?.(key)) {
|
|
3599
|
+
const formula = helpers.toServerFormula?.(key);
|
|
3600
|
+
if (formula) {
|
|
3601
|
+
derived[key] = formula;
|
|
3602
|
+
for (const ref of formula.runtimeRefs) {
|
|
3603
|
+
runtimeNamespaces.add(ref.split(".")[0] ?? "");
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
continue;
|
|
3607
|
+
}
|
|
3608
|
+
values[key] = helpers.read ? helpers.read(key) : entry.value;
|
|
2502
3609
|
namespaces.add(entry.namespace);
|
|
2503
3610
|
}
|
|
2504
3611
|
}
|
|
@@ -2509,8 +3616,10 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
|
|
|
2509
3616
|
resolvedAt: graph.resolvedAt,
|
|
2510
3617
|
configHash: configHash(values),
|
|
2511
3618
|
values: stableSortObject(values),
|
|
3619
|
+
derived: stableSortObject(derived),
|
|
2512
3620
|
secretRefs: stableSortObject(secretRefs),
|
|
2513
3621
|
publicKeys,
|
|
3622
|
+
runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
|
|
2514
3623
|
meta: {
|
|
2515
3624
|
workspace: graph.workspace.workspaceId,
|
|
2516
3625
|
profile: graph.profile,
|
|
@@ -2522,6 +3631,19 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
|
|
|
2522
3631
|
|
|
2523
3632
|
// ../core/src/orchestrator/runtime.ts
|
|
2524
3633
|
function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
|
|
3634
|
+
const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
|
|
3635
|
+
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
3636
|
+
function resolveProjectedSourceKey(key) {
|
|
3637
|
+
if (!key.startsWith("public.")) {
|
|
3638
|
+
return key;
|
|
3639
|
+
}
|
|
3640
|
+
const promotedFrom = graph.entries.get(key)?.winner.metadata?.promotedFrom;
|
|
3641
|
+
if (typeof promotedFrom === "string") {
|
|
3642
|
+
return promotedFrom;
|
|
3643
|
+
}
|
|
3644
|
+
const fallback = `value.${key.slice("public.".length)}`;
|
|
3645
|
+
return graph.entries.has(fallback) ? fallback : key;
|
|
3646
|
+
}
|
|
2525
3647
|
async function refreshSecretEntry(key) {
|
|
2526
3648
|
const entry = graph.entries.get(key);
|
|
2527
3649
|
if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
|
|
@@ -2553,6 +3675,19 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
2553
3675
|
}
|
|
2554
3676
|
}
|
|
2555
3677
|
function readLogicalKey(key) {
|
|
3678
|
+
const resolved = derivedSupport.read(key, (ref) => {
|
|
3679
|
+
const entry2 = graph.entries.get(ref);
|
|
3680
|
+
if (!entry2) {
|
|
3681
|
+
return void 0;
|
|
3682
|
+
}
|
|
3683
|
+
if (!secretCache) {
|
|
3684
|
+
return entry2.value;
|
|
3685
|
+
}
|
|
3686
|
+
return resolveSecretEntryValue(ref, entry2.value, secretCache);
|
|
3687
|
+
});
|
|
3688
|
+
if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
|
|
3689
|
+
return resolved;
|
|
3690
|
+
}
|
|
2556
3691
|
const entry = graph.entries.get(key);
|
|
2557
3692
|
if (!entry) {
|
|
2558
3693
|
return void 0;
|
|
@@ -2577,34 +3712,64 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
2577
3712
|
return value;
|
|
2578
3713
|
},
|
|
2579
3714
|
readOr(key, fallback) {
|
|
2580
|
-
|
|
3715
|
+
const value = readLogicalKey(key);
|
|
3716
|
+
return value === void 0 ? fallback : value;
|
|
2581
3717
|
},
|
|
2582
|
-
value(
|
|
2583
|
-
return readLogicalKey(toLogicalKey("value",
|
|
3718
|
+
value(path14) {
|
|
3719
|
+
return readLogicalKey(toLogicalKey("value", path14));
|
|
2584
3720
|
},
|
|
2585
|
-
secret(
|
|
2586
|
-
return readLogicalKey(toLogicalKey("secret",
|
|
3721
|
+
secret(path14) {
|
|
3722
|
+
return readLogicalKey(toLogicalKey("secret", path14));
|
|
2587
3723
|
},
|
|
2588
|
-
meta(
|
|
2589
|
-
return readLogicalKey(toLogicalKey("meta",
|
|
3724
|
+
meta(path14) {
|
|
3725
|
+
return readLogicalKey(toLogicalKey("meta", path14));
|
|
2590
3726
|
},
|
|
2591
3727
|
inspect(key) {
|
|
2592
|
-
return inspectValue(graph, key
|
|
3728
|
+
return inspectValue(graph, key, {
|
|
3729
|
+
read: (ref) => readLogicalKey(ref),
|
|
3730
|
+
describeDerived: (ref) => derivedSupport.describe(ref, (candidate) => {
|
|
3731
|
+
const entry = graph.entries.get(candidate);
|
|
3732
|
+
if (!entry) {
|
|
3733
|
+
return void 0;
|
|
3734
|
+
}
|
|
3735
|
+
if (!secretCache) {
|
|
3736
|
+
return entry.value;
|
|
3737
|
+
}
|
|
3738
|
+
return resolveSecretEntryValue(candidate, entry.value, secretCache);
|
|
3739
|
+
})
|
|
3740
|
+
});
|
|
2593
3741
|
},
|
|
2594
3742
|
toObject() {
|
|
2595
|
-
return toNamespaceObject(graph);
|
|
3743
|
+
return toNamespaceObject(graph, void 0, (key) => readLogicalKey(key));
|
|
2596
3744
|
},
|
|
2597
3745
|
toNamespace(namespace) {
|
|
2598
|
-
return toNamespaceObject(graph, namespace);
|
|
3746
|
+
return toNamespaceObject(graph, namespace, (key) => readLogicalKey(key));
|
|
2599
3747
|
},
|
|
2600
3748
|
toEnv(options) {
|
|
2601
|
-
return toEnv(graph, manifest, options
|
|
3749
|
+
return toEnv(graph, manifest, options, {
|
|
3750
|
+
read: (key) => readLogicalKey(key),
|
|
3751
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
|
|
3752
|
+
});
|
|
2602
3753
|
},
|
|
2603
3754
|
toPublicEnv(options) {
|
|
2604
|
-
return toPublicEnv(graph, manifest, options
|
|
3755
|
+
return toPublicEnv(graph, manifest, options, {
|
|
3756
|
+
read: (key) => derivedSupport.toConcreteValue(
|
|
3757
|
+
resolveProjectedSourceKey(key),
|
|
3758
|
+
(candidate) => readLogicalKey(candidate),
|
|
3759
|
+
"public"
|
|
3760
|
+
),
|
|
3761
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(resolveProjectedSourceKey(key))
|
|
3762
|
+
});
|
|
2605
3763
|
},
|
|
2606
3764
|
toServerProjection() {
|
|
2607
|
-
return toServerProjection(graph, manifest, cnosVersion
|
|
3765
|
+
return toServerProjection(graph, manifest, cnosVersion, {
|
|
3766
|
+
read: (key) => derivedSupport.toConcreteValue(key, (candidate) => readLogicalKey(candidate), "server"),
|
|
3767
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key),
|
|
3768
|
+
toServerFormula: (key) => derivedSupport.toServerFormula(key)
|
|
3769
|
+
});
|
|
3770
|
+
},
|
|
3771
|
+
registerRuntimeProvider(namespace, provider) {
|
|
3772
|
+
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
2608
3773
|
},
|
|
2609
3774
|
async refreshSecrets() {
|
|
2610
3775
|
await refreshAllSecrets();
|
|
@@ -2711,7 +3876,11 @@ function appendMetaEntries(graph, cnosVersion) {
|
|
|
2711
3876
|
async function createCnos(options = {}) {
|
|
2712
3877
|
const loadedManifest = await loadManifest({
|
|
2713
3878
|
...options.root ? { root: options.root } : {},
|
|
2714
|
-
...options.cwd ? { cwd: options.cwd } : {}
|
|
3879
|
+
...options.cwd ? { cwd: options.cwd } : {},
|
|
3880
|
+
...options.processEnv ? { processEnv: options.processEnv } : {},
|
|
3881
|
+
...options.cacheMode ? { cacheMode: options.cacheMode } : {},
|
|
3882
|
+
...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
|
|
3883
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
2715
3884
|
});
|
|
2716
3885
|
for (const key of loadedManifest.manifest.public.promote) {
|
|
2717
3886
|
ensureProjectionAllowed(loadedManifest.manifest, key, "public");
|
|
@@ -2775,12 +3944,27 @@ export {
|
|
|
2775
3944
|
CnosManifestError,
|
|
2776
3945
|
CnosSecurityError,
|
|
2777
3946
|
CnosAuthenticationError,
|
|
3947
|
+
isDerivedValue,
|
|
3948
|
+
parseDerivation,
|
|
3949
|
+
validateDerivedTargetNamespace,
|
|
3950
|
+
validateParsedDerivation,
|
|
3951
|
+
normalizeDerivedValue,
|
|
3952
|
+
createDerivedRuntimeSupport,
|
|
3953
|
+
registerRuntimeProvider,
|
|
2778
3954
|
inspectValue,
|
|
2779
3955
|
createProvenanceInspector,
|
|
2780
3956
|
readKeychain,
|
|
2781
3957
|
writeKeychain,
|
|
2782
3958
|
parseYaml,
|
|
2783
3959
|
stringifyYaml,
|
|
3960
|
+
parseGitUri,
|
|
3961
|
+
isImmutableGitRef,
|
|
3962
|
+
readRemoteRootCacheMetadata,
|
|
3963
|
+
writeRemoteRootCacheMetadata,
|
|
3964
|
+
resolveCnosCacheRoot,
|
|
3965
|
+
createRemoteRootCacheKey,
|
|
3966
|
+
resolveRemoteRootCachePaths,
|
|
3967
|
+
resolveRootUri,
|
|
2784
3968
|
resolveManifestRoot,
|
|
2785
3969
|
resolveWorkspaceScopedPath,
|
|
2786
3970
|
resolveConfigDocumentPath,
|
|
@@ -2818,8 +4002,8 @@ export {
|
|
|
2818
4002
|
resolveVaultAuth,
|
|
2819
4003
|
toNamespaceObject,
|
|
2820
4004
|
readValue,
|
|
2821
|
-
readOrValue,
|
|
2822
4005
|
requireValue,
|
|
4006
|
+
createDefaultRuntimeProviders,
|
|
2823
4007
|
toEnv,
|
|
2824
4008
|
toPublicEnv,
|
|
2825
4009
|
createCnos,
|