@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
package/dist/index.cjs
CHANGED
|
@@ -37,7 +37,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
37
37
|
|
|
38
38
|
// src/runtime/index.ts
|
|
39
39
|
var import_node_fs = require("fs");
|
|
40
|
-
var
|
|
40
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
41
41
|
|
|
42
42
|
// ../core/src/errors.ts
|
|
43
43
|
var CnosError = class extends Error {
|
|
@@ -75,16 +75,673 @@ var CnosKeyNotFoundError = class extends CnosError {
|
|
|
75
75
|
}
|
|
76
76
|
key;
|
|
77
77
|
};
|
|
78
|
+
var CnosDerivedExpressionError = class extends CnosError {
|
|
79
|
+
constructor(message, expression) {
|
|
80
|
+
super(expression ? `${message} (${expression})` : message);
|
|
81
|
+
this.expression = expression;
|
|
82
|
+
}
|
|
83
|
+
expression;
|
|
84
|
+
};
|
|
85
|
+
var CnosDerivedCycleError = class extends CnosError {
|
|
86
|
+
constructor(message) {
|
|
87
|
+
super(message);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var CnosDerivedResolutionError = class extends CnosError {
|
|
91
|
+
constructor(key, message) {
|
|
92
|
+
super(message);
|
|
93
|
+
this.key = key;
|
|
94
|
+
}
|
|
95
|
+
key;
|
|
96
|
+
};
|
|
97
|
+
var CnosRuntimeProviderError = class extends CnosError {
|
|
98
|
+
constructor(message) {
|
|
99
|
+
super(message);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// ../core/src/derive/builtins.ts
|
|
104
|
+
function stringify(value) {
|
|
105
|
+
if (value === void 0 || value === null) {
|
|
106
|
+
return "";
|
|
107
|
+
}
|
|
108
|
+
if (typeof value === "string") {
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
112
|
+
return String(value);
|
|
113
|
+
}
|
|
114
|
+
return JSON.stringify(value);
|
|
115
|
+
}
|
|
116
|
+
var DERIVE_BUILTINS = {
|
|
117
|
+
concat: (...args) => args.map((value) => stringify(value)).join(""),
|
|
118
|
+
coalesce: (...args) => args.find((value) => value !== void 0 && value !== null),
|
|
119
|
+
when: (condition, whenTrue, whenFalse) => condition ? whenTrue : whenFalse,
|
|
120
|
+
exists: (value) => value !== void 0 && value !== null,
|
|
121
|
+
eq: (left, right) => left === right,
|
|
122
|
+
ne: (left, right) => left !== right
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// ../core/src/derive/depGraph.ts
|
|
126
|
+
function detectDerivationCycles(dependencyMap) {
|
|
127
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
128
|
+
const visited = /* @__PURE__ */ new Set();
|
|
129
|
+
const stack = [];
|
|
130
|
+
const visit = (key) => {
|
|
131
|
+
if (visited.has(key)) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (visiting.has(key)) {
|
|
135
|
+
const start = stack.indexOf(key);
|
|
136
|
+
const cycle = [...stack.slice(start), key].join(" -> ");
|
|
137
|
+
throw new CnosDerivedCycleError(`Derivation cycle detected: ${cycle}`);
|
|
138
|
+
}
|
|
139
|
+
visiting.add(key);
|
|
140
|
+
stack.push(key);
|
|
141
|
+
for (const dependency of dependencyMap.get(key) ?? []) {
|
|
142
|
+
visit(dependency);
|
|
143
|
+
}
|
|
144
|
+
stack.pop();
|
|
145
|
+
visiting.delete(key);
|
|
146
|
+
visited.add(key);
|
|
147
|
+
};
|
|
148
|
+
for (const key of dependencyMap.keys()) {
|
|
149
|
+
visit(key);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ../core/src/derive/parser.ts
|
|
154
|
+
function isWhitespace(value) {
|
|
155
|
+
return value === " " || value === "\n" || value === "\r" || value === " ";
|
|
156
|
+
}
|
|
157
|
+
function skipWhitespace(state) {
|
|
158
|
+
while (isWhitespace(state.source[state.index])) {
|
|
159
|
+
state.index += 1;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function isIdentifierStart(value) {
|
|
163
|
+
return typeof value === "string" && /[A-Za-z_]/.test(value);
|
|
164
|
+
}
|
|
165
|
+
function isIdentifierPart(value) {
|
|
166
|
+
return typeof value === "string" && /[A-Za-z0-9_.-]/.test(value);
|
|
167
|
+
}
|
|
168
|
+
function errorAt(state, message) {
|
|
169
|
+
throw new CnosDerivedExpressionError(`${message} at position ${state.index + 1}`, state.source);
|
|
170
|
+
}
|
|
171
|
+
function parseStringLiteral(state) {
|
|
172
|
+
const quote = state.source[state.index];
|
|
173
|
+
if (quote !== "'") {
|
|
174
|
+
errorAt(state, "Expected string literal");
|
|
175
|
+
}
|
|
176
|
+
state.index += 1;
|
|
177
|
+
let value = "";
|
|
178
|
+
while (state.index < state.source.length) {
|
|
179
|
+
const current = state.source[state.index];
|
|
180
|
+
if (current === "\\") {
|
|
181
|
+
const next = state.source[state.index + 1];
|
|
182
|
+
if (next === void 0) {
|
|
183
|
+
errorAt(state, "Unterminated escape sequence");
|
|
184
|
+
}
|
|
185
|
+
value += next;
|
|
186
|
+
state.index += 2;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (current === "'") {
|
|
190
|
+
state.index += 1;
|
|
191
|
+
return {
|
|
192
|
+
type: "literal",
|
|
193
|
+
value
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
value += current;
|
|
197
|
+
state.index += 1;
|
|
198
|
+
}
|
|
199
|
+
errorAt(state, "Unterminated string literal");
|
|
200
|
+
}
|
|
201
|
+
function parseNumberLiteral(state) {
|
|
202
|
+
const start = state.index;
|
|
203
|
+
while (/[0-9]/.test(state.source[state.index] ?? "")) {
|
|
204
|
+
state.index += 1;
|
|
205
|
+
}
|
|
206
|
+
if (state.source[state.index] === ".") {
|
|
207
|
+
state.index += 1;
|
|
208
|
+
while (/[0-9]/.test(state.source[state.index] ?? "")) {
|
|
209
|
+
state.index += 1;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
type: "literal",
|
|
214
|
+
value: Number(state.source.slice(start, state.index))
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function parseIdentifier(state) {
|
|
218
|
+
if (!isIdentifierStart(state.source[state.index])) {
|
|
219
|
+
errorAt(state, "Expected identifier");
|
|
220
|
+
}
|
|
221
|
+
const start = state.index;
|
|
222
|
+
state.index += 1;
|
|
223
|
+
while (isIdentifierPart(state.source[state.index])) {
|
|
224
|
+
state.index += 1;
|
|
225
|
+
}
|
|
226
|
+
return state.source.slice(start, state.index);
|
|
227
|
+
}
|
|
228
|
+
function parseArguments(state) {
|
|
229
|
+
const args = [];
|
|
230
|
+
skipWhitespace(state);
|
|
231
|
+
if (state.source[state.index] === ")") {
|
|
232
|
+
state.index += 1;
|
|
233
|
+
return args;
|
|
234
|
+
}
|
|
235
|
+
while (state.index < state.source.length) {
|
|
236
|
+
args.push(parseExpressionNode(state));
|
|
237
|
+
skipWhitespace(state);
|
|
238
|
+
const current = state.source[state.index];
|
|
239
|
+
if (current === ",") {
|
|
240
|
+
state.index += 1;
|
|
241
|
+
skipWhitespace(state);
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (current === ")") {
|
|
245
|
+
state.index += 1;
|
|
246
|
+
return args;
|
|
247
|
+
}
|
|
248
|
+
errorAt(state, 'Expected "," or ")"');
|
|
249
|
+
}
|
|
250
|
+
errorAt(state, "Unterminated function call");
|
|
251
|
+
}
|
|
252
|
+
function parseIdentifierOrCall(state) {
|
|
253
|
+
const identifier = parseIdentifier(state);
|
|
254
|
+
skipWhitespace(state);
|
|
255
|
+
if (state.source[state.index] === "(") {
|
|
256
|
+
if (!(identifier in DERIVE_BUILTINS)) {
|
|
257
|
+
throw new CnosDerivedExpressionError(`Unknown derive function: ${identifier}`, state.source);
|
|
258
|
+
}
|
|
259
|
+
state.index += 1;
|
|
260
|
+
return {
|
|
261
|
+
type: "call",
|
|
262
|
+
name: identifier,
|
|
263
|
+
args: parseArguments(state)
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
if (identifier === "true" || identifier === "false") {
|
|
267
|
+
return {
|
|
268
|
+
type: "literal",
|
|
269
|
+
value: identifier === "true"
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
if (identifier === "null") {
|
|
273
|
+
return {
|
|
274
|
+
type: "literal",
|
|
275
|
+
value: null
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
type: "ref",
|
|
280
|
+
path: identifier
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function parseExpressionNode(state) {
|
|
284
|
+
skipWhitespace(state);
|
|
285
|
+
const current = state.source[state.index];
|
|
286
|
+
if (current === "'") {
|
|
287
|
+
return parseStringLiteral(state);
|
|
288
|
+
}
|
|
289
|
+
if (/[0-9]/.test(current ?? "")) {
|
|
290
|
+
return parseNumberLiteral(state);
|
|
291
|
+
}
|
|
292
|
+
if (isIdentifierStart(current)) {
|
|
293
|
+
return parseIdentifierOrCall(state);
|
|
294
|
+
}
|
|
295
|
+
errorAt(state, "Unexpected token");
|
|
296
|
+
}
|
|
297
|
+
function parseExpression(source) {
|
|
298
|
+
const state = {
|
|
299
|
+
source,
|
|
300
|
+
index: 0
|
|
301
|
+
};
|
|
302
|
+
const ast = parseExpressionNode(state);
|
|
303
|
+
skipWhitespace(state);
|
|
304
|
+
if (state.index !== source.length) {
|
|
305
|
+
errorAt(state, "Unexpected trailing input");
|
|
306
|
+
}
|
|
307
|
+
return ast;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ../core/src/derive/templateParser.ts
|
|
311
|
+
function toLiteral(value) {
|
|
312
|
+
return {
|
|
313
|
+
type: "literal",
|
|
314
|
+
value
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function toRef(path17) {
|
|
318
|
+
return {
|
|
319
|
+
type: "ref",
|
|
320
|
+
path: path17
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function parseTemplate(source) {
|
|
324
|
+
const parts = [];
|
|
325
|
+
let cursor = 0;
|
|
326
|
+
while (cursor < source.length) {
|
|
327
|
+
const start = source.indexOf("${", cursor);
|
|
328
|
+
if (start < 0) {
|
|
329
|
+
if (cursor < source.length) {
|
|
330
|
+
parts.push(toLiteral(source.slice(cursor)));
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
if (start > cursor) {
|
|
335
|
+
parts.push(toLiteral(source.slice(cursor, start)));
|
|
336
|
+
}
|
|
337
|
+
const end = source.indexOf("}", start + 2);
|
|
338
|
+
if (end < 0) {
|
|
339
|
+
throw new CnosDerivedExpressionError(`Invalid derivation template: unclosed \${...} at position ${start + 1}`, source);
|
|
340
|
+
}
|
|
341
|
+
const ref = source.slice(start + 2, end).trim();
|
|
342
|
+
if (!ref) {
|
|
343
|
+
throw new CnosDerivedExpressionError(`Invalid derivation template: empty reference at position ${start + 1}`, source);
|
|
344
|
+
}
|
|
345
|
+
if (!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(ref)) {
|
|
346
|
+
throw new CnosDerivedExpressionError(`Invalid derivation template reference "${ref}"`, source);
|
|
347
|
+
}
|
|
348
|
+
parts.push(toRef(ref));
|
|
349
|
+
cursor = end + 1;
|
|
350
|
+
}
|
|
351
|
+
if (parts.length === 0) {
|
|
352
|
+
return toLiteral("");
|
|
353
|
+
}
|
|
354
|
+
if (parts.length === 1) {
|
|
355
|
+
return parts[0];
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
type: "call",
|
|
359
|
+
name: "concat",
|
|
360
|
+
args: parts
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ../core/src/derive/evaluator.ts
|
|
365
|
+
function isDerivedValue(value) {
|
|
366
|
+
return Boolean(
|
|
367
|
+
value && typeof value === "object" && !Array.isArray(value) && "$derive" in value
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
function extractRefs(node, refs = /* @__PURE__ */ new Set()) {
|
|
371
|
+
if (node.type === "ref") {
|
|
372
|
+
refs.add(node.path);
|
|
373
|
+
return refs;
|
|
374
|
+
}
|
|
375
|
+
if (node.type === "call") {
|
|
376
|
+
for (const arg of node.args) {
|
|
377
|
+
extractRefs(arg, refs);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return refs;
|
|
381
|
+
}
|
|
382
|
+
function parseDerivation(value) {
|
|
383
|
+
const source = typeof value.$derive === "string" ? value.$derive : value.$derive?.expr;
|
|
384
|
+
if (typeof source !== "string") {
|
|
385
|
+
throw new CnosDerivedExpressionError("Derived value requires either a template string or { expr } object");
|
|
386
|
+
}
|
|
387
|
+
const type = typeof value.$derive === "string" ? "template" : "expression";
|
|
388
|
+
const ast = type === "template" ? parseTemplate(source) : parseExpression(source);
|
|
389
|
+
const refs = Array.from(extractRefs(ast)).sort((left, right) => left.localeCompare(right));
|
|
390
|
+
return {
|
|
391
|
+
type,
|
|
392
|
+
raw: source,
|
|
393
|
+
ast,
|
|
394
|
+
refs,
|
|
395
|
+
runtimeRefs: [],
|
|
396
|
+
isRuntimeDependent: false
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function normalizeConcatValue(value) {
|
|
400
|
+
if (value === void 0 || value === null) {
|
|
401
|
+
return "";
|
|
402
|
+
}
|
|
403
|
+
if (typeof value === "string") {
|
|
404
|
+
return value;
|
|
405
|
+
}
|
|
406
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
407
|
+
return String(value);
|
|
408
|
+
}
|
|
409
|
+
return JSON.stringify(value);
|
|
410
|
+
}
|
|
411
|
+
function evaluateNode(node, resolveRef) {
|
|
412
|
+
switch (node.type) {
|
|
413
|
+
case "literal":
|
|
414
|
+
return node.value;
|
|
415
|
+
case "ref":
|
|
416
|
+
return resolveRef(node.path);
|
|
417
|
+
case "call": {
|
|
418
|
+
const args = node.args.map((arg) => evaluateNode(arg, resolveRef));
|
|
419
|
+
switch (node.name) {
|
|
420
|
+
case "concat":
|
|
421
|
+
return args.map((value) => normalizeConcatValue(value)).join("");
|
|
422
|
+
case "coalesce":
|
|
423
|
+
return DERIVE_BUILTINS.coalesce(...args);
|
|
424
|
+
case "when":
|
|
425
|
+
return DERIVE_BUILTINS.when(args[0], args[1], args[2]);
|
|
426
|
+
case "exists":
|
|
427
|
+
return DERIVE_BUILTINS.exists(args[0]);
|
|
428
|
+
case "eq":
|
|
429
|
+
return DERIVE_BUILTINS.eq(args[0], args[1]);
|
|
430
|
+
case "ne":
|
|
431
|
+
return DERIVE_BUILTINS.ne(args[0], args[1]);
|
|
432
|
+
default:
|
|
433
|
+
throw new CnosDerivedExpressionError(`Unknown derive function: ${String(node.name)}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
default:
|
|
437
|
+
throw new CnosDerivedExpressionError(`Unsupported derive AST node ${node.type ?? "unknown"}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function evaluateDerivation(options) {
|
|
441
|
+
const missingRefs = /* @__PURE__ */ new Set();
|
|
442
|
+
const value = evaluateNode(options.parsed.ast, (ref) => {
|
|
443
|
+
const resolved = options.resolveRef(ref);
|
|
444
|
+
if (resolved === void 0) {
|
|
445
|
+
missingRefs.add(ref);
|
|
446
|
+
options.onMissing?.(ref);
|
|
447
|
+
}
|
|
448
|
+
return resolved;
|
|
449
|
+
});
|
|
450
|
+
if (missingRefs.size > 0 && options.parsed.ast.type === "ref") {
|
|
451
|
+
throw new CnosDerivedResolutionError(
|
|
452
|
+
options.key,
|
|
453
|
+
`Unable to resolve derived config key ${options.key} because ${Array.from(missingRefs).join(", ")} is missing.`
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
return value;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ../core/src/derive/validate.ts
|
|
460
|
+
var FORBIDDEN_TARGET_NAMESPACES = /* @__PURE__ */ new Set(["public", "meta", "secret"]);
|
|
461
|
+
var FORBIDDEN_REF_NAMESPACES = /* @__PURE__ */ new Set(["public", "secret"]);
|
|
462
|
+
function validateDerivedTargetNamespace(manifest, namespace) {
|
|
463
|
+
if (FORBIDDEN_TARGET_NAMESPACES.has(namespace)) {
|
|
464
|
+
throw new CnosManifestError(`Cannot define derived values under namespace "${namespace}".`);
|
|
465
|
+
}
|
|
466
|
+
if (manifest.runtimeNamespaces[namespace]) {
|
|
467
|
+
throw new CnosManifestError(`Cannot define derived values under runtime namespace "${namespace}".`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
function validateParsedDerivation(manifest, parsed) {
|
|
471
|
+
for (const ref of parsed.refs) {
|
|
472
|
+
const namespace = ref.split(".")[0] ?? "";
|
|
473
|
+
if (FORBIDDEN_REF_NAMESPACES.has(namespace)) {
|
|
474
|
+
throw new CnosDerivedExpressionError(`Derived expressions cannot reference ${namespace}.* keys.`, parsed.raw);
|
|
475
|
+
}
|
|
476
|
+
if (manifest.runtimeNamespaces[namespace]) {
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
if (!manifest.namespaces[namespace] && namespace !== "value" && namespace !== "meta") {
|
|
480
|
+
throw new CnosDerivedExpressionError(`Unknown derive reference namespace: ${namespace}`, parsed.raw);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// ../core/src/derive/runtime.ts
|
|
486
|
+
function namespaceForKey(key) {
|
|
487
|
+
return key.split(".")[0] ?? "";
|
|
488
|
+
}
|
|
489
|
+
function dependencyNamespaces(key, entries, memo) {
|
|
490
|
+
if (memo.has(key)) {
|
|
491
|
+
return memo.get(key);
|
|
492
|
+
}
|
|
493
|
+
const entry = entries.get(key);
|
|
494
|
+
if (!entry) {
|
|
495
|
+
memo.set(key, []);
|
|
496
|
+
return [];
|
|
497
|
+
}
|
|
498
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
499
|
+
for (const ref of entry.parsed.refs) {
|
|
500
|
+
const namespace = namespaceForKey(ref);
|
|
501
|
+
if (!entries.has(ref)) {
|
|
502
|
+
namespaces.add(namespace);
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
for (const dependencyNamespace of dependencyNamespaces(ref, entries, memo)) {
|
|
506
|
+
namespaces.add(dependencyNamespace);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
const result = Array.from(namespaces).sort((left, right) => left.localeCompare(right));
|
|
510
|
+
memo.set(key, result);
|
|
511
|
+
return result;
|
|
512
|
+
}
|
|
513
|
+
function isRuntimeDependentKey(key, entries, manifest, memo) {
|
|
514
|
+
if (memo.has(key)) {
|
|
515
|
+
return memo.get(key);
|
|
516
|
+
}
|
|
517
|
+
const entry = entries.get(key);
|
|
518
|
+
if (!entry) {
|
|
519
|
+
memo.set(key, false);
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
for (const ref of entry.parsed.refs) {
|
|
523
|
+
const namespace = namespaceForKey(ref);
|
|
524
|
+
if (manifest.runtimeNamespaces[namespace]) {
|
|
525
|
+
memo.set(key, true);
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
if (entries.has(ref) && isRuntimeDependentKey(ref, entries, manifest, memo)) {
|
|
529
|
+
memo.set(key, true);
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
memo.set(key, false);
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
function prepareEntries(graph, manifest) {
|
|
537
|
+
const entries = /* @__PURE__ */ new Map();
|
|
538
|
+
for (const [key, entry] of graph.entries) {
|
|
539
|
+
if (!isDerivedValue(entry.value)) {
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
const namespaceDefinition = manifest.namespaces[entry.namespace];
|
|
543
|
+
if (!namespaceDefinition || namespaceDefinition.kind === "data") {
|
|
544
|
+
validateDerivedTargetNamespace(manifest, entry.namespace);
|
|
545
|
+
}
|
|
546
|
+
const parsed = parseDerivation(entry.value);
|
|
547
|
+
validateParsedDerivation(manifest, parsed);
|
|
548
|
+
entries.set(key, {
|
|
549
|
+
key,
|
|
550
|
+
namespace: entry.namespace,
|
|
551
|
+
value: entry.value,
|
|
552
|
+
parsed
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
detectDerivationCycles(
|
|
556
|
+
new Map(
|
|
557
|
+
Array.from(entries.values()).map((entry) => [
|
|
558
|
+
entry.key,
|
|
559
|
+
entry.parsed.refs.filter((ref) => entries.has(ref))
|
|
560
|
+
])
|
|
561
|
+
)
|
|
562
|
+
);
|
|
563
|
+
const runtimeMemo = /* @__PURE__ */ new Map();
|
|
564
|
+
const namespaceMemo = /* @__PURE__ */ new Map();
|
|
565
|
+
for (const entry of entries.values()) {
|
|
566
|
+
entry.parsed.isRuntimeDependent = isRuntimeDependentKey(entry.key, entries, manifest, runtimeMemo);
|
|
567
|
+
entry.parsed.runtimeRefs = entry.parsed.refs.filter((ref) => manifest.runtimeNamespaces[namespaceForKey(ref)]);
|
|
568
|
+
if (entry.parsed.runtimeRefs.length === 0 && entry.parsed.isRuntimeDependent) {
|
|
569
|
+
entry.parsed.runtimeRefs = dependencyNamespaces(entry.key, entries, namespaceMemo).filter((namespace) => manifest.runtimeNamespaces[namespace]).map((namespace) => `${namespace}.*`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return entries;
|
|
573
|
+
}
|
|
574
|
+
function createDerivedRuntimeSupport(graph, manifest, runtimeProviders) {
|
|
575
|
+
const entries = prepareEntries(graph, manifest);
|
|
576
|
+
const configCache = /* @__PURE__ */ new Map();
|
|
577
|
+
const runtimeDependencyMemo = /* @__PURE__ */ new Map();
|
|
578
|
+
const support = {};
|
|
579
|
+
Object.assign(support, {
|
|
580
|
+
runtimeProviders,
|
|
581
|
+
read(key, readBase) {
|
|
582
|
+
const namespace = namespaceForKey(key);
|
|
583
|
+
if (runtimeProviders.has(namespace)) {
|
|
584
|
+
const provider = runtimeProviders.get(namespace);
|
|
585
|
+
return provider(key.slice(namespace.length + 1));
|
|
586
|
+
}
|
|
587
|
+
if (entries.has(key)) {
|
|
588
|
+
return readDerived(key, readBase);
|
|
589
|
+
}
|
|
590
|
+
return readBase(key);
|
|
591
|
+
},
|
|
592
|
+
describe(key, readBase) {
|
|
593
|
+
const entry = entries.get(key);
|
|
594
|
+
if (!entry) {
|
|
595
|
+
return void 0;
|
|
596
|
+
}
|
|
597
|
+
const runtimeNamespaces = Array.from(
|
|
598
|
+
new Set(
|
|
599
|
+
entry.parsed.refs.map((ref) => namespaceForKey(ref)).filter((namespace) => manifest.runtimeNamespaces[namespace])
|
|
600
|
+
)
|
|
601
|
+
).sort((left, right) => left.localeCompare(right));
|
|
602
|
+
return {
|
|
603
|
+
key,
|
|
604
|
+
type: entry.parsed.type,
|
|
605
|
+
expression: entry.parsed.raw,
|
|
606
|
+
dependencies: entry.parsed.refs.map((ref) => {
|
|
607
|
+
const namespace = namespaceForKey(ref);
|
|
608
|
+
return {
|
|
609
|
+
key: ref,
|
|
610
|
+
value: support.read(ref, readBase),
|
|
611
|
+
...manifest.runtimeNamespaces[namespace] ? {
|
|
612
|
+
runtimeNamespace: namespace
|
|
613
|
+
} : {}
|
|
614
|
+
};
|
|
615
|
+
}),
|
|
616
|
+
runtimeDependent: entry.parsed.isRuntimeDependent,
|
|
617
|
+
runtimeNamespaces,
|
|
618
|
+
...entry.parsed.isRuntimeDependent ? {
|
|
619
|
+
promotionWarning: "Cannot be promoted to browser/public."
|
|
620
|
+
} : {}
|
|
621
|
+
};
|
|
622
|
+
},
|
|
623
|
+
isDerivedKey(key) {
|
|
624
|
+
return entries.has(key);
|
|
625
|
+
},
|
|
626
|
+
isRuntimeDependentKey(key) {
|
|
627
|
+
if (runtimeDependencyMemo.has(key)) {
|
|
628
|
+
return runtimeDependencyMemo.get(key);
|
|
629
|
+
}
|
|
630
|
+
const value = entries.get(key)?.parsed.isRuntimeDependent ?? false;
|
|
631
|
+
runtimeDependencyMemo.set(key, value);
|
|
632
|
+
return value;
|
|
633
|
+
},
|
|
634
|
+
toConcreteValue(key, readBase, mode) {
|
|
635
|
+
const entry = entries.get(key);
|
|
636
|
+
if (!entry) {
|
|
637
|
+
return support.read(key, readBase);
|
|
638
|
+
}
|
|
639
|
+
if (!entry.parsed.isRuntimeDependent) {
|
|
640
|
+
return support.read(key, readBase);
|
|
641
|
+
}
|
|
642
|
+
if (mode === "server" || mode === "runtime") {
|
|
643
|
+
return support.read(key, readBase);
|
|
644
|
+
}
|
|
645
|
+
for (const ref of entry.parsed.refs) {
|
|
646
|
+
const namespace = namespaceForKey(ref);
|
|
647
|
+
const runtimeNamespace = manifest.runtimeNamespaces[namespace];
|
|
648
|
+
if (!runtimeNamespace) {
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
if (runtimeNamespace.serverOnly) {
|
|
652
|
+
throw new CnosDerivedResolutionError(
|
|
653
|
+
key,
|
|
654
|
+
`Cannot resolve ${key} for ${mode} output because it depends on runtime namespace ${namespace}.`
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
if (!runtimeProviders.has(namespace)) {
|
|
658
|
+
if (mode === "env") {
|
|
659
|
+
return void 0;
|
|
660
|
+
}
|
|
661
|
+
throw new CnosDerivedResolutionError(
|
|
662
|
+
key,
|
|
663
|
+
`Cannot resolve ${key} for ${mode} output because runtime namespace ${namespace} has no registered provider.`
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return support.read(key, readBase);
|
|
668
|
+
},
|
|
669
|
+
toServerFormula(key) {
|
|
670
|
+
const entry = entries.get(key);
|
|
671
|
+
if (!entry || !entry.parsed.isRuntimeDependent) {
|
|
672
|
+
return void 0;
|
|
673
|
+
}
|
|
674
|
+
return {
|
|
675
|
+
expr: entry.parsed.raw,
|
|
676
|
+
deps: entry.parsed.refs.filter((ref) => !manifest.runtimeNamespaces[namespaceForKey(ref)]),
|
|
677
|
+
runtimeRefs: entry.parsed.refs.filter((ref) => manifest.runtimeNamespaces[namespaceForKey(ref)])
|
|
678
|
+
};
|
|
679
|
+
},
|
|
680
|
+
derivedKeys: Array.from(entries.keys()).sort((left, right) => left.localeCompare(right))
|
|
681
|
+
});
|
|
682
|
+
const readDerived = (key, readBase, evaluationStack = /* @__PURE__ */ new Set()) => {
|
|
683
|
+
const entry = entries.get(key);
|
|
684
|
+
if (!entry) {
|
|
685
|
+
return readBase(key);
|
|
686
|
+
}
|
|
687
|
+
if (!entry.parsed.isRuntimeDependent && configCache.has(key)) {
|
|
688
|
+
return configCache.get(key);
|
|
689
|
+
}
|
|
690
|
+
const value = evaluateDerivation({
|
|
691
|
+
key,
|
|
692
|
+
parsed: entry.parsed,
|
|
693
|
+
resolveRef: (ref) => {
|
|
694
|
+
const namespace = namespaceForKey(ref);
|
|
695
|
+
if (runtimeProviders.has(namespace)) {
|
|
696
|
+
const provider = runtimeProviders.get(namespace);
|
|
697
|
+
return provider(ref.slice(namespace.length + 1));
|
|
698
|
+
}
|
|
699
|
+
if (entries.has(ref)) {
|
|
700
|
+
if (evaluationStack.has(ref)) {
|
|
701
|
+
throw new CnosDerivedResolutionError(key, `Unable to resolve derived config key ${key} because of a recursive dependency on ${ref}.`);
|
|
702
|
+
}
|
|
703
|
+
evaluationStack.add(ref);
|
|
704
|
+
const resolved = readDerived(ref, readBase, evaluationStack);
|
|
705
|
+
evaluationStack.delete(ref);
|
|
706
|
+
return resolved;
|
|
707
|
+
}
|
|
708
|
+
return readBase(ref);
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
if (!entry.parsed.isRuntimeDependent) {
|
|
712
|
+
configCache.set(key, value);
|
|
713
|
+
}
|
|
714
|
+
return value;
|
|
715
|
+
};
|
|
716
|
+
for (const key of Array.from(entries.keys()).sort((left, right) => left.localeCompare(right))) {
|
|
717
|
+
const entry = entries.get(key);
|
|
718
|
+
if (!entry.parsed.isRuntimeDependent) {
|
|
719
|
+
readDerived(key, (ref) => graph.entries.get(ref)?.value);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return support;
|
|
723
|
+
}
|
|
724
|
+
function registerRuntimeProvider(manifest, runtimeProviders, namespace, provider) {
|
|
725
|
+
const definition = manifest.runtimeNamespaces[namespace];
|
|
726
|
+
if (!definition) {
|
|
727
|
+
throw new CnosRuntimeProviderError(`Cannot register runtime provider for undeclared namespace "${namespace}".`);
|
|
728
|
+
}
|
|
729
|
+
if (definition.builtIn) {
|
|
730
|
+
throw new CnosRuntimeProviderError(`Cannot override built-in runtime namespace "${namespace}".`);
|
|
731
|
+
}
|
|
732
|
+
runtimeProviders.set(namespace, provider);
|
|
733
|
+
}
|
|
78
734
|
|
|
79
735
|
// ../core/src/runtime/inspect.ts
|
|
80
|
-
function inspectValue(graph, key) {
|
|
736
|
+
function inspectValue(graph, key, helpers = {}) {
|
|
81
737
|
const entry = graph.entries.get(key);
|
|
82
738
|
if (!entry) {
|
|
83
739
|
throw new CnosKeyNotFoundError(key);
|
|
84
740
|
}
|
|
741
|
+
const derived = helpers.describeDerived?.(key);
|
|
85
742
|
return {
|
|
86
743
|
key: entry.key,
|
|
87
|
-
value: entry.value,
|
|
744
|
+
value: helpers.read ? helpers.read(entry.key) : entry.value,
|
|
88
745
|
namespace: entry.namespace,
|
|
89
746
|
profile: graph.profile,
|
|
90
747
|
profileSource: graph.profileSource,
|
|
@@ -105,7 +762,10 @@ function inspectValue(graph, key) {
|
|
|
105
762
|
workspaceId: override.workspaceId,
|
|
106
763
|
value: override.value,
|
|
107
764
|
...override.origin ? { origin: override.origin } : {}
|
|
108
|
-
}))
|
|
765
|
+
})),
|
|
766
|
+
...derived ? {
|
|
767
|
+
derived
|
|
768
|
+
} : {}
|
|
109
769
|
};
|
|
110
770
|
}
|
|
111
771
|
|
|
@@ -155,59 +815,364 @@ var execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process3
|
|
|
155
815
|
function wrap(script) {
|
|
156
816
|
return ["-NoProfile", "-Command", script];
|
|
157
817
|
}
|
|
158
|
-
async function readWindowsKeychain(entry) {
|
|
159
|
-
try {
|
|
160
|
-
const { stdout } = await execFileAsync3(
|
|
161
|
-
"powershell",
|
|
162
|
-
wrap(`Add-Type -AssemblyName System.Runtime.WindowsRuntime; [Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime] > $null; $vault = New-Object Windows.Security.Credentials.PasswordVault; $credential = $vault.Retrieve('cnos','${entry}'); $credential.RetrievePassword(); Write-Output $credential.Password`)
|
|
818
|
+
async function readWindowsKeychain(entry) {
|
|
819
|
+
try {
|
|
820
|
+
const { stdout } = await execFileAsync3(
|
|
821
|
+
"powershell",
|
|
822
|
+
wrap(`Add-Type -AssemblyName System.Runtime.WindowsRuntime; [Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime] > $null; $vault = New-Object Windows.Security.Credentials.PasswordVault; $credential = $vault.Retrieve('cnos','${entry}'); $credential.RetrievePassword(); Write-Output $credential.Password`)
|
|
823
|
+
);
|
|
824
|
+
const value = stdout.trim();
|
|
825
|
+
return value.length > 0 ? value : void 0;
|
|
826
|
+
} catch {
|
|
827
|
+
return void 0;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// ../core/src/keychain/index.ts
|
|
832
|
+
async function readKeychain(entry) {
|
|
833
|
+
if (process.platform === "win32") {
|
|
834
|
+
return readWindowsKeychain(entry);
|
|
835
|
+
}
|
|
836
|
+
if (process.platform === "darwin") {
|
|
837
|
+
return readMacosKeychain(entry);
|
|
838
|
+
}
|
|
839
|
+
if (process.platform === "linux") {
|
|
840
|
+
return readLinuxKeychain(entry);
|
|
841
|
+
}
|
|
842
|
+
return void 0;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// ../core/src/manifest/loadManifest.ts
|
|
846
|
+
var import_promises5 = require("fs/promises");
|
|
847
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
848
|
+
|
|
849
|
+
// ../core/src/utils/path.ts
|
|
850
|
+
var import_promises4 = require("fs/promises");
|
|
851
|
+
var import_node_os3 = __toESM(require("os"), 1);
|
|
852
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
853
|
+
|
|
854
|
+
// ../core/src/discovery/findCnosrc.ts
|
|
855
|
+
var import_promises3 = require("fs/promises");
|
|
856
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
857
|
+
|
|
858
|
+
// ../core/src/utils/yaml.ts
|
|
859
|
+
var import_yaml = require("yaml");
|
|
860
|
+
function parseYaml(source) {
|
|
861
|
+
return (0, import_yaml.parse)(source);
|
|
862
|
+
}
|
|
863
|
+
function stringifyYaml(value) {
|
|
864
|
+
return (0, import_yaml.stringify)(value);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// ../core/src/discovery/resolveRoot.ts
|
|
868
|
+
var import_promises2 = require("fs/promises");
|
|
869
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
870
|
+
var import_node_child_process4 = require("child_process");
|
|
871
|
+
var import_node_os2 = __toESM(require("os"), 1);
|
|
872
|
+
|
|
873
|
+
// ../core/src/discovery/parseGitUri.ts
|
|
874
|
+
function isGitRootUri(uri) {
|
|
875
|
+
return /^git\+[a-z]+:\/\//i.test(uri);
|
|
876
|
+
}
|
|
877
|
+
function parseGitUri(uri) {
|
|
878
|
+
if (!isGitRootUri(uri)) {
|
|
879
|
+
throw new CnosDiscoveryError(`Unsupported git root URI: ${uri}`);
|
|
880
|
+
}
|
|
881
|
+
const withoutPrefix = uri.slice("git+".length);
|
|
882
|
+
const hashIndex = withoutPrefix.indexOf("#");
|
|
883
|
+
if (hashIndex < 0) {
|
|
884
|
+
throw new CnosDiscoveryError(
|
|
885
|
+
`Git root URI must include a #ref (tag, branch, or commit). Got: ${uri}`
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
const cloneUrl = withoutPrefix.slice(0, hashIndex);
|
|
889
|
+
const fragment = withoutPrefix.slice(hashIndex + 1);
|
|
890
|
+
const separatorIndex = fragment.indexOf(":");
|
|
891
|
+
const ref = (separatorIndex >= 0 ? fragment.slice(0, separatorIndex) : fragment).trim();
|
|
892
|
+
const subpath = (separatorIndex >= 0 ? fragment.slice(separatorIndex + 1) : ".cnos").trim() || ".cnos";
|
|
893
|
+
const protocol = cloneUrl.slice(0, cloneUrl.indexOf("://"));
|
|
894
|
+
if (!cloneUrl || !ref) {
|
|
895
|
+
throw new CnosDiscoveryError(
|
|
896
|
+
`Git root URI must include both a clone URL and #ref. Got: ${uri}`
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
return {
|
|
900
|
+
uri,
|
|
901
|
+
cloneUrl,
|
|
902
|
+
ref,
|
|
903
|
+
subpath,
|
|
904
|
+
transport: protocol === "https" ? "https" : protocol === "ssh" ? "ssh" : protocol === "file" ? "file" : "custom"
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// ../core/src/discovery/cache/cacheManager.ts
|
|
909
|
+
var SEMVER_TAG_RE = /^v?\d+\.\d+(?:\.\d+)?(?:[-+][A-Za-z0-9.-]+)?$/;
|
|
910
|
+
var COMMIT_SHA_RE = /^[0-9a-f]{40}$/i;
|
|
911
|
+
function isImmutableGitRef(ref) {
|
|
912
|
+
return SEMVER_TAG_RE.test(ref) || COMMIT_SHA_RE.test(ref);
|
|
913
|
+
}
|
|
914
|
+
function resolveRemoteRootCacheTtlSeconds(mode = "runtime", processEnv = process.env, override) {
|
|
915
|
+
if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
|
|
916
|
+
return override;
|
|
917
|
+
}
|
|
918
|
+
const fromEnv = Number(processEnv.CNOS_CACHE_TTL ?? "");
|
|
919
|
+
if (Number.isFinite(fromEnv) && fromEnv >= 0) {
|
|
920
|
+
return fromEnv;
|
|
921
|
+
}
|
|
922
|
+
switch (mode) {
|
|
923
|
+
case "build":
|
|
924
|
+
return 0;
|
|
925
|
+
case "dev":
|
|
926
|
+
return 30;
|
|
927
|
+
case "runtime":
|
|
928
|
+
default:
|
|
929
|
+
return 300;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
function isRemoteRootCacheFresh(metadata, options) {
|
|
933
|
+
if (!metadata || options.forceRefresh) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
if (metadata.uri !== options.uri || metadata.ref !== options.ref) {
|
|
937
|
+
return false;
|
|
938
|
+
}
|
|
939
|
+
if (metadata.isImmutable) {
|
|
940
|
+
return true;
|
|
941
|
+
}
|
|
942
|
+
const ttlSeconds = resolveRemoteRootCacheTtlSeconds(
|
|
943
|
+
options.mode,
|
|
944
|
+
options.processEnv,
|
|
945
|
+
options.ttlSeconds
|
|
946
|
+
);
|
|
947
|
+
if (ttlSeconds <= 0) {
|
|
948
|
+
return false;
|
|
949
|
+
}
|
|
950
|
+
const cachedAtMs = Date.parse(metadata.cachedAt);
|
|
951
|
+
if (Number.isNaN(cachedAtMs)) {
|
|
952
|
+
return false;
|
|
953
|
+
}
|
|
954
|
+
return Date.now() - cachedAtMs <= ttlSeconds * 1e3;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// ../core/src/discovery/cache/cacheMetadata.ts
|
|
958
|
+
var import_promises = require("fs/promises");
|
|
959
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
960
|
+
async function readRemoteRootCacheMetadata(metaPath) {
|
|
961
|
+
try {
|
|
962
|
+
const source = await (0, import_promises.readFile)(metaPath, "utf8");
|
|
963
|
+
const parsed = JSON.parse(source);
|
|
964
|
+
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") {
|
|
965
|
+
return void 0;
|
|
966
|
+
}
|
|
967
|
+
return parsed;
|
|
968
|
+
} catch {
|
|
969
|
+
return void 0;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
async function writeRemoteRootCacheMetadata(metaPath, metadata) {
|
|
973
|
+
await (0, import_promises.mkdir)(import_node_path.default.dirname(metaPath), { recursive: true });
|
|
974
|
+
await (0, import_promises.writeFile)(metaPath, `${JSON.stringify(metadata, null, 2)}
|
|
975
|
+
`, "utf8");
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// ../core/src/discovery/cache/cachePaths.ts
|
|
979
|
+
var import_node_crypto = require("crypto");
|
|
980
|
+
var import_node_os = __toESM(require("os"), 1);
|
|
981
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
982
|
+
function resolveCnosCacheRoot(processEnv = process.env) {
|
|
983
|
+
return import_node_path2.default.resolve(
|
|
984
|
+
expandHomePath(processEnv.CNOS_CACHE_DIR ?? import_node_path2.default.join(import_node_os.default.homedir(), ".cnos", "cache"))
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
function createRemoteRootCacheKey(uri) {
|
|
988
|
+
return (0, import_node_crypto.createHash)("sha256").update(uri).digest("hex");
|
|
989
|
+
}
|
|
990
|
+
function resolveRemoteRootCachePaths(uri, processEnv = process.env) {
|
|
991
|
+
const cacheRoot = resolveCnosCacheRoot(processEnv);
|
|
992
|
+
const cacheDir = import_node_path2.default.join(cacheRoot, "roots", createRemoteRootCacheKey(uri));
|
|
993
|
+
return {
|
|
994
|
+
cacheRoot,
|
|
995
|
+
cacheDir,
|
|
996
|
+
repoDir: import_node_path2.default.join(cacheDir, "repo"),
|
|
997
|
+
metaPath: import_node_path2.default.join(cacheDir, ".cnos-cache-meta.json")
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// ../core/src/discovery/resolveRoot.ts
|
|
1002
|
+
async function pathExists(targetPath) {
|
|
1003
|
+
try {
|
|
1004
|
+
await (0, import_promises2.access)(targetPath);
|
|
1005
|
+
return true;
|
|
1006
|
+
} catch {
|
|
1007
|
+
return false;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
function expandHomePath2(targetPath) {
|
|
1011
|
+
if (targetPath === "~") {
|
|
1012
|
+
return import_node_os2.default.homedir();
|
|
1013
|
+
}
|
|
1014
|
+
if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
|
|
1015
|
+
return import_node_path3.default.join(import_node_os2.default.homedir(), targetPath.slice(2));
|
|
1016
|
+
}
|
|
1017
|
+
return targetPath;
|
|
1018
|
+
}
|
|
1019
|
+
function isLocalRootUri(rootUri) {
|
|
1020
|
+
return !isGitRootUri2(rootUri) && !isCnosHostedRootUri(rootUri);
|
|
1021
|
+
}
|
|
1022
|
+
function isCnosHostedRootUri(rootUri) {
|
|
1023
|
+
return rootUri.startsWith("cnos://");
|
|
1024
|
+
}
|
|
1025
|
+
function isGitRootUri2(rootUri) {
|
|
1026
|
+
return rootUri.startsWith("git+");
|
|
1027
|
+
}
|
|
1028
|
+
async function runGitCommand(args, options = {}) {
|
|
1029
|
+
return new Promise((resolve, reject) => {
|
|
1030
|
+
const child = (0, import_node_child_process4.spawn)("git", args, {
|
|
1031
|
+
cwd: options.cwd,
|
|
1032
|
+
env: options.processEnv ?? process.env,
|
|
1033
|
+
shell: process.platform === "win32",
|
|
1034
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1035
|
+
});
|
|
1036
|
+
let stdout = "";
|
|
1037
|
+
let stderr = "";
|
|
1038
|
+
child.stdout.on("data", (chunk) => {
|
|
1039
|
+
stdout += chunk.toString();
|
|
1040
|
+
});
|
|
1041
|
+
child.stderr.on("data", (chunk) => {
|
|
1042
|
+
stderr += chunk.toString();
|
|
1043
|
+
});
|
|
1044
|
+
child.on("error", (error) => {
|
|
1045
|
+
reject(
|
|
1046
|
+
new CnosDiscoveryError(
|
|
1047
|
+
`Failed to run git. Make sure git is installed and available on PATH. ${error.message}`
|
|
1048
|
+
)
|
|
1049
|
+
);
|
|
1050
|
+
});
|
|
1051
|
+
child.on("close", (code) => {
|
|
1052
|
+
if (code === 0) {
|
|
1053
|
+
resolve(stdout.trim());
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
const details = stderr.trim() || stdout.trim();
|
|
1057
|
+
reject(
|
|
1058
|
+
new CnosDiscoveryError(
|
|
1059
|
+
details ? `Git command failed: ${details}` : `Git command failed with exit code ${code ?? 1}`
|
|
1060
|
+
)
|
|
1061
|
+
);
|
|
1062
|
+
});
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
async function resolveLocalRoot(rootUri, cnosrcDir) {
|
|
1066
|
+
const candidateRoot = rootUri.startsWith("~") ? expandHomePath2(rootUri) : rootUri;
|
|
1067
|
+
const manifestRoot = import_node_path3.default.resolve(cnosrcDir, candidateRoot);
|
|
1068
|
+
const manifestPath = import_node_path3.default.join(manifestRoot, "cnos.yml");
|
|
1069
|
+
if (!await pathExists(manifestPath)) {
|
|
1070
|
+
throw new CnosDiscoveryError(`.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`);
|
|
1071
|
+
}
|
|
1072
|
+
return {
|
|
1073
|
+
manifestRoot,
|
|
1074
|
+
resolution: {
|
|
1075
|
+
rootUri,
|
|
1076
|
+
protocol: "local",
|
|
1077
|
+
remote: false,
|
|
1078
|
+
readOnly: false
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
async function ensureGitCheckout(parsed, repoDir, processEnv) {
|
|
1083
|
+
const hasRepo = await pathExists(import_node_path3.default.join(repoDir, ".git"));
|
|
1084
|
+
if (!hasRepo) {
|
|
1085
|
+
await (0, import_promises2.mkdir)(import_node_path3.default.dirname(repoDir), { recursive: true });
|
|
1086
|
+
await runGitCommand(["clone", "--no-checkout", parsed.cloneUrl, repoDir], { processEnv });
|
|
1087
|
+
} else {
|
|
1088
|
+
await runGitCommand(["-C", repoDir, "remote", "set-url", "origin", parsed.cloneUrl], {
|
|
1089
|
+
processEnv
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
await runGitCommand(["-C", repoDir, "fetch", "--tags", "--force", "origin"], { processEnv });
|
|
1093
|
+
await runGitCommand(["-C", repoDir, "checkout", "--force", parsed.ref], { processEnv });
|
|
1094
|
+
await runGitCommand(["-C", repoDir, "clean", "-fdx"], { processEnv });
|
|
1095
|
+
}
|
|
1096
|
+
async function resolveGitRoot(rootUri, options = {}) {
|
|
1097
|
+
const processEnv = options.processEnv ?? process.env;
|
|
1098
|
+
const parsed = parseGitUri(rootUri);
|
|
1099
|
+
const cachePaths = resolveRemoteRootCachePaths(rootUri, processEnv);
|
|
1100
|
+
const metadata = await readRemoteRootCacheMetadata(cachePaths.metaPath);
|
|
1101
|
+
const immutable = isImmutableGitRef(parsed.ref);
|
|
1102
|
+
const cacheFresh = isRemoteRootCacheFresh(metadata, {
|
|
1103
|
+
uri: rootUri,
|
|
1104
|
+
ref: parsed.ref,
|
|
1105
|
+
...options.cacheMode ? { mode: options.cacheMode } : {},
|
|
1106
|
+
processEnv,
|
|
1107
|
+
...typeof options.cacheTtlSeconds === "number" ? { ttlSeconds: options.cacheTtlSeconds } : {},
|
|
1108
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
1109
|
+
});
|
|
1110
|
+
if (!cacheFresh) {
|
|
1111
|
+
try {
|
|
1112
|
+
await ensureGitCheckout(parsed, cachePaths.repoDir, processEnv);
|
|
1113
|
+
} catch (error) {
|
|
1114
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1115
|
+
const authHint = parsed.transport === "ssh" ? " Check your SSH key and git access." : " Check the URL and your git credential helper or token setup.";
|
|
1116
|
+
throw new CnosDiscoveryError(`Failed to resolve remote git root ${rootUri}. ${message}${authHint}`);
|
|
1117
|
+
}
|
|
1118
|
+
const resolvedCommit = await runGitCommand(["-C", cachePaths.repoDir, "rev-parse", "HEAD"], {
|
|
1119
|
+
processEnv
|
|
1120
|
+
});
|
|
1121
|
+
await writeRemoteRootCacheMetadata(cachePaths.metaPath, {
|
|
1122
|
+
uri: rootUri,
|
|
1123
|
+
cloneUrl: parsed.cloneUrl,
|
|
1124
|
+
ref: parsed.ref,
|
|
1125
|
+
subpath: parsed.subpath,
|
|
1126
|
+
resolvedCommit,
|
|
1127
|
+
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1128
|
+
isImmutable: immutable
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
const nextMetadata = metadata && cacheFresh ? metadata : await readRemoteRootCacheMetadata(cachePaths.metaPath);
|
|
1132
|
+
const manifestRoot = import_node_path3.default.join(cachePaths.repoDir, parsed.subpath);
|
|
1133
|
+
if (!await pathExists(import_node_path3.default.join(manifestRoot, "cnos.yml"))) {
|
|
1134
|
+
throw new CnosDiscoveryError(
|
|
1135
|
+
`Git root ${rootUri} resolved to ${manifestRoot} but no cnos.yml was found there. Check the :subpath segment.`
|
|
163
1136
|
);
|
|
164
|
-
const value = stdout.trim();
|
|
165
|
-
return value.length > 0 ? value : void 0;
|
|
166
|
-
} catch {
|
|
167
|
-
return void 0;
|
|
168
1137
|
}
|
|
1138
|
+
return {
|
|
1139
|
+
manifestRoot,
|
|
1140
|
+
resolution: {
|
|
1141
|
+
rootUri,
|
|
1142
|
+
protocol: "git",
|
|
1143
|
+
remote: true,
|
|
1144
|
+
readOnly: true,
|
|
1145
|
+
cacheDir: cachePaths.cacheDir,
|
|
1146
|
+
cacheMetaPath: cachePaths.metaPath,
|
|
1147
|
+
ref: parsed.ref,
|
|
1148
|
+
subpath: parsed.subpath,
|
|
1149
|
+
immutable,
|
|
1150
|
+
...nextMetadata?.resolvedCommit ? { resolvedCommit: nextMetadata.resolvedCommit } : {},
|
|
1151
|
+
...nextMetadata?.cachedAt ? { cachedAt: nextMetadata.cachedAt } : {}
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
169
1154
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (process.platform === "win32") {
|
|
174
|
-
return readWindowsKeychain(entry);
|
|
1155
|
+
async function resolveRootUri(rootUri, cnosrcDir, options = {}) {
|
|
1156
|
+
if (isLocalRootUri(rootUri)) {
|
|
1157
|
+
return resolveLocalRoot(rootUri, cnosrcDir);
|
|
175
1158
|
}
|
|
176
|
-
if (
|
|
177
|
-
return
|
|
1159
|
+
if (isGitRootUri2(rootUri)) {
|
|
1160
|
+
return resolveGitRoot(rootUri, options);
|
|
178
1161
|
}
|
|
179
|
-
if (
|
|
180
|
-
|
|
1162
|
+
if (isCnosHostedRootUri(rootUri)) {
|
|
1163
|
+
throw new CnosDiscoveryError(
|
|
1164
|
+
`The cnos:// remote root protocol is reserved but not implemented yet. Use git+https:// or git+ssh:// for now.`
|
|
1165
|
+
);
|
|
181
1166
|
}
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// ../core/src/manifest/loadManifest.ts
|
|
186
|
-
var import_promises3 = require("fs/promises");
|
|
187
|
-
var import_node_path3 = __toESM(require("path"), 1);
|
|
188
|
-
|
|
189
|
-
// ../core/src/utils/path.ts
|
|
190
|
-
var import_promises2 = require("fs/promises");
|
|
191
|
-
var import_node_os = __toESM(require("os"), 1);
|
|
192
|
-
var import_node_path2 = __toESM(require("path"), 1);
|
|
193
|
-
|
|
194
|
-
// ../core/src/discovery/findCnosrc.ts
|
|
195
|
-
var import_promises = require("fs/promises");
|
|
196
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
197
|
-
|
|
198
|
-
// ../core/src/utils/yaml.ts
|
|
199
|
-
var import_yaml = require("yaml");
|
|
200
|
-
function parseYaml(source) {
|
|
201
|
-
return (0, import_yaml.parse)(source);
|
|
202
|
-
}
|
|
203
|
-
function stringifyYaml(value) {
|
|
204
|
-
return (0, import_yaml.stringify)(value);
|
|
1167
|
+
throw new CnosDiscoveryError(
|
|
1168
|
+
`Unknown root protocol: ${rootUri}. Supported root protocols are local paths, git+https://..., and git+ssh://....`
|
|
1169
|
+
);
|
|
205
1170
|
}
|
|
206
1171
|
|
|
207
1172
|
// ../core/src/discovery/findCnosrc.ts
|
|
208
1173
|
async function exists(targetPath) {
|
|
209
1174
|
try {
|
|
210
|
-
await (0,
|
|
1175
|
+
await (0, import_promises3.access)(targetPath);
|
|
211
1176
|
return true;
|
|
212
1177
|
} catch {
|
|
213
1178
|
return false;
|
|
@@ -228,13 +1193,13 @@ function validateCnosrc(value, filePath) {
|
|
|
228
1193
|
};
|
|
229
1194
|
}
|
|
230
1195
|
async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
|
|
231
|
-
let current =
|
|
1196
|
+
let current = import_node_path4.default.resolve(startDir);
|
|
232
1197
|
for (let depth = 0; depth <= maxLevels; depth += 1) {
|
|
233
|
-
const candidate =
|
|
1198
|
+
const candidate = import_node_path4.default.join(current, ".cnosrc.yml");
|
|
234
1199
|
if (await exists(candidate)) {
|
|
235
1200
|
return candidate;
|
|
236
1201
|
}
|
|
237
|
-
const parent =
|
|
1202
|
+
const parent = import_node_path4.default.dirname(current);
|
|
238
1203
|
if (parent === current) {
|
|
239
1204
|
break;
|
|
240
1205
|
}
|
|
@@ -242,27 +1207,22 @@ async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
|
|
|
242
1207
|
}
|
|
243
1208
|
return void 0;
|
|
244
1209
|
}
|
|
245
|
-
async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3) {
|
|
1210
|
+
async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3, options = {}) {
|
|
246
1211
|
const anchorPath = await findCnosrc(startDir, maxLevels);
|
|
247
1212
|
if (!anchorPath) {
|
|
248
1213
|
throw new CnosDiscoveryError(
|
|
249
1214
|
"No .cnosrc.yml found. Run cnos init or create .cnosrc.yml in your package root."
|
|
250
1215
|
);
|
|
251
1216
|
}
|
|
252
|
-
const source = await (0,
|
|
1217
|
+
const source = await (0, import_promises3.readFile)(anchorPath, "utf8");
|
|
253
1218
|
const parsed = validateCnosrc(parseYaml(source), anchorPath);
|
|
254
|
-
const consumerRoot =
|
|
255
|
-
const
|
|
256
|
-
const manifestPath = import_node_path.default.join(manifestRoot, "cnos.yml");
|
|
257
|
-
if (!await exists(manifestPath)) {
|
|
258
|
-
throw new CnosDiscoveryError(
|
|
259
|
-
`.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`
|
|
260
|
-
);
|
|
261
|
-
}
|
|
1219
|
+
const consumerRoot = import_node_path4.default.dirname(anchorPath);
|
|
1220
|
+
const resolvedRoot = await resolveRootUri(parsed.root, consumerRoot, options);
|
|
262
1221
|
return {
|
|
263
1222
|
anchorPath,
|
|
264
1223
|
consumerRoot,
|
|
265
|
-
manifestRoot,
|
|
1224
|
+
manifestRoot: resolvedRoot.manifestRoot,
|
|
1225
|
+
rootResolution: resolvedRoot.resolution,
|
|
266
1226
|
...parsed.workspace ? { workspace: parsed.workspace } : {}
|
|
267
1227
|
};
|
|
268
1228
|
}
|
|
@@ -272,21 +1232,21 @@ var PRIMARY_CNOS_DIR = ".cnos";
|
|
|
272
1232
|
var LEGACY_CNOS_DIR = "cnos";
|
|
273
1233
|
async function exists2(filePath) {
|
|
274
1234
|
try {
|
|
275
|
-
await (0,
|
|
1235
|
+
await (0, import_promises4.access)(filePath);
|
|
276
1236
|
return true;
|
|
277
1237
|
} catch {
|
|
278
1238
|
return false;
|
|
279
1239
|
}
|
|
280
1240
|
}
|
|
281
1241
|
async function resolveCnosRoot(root = process.cwd()) {
|
|
282
|
-
const basePath =
|
|
1242
|
+
const basePath = import_node_path5.default.resolve(root);
|
|
283
1243
|
const candidates = [
|
|
284
|
-
|
|
285
|
-
|
|
1244
|
+
import_node_path5.default.join(basePath, PRIMARY_CNOS_DIR),
|
|
1245
|
+
import_node_path5.default.join(basePath, LEGACY_CNOS_DIR),
|
|
286
1246
|
basePath
|
|
287
1247
|
];
|
|
288
1248
|
for (const candidate of candidates) {
|
|
289
|
-
if (await exists2(
|
|
1249
|
+
if (await exists2(import_node_path5.default.join(candidate, "cnos.yml"))) {
|
|
290
1250
|
return candidate;
|
|
291
1251
|
}
|
|
292
1252
|
}
|
|
@@ -296,18 +1256,44 @@ async function resolveCnosRoot(root = process.cwd()) {
|
|
|
296
1256
|
}
|
|
297
1257
|
async function resolveManifestRoot(options = {}) {
|
|
298
1258
|
if (options.root) {
|
|
1259
|
+
if (options.root.startsWith("git+") || options.root.startsWith("cnos://")) {
|
|
1260
|
+
const consumerRoot2 = import_node_path5.default.resolve(options.cwd ?? process.cwd());
|
|
1261
|
+
const resolvedRoot2 = await resolveRootUri(options.root, consumerRoot2, {
|
|
1262
|
+
...options.processEnv ? { processEnv: options.processEnv } : {},
|
|
1263
|
+
...options.cacheMode ? { cacheMode: options.cacheMode } : {},
|
|
1264
|
+
...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
|
|
1265
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
1266
|
+
});
|
|
1267
|
+
return {
|
|
1268
|
+
manifestRoot: resolvedRoot2.manifestRoot,
|
|
1269
|
+
consumerRoot: consumerRoot2,
|
|
1270
|
+
rootResolution: resolvedRoot2.resolution
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
299
1273
|
const manifestRoot = await resolveCnosRoot(options.root);
|
|
300
|
-
const resolvedRoot =
|
|
301
|
-
const consumerRoot =
|
|
1274
|
+
const resolvedRoot = import_node_path5.default.resolve(options.root);
|
|
1275
|
+
const consumerRoot = import_node_path5.default.basename(manifestRoot) === PRIMARY_CNOS_DIR || import_node_path5.default.basename(manifestRoot) === LEGACY_CNOS_DIR ? import_node_path5.default.dirname(manifestRoot) : resolvedRoot;
|
|
302
1276
|
return {
|
|
303
1277
|
manifestRoot,
|
|
304
|
-
consumerRoot
|
|
1278
|
+
consumerRoot,
|
|
1279
|
+
rootResolution: {
|
|
1280
|
+
rootUri: manifestRoot,
|
|
1281
|
+
protocol: "local",
|
|
1282
|
+
remote: false,
|
|
1283
|
+
readOnly: false
|
|
1284
|
+
}
|
|
305
1285
|
};
|
|
306
1286
|
}
|
|
307
|
-
const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd()
|
|
1287
|
+
const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd(), 3, {
|
|
1288
|
+
...options.processEnv ? { processEnv: options.processEnv } : {},
|
|
1289
|
+
...options.cacheMode ? { cacheMode: options.cacheMode } : {},
|
|
1290
|
+
...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
|
|
1291
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
1292
|
+
});
|
|
308
1293
|
return {
|
|
309
1294
|
manifestRoot: discovered.manifestRoot,
|
|
310
1295
|
consumerRoot: discovered.consumerRoot,
|
|
1296
|
+
rootResolution: discovered.rootResolution,
|
|
311
1297
|
anchorPath: discovered.anchorPath,
|
|
312
1298
|
...discovered.workspace ? { workspace: discovered.workspace } : {}
|
|
313
1299
|
};
|
|
@@ -320,10 +1306,10 @@ function interpolatePathTemplate(template, tokens) {
|
|
|
320
1306
|
}
|
|
321
1307
|
function expandHomePath(targetPath) {
|
|
322
1308
|
if (targetPath === "~") {
|
|
323
|
-
return
|
|
1309
|
+
return import_node_os3.default.homedir();
|
|
324
1310
|
}
|
|
325
1311
|
if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
|
|
326
|
-
return
|
|
1312
|
+
return import_node_path5.default.join(import_node_os3.default.homedir(), targetPath.slice(2));
|
|
327
1313
|
}
|
|
328
1314
|
return targetPath;
|
|
329
1315
|
}
|
|
@@ -341,7 +1327,7 @@ function stripWorkspaceTemplatePrefix(template) {
|
|
|
341
1327
|
function resolveWorkspaceScopedPath(workspaceRoot, template, tokens) {
|
|
342
1328
|
const relativeTemplate = stripWorkspaceTemplatePrefix(template);
|
|
343
1329
|
const interpolated = interpolatePathTemplate(relativeTemplate, tokens);
|
|
344
|
-
return
|
|
1330
|
+
return import_node_path5.default.resolve(workspaceRoot, interpolated);
|
|
345
1331
|
}
|
|
346
1332
|
function toPortablePath(targetPath) {
|
|
347
1333
|
return targetPath.replace(/\\/g, "/");
|
|
@@ -407,6 +1393,13 @@ var DEFAULT_NAMESPACES = {
|
|
|
407
1393
|
readonly: true
|
|
408
1394
|
}
|
|
409
1395
|
};
|
|
1396
|
+
var DEFAULT_RUNTIME_NAMESPACES = {
|
|
1397
|
+
process: {
|
|
1398
|
+
description: "Live process runtime values.",
|
|
1399
|
+
serverOnly: true,
|
|
1400
|
+
builtIn: true
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
410
1403
|
function validateResolveFrom(resolveFrom) {
|
|
411
1404
|
const validValues = ["cli.profile", "env.CNOS_PROFILE", "default"];
|
|
412
1405
|
for (const entry of resolveFrom) {
|
|
@@ -429,7 +1422,7 @@ function normalizeWorkspaceItems(items) {
|
|
|
429
1422
|
}
|
|
430
1423
|
function normalizeNamespaces(namespaces) {
|
|
431
1424
|
const normalized = Object.fromEntries(
|
|
432
|
-
Object.entries(namespaces ?? {}).map(([namespace, definition]) => [
|
|
1425
|
+
Object.entries(namespaces ?? {}).filter(([namespace]) => namespace !== "runtime").map(([namespace, definition]) => [
|
|
433
1426
|
namespace,
|
|
434
1427
|
{
|
|
435
1428
|
kind: definition.kind ?? "data",
|
|
@@ -445,6 +1438,29 @@ function normalizeNamespaces(namespaces) {
|
|
|
445
1438
|
...normalized
|
|
446
1439
|
};
|
|
447
1440
|
}
|
|
1441
|
+
function normalizeRuntimeNamespaces(namespaces) {
|
|
1442
|
+
const runtimeEntries = namespaces?.runtime ?? {};
|
|
1443
|
+
const normalized = Object.fromEntries(
|
|
1444
|
+
Object.entries(runtimeEntries).map(([namespace, definition]) => [
|
|
1445
|
+
namespace,
|
|
1446
|
+
{
|
|
1447
|
+
...definition.description?.trim() ? {
|
|
1448
|
+
description: definition.description.trim()
|
|
1449
|
+
} : {},
|
|
1450
|
+
serverOnly: definition.server_only ?? true
|
|
1451
|
+
}
|
|
1452
|
+
])
|
|
1453
|
+
);
|
|
1454
|
+
for (const namespace of Object.keys(normalized)) {
|
|
1455
|
+
if (DEFAULT_NAMESPACES[namespace] || namespace === "runtime") {
|
|
1456
|
+
throw new CnosManifestError(`Runtime namespace "${namespace}" conflicts with a built-in or reserved namespace.`);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return {
|
|
1460
|
+
...DEFAULT_RUNTIME_NAMESPACES,
|
|
1461
|
+
...normalized
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
448
1464
|
function normalizeVaults(vaults) {
|
|
449
1465
|
return Object.fromEntries(
|
|
450
1466
|
Object.entries(vaults ?? {}).map(([name, definition]) => {
|
|
@@ -536,6 +1552,7 @@ function normalizeManifest(manifest) {
|
|
|
536
1552
|
const defaultProfile = manifest.profiles?.default?.trim() || "base";
|
|
537
1553
|
const workspaceItems = normalizeWorkspaceItems(manifest.workspaces?.items);
|
|
538
1554
|
const resolveFrom = validateResolveFrom(manifest.profiles?.resolveFrom ?? DEFAULT_RESOLVE_FROM);
|
|
1555
|
+
const runtimeNamespaces = normalizeRuntimeNamespaces(manifest.namespaces);
|
|
539
1556
|
const filesystemValues = {
|
|
540
1557
|
root: "./",
|
|
541
1558
|
format: "yaml",
|
|
@@ -609,6 +1626,7 @@ function normalizeManifest(manifest) {
|
|
|
609
1626
|
}
|
|
610
1627
|
},
|
|
611
1628
|
namespaces: normalizeNamespaces(manifest.namespaces),
|
|
1629
|
+
runtimeNamespaces,
|
|
612
1630
|
vaults: normalizeVaults(manifest.vaults),
|
|
613
1631
|
writePolicy: {
|
|
614
1632
|
define: {
|
|
@@ -627,13 +1645,17 @@ function normalizeManifest(manifest) {
|
|
|
627
1645
|
async function loadManifest(options = {}) {
|
|
628
1646
|
const resolved = await resolveManifestRoot({
|
|
629
1647
|
...options.root ? { root: options.root } : {},
|
|
630
|
-
...options.cwd ? { cwd: options.cwd } : {}
|
|
1648
|
+
...options.cwd ? { cwd: options.cwd } : {},
|
|
1649
|
+
...options.processEnv ? { processEnv: options.processEnv } : {},
|
|
1650
|
+
...options.cacheMode ? { cacheMode: options.cacheMode } : {},
|
|
1651
|
+
...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
|
|
1652
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
631
1653
|
});
|
|
632
1654
|
const manifestRoot = resolved.manifestRoot;
|
|
633
|
-
const manifestPath =
|
|
1655
|
+
const manifestPath = import_node_path6.default.join(manifestRoot, "cnos.yml");
|
|
634
1656
|
let source;
|
|
635
1657
|
try {
|
|
636
|
-
source = await (0,
|
|
1658
|
+
source = await (0, import_promises5.readFile)(manifestPath, "utf8");
|
|
637
1659
|
} catch {
|
|
638
1660
|
throw new CnosManifestError("Unable to read CNOS manifest", manifestPath);
|
|
639
1661
|
}
|
|
@@ -643,10 +1665,11 @@ async function loadManifest(options = {}) {
|
|
|
643
1665
|
}
|
|
644
1666
|
return {
|
|
645
1667
|
manifestRoot,
|
|
646
|
-
repoRoot:
|
|
1668
|
+
repoRoot: import_node_path6.default.dirname(manifestRoot),
|
|
647
1669
|
consumerRoot: resolved.consumerRoot,
|
|
648
1670
|
...resolved.anchorPath ? { anchorPath: resolved.anchorPath } : {},
|
|
649
1671
|
...resolved.workspace ? { anchoredWorkspace: resolved.workspace } : {},
|
|
1672
|
+
rootResolution: resolved.rootResolution,
|
|
650
1673
|
manifestPath,
|
|
651
1674
|
manifest: normalizeManifest(rawManifest),
|
|
652
1675
|
rawManifest
|
|
@@ -654,12 +1677,12 @@ async function loadManifest(options = {}) {
|
|
|
654
1677
|
}
|
|
655
1678
|
|
|
656
1679
|
// ../core/src/manifest/loadWorkspaceFile.ts
|
|
657
|
-
var
|
|
658
|
-
var
|
|
1680
|
+
var import_promises6 = require("fs/promises");
|
|
1681
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
659
1682
|
async function loadWorkspaceFile(repoRoot) {
|
|
660
|
-
const workspaceFilePath =
|
|
1683
|
+
const workspaceFilePath = import_node_path7.default.join(repoRoot, ".cnos-workspace.yml");
|
|
661
1684
|
try {
|
|
662
|
-
const source = await (0,
|
|
1685
|
+
const source = await (0, import_promises6.readFile)(workspaceFilePath, "utf8");
|
|
663
1686
|
const parsed = parseYaml(source);
|
|
664
1687
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
665
1688
|
throw new CnosManifestError(".cnos-workspace.yml must be a YAML object", workspaceFilePath);
|
|
@@ -682,11 +1705,11 @@ async function loadWorkspaceFile(repoRoot) {
|
|
|
682
1705
|
}
|
|
683
1706
|
|
|
684
1707
|
// ../core/src/profiles/expandProfileChain.ts
|
|
685
|
-
var
|
|
686
|
-
var
|
|
1708
|
+
var import_promises7 = require("fs/promises");
|
|
1709
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
687
1710
|
async function fileExists(targetPath) {
|
|
688
1711
|
try {
|
|
689
|
-
await (0,
|
|
1712
|
+
await (0, import_promises7.access)(targetPath);
|
|
690
1713
|
return true;
|
|
691
1714
|
} catch {
|
|
692
1715
|
return false;
|
|
@@ -720,11 +1743,11 @@ async function loadProfileDefinition(profileName, options) {
|
|
|
720
1743
|
return normalizeProfileDefinition(profileName, void 0);
|
|
721
1744
|
}
|
|
722
1745
|
for (const workspaceRoot of [...workspaceRoots].reverse()) {
|
|
723
|
-
const profilePath =
|
|
1746
|
+
const profilePath = import_node_path8.default.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
|
|
724
1747
|
if (!await fileExists(profilePath)) {
|
|
725
1748
|
continue;
|
|
726
1749
|
}
|
|
727
|
-
const document = await (0,
|
|
1750
|
+
const document = await (0, import_promises7.readFile)(profilePath, "utf8");
|
|
728
1751
|
const parsed = parseYaml(document);
|
|
729
1752
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
730
1753
|
throw new CnosManifestError("Profile definition must be a YAML object", profilePath);
|
|
@@ -732,7 +1755,7 @@ async function loadProfileDefinition(profileName, options) {
|
|
|
732
1755
|
const definition = normalizeProfileDefinition(
|
|
733
1756
|
profileName,
|
|
734
1757
|
parsed,
|
|
735
|
-
options.manifestRoot ? toPortablePath(
|
|
1758
|
+
options.manifestRoot ? toPortablePath(import_node_path8.default.relative(import_node_path8.default.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
|
|
736
1759
|
);
|
|
737
1760
|
if (definition.name !== profileName) {
|
|
738
1761
|
throw new CnosManifestError(
|
|
@@ -1014,8 +2037,8 @@ function createProfileAwareResolver() {
|
|
|
1014
2037
|
}
|
|
1015
2038
|
|
|
1016
2039
|
// ../core/src/workspaces/resolveWorkspaceContext.ts
|
|
1017
|
-
var
|
|
1018
|
-
var
|
|
2040
|
+
var import_promises8 = require("fs/promises");
|
|
2041
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
1019
2042
|
|
|
1020
2043
|
// ../core/src/workspaces/expandWorkspaceChain.ts
|
|
1021
2044
|
function expandWorkspaceChain(workspaceId, items) {
|
|
@@ -1054,14 +2077,14 @@ function expandWorkspaceChain(workspaceId, items) {
|
|
|
1054
2077
|
// ../core/src/workspaces/resolveWorkspaceContext.ts
|
|
1055
2078
|
async function exists3(targetPath) {
|
|
1056
2079
|
try {
|
|
1057
|
-
await (0,
|
|
2080
|
+
await (0, import_promises8.access)(targetPath);
|
|
1058
2081
|
return true;
|
|
1059
2082
|
} catch {
|
|
1060
2083
|
return false;
|
|
1061
2084
|
}
|
|
1062
2085
|
}
|
|
1063
2086
|
async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
|
|
1064
|
-
const workspaceRoot =
|
|
2087
|
+
const workspaceRoot = import_node_path9.default.join(manifestRoot, "workspaces", workspaceId);
|
|
1065
2088
|
if (await exists3(workspaceRoot)) {
|
|
1066
2089
|
return workspaceRoot;
|
|
1067
2090
|
}
|
|
@@ -1069,7 +2092,7 @@ async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
|
|
|
1069
2092
|
([namespace, definition]) => namespace !== "value" && namespace !== "secret" && definition.kind === "data" && !definition.sensitive
|
|
1070
2093
|
).map(([namespace]) => namespace);
|
|
1071
2094
|
const legacyMarkers = ["values", "secrets", "env", "profiles", ...customDataNamespaceRoots].map(
|
|
1072
|
-
(segment) =>
|
|
2095
|
+
(segment) => import_node_path9.default.join(manifestRoot, segment)
|
|
1073
2096
|
);
|
|
1074
2097
|
if ((await Promise.all(legacyMarkers.map((marker) => exists3(marker)))).some(Boolean)) {
|
|
1075
2098
|
return manifestRoot;
|
|
@@ -1117,26 +2140,26 @@ function resolveGlobalRoot(manifest, workspaceFile, options) {
|
|
|
1117
2140
|
}
|
|
1118
2141
|
if (options.globalRoot) {
|
|
1119
2142
|
return {
|
|
1120
|
-
value:
|
|
2143
|
+
value: import_node_path9.default.resolve(expandHomePath(options.globalRoot)),
|
|
1121
2144
|
source: "cli"
|
|
1122
2145
|
};
|
|
1123
2146
|
}
|
|
1124
2147
|
if (workspaceFile?.globalRoot) {
|
|
1125
2148
|
return {
|
|
1126
|
-
value:
|
|
2149
|
+
value: import_node_path9.default.resolve(expandHomePath(workspaceFile.globalRoot)),
|
|
1127
2150
|
source: "workspace-file"
|
|
1128
2151
|
};
|
|
1129
2152
|
}
|
|
1130
2153
|
if (manifest.workspaces.global.root) {
|
|
1131
2154
|
return {
|
|
1132
|
-
value:
|
|
2155
|
+
value: import_node_path9.default.resolve(expandHomePath(manifest.workspaces.global.root)),
|
|
1133
2156
|
source: "manifest"
|
|
1134
2157
|
};
|
|
1135
2158
|
}
|
|
1136
2159
|
const cnosHome = options.processEnv?.CNOS_HOME;
|
|
1137
2160
|
if (cnosHome) {
|
|
1138
2161
|
return {
|
|
1139
|
-
value:
|
|
2162
|
+
value: import_node_path9.default.resolve(expandHomePath(cnosHome)),
|
|
1140
2163
|
source: "CNOS_HOME"
|
|
1141
2164
|
};
|
|
1142
2165
|
}
|
|
@@ -1158,7 +2181,7 @@ async function resolveWorkspaceContext(manifest, options) {
|
|
|
1158
2181
|
workspaceRoots.push({
|
|
1159
2182
|
scope: "global",
|
|
1160
2183
|
workspaceId: chainWorkspaceId,
|
|
1161
|
-
path:
|
|
2184
|
+
path: import_node_path9.default.join(globalRoot.value, "workspaces", globalWorkspaceId)
|
|
1162
2185
|
});
|
|
1163
2186
|
}
|
|
1164
2187
|
}
|
|
@@ -1281,6 +2304,10 @@ function applySchemaRules(graph, schema) {
|
|
|
1281
2304
|
}
|
|
1282
2305
|
continue;
|
|
1283
2306
|
}
|
|
2307
|
+
if (isDerivedValue(resolvedEntry.value)) {
|
|
2308
|
+
nextEntries.set(key, resolvedEntry);
|
|
2309
|
+
continue;
|
|
2310
|
+
}
|
|
1284
2311
|
const coercedValue = coerceValue(resolvedEntry.value, rule);
|
|
1285
2312
|
const nextResolvedEntry = coercedValue === resolvedEntry.value ? resolvedEntry : {
|
|
1286
2313
|
...resolvedEntry,
|
|
@@ -1350,26 +2377,26 @@ async function runPipeline(options) {
|
|
|
1350
2377
|
}
|
|
1351
2378
|
|
|
1352
2379
|
// ../core/src/secrets/auditLog.ts
|
|
1353
|
-
var
|
|
1354
|
-
var
|
|
2380
|
+
var import_promises11 = require("fs/promises");
|
|
2381
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
1355
2382
|
|
|
1356
2383
|
// ../core/src/utils/secretStore.ts
|
|
1357
|
-
var
|
|
1358
|
-
var
|
|
1359
|
-
var
|
|
2384
|
+
var import_node_crypto2 = require("crypto");
|
|
2385
|
+
var import_promises10 = require("fs/promises");
|
|
2386
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
1360
2387
|
|
|
1361
2388
|
// ../core/src/secrets/sessionStore.ts
|
|
1362
|
-
var
|
|
1363
|
-
var
|
|
2389
|
+
var import_promises9 = require("fs/promises");
|
|
2390
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
1364
2391
|
function buildSessionRoot(processEnv = process.env) {
|
|
1365
|
-
return
|
|
2392
|
+
return import_node_path10.default.join(import_node_path10.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
|
|
1366
2393
|
}
|
|
1367
2394
|
function buildSessionPath(vault, processEnv) {
|
|
1368
|
-
return
|
|
2395
|
+
return import_node_path10.default.join(buildSessionRoot(processEnv), `${vault}.json`);
|
|
1369
2396
|
}
|
|
1370
2397
|
async function readVaultSessionKey(vault, processEnv) {
|
|
1371
2398
|
try {
|
|
1372
|
-
const source = await (0,
|
|
2399
|
+
const source = await (0, import_promises9.readFile)(buildSessionPath(vault, processEnv), "utf8");
|
|
1373
2400
|
const document = JSON.parse(source);
|
|
1374
2401
|
if (document.version !== 1 || typeof document.derivedKey !== "string") {
|
|
1375
2402
|
return void 0;
|
|
@@ -1398,7 +2425,7 @@ function isSecretReference(value) {
|
|
|
1398
2425
|
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));
|
|
1399
2426
|
}
|
|
1400
2427
|
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
1401
|
-
return
|
|
2428
|
+
return import_node_path11.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
1402
2429
|
}
|
|
1403
2430
|
function normalizeVaultToken(vault = "default") {
|
|
1404
2431
|
return vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
@@ -1427,19 +2454,19 @@ function resolveVaultSessionKey(vault = "default", processEnv = process.env) {
|
|
|
1427
2454
|
}
|
|
1428
2455
|
}
|
|
1429
2456
|
function deriveVaultKey(passphrase, salt, iterations = PBKDF2_ITERATIONS) {
|
|
1430
|
-
return (0,
|
|
2457
|
+
return (0, import_node_crypto2.pbkdf2Sync)(passphrase, salt, iterations, KEY_LENGTH, "sha512");
|
|
1431
2458
|
}
|
|
1432
2459
|
function buildMetaPath(storeRoot, vault = "default") {
|
|
1433
|
-
return
|
|
2460
|
+
return import_node_path11.default.join(storeRoot, "vaults", vault, META_FILENAME);
|
|
1434
2461
|
}
|
|
1435
2462
|
function buildKeystorePath(storeRoot, vault = "default") {
|
|
1436
|
-
return
|
|
2463
|
+
return import_node_path11.default.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
|
|
1437
2464
|
}
|
|
1438
2465
|
function buildLegacyVaultFile(storeRoot, vault = "default") {
|
|
1439
|
-
return
|
|
2466
|
+
return import_node_path11.default.join(storeRoot, "vaults", `${vault}.json`);
|
|
1440
2467
|
}
|
|
1441
2468
|
function buildLegacyVaultStoreRoot(storeRoot, vault = "default") {
|
|
1442
|
-
return
|
|
2469
|
+
return import_node_path11.default.join(storeRoot, "vaults", vault, "store");
|
|
1443
2470
|
}
|
|
1444
2471
|
function assertVaultMetadata(value, filePath) {
|
|
1445
2472
|
if (!isObject(value)) {
|
|
@@ -1452,7 +2479,7 @@ function assertVaultMetadata(value, filePath) {
|
|
|
1452
2479
|
}
|
|
1453
2480
|
async function exists4(targetPath) {
|
|
1454
2481
|
try {
|
|
1455
|
-
await (0,
|
|
2482
|
+
await (0, import_promises10.stat)(targetPath);
|
|
1456
2483
|
return true;
|
|
1457
2484
|
} catch {
|
|
1458
2485
|
return false;
|
|
@@ -1479,8 +2506,8 @@ async function assertNoLegacyVaultFormat(storeRoot, vault = "default") {
|
|
|
1479
2506
|
);
|
|
1480
2507
|
}
|
|
1481
2508
|
function encryptPayload(payload, key) {
|
|
1482
|
-
const iv = (0,
|
|
1483
|
-
const cipher = (0,
|
|
2509
|
+
const iv = (0, import_node_crypto2.randomBytes)(IV_LENGTH);
|
|
2510
|
+
const cipher = (0, import_node_crypto2.createCipheriv)("aes-256-gcm", key, iv);
|
|
1484
2511
|
const plaintext = Buffer.from(JSON.stringify(payload), "utf8");
|
|
1485
2512
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
1486
2513
|
const tag = cipher.getAuthTag();
|
|
@@ -1505,7 +2532,7 @@ function decryptPayload(buffer, key) {
|
|
|
1505
2532
|
const iv = buffer.subarray(ivOffset, tagOffset);
|
|
1506
2533
|
const tag = buffer.subarray(tagOffset, cipherOffset);
|
|
1507
2534
|
const ciphertext = buffer.subarray(cipherOffset);
|
|
1508
|
-
const decipher = (0,
|
|
2535
|
+
const decipher = (0, import_node_crypto2.createDecipheriv)("aes-256-gcm", key, iv);
|
|
1509
2536
|
decipher.setAuthTag(tag);
|
|
1510
2537
|
try {
|
|
1511
2538
|
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
@@ -1536,15 +2563,15 @@ function buildInitialPayload() {
|
|
|
1536
2563
|
async function writeVaultFiles(storeRoot, vault, meta, payload, key) {
|
|
1537
2564
|
const metaPath = buildMetaPath(storeRoot, vault);
|
|
1538
2565
|
const keystorePath = buildKeystorePath(storeRoot, vault);
|
|
1539
|
-
await (0,
|
|
1540
|
-
await (0,
|
|
1541
|
-
await (0,
|
|
2566
|
+
await (0, import_promises10.mkdir)(import_node_path11.default.dirname(metaPath), { recursive: true });
|
|
2567
|
+
await (0, import_promises10.writeFile)(metaPath, stringifyYaml(meta), "utf8");
|
|
2568
|
+
await (0, import_promises10.writeFile)(keystorePath, encryptPayload(payload, key));
|
|
1542
2569
|
}
|
|
1543
2570
|
async function readVaultMetadata(storeRoot, vault = "default") {
|
|
1544
2571
|
await assertNoLegacyVaultFormat(storeRoot, vault);
|
|
1545
2572
|
const metaPath = buildMetaPath(storeRoot, vault);
|
|
1546
2573
|
try {
|
|
1547
|
-
const source = await (0,
|
|
2574
|
+
const source = await (0, import_promises10.readFile)(metaPath, "utf8");
|
|
1548
2575
|
return assertVaultMetadata(parseYaml(source), metaPath);
|
|
1549
2576
|
} catch (error) {
|
|
1550
2577
|
if (error.code === "ENOENT") {
|
|
@@ -1556,7 +2583,7 @@ async function readVaultMetadata(storeRoot, vault = "default") {
|
|
|
1556
2583
|
async function createSecretVault(storeRoot, vault, passphrase) {
|
|
1557
2584
|
const normalizedVault = vault.trim() || "default";
|
|
1558
2585
|
await assertNoLegacyVaultFormat(storeRoot, normalizedVault);
|
|
1559
|
-
const salt = (0,
|
|
2586
|
+
const salt = (0, import_node_crypto2.randomBytes)(SALT_LENGTH);
|
|
1560
2587
|
const key = deriveVaultKey(passphrase, salt, PBKDF2_ITERATIONS);
|
|
1561
2588
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1562
2589
|
const meta = {
|
|
@@ -1635,7 +2662,7 @@ async function loadVaultPayload(storeRoot, vault, auth) {
|
|
|
1635
2662
|
if (!key) {
|
|
1636
2663
|
throw new CnosAuthenticationError(`Vault "${vault}" requires authentication before access.`);
|
|
1637
2664
|
}
|
|
1638
|
-
const buffer = await (0,
|
|
2665
|
+
const buffer = await (0, import_promises10.readFile)(buildKeystorePath(storeRoot, vault));
|
|
1639
2666
|
return {
|
|
1640
2667
|
meta,
|
|
1641
2668
|
payload: decryptPayload(buffer, key),
|
|
@@ -1710,9 +2737,9 @@ function resolveVaultDefinition(vaults, vault = "default") {
|
|
|
1710
2737
|
|
|
1711
2738
|
// ../core/src/secrets/auditLog.ts
|
|
1712
2739
|
async function appendAuditEvent(event, processEnv = process.env) {
|
|
1713
|
-
const auditFile = processEnv.CNOS_AUDIT_FILE ??
|
|
1714
|
-
await (0,
|
|
1715
|
-
await (0,
|
|
2740
|
+
const auditFile = processEnv.CNOS_AUDIT_FILE ?? import_node_path12.default.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
|
|
2741
|
+
await (0, import_promises11.mkdir)(import_node_path12.default.dirname(auditFile), { recursive: true });
|
|
2742
|
+
await (0, import_promises11.appendFile)(
|
|
1716
2743
|
auditFile,
|
|
1717
2744
|
`${JSON.stringify({
|
|
1718
2745
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2070,7 +3097,7 @@ function setNestedValue(target, pathSegments, value) {
|
|
|
2070
3097
|
target[head] = nextTarget;
|
|
2071
3098
|
setNestedValue(nextTarget, tail, value);
|
|
2072
3099
|
}
|
|
2073
|
-
function toNamespaceObject(graph, namespace) {
|
|
3100
|
+
function toNamespaceObject(graph, namespace, readValueForKey = (key) => graph.entries.get(key)?.value) {
|
|
2074
3101
|
const output = {};
|
|
2075
3102
|
const resolvedEntries = Array.from(graph.entries.values()).sort(
|
|
2076
3103
|
(left, right) => left.key.localeCompare(right.key)
|
|
@@ -2080,7 +3107,11 @@ function toNamespaceObject(graph, namespace) {
|
|
|
2080
3107
|
continue;
|
|
2081
3108
|
}
|
|
2082
3109
|
const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
|
|
2083
|
-
|
|
3110
|
+
const value = readValueForKey(entry.key);
|
|
3111
|
+
if (value === void 0) {
|
|
3112
|
+
continue;
|
|
3113
|
+
}
|
|
3114
|
+
setNestedValue(output, valuePath.split("."), value);
|
|
2084
3115
|
}
|
|
2085
3116
|
return output;
|
|
2086
3117
|
}
|
|
@@ -2090,12 +3121,6 @@ function readValue(graph, key) {
|
|
|
2090
3121
|
return graph.entries.get(key)?.value;
|
|
2091
3122
|
}
|
|
2092
3123
|
|
|
2093
|
-
// ../core/src/runtime/readOr.ts
|
|
2094
|
-
function readOrValue(graph, key, fallback) {
|
|
2095
|
-
const value = readValue(graph, key);
|
|
2096
|
-
return value === void 0 ? fallback : value;
|
|
2097
|
-
}
|
|
2098
|
-
|
|
2099
3124
|
// ../core/src/runtime/require.ts
|
|
2100
3125
|
function requireValue(graph, key) {
|
|
2101
3126
|
const value = readValue(graph, key);
|
|
@@ -2105,8 +3130,38 @@ function requireValue(graph, key) {
|
|
|
2105
3130
|
return value;
|
|
2106
3131
|
}
|
|
2107
3132
|
|
|
3133
|
+
// ../core/src/runtime/runtimeProviders.ts
|
|
3134
|
+
function createDefaultRuntimeProviders(manifest, processEnv) {
|
|
3135
|
+
const providers = /* @__PURE__ */ new Map();
|
|
3136
|
+
if (manifest.runtimeNamespaces.process) {
|
|
3137
|
+
providers.set("process", (key) => {
|
|
3138
|
+
const segments = key.split(".");
|
|
3139
|
+
if (segments[0] === "env") {
|
|
3140
|
+
return processEnv[segments.slice(1).join(".")];
|
|
3141
|
+
}
|
|
3142
|
+
if (key === "cwd") {
|
|
3143
|
+
return process.cwd();
|
|
3144
|
+
}
|
|
3145
|
+
if (key === "platform") {
|
|
3146
|
+
return process.platform;
|
|
3147
|
+
}
|
|
3148
|
+
if (key === "arch") {
|
|
3149
|
+
return process.arch;
|
|
3150
|
+
}
|
|
3151
|
+
if (key === "pid") {
|
|
3152
|
+
return process.pid;
|
|
3153
|
+
}
|
|
3154
|
+
if (key === "node.version") {
|
|
3155
|
+
return process.version;
|
|
3156
|
+
}
|
|
3157
|
+
return void 0;
|
|
3158
|
+
});
|
|
3159
|
+
}
|
|
3160
|
+
return providers;
|
|
3161
|
+
}
|
|
3162
|
+
|
|
2108
3163
|
// ../core/src/runtime/toServerProjection.ts
|
|
2109
|
-
var
|
|
3164
|
+
var import_node_crypto3 = require("crypto");
|
|
2110
3165
|
function stableSortObject(value) {
|
|
2111
3166
|
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
|
|
2112
3167
|
}
|
|
@@ -2115,12 +3170,14 @@ function stripValuePrefix(key) {
|
|
|
2115
3170
|
}
|
|
2116
3171
|
function configHash(values) {
|
|
2117
3172
|
const serialized = JSON.stringify(stableSortObject(values));
|
|
2118
|
-
return (0,
|
|
3173
|
+
return (0, import_node_crypto3.createHash)("sha256").update(serialized).digest("hex");
|
|
2119
3174
|
}
|
|
2120
|
-
function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
|
|
3175
|
+
function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
|
|
2121
3176
|
const values = {};
|
|
3177
|
+
const derived = {};
|
|
2122
3178
|
const secretRefs = {};
|
|
2123
3179
|
const namespaces = /* @__PURE__ */ new Set();
|
|
3180
|
+
const runtimeNamespaces = /* @__PURE__ */ new Set();
|
|
2124
3181
|
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));
|
|
2125
3182
|
for (const [key, entry] of graph.entries) {
|
|
2126
3183
|
if (entry.namespace === "secret" && isSecretReference(entry.value)) {
|
|
@@ -2132,12 +3189,33 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
|
|
|
2132
3189
|
continue;
|
|
2133
3190
|
}
|
|
2134
3191
|
if (entry.namespace === "value") {
|
|
2135
|
-
|
|
3192
|
+
if (helpers.isRuntimeDependent?.(key)) {
|
|
3193
|
+
const formula = helpers.toServerFormula?.(key);
|
|
3194
|
+
if (formula) {
|
|
3195
|
+
derived[stripValuePrefix(key)] = formula;
|
|
3196
|
+
for (const ref of formula.runtimeRefs) {
|
|
3197
|
+
runtimeNamespaces.add(ref.split(".")[0] ?? "");
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
continue;
|
|
3201
|
+
}
|
|
3202
|
+
const value = helpers.read ? helpers.read(key) : entry.value;
|
|
3203
|
+
values[stripValuePrefix(key)] = value;
|
|
2136
3204
|
continue;
|
|
2137
3205
|
}
|
|
2138
3206
|
const namespaceDefinition = manifest.namespaces[entry.namespace];
|
|
2139
3207
|
if (namespaceDefinition && namespaceDefinition.kind === "data" && !namespaceDefinition.sensitive && entry.namespace !== "public") {
|
|
2140
|
-
|
|
3208
|
+
if (helpers.isRuntimeDependent?.(key)) {
|
|
3209
|
+
const formula = helpers.toServerFormula?.(key);
|
|
3210
|
+
if (formula) {
|
|
3211
|
+
derived[key] = formula;
|
|
3212
|
+
for (const ref of formula.runtimeRefs) {
|
|
3213
|
+
runtimeNamespaces.add(ref.split(".")[0] ?? "");
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
continue;
|
|
3217
|
+
}
|
|
3218
|
+
values[key] = helpers.read ? helpers.read(key) : entry.value;
|
|
2141
3219
|
namespaces.add(entry.namespace);
|
|
2142
3220
|
}
|
|
2143
3221
|
}
|
|
@@ -2148,8 +3226,10 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
|
|
|
2148
3226
|
resolvedAt: graph.resolvedAt,
|
|
2149
3227
|
configHash: configHash(values),
|
|
2150
3228
|
values: stableSortObject(values),
|
|
3229
|
+
derived: stableSortObject(derived),
|
|
2151
3230
|
secretRefs: stableSortObject(secretRefs),
|
|
2152
3231
|
publicKeys,
|
|
3232
|
+
runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
|
|
2153
3233
|
meta: {
|
|
2154
3234
|
workspace: graph.workspace.workspaceId,
|
|
2155
3235
|
profile: graph.profile,
|
|
@@ -2172,7 +3252,7 @@ function normalizeEnvValue(value) {
|
|
|
2172
3252
|
}
|
|
2173
3253
|
return JSON.stringify(value);
|
|
2174
3254
|
}
|
|
2175
|
-
function toEnv(graph, manifest, options = {}) {
|
|
3255
|
+
function toEnv(graph, manifest, options = {}, helpers = {}) {
|
|
2176
3256
|
const includeSecrets = options.includeSecrets ?? true;
|
|
2177
3257
|
const output = {};
|
|
2178
3258
|
const mappedEntries = Object.entries(manifest.envMapping.explicit).sort(
|
|
@@ -2193,7 +3273,11 @@ function toEnv(graph, manifest, options = {}) {
|
|
|
2193
3273
|
if (isSecretReference(entry.value)) {
|
|
2194
3274
|
continue;
|
|
2195
3275
|
}
|
|
2196
|
-
|
|
3276
|
+
const value = helpers.read ? helpers.read(logicalKey) : entry.value;
|
|
3277
|
+
if (value === void 0) {
|
|
3278
|
+
continue;
|
|
3279
|
+
}
|
|
3280
|
+
output[envVar] = normalizeEnvValue(value);
|
|
2197
3281
|
}
|
|
2198
3282
|
return output;
|
|
2199
3283
|
}
|
|
@@ -2230,20 +3314,43 @@ function resolvePublicPrefix(manifest, options) {
|
|
|
2230
3314
|
}
|
|
2231
3315
|
return manifest.public.frameworks[options.framework] ?? "";
|
|
2232
3316
|
}
|
|
2233
|
-
function toPublicEnv(graph, manifest, options = {}) {
|
|
3317
|
+
function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
|
|
2234
3318
|
const prefix = resolvePublicPrefix(manifest, options);
|
|
2235
3319
|
const output = {};
|
|
2236
3320
|
const promotions = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").sort((left, right) => left.key.localeCompare(right.key));
|
|
2237
3321
|
for (const resolved of promotions) {
|
|
3322
|
+
if (helpers.isRuntimeDependent?.(resolved.key)) {
|
|
3323
|
+
const value2 = helpers.read?.(resolved.key);
|
|
3324
|
+
if (value2 === void 0) {
|
|
3325
|
+
throw new CnosManifestError(`Cannot build public output for ${resolved.key} because it depends on runtime-only values.`);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
2238
3328
|
const baseEnvVar = fallbackPublicEnvVar(stripNamespace(resolved.key));
|
|
2239
3329
|
const envVar = prefix && !baseEnvVar.startsWith(prefix) ? `${prefix}${baseEnvVar}` : baseEnvVar;
|
|
2240
|
-
|
|
3330
|
+
const value = helpers.read ? helpers.read(resolved.key) : resolved.value;
|
|
3331
|
+
if (value === void 0) {
|
|
3332
|
+
continue;
|
|
3333
|
+
}
|
|
3334
|
+
output[envVar] = normalizeEnvValue2(value);
|
|
2241
3335
|
}
|
|
2242
3336
|
return output;
|
|
2243
3337
|
}
|
|
2244
3338
|
|
|
2245
3339
|
// ../core/src/orchestrator/runtime.ts
|
|
2246
3340
|
function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
|
|
3341
|
+
const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
|
|
3342
|
+
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
3343
|
+
function resolveProjectedSourceKey(key) {
|
|
3344
|
+
if (!key.startsWith("public.")) {
|
|
3345
|
+
return key;
|
|
3346
|
+
}
|
|
3347
|
+
const promotedFrom = graph.entries.get(key)?.winner.metadata?.promotedFrom;
|
|
3348
|
+
if (typeof promotedFrom === "string") {
|
|
3349
|
+
return promotedFrom;
|
|
3350
|
+
}
|
|
3351
|
+
const fallback = `value.${key.slice("public.".length)}`;
|
|
3352
|
+
return graph.entries.has(fallback) ? fallback : key;
|
|
3353
|
+
}
|
|
2247
3354
|
async function refreshSecretEntry(key) {
|
|
2248
3355
|
const entry = graph.entries.get(key);
|
|
2249
3356
|
if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
|
|
@@ -2275,6 +3382,19 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
2275
3382
|
}
|
|
2276
3383
|
}
|
|
2277
3384
|
function readLogicalKey2(key) {
|
|
3385
|
+
const resolved = derivedSupport.read(key, (ref) => {
|
|
3386
|
+
const entry2 = graph.entries.get(ref);
|
|
3387
|
+
if (!entry2) {
|
|
3388
|
+
return void 0;
|
|
3389
|
+
}
|
|
3390
|
+
if (!secretCache) {
|
|
3391
|
+
return entry2.value;
|
|
3392
|
+
}
|
|
3393
|
+
return resolveSecretEntryValue(ref, entry2.value, secretCache);
|
|
3394
|
+
});
|
|
3395
|
+
if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
|
|
3396
|
+
return resolved;
|
|
3397
|
+
}
|
|
2278
3398
|
const entry = graph.entries.get(key);
|
|
2279
3399
|
if (!entry) {
|
|
2280
3400
|
return void 0;
|
|
@@ -2299,34 +3419,64 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
2299
3419
|
return value;
|
|
2300
3420
|
},
|
|
2301
3421
|
readOr(key, fallback) {
|
|
2302
|
-
|
|
3422
|
+
const value = readLogicalKey2(key);
|
|
3423
|
+
return value === void 0 ? fallback : value;
|
|
2303
3424
|
},
|
|
2304
|
-
value(
|
|
2305
|
-
return readLogicalKey2(toLogicalKey("value",
|
|
3425
|
+
value(path17) {
|
|
3426
|
+
return readLogicalKey2(toLogicalKey("value", path17));
|
|
2306
3427
|
},
|
|
2307
|
-
secret(
|
|
2308
|
-
return readLogicalKey2(toLogicalKey("secret",
|
|
3428
|
+
secret(path17) {
|
|
3429
|
+
return readLogicalKey2(toLogicalKey("secret", path17));
|
|
2309
3430
|
},
|
|
2310
|
-
meta(
|
|
2311
|
-
return readLogicalKey2(toLogicalKey("meta",
|
|
3431
|
+
meta(path17) {
|
|
3432
|
+
return readLogicalKey2(toLogicalKey("meta", path17));
|
|
2312
3433
|
},
|
|
2313
3434
|
inspect(key) {
|
|
2314
|
-
return inspectValue(graph, key
|
|
3435
|
+
return inspectValue(graph, key, {
|
|
3436
|
+
read: (ref) => readLogicalKey2(ref),
|
|
3437
|
+
describeDerived: (ref) => derivedSupport.describe(ref, (candidate) => {
|
|
3438
|
+
const entry = graph.entries.get(candidate);
|
|
3439
|
+
if (!entry) {
|
|
3440
|
+
return void 0;
|
|
3441
|
+
}
|
|
3442
|
+
if (!secretCache) {
|
|
3443
|
+
return entry.value;
|
|
3444
|
+
}
|
|
3445
|
+
return resolveSecretEntryValue(candidate, entry.value, secretCache);
|
|
3446
|
+
})
|
|
3447
|
+
});
|
|
2315
3448
|
},
|
|
2316
3449
|
toObject() {
|
|
2317
|
-
return toNamespaceObject(graph);
|
|
3450
|
+
return toNamespaceObject(graph, void 0, (key) => readLogicalKey2(key));
|
|
2318
3451
|
},
|
|
2319
3452
|
toNamespace(namespace) {
|
|
2320
|
-
return toNamespaceObject(graph, namespace);
|
|
3453
|
+
return toNamespaceObject(graph, namespace, (key) => readLogicalKey2(key));
|
|
2321
3454
|
},
|
|
2322
3455
|
toEnv(options) {
|
|
2323
|
-
return toEnv(graph, manifest, options
|
|
3456
|
+
return toEnv(graph, manifest, options, {
|
|
3457
|
+
read: (key) => readLogicalKey2(key),
|
|
3458
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
|
|
3459
|
+
});
|
|
2324
3460
|
},
|
|
2325
3461
|
toPublicEnv(options) {
|
|
2326
|
-
return toPublicEnv(graph, manifest, options
|
|
3462
|
+
return toPublicEnv(graph, manifest, options, {
|
|
3463
|
+
read: (key) => derivedSupport.toConcreteValue(
|
|
3464
|
+
resolveProjectedSourceKey(key),
|
|
3465
|
+
(candidate) => readLogicalKey2(candidate),
|
|
3466
|
+
"public"
|
|
3467
|
+
),
|
|
3468
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(resolveProjectedSourceKey(key))
|
|
3469
|
+
});
|
|
2327
3470
|
},
|
|
2328
3471
|
toServerProjection() {
|
|
2329
|
-
return toServerProjection(graph, manifest, cnosVersion
|
|
3472
|
+
return toServerProjection(graph, manifest, cnosVersion, {
|
|
3473
|
+
read: (key) => derivedSupport.toConcreteValue(key, (candidate) => readLogicalKey2(candidate), "server"),
|
|
3474
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key),
|
|
3475
|
+
toServerFormula: (key) => derivedSupport.toServerFormula(key)
|
|
3476
|
+
});
|
|
3477
|
+
},
|
|
3478
|
+
registerRuntimeProvider(namespace, provider) {
|
|
3479
|
+
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
2330
3480
|
},
|
|
2331
3481
|
async refreshSecrets() {
|
|
2332
3482
|
await refreshAllSecrets();
|
|
@@ -2433,7 +3583,11 @@ function appendMetaEntries(graph, cnosVersion) {
|
|
|
2433
3583
|
async function createCnos(options = {}) {
|
|
2434
3584
|
const loadedManifest = await loadManifest({
|
|
2435
3585
|
...options.root ? { root: options.root } : {},
|
|
2436
|
-
...options.cwd ? { cwd: options.cwd } : {}
|
|
3586
|
+
...options.cwd ? { cwd: options.cwd } : {},
|
|
3587
|
+
...options.processEnv ? { processEnv: options.processEnv } : {},
|
|
3588
|
+
...options.cacheMode ? { cacheMode: options.cacheMode } : {},
|
|
3589
|
+
...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
|
|
3590
|
+
...options.forceRefresh ? { forceRefresh: true } : {}
|
|
2437
3591
|
});
|
|
2438
3592
|
for (const key of loadedManifest.manifest.public.promote) {
|
|
2439
3593
|
ensureProjectionAllowed(loadedManifest.manifest, key, "public");
|
|
@@ -2494,8 +3648,8 @@ async function createCnos(options = {}) {
|
|
|
2494
3648
|
}
|
|
2495
3649
|
|
|
2496
3650
|
// ../core/src/runtime/dump.ts
|
|
2497
|
-
var
|
|
2498
|
-
var
|
|
3651
|
+
var import_promises12 = require("fs/promises");
|
|
3652
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
2499
3653
|
|
|
2500
3654
|
// ../core/src/utils/envNaming.ts
|
|
2501
3655
|
function normalizeMappingConfig(config = {}) {
|
|
@@ -2504,8 +3658,8 @@ function normalizeMappingConfig(config = {}) {
|
|
|
2504
3658
|
explicit: config.explicit ?? {}
|
|
2505
3659
|
};
|
|
2506
3660
|
}
|
|
2507
|
-
function fromScreamingSnake(
|
|
2508
|
-
return
|
|
3661
|
+
function fromScreamingSnake(path17) {
|
|
3662
|
+
return path17.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
|
|
2509
3663
|
}
|
|
2510
3664
|
function envVarToLogicalKey(envVar, config = {}) {
|
|
2511
3665
|
const normalized = normalizeMappingConfig(config);
|
|
@@ -2532,7 +3686,7 @@ function envVarToLogicalKey(envVar, config = {}) {
|
|
|
2532
3686
|
// package.json
|
|
2533
3687
|
var package_default = {
|
|
2534
3688
|
name: "@kitsy/cnos",
|
|
2535
|
-
version: "1.
|
|
3689
|
+
version: "1.7.0",
|
|
2536
3690
|
description: "Batteries-included CNOS runtime package wired with the official plugins.",
|
|
2537
3691
|
type: "module",
|
|
2538
3692
|
main: "./dist/index.cjs",
|
|
@@ -2731,8 +3885,8 @@ function createCliArgsPlugin() {
|
|
|
2731
3885
|
}
|
|
2732
3886
|
|
|
2733
3887
|
// ../../plugins/dotenv/src/index.ts
|
|
2734
|
-
var
|
|
2735
|
-
var
|
|
3888
|
+
var import_promises13 = require("fs/promises");
|
|
3889
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
2736
3890
|
var DOTENV_PLUGIN_ID = "@kitsy/cnos/plugins/dotenv";
|
|
2737
3891
|
function parseDoubleQuoted(value) {
|
|
2738
3892
|
return value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
@@ -2789,7 +3943,7 @@ function dotenvEntriesFromObject(values, mapping = {}, originFile, workspaceId =
|
|
|
2789
3943
|
}
|
|
2790
3944
|
async function readIfPresent(filePath) {
|
|
2791
3945
|
try {
|
|
2792
|
-
return await (0,
|
|
3946
|
+
return await (0, import_promises13.readFile)(filePath, "utf8");
|
|
2793
3947
|
} catch {
|
|
2794
3948
|
return void 0;
|
|
2795
3949
|
}
|
|
@@ -2808,7 +3962,7 @@ function createDotenvPlugin() {
|
|
|
2808
3962
|
workspace: workspaceRoot.workspaceId
|
|
2809
3963
|
});
|
|
2810
3964
|
for (const fileName of fileNames) {
|
|
2811
|
-
const absolutePath =
|
|
3965
|
+
const absolutePath = import_node_path14.default.join(envRoot, fileName);
|
|
2812
3966
|
const document = await readIfPresent(absolutePath);
|
|
2813
3967
|
if (!document) {
|
|
2814
3968
|
continue;
|
|
@@ -2817,7 +3971,7 @@ function createDotenvPlugin() {
|
|
|
2817
3971
|
...dotenvEntriesFromObject(
|
|
2818
3972
|
parseDotenv(document),
|
|
2819
3973
|
config.envMapping,
|
|
2820
|
-
toPortablePath(
|
|
3974
|
+
toPortablePath(import_node_path14.default.relative(import_node_path14.default.dirname(context.manifestRoot), absolutePath)),
|
|
2821
3975
|
workspaceRoot.workspaceId
|
|
2822
3976
|
)
|
|
2823
3977
|
);
|
|
@@ -2855,16 +4009,16 @@ function createPublicEnvExportPlugin() {
|
|
|
2855
4009
|
}
|
|
2856
4010
|
|
|
2857
4011
|
// ../../plugins/filesystem/src/filesystemSecretsReader.ts
|
|
2858
|
-
var
|
|
4012
|
+
var import_promises15 = require("fs/promises");
|
|
2859
4013
|
|
|
2860
4014
|
// ../../plugins/filesystem/src/helpers.ts
|
|
2861
|
-
var
|
|
2862
|
-
var
|
|
4015
|
+
var import_promises14 = require("fs/promises");
|
|
4016
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
2863
4017
|
var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
|
|
2864
4018
|
var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
|
|
2865
4019
|
async function existsDirectory(targetPath) {
|
|
2866
4020
|
try {
|
|
2867
|
-
const stat2 = await (0,
|
|
4021
|
+
const stat2 = await (0, import_promises14.readdir)(targetPath);
|
|
2868
4022
|
void stat2;
|
|
2869
4023
|
return true;
|
|
2870
4024
|
} catch {
|
|
@@ -2872,15 +4026,15 @@ async function existsDirectory(targetPath) {
|
|
|
2872
4026
|
}
|
|
2873
4027
|
}
|
|
2874
4028
|
async function collectYamlFiles(root) {
|
|
2875
|
-
const entries = await (0,
|
|
4029
|
+
const entries = await (0, import_promises14.readdir)(root, { withFileTypes: true });
|
|
2876
4030
|
const results = [];
|
|
2877
4031
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
2878
|
-
const absolutePath =
|
|
4032
|
+
const absolutePath = import_node_path15.default.join(root, entry.name);
|
|
2879
4033
|
if (entry.isDirectory()) {
|
|
2880
4034
|
results.push(...await collectYamlFiles(absolutePath));
|
|
2881
4035
|
continue;
|
|
2882
4036
|
}
|
|
2883
|
-
if (entry.isFile() && YAML_EXTENSIONS.has(
|
|
4037
|
+
if (entry.isFile() && YAML_EXTENSIONS.has(import_node_path15.default.extname(entry.name).toLowerCase())) {
|
|
2884
4038
|
results.push(absolutePath);
|
|
2885
4039
|
}
|
|
2886
4040
|
}
|
|
@@ -2888,16 +4042,16 @@ async function collectYamlFiles(root) {
|
|
|
2888
4042
|
}
|
|
2889
4043
|
async function collectFilesystemLayerFiles(manifestRoot, workspaceRoots, sourceRoot, activeLayers) {
|
|
2890
4044
|
const files = [];
|
|
2891
|
-
const repoRoot =
|
|
4045
|
+
const repoRoot = import_node_path15.default.dirname(manifestRoot);
|
|
2892
4046
|
for (const workspaceRoot of workspaceRoots) {
|
|
2893
|
-
const resolvedRoot =
|
|
4047
|
+
const resolvedRoot = import_node_path15.default.resolve(workspaceRoot.path, sourceRoot);
|
|
2894
4048
|
for (const layer of activeLayers) {
|
|
2895
|
-
const layerRoot =
|
|
4049
|
+
const layerRoot = import_node_path15.default.join(resolvedRoot, layer);
|
|
2896
4050
|
if (!await existsDirectory(layerRoot)) {
|
|
2897
4051
|
continue;
|
|
2898
4052
|
}
|
|
2899
4053
|
for (const absolutePath of await collectYamlFiles(layerRoot)) {
|
|
2900
|
-
const relativePath =
|
|
4054
|
+
const relativePath = import_node_path15.default.relative(repoRoot, absolutePath);
|
|
2901
4055
|
files.push({
|
|
2902
4056
|
absolutePath,
|
|
2903
4057
|
relativePath: toPortablePath(relativePath.startsWith("..") ? absolutePath : relativePath),
|
|
@@ -2917,7 +4071,7 @@ function assertObjectDocument(value, filePath) {
|
|
|
2917
4071
|
function flattenConfigObject(value, options = {}, prefix = "") {
|
|
2918
4072
|
return Object.entries(value).reduce((accumulator, [key, nestedValue]) => {
|
|
2919
4073
|
const nextKey = prefix ? `${prefix}.${key}` : key;
|
|
2920
|
-
if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue) && !options.stopAtLeaf?.(nestedValue)) {
|
|
4074
|
+
if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue) && !isDerivedValue(nestedValue) && !options.stopAtLeaf?.(nestedValue)) {
|
|
2921
4075
|
Object.assign(
|
|
2922
4076
|
accumulator,
|
|
2923
4077
|
flattenConfigObject(nestedValue, options, nextKey)
|
|
@@ -2974,7 +4128,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
2974
4128
|
);
|
|
2975
4129
|
const entries = [];
|
|
2976
4130
|
for (const file of files) {
|
|
2977
|
-
const document = await (0,
|
|
4131
|
+
const document = await (0, import_promises15.readFile)(file.absolutePath, "utf8");
|
|
2978
4132
|
const fileEntries = filesystemSecretsReader(file.relativePath, document, file.workspaceId);
|
|
2979
4133
|
for (const entry of fileEntries) {
|
|
2980
4134
|
const metadata = toSecretReferenceMetadata(entry.value);
|
|
@@ -2990,7 +4144,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
2990
4144
|
}
|
|
2991
4145
|
|
|
2992
4146
|
// ../../plugins/filesystem/src/filesystemValuesReader.ts
|
|
2993
|
-
var
|
|
4147
|
+
var import_promises16 = require("fs/promises");
|
|
2994
4148
|
function filesystemValuesReader(filePath, document, workspaceId = "default") {
|
|
2995
4149
|
return yamlObjectToEntries(document, filePath, "value", "filesystem-values", workspaceId);
|
|
2996
4150
|
}
|
|
@@ -3011,7 +4165,7 @@ function createFilesystemValuesPlugin() {
|
|
|
3011
4165
|
).map(([namespace]) => namespace);
|
|
3012
4166
|
const entries = [];
|
|
3013
4167
|
for (const file of files) {
|
|
3014
|
-
const document = await (0,
|
|
4168
|
+
const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
|
|
3015
4169
|
entries.push(...filesystemValuesReader(file.relativePath, document, file.workspaceId));
|
|
3016
4170
|
}
|
|
3017
4171
|
for (const namespace of customNamespaces) {
|
|
@@ -3026,7 +4180,7 @@ function createFilesystemValuesPlugin() {
|
|
|
3026
4180
|
layers
|
|
3027
4181
|
);
|
|
3028
4182
|
for (const file of namespaceFiles) {
|
|
3029
|
-
const document = await (0,
|
|
4183
|
+
const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
|
|
3030
4184
|
entries.push(...yamlObjectToEntries(document, file.relativePath, namespace, "filesystem-values", file.workspaceId));
|
|
3031
4185
|
}
|
|
3032
4186
|
}
|
|
@@ -3196,7 +4350,7 @@ async function createCnos2(options = {}) {
|
|
|
3196
4350
|
}
|
|
3197
4351
|
|
|
3198
4352
|
// src/runtime/bootstrap.ts
|
|
3199
|
-
var
|
|
4353
|
+
var import_node_crypto4 = require("crypto");
|
|
3200
4354
|
var CNOS_GRAPH_ENV_VAR = "__CNOS_GRAPH__";
|
|
3201
4355
|
var CNOS_PROJECTION_ENV_VAR = "__CNOS_PROJECTION__";
|
|
3202
4356
|
var CNOS_SECRET_PAYLOAD_ENV_VAR = "__CNOS_SECRET_PAYLOAD__";
|
|
@@ -3206,7 +4360,11 @@ function deserializeServerProjection(source) {
|
|
|
3206
4360
|
if (!payload || payload.version !== 1 || typeof payload.workspace !== "string" || typeof payload.profile !== "string" || typeof payload.resolvedAt !== "string" || typeof payload.configHash !== "string" || !payload.values || typeof payload.values !== "object" || Array.isArray(payload.values) || !payload.secretRefs || typeof payload.secretRefs !== "object" || Array.isArray(payload.secretRefs) || !Array.isArray(payload.publicKeys) || !payload.meta || typeof payload.meta !== "object") {
|
|
3207
4361
|
throw new Error("Invalid CNOS server projection payload");
|
|
3208
4362
|
}
|
|
3209
|
-
return
|
|
4363
|
+
return {
|
|
4364
|
+
...payload,
|
|
4365
|
+
derived: payload.derived && typeof payload.derived === "object" && !Array.isArray(payload.derived) ? payload.derived : {},
|
|
4366
|
+
runtimeNamespaces: Array.isArray(payload.runtimeNamespaces) ? payload.runtimeNamespaces : []
|
|
4367
|
+
};
|
|
3210
4368
|
}
|
|
3211
4369
|
function deserializeRuntimeGraph(source) {
|
|
3212
4370
|
const payload = JSON.parse(source);
|
|
@@ -3241,7 +4399,7 @@ function decryptSecretPayload(serialized, sessionKey) {
|
|
|
3241
4399
|
const iv = Buffer.from(payload.iv, "base64");
|
|
3242
4400
|
const tag = Buffer.from(payload.tag, "base64");
|
|
3243
4401
|
const ciphertext = Buffer.from(payload.ciphertext, "base64");
|
|
3244
|
-
const decipher = (0,
|
|
4402
|
+
const decipher = (0, import_node_crypto4.createDecipheriv)("aes-256-gcm", key, iv);
|
|
3245
4403
|
decipher.setAuthTag(tag);
|
|
3246
4404
|
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
3247
4405
|
return JSON.parse(plaintext);
|
|
@@ -3316,6 +4474,27 @@ function formatMessage(runtime, message) {
|
|
|
3316
4474
|
return value === void 0 ? match : stringifyLogValue(value);
|
|
3317
4475
|
});
|
|
3318
4476
|
}
|
|
4477
|
+
function discoverRuntimeNamespacesFromGraph(graph) {
|
|
4478
|
+
const configNamespaces = /* @__PURE__ */ new Set(["value", "secret", "meta", "public"]);
|
|
4479
|
+
for (const entry of graph.entries.values()) {
|
|
4480
|
+
configNamespaces.add(entry.namespace);
|
|
4481
|
+
}
|
|
4482
|
+
const runtimeNamespaces = /* @__PURE__ */ new Set();
|
|
4483
|
+
for (const entry of graph.entries.values()) {
|
|
4484
|
+
if (!isDerivedValue(entry.value)) {
|
|
4485
|
+
continue;
|
|
4486
|
+
}
|
|
4487
|
+
const parsed = parseDerivation(entry.value);
|
|
4488
|
+
for (const ref of parsed.refs) {
|
|
4489
|
+
const namespace = ref.split(".")[0] ?? "";
|
|
4490
|
+
if (!namespace || configNamespaces.has(namespace)) {
|
|
4491
|
+
continue;
|
|
4492
|
+
}
|
|
4493
|
+
runtimeNamespaces.add(namespace);
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
return Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right));
|
|
4497
|
+
}
|
|
3319
4498
|
function attachBootstrappedGraph(graph) {
|
|
3320
4499
|
if (getSingletonRuntime()) {
|
|
3321
4500
|
return;
|
|
@@ -3362,6 +4541,21 @@ function attachBootstrappedGraph(graph) {
|
|
|
3362
4541
|
frameworks: {}
|
|
3363
4542
|
},
|
|
3364
4543
|
namespaces: {},
|
|
4544
|
+
runtimeNamespaces: {
|
|
4545
|
+
process: {
|
|
4546
|
+
description: "Live process runtime values.",
|
|
4547
|
+
serverOnly: true,
|
|
4548
|
+
builtIn: true
|
|
4549
|
+
},
|
|
4550
|
+
...Object.fromEntries(
|
|
4551
|
+
discoverRuntimeNamespacesFromGraph(graph).map((namespace) => [
|
|
4552
|
+
namespace,
|
|
4553
|
+
{
|
|
4554
|
+
serverOnly: true
|
|
4555
|
+
}
|
|
4556
|
+
])
|
|
4557
|
+
)
|
|
4558
|
+
},
|
|
3365
4559
|
vaults: {},
|
|
3366
4560
|
writePolicy: {
|
|
3367
4561
|
define: {
|
|
@@ -3374,46 +4568,76 @@ function attachBootstrappedGraph(graph) {
|
|
|
3374
4568
|
},
|
|
3375
4569
|
schema: {}
|
|
3376
4570
|
};
|
|
4571
|
+
const runtimeProviders = createDefaultRuntimeProviders(bootstrappedManifest, process.env);
|
|
4572
|
+
const derivedSupport = createDerivedRuntimeSupport(graph, bootstrappedManifest, runtimeProviders);
|
|
4573
|
+
const resolveProjectedSourceKey = (key) => {
|
|
4574
|
+
if (!key.startsWith("public.")) {
|
|
4575
|
+
return key;
|
|
4576
|
+
}
|
|
4577
|
+
const promotedFrom = graph.entries.get(key)?.winner.metadata?.promotedFrom;
|
|
4578
|
+
if (typeof promotedFrom === "string") {
|
|
4579
|
+
return promotedFrom;
|
|
4580
|
+
}
|
|
4581
|
+
const fallback = `value.${key.slice("public.".length)}`;
|
|
4582
|
+
return graph.entries.has(fallback) ? fallback : key;
|
|
4583
|
+
};
|
|
3377
4584
|
const runtime = {
|
|
3378
4585
|
manifest: bootstrappedManifest,
|
|
3379
4586
|
plugins: [],
|
|
3380
4587
|
graph,
|
|
3381
4588
|
read(key) {
|
|
3382
|
-
return readValue(graph,
|
|
4589
|
+
return derivedSupport.read(key, (ref) => readValue(graph, ref));
|
|
3383
4590
|
},
|
|
3384
4591
|
require(key) {
|
|
3385
|
-
|
|
4592
|
+
const value = this.read(key);
|
|
4593
|
+
if (value === void 0) {
|
|
4594
|
+
return requireValue(graph, key);
|
|
4595
|
+
}
|
|
4596
|
+
return value;
|
|
3386
4597
|
},
|
|
3387
4598
|
readOr(key, fallback) {
|
|
3388
|
-
|
|
4599
|
+
const value = this.read(key);
|
|
4600
|
+
return value === void 0 ? fallback : value;
|
|
3389
4601
|
},
|
|
3390
|
-
value(
|
|
3391
|
-
return readValue(graph, toLogicalKey("value",
|
|
4602
|
+
value(path17) {
|
|
4603
|
+
return readValue(graph, toLogicalKey("value", path17));
|
|
3392
4604
|
},
|
|
3393
|
-
secret(
|
|
3394
|
-
return readValue(graph, toLogicalKey("secret",
|
|
4605
|
+
secret(path17) {
|
|
4606
|
+
return readValue(graph, toLogicalKey("secret", path17));
|
|
3395
4607
|
},
|
|
3396
|
-
meta(
|
|
3397
|
-
return readValue(graph, toLogicalKey("meta",
|
|
4608
|
+
meta(path17) {
|
|
4609
|
+
return readValue(graph, toLogicalKey("meta", path17));
|
|
3398
4610
|
},
|
|
3399
4611
|
toNamespace(namespace) {
|
|
3400
|
-
return toNamespaceObject(graph, namespace);
|
|
4612
|
+
return toNamespaceObject(graph, namespace, (key) => this.read(key));
|
|
3401
4613
|
},
|
|
3402
4614
|
toEnv(options) {
|
|
3403
|
-
return toEnv(graph, bootstrappedManifest, options
|
|
4615
|
+
return toEnv(graph, bootstrappedManifest, options, {
|
|
4616
|
+
read: (key) => this.read(key),
|
|
4617
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
|
|
4618
|
+
});
|
|
3404
4619
|
},
|
|
3405
4620
|
toPublicEnv(options) {
|
|
3406
|
-
return toPublicEnv(graph, bootstrappedManifest, options
|
|
4621
|
+
return toPublicEnv(graph, bootstrappedManifest, options, {
|
|
4622
|
+
read: (key) => derivedSupport.toConcreteValue(resolveProjectedSourceKey(key), (ref) => readValue(graph, ref), "public"),
|
|
4623
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(resolveProjectedSourceKey(key))
|
|
4624
|
+
});
|
|
3407
4625
|
},
|
|
3408
4626
|
inspect(key) {
|
|
3409
|
-
return inspectValue(graph, key
|
|
4627
|
+
return inspectValue(graph, key, {
|
|
4628
|
+
read: (ref) => this.read(ref),
|
|
4629
|
+
describeDerived: (ref) => derivedSupport.describe(ref, (candidate) => readValue(graph, candidate))
|
|
4630
|
+
});
|
|
3410
4631
|
},
|
|
3411
4632
|
toObject() {
|
|
3412
|
-
return toNamespaceObject(graph);
|
|
4633
|
+
return toNamespaceObject(graph, void 0, (key) => this.read(key));
|
|
3413
4634
|
},
|
|
3414
4635
|
toServerProjection() {
|
|
3415
4636
|
throw new Error("CNOS graph bootstrap payload does not support server projection export.");
|
|
3416
4637
|
},
|
|
4638
|
+
registerRuntimeProvider(namespace, provider) {
|
|
4639
|
+
registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
|
|
4640
|
+
},
|
|
3417
4641
|
async refreshSecrets() {
|
|
3418
4642
|
return;
|
|
3419
4643
|
},
|
|
@@ -3424,7 +4648,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
3424
4648
|
setSingletonRuntime(runtime);
|
|
3425
4649
|
setBootstrappedSecretHydrationRequired(graphRequiresSecretHydration(graph));
|
|
3426
4650
|
}
|
|
3427
|
-
function toBootstrappedManifest(graph) {
|
|
4651
|
+
function toBootstrappedManifest(graph, runtimeNamespaces = []) {
|
|
3428
4652
|
return {
|
|
3429
4653
|
version: 1,
|
|
3430
4654
|
project: {
|
|
@@ -3467,8 +4691,24 @@ function toBootstrappedManifest(graph) {
|
|
|
3467
4691
|
value: { kind: "data", shareable: true },
|
|
3468
4692
|
secret: { kind: "data", shareable: false, sensitive: true },
|
|
3469
4693
|
meta: { kind: "system", shareable: false, readonly: true },
|
|
4694
|
+
process: { kind: "system", shareable: false, readonly: true },
|
|
3470
4695
|
public: { kind: "projection", shareable: true, readonly: true, source: "promote" }
|
|
3471
4696
|
},
|
|
4697
|
+
runtimeNamespaces: {
|
|
4698
|
+
process: {
|
|
4699
|
+
description: "Live process runtime values.",
|
|
4700
|
+
serverOnly: true,
|
|
4701
|
+
builtIn: true
|
|
4702
|
+
},
|
|
4703
|
+
...Object.fromEntries(
|
|
4704
|
+
runtimeNamespaces.filter((namespace) => namespace !== "process").map((namespace) => [
|
|
4705
|
+
namespace,
|
|
4706
|
+
{
|
|
4707
|
+
serverOnly: true
|
|
4708
|
+
}
|
|
4709
|
+
])
|
|
4710
|
+
)
|
|
4711
|
+
},
|
|
3472
4712
|
vaults: {},
|
|
3473
4713
|
writePolicy: {
|
|
3474
4714
|
define: {
|
|
@@ -3507,6 +4747,31 @@ function graphFromProjection(projection) {
|
|
|
3507
4747
|
overridden: []
|
|
3508
4748
|
});
|
|
3509
4749
|
}
|
|
4750
|
+
for (const [key, formula] of Object.entries(projection.derived)) {
|
|
4751
|
+
const firstSegment = key.split(".")[0] ?? "";
|
|
4752
|
+
const logicalKey = key.startsWith("value.") || key.startsWith("public.") || explicitNamespaces.has(firstSegment) ? key : `value.${key}`;
|
|
4753
|
+
const namespace = logicalKey.slice(0, logicalKey.indexOf("."));
|
|
4754
|
+
const winner = {
|
|
4755
|
+
key: logicalKey,
|
|
4756
|
+
value: {
|
|
4757
|
+
$derive: {
|
|
4758
|
+
expr: formula.expr
|
|
4759
|
+
}
|
|
4760
|
+
},
|
|
4761
|
+
namespace,
|
|
4762
|
+
sourceId: "server-projection",
|
|
4763
|
+
pluginId: "cnos",
|
|
4764
|
+
workspaceId: projection.workspace,
|
|
4765
|
+
profile: projection.profile
|
|
4766
|
+
};
|
|
4767
|
+
entries.set(logicalKey, {
|
|
4768
|
+
key: logicalKey,
|
|
4769
|
+
value: winner.value,
|
|
4770
|
+
namespace,
|
|
4771
|
+
winner,
|
|
4772
|
+
overridden: []
|
|
4773
|
+
});
|
|
4774
|
+
}
|
|
3510
4775
|
for (const [key, ref] of Object.entries(projection.secretRefs)) {
|
|
3511
4776
|
const logicalKey = `secret.${key}`;
|
|
3512
4777
|
entries.set(logicalKey, {
|
|
@@ -3543,7 +4808,10 @@ function graphFromProjection(projection) {
|
|
|
3543
4808
|
sourceId: "server-projection",
|
|
3544
4809
|
pluginId: "cnos",
|
|
3545
4810
|
workspaceId: projection.workspace,
|
|
3546
|
-
profile: projection.profile
|
|
4811
|
+
profile: projection.profile,
|
|
4812
|
+
metadata: {
|
|
4813
|
+
promotedFrom: valueKey
|
|
4814
|
+
}
|
|
3547
4815
|
},
|
|
3548
4816
|
overridden: []
|
|
3549
4817
|
});
|
|
@@ -3581,8 +4849,21 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
3581
4849
|
return;
|
|
3582
4850
|
}
|
|
3583
4851
|
const graph = graphFromProjection(projection);
|
|
3584
|
-
const manifest = toBootstrappedManifest(graph);
|
|
4852
|
+
const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces);
|
|
3585
4853
|
const hydratedSecrets = /* @__PURE__ */ new Map();
|
|
4854
|
+
const runtimeProviders = createDefaultRuntimeProviders(manifest, process.env);
|
|
4855
|
+
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
4856
|
+
const resolveProjectedSourceKey = (key) => {
|
|
4857
|
+
if (!key.startsWith("public.")) {
|
|
4858
|
+
return key;
|
|
4859
|
+
}
|
|
4860
|
+
const promotedFrom = graph.entries.get(key)?.winner.metadata?.promotedFrom;
|
|
4861
|
+
if (typeof promotedFrom === "string") {
|
|
4862
|
+
return promotedFrom;
|
|
4863
|
+
}
|
|
4864
|
+
const fallback = `value.${key.slice("public.".length)}`;
|
|
4865
|
+
return graph.entries.has(fallback) ? fallback : key;
|
|
4866
|
+
};
|
|
3586
4867
|
const resolveSecretValue = async (key) => {
|
|
3587
4868
|
const entry = graph.entries.get(key);
|
|
3588
4869
|
if (!entry || entry.namespace !== "secret") {
|
|
@@ -3608,14 +4889,16 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
3608
4889
|
plugins: [],
|
|
3609
4890
|
graph,
|
|
3610
4891
|
read(key) {
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
4892
|
+
return derivedSupport.read(key, (ref) => {
|
|
4893
|
+
const entry = graph.entries.get(ref);
|
|
4894
|
+
if (!entry) {
|
|
4895
|
+
return void 0;
|
|
4896
|
+
}
|
|
4897
|
+
if (entry.namespace === "secret") {
|
|
4898
|
+
return hydratedSecrets.get(ref);
|
|
4899
|
+
}
|
|
4900
|
+
return entry.value;
|
|
4901
|
+
});
|
|
3619
4902
|
},
|
|
3620
4903
|
require(key) {
|
|
3621
4904
|
const value = this.read(key);
|
|
@@ -3647,24 +4930,59 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
3647
4930
|
])
|
|
3648
4931
|
)
|
|
3649
4932
|
},
|
|
3650
|
-
key
|
|
4933
|
+
key,
|
|
4934
|
+
{
|
|
4935
|
+
read: (ref) => this.read(ref),
|
|
4936
|
+
describeDerived: (ref) => derivedSupport.describe(ref, (candidate) => {
|
|
4937
|
+
const entry = graph.entries.get(candidate);
|
|
4938
|
+
if (!entry) {
|
|
4939
|
+
return void 0;
|
|
4940
|
+
}
|
|
4941
|
+
if (entry.namespace === "secret") {
|
|
4942
|
+
return hydratedSecrets.get(candidate);
|
|
4943
|
+
}
|
|
4944
|
+
return entry.value;
|
|
4945
|
+
})
|
|
4946
|
+
}
|
|
3651
4947
|
);
|
|
3652
4948
|
},
|
|
3653
4949
|
toObject() {
|
|
3654
|
-
return toNamespaceObject(graph);
|
|
4950
|
+
return toNamespaceObject(graph, void 0, (key) => this.read(key));
|
|
3655
4951
|
},
|
|
3656
4952
|
toNamespace(namespace) {
|
|
3657
|
-
return toNamespaceObject(graph, namespace);
|
|
4953
|
+
return toNamespaceObject(graph, namespace, (key) => this.read(key));
|
|
3658
4954
|
},
|
|
3659
4955
|
toEnv(options) {
|
|
3660
|
-
return toEnv(graph, manifest, options
|
|
4956
|
+
return toEnv(graph, manifest, options, {
|
|
4957
|
+
read: (key) => this.read(key),
|
|
4958
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
|
|
4959
|
+
});
|
|
3661
4960
|
},
|
|
3662
4961
|
toPublicEnv(options) {
|
|
3663
|
-
return toPublicEnv(graph, manifest, options
|
|
4962
|
+
return toPublicEnv(graph, manifest, options, {
|
|
4963
|
+
read: (key) => derivedSupport.toConcreteValue(
|
|
4964
|
+
resolveProjectedSourceKey(key),
|
|
4965
|
+
(ref) => {
|
|
4966
|
+
const entry = graph.entries.get(ref);
|
|
4967
|
+
if (!entry) {
|
|
4968
|
+
return void 0;
|
|
4969
|
+
}
|
|
4970
|
+
if (entry.namespace === "secret") {
|
|
4971
|
+
return hydratedSecrets.get(ref);
|
|
4972
|
+
}
|
|
4973
|
+
return entry.value;
|
|
4974
|
+
},
|
|
4975
|
+
"public"
|
|
4976
|
+
),
|
|
4977
|
+
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(resolveProjectedSourceKey(key))
|
|
4978
|
+
});
|
|
3664
4979
|
},
|
|
3665
4980
|
toServerProjection() {
|
|
3666
4981
|
return projection;
|
|
3667
4982
|
},
|
|
4983
|
+
registerRuntimeProvider(namespace, provider) {
|
|
4984
|
+
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
4985
|
+
},
|
|
3668
4986
|
async refreshSecrets() {
|
|
3669
4987
|
for (const key of Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`)) {
|
|
3670
4988
|
hydratedSecrets.delete(key);
|
|
@@ -3699,7 +5017,7 @@ function bootstrapFromProcessEnv() {
|
|
|
3699
5017
|
function discoverProjectionPathSync() {
|
|
3700
5018
|
const cwd = process.cwd();
|
|
3701
5019
|
const directCandidates = [
|
|
3702
|
-
|
|
5020
|
+
import_node_path16.default.join(cwd, ".cnos-server.json")
|
|
3703
5021
|
];
|
|
3704
5022
|
for (const candidate of directCandidates) {
|
|
3705
5023
|
if ((0, import_node_fs.existsSync)(candidate)) {
|
|
@@ -3708,14 +5026,14 @@ function discoverProjectionPathSync() {
|
|
|
3708
5026
|
}
|
|
3709
5027
|
let current = cwd;
|
|
3710
5028
|
for (let depth = 0; depth <= 3; depth += 1) {
|
|
3711
|
-
const rcCandidate =
|
|
5029
|
+
const rcCandidate = import_node_path16.default.join(current, ".cnosrc.yml");
|
|
3712
5030
|
if ((0, import_node_fs.existsSync)(rcCandidate)) {
|
|
3713
|
-
const projectionCandidate =
|
|
5031
|
+
const projectionCandidate = import_node_path16.default.join(current, ".cnos-server.json");
|
|
3714
5032
|
if ((0, import_node_fs.existsSync)(projectionCandidate)) {
|
|
3715
5033
|
return projectionCandidate;
|
|
3716
5034
|
}
|
|
3717
5035
|
}
|
|
3718
|
-
const parent =
|
|
5036
|
+
const parent = import_node_path16.default.dirname(current);
|
|
3719
5037
|
if (parent === current) {
|
|
3720
5038
|
break;
|
|
3721
5039
|
}
|
|
@@ -3751,14 +5069,14 @@ var cnos = Object.assign(
|
|
|
3751
5069
|
readOr(key, fallback) {
|
|
3752
5070
|
return getRuntimeOrThrow().readOr(key, fallback);
|
|
3753
5071
|
},
|
|
3754
|
-
value(
|
|
3755
|
-
return getRuntimeOrThrow().value(
|
|
5072
|
+
value(path17) {
|
|
5073
|
+
return getRuntimeOrThrow().value(path17);
|
|
3756
5074
|
},
|
|
3757
|
-
secret(
|
|
3758
|
-
return getRuntimeOrThrow().secret(
|
|
5075
|
+
secret(path17) {
|
|
5076
|
+
return getRuntimeOrThrow().secret(path17);
|
|
3759
5077
|
},
|
|
3760
|
-
meta(
|
|
3761
|
-
return getRuntimeOrThrow().meta(
|
|
5078
|
+
meta(path17) {
|
|
5079
|
+
return getRuntimeOrThrow().meta(path17);
|
|
3762
5080
|
},
|
|
3763
5081
|
inspect(key) {
|
|
3764
5082
|
return getRuntimeOrThrow().inspect(key);
|
|
@@ -3781,11 +5099,14 @@ var cnos = Object.assign(
|
|
|
3781
5099
|
return formatted;
|
|
3782
5100
|
},
|
|
3783
5101
|
async loadProjection(source) {
|
|
3784
|
-
const resolvedSource =
|
|
5102
|
+
const resolvedSource = import_node_path16.default.resolve(source);
|
|
3785
5103
|
const projection = deserializeServerProjection((0, import_node_fs.readFileSync)(resolvedSource, "utf8"));
|
|
3786
5104
|
attachBootstrappedProjection(projection, true);
|
|
3787
5105
|
setBootstrappedSecretHydrationRequired(Object.keys(projection.secretRefs).length > 0);
|
|
3788
5106
|
},
|
|
5107
|
+
registerRuntimeProvider(namespace, provider) {
|
|
5108
|
+
getRuntimeOrThrow().registerRuntimeProvider(namespace, provider);
|
|
5109
|
+
},
|
|
3789
5110
|
async refreshSecrets() {
|
|
3790
5111
|
await getRuntimeOrThrow().refreshSecrets();
|
|
3791
5112
|
setBootstrappedSecretHydrationRequired(false);
|