@kitsy/cnos 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +4 -1
  2. package/dist/browser/index.cjs +94 -0
  3. package/dist/browser/index.d.cts +16 -0
  4. package/dist/browser/index.d.ts +16 -0
  5. package/dist/browser/index.js +67 -0
  6. package/dist/build/index.cjs +2100 -0
  7. package/dist/build/index.d.cts +5 -0
  8. package/dist/build/index.d.ts +5 -0
  9. package/dist/build/index.js +14 -0
  10. package/dist/{chunk-33ZDYDQJ.js → chunk-APCTXRUN.js} +550 -349
  11. package/dist/{chunk-IHSV5AFX.js → chunk-EIN55XXA.js} +1 -1
  12. package/dist/chunk-JUHPBAEH.js +20 -0
  13. package/dist/{chunk-JQGGSNCL.js → chunk-MLQGYCO7.js} +1 -1
  14. package/dist/chunk-PQ4KSV76.js +50 -0
  15. package/dist/{chunk-IQOUWY6T.js → chunk-RD5WMHPM.js} +1 -1
  16. package/dist/chunk-SO5XREEU.js +179 -0
  17. package/dist/{chunk-7FBRVJD6.js → chunk-SXTMTACL.js} +2 -2
  18. package/dist/{chunk-53HXUSM6.js → chunk-WHUGFPE4.js} +1 -1
  19. package/dist/{chunk-HOS4E7XO.js → chunk-ZA74BO47.js} +1 -1
  20. package/dist/{envNaming-BrOk5ndZ.d.cts → envNaming-BTJpH93W.d.cts} +1 -1
  21. package/dist/{envNaming-DCaNdnrF.d.ts → envNaming-CcsqAel3.d.ts} +1 -1
  22. package/dist/index.cjs +242 -74
  23. package/dist/index.d.cts +4 -3
  24. package/dist/index.d.ts +4 -3
  25. package/dist/index.js +14 -132
  26. package/dist/internal.cjs +428 -10
  27. package/dist/internal.d.cts +29 -3
  28. package/dist/internal.d.ts +29 -3
  29. package/dist/internal.js +27 -1
  30. package/dist/plugin/basic-schema.d.cts +1 -1
  31. package/dist/plugin/basic-schema.d.ts +1 -1
  32. package/dist/plugin/basic-schema.js +2 -2
  33. package/dist/plugin/cli-args.d.cts +1 -1
  34. package/dist/plugin/cli-args.d.ts +1 -1
  35. package/dist/plugin/cli-args.js +2 -2
  36. package/dist/plugin/dotenv.cjs +4 -4
  37. package/dist/plugin/dotenv.d.cts +2 -2
  38. package/dist/plugin/dotenv.d.ts +2 -2
  39. package/dist/plugin/dotenv.js +2 -2
  40. package/dist/plugin/env-export.cjs +29 -46
  41. package/dist/plugin/env-export.d.cts +2 -2
  42. package/dist/plugin/env-export.d.ts +2 -2
  43. package/dist/plugin/env-export.js +2 -2
  44. package/dist/plugin/filesystem.cjs +1 -1
  45. package/dist/plugin/filesystem.d.cts +1 -1
  46. package/dist/plugin/filesystem.d.ts +1 -1
  47. package/dist/plugin/filesystem.js +2 -2
  48. package/dist/plugin/process-env.cjs +4 -4
  49. package/dist/plugin/process-env.d.cts +2 -2
  50. package/dist/plugin/process-env.d.ts +2 -2
  51. package/dist/plugin/process-env.js +2 -2
  52. package/dist/{plugin-BVNEHj19.d.cts → plugin-DkOIT5uI.d.cts} +30 -2
  53. package/dist/{plugin-BVNEHj19.d.ts → plugin-DkOIT5uI.d.ts} +30 -2
  54. package/dist/runtime/index.cjs +2288 -0
  55. package/dist/runtime/index.d.cts +23 -0
  56. package/dist/runtime/index.d.ts +23 -0
  57. package/dist/runtime/index.js +190 -0
  58. package/dist/{toPublicEnv-Gwz3xTK0.d.ts → toPublicEnv-C9clvXLo.d.ts} +1 -1
  59. package/dist/{toPublicEnv-Dd152fFy.d.cts → toPublicEnv-DvFeV3qG.d.cts} +1 -1
  60. package/package.json +16 -1
@@ -1,8 +1,3 @@
1
- // ../core/src/utils/path.ts
2
- import { access } from "fs/promises";
3
- import os from "os";
4
- import path from "path";
5
-
6
1
  // ../core/src/errors.ts
7
2
  var CnosError = class extends Error {
8
3
  constructor(message) {
@@ -17,6 +12,11 @@ var CnosManifestError = class extends CnosError {
17
12
  }
18
13
  manifestPath;
19
14
  };
15
+ var CnosSecurityError = class extends CnosError {
16
+ constructor(message) {
17
+ super(message);
18
+ }
19
+ };
20
20
  var CnosKeyNotFoundError = class extends CnosError {
21
21
  constructor(key) {
22
22
  super(`Missing required CNOS config key: ${key}`);
@@ -25,7 +25,43 @@ var CnosKeyNotFoundError = class extends CnosError {
25
25
  key;
26
26
  };
27
27
 
28
+ // ../core/src/runtime/inspect.ts
29
+ function inspectValue(graph, key) {
30
+ const entry = graph.entries.get(key);
31
+ if (!entry) {
32
+ throw new CnosKeyNotFoundError(key);
33
+ }
34
+ return {
35
+ key: entry.key,
36
+ value: entry.value,
37
+ namespace: entry.namespace,
38
+ profile: graph.profile,
39
+ profileSource: graph.profileSource,
40
+ workspace: {
41
+ id: graph.workspace.workspaceId,
42
+ source: graph.workspace.workspaceSource,
43
+ chain: graph.workspace.workspaceChain
44
+ },
45
+ winner: {
46
+ sourceId: entry.winner.sourceId,
47
+ pluginId: entry.winner.pluginId,
48
+ workspaceId: entry.winner.workspaceId,
49
+ ...entry.winner.origin ? { origin: entry.winner.origin } : {}
50
+ },
51
+ overridden: entry.overridden.map((override) => ({
52
+ sourceId: override.sourceId,
53
+ pluginId: override.pluginId,
54
+ workspaceId: override.workspaceId,
55
+ value: override.value,
56
+ ...override.origin ? { origin: override.origin } : {}
57
+ }))
58
+ };
59
+ }
60
+
28
61
  // ../core/src/utils/path.ts
62
+ import { access } from "fs/promises";
63
+ import os from "os";
64
+ import path from "path";
29
65
  var PRIMARY_CNOS_DIR = ".cnos";
30
66
  var LEGACY_CNOS_DIR = "cnos";
31
67
  async function exists(filePath) {
@@ -120,10 +156,336 @@ function stringifyYaml(value) {
120
156
  return stringify(value);
121
157
  }
122
158
 
159
+ // ../core/src/manifest/loadManifest.ts
160
+ import { readFile } from "fs/promises";
161
+ import path2 from "path";
162
+
163
+ // ../core/src/manifest/normalizeManifest.ts
164
+ var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
165
+ var DEFAULT_LOADERS = [
166
+ "filesystem-values",
167
+ "filesystem-secrets",
168
+ "dotenv",
169
+ "process-env",
170
+ "cli-args"
171
+ ];
172
+ var DEFAULT_VALIDATORS = ["basic-schema"];
173
+ var DEFAULT_EXPORTERS = ["env", "public-env"];
174
+ var DEFAULT_INSPECTORS = ["provenance"];
175
+ var DEFAULT_FRAMEWORK_PREFIXES = {
176
+ next: "NEXT_PUBLIC_",
177
+ vite: "VITE_",
178
+ nuxt: "NUXT_PUBLIC_"
179
+ };
180
+ var DEFAULT_NAMESPACES = {
181
+ value: {
182
+ kind: "data",
183
+ shareable: true
184
+ },
185
+ secret: {
186
+ kind: "data",
187
+ shareable: false,
188
+ sensitive: true
189
+ },
190
+ meta: {
191
+ kind: "system",
192
+ shareable: false,
193
+ readonly: true
194
+ },
195
+ public: {
196
+ kind: "projection",
197
+ source: "promote",
198
+ shareable: true,
199
+ readonly: true
200
+ },
201
+ env: {
202
+ kind: "projection",
203
+ source: "envMapping",
204
+ shareable: true,
205
+ readonly: true
206
+ }
207
+ };
208
+ function validateResolveFrom(resolveFrom) {
209
+ const validValues = ["cli.profile", "env.CNOS_PROFILE", "default"];
210
+ for (const entry of resolveFrom) {
211
+ if (!validValues.includes(entry)) {
212
+ throw new CnosManifestError(`Unsupported profiles.resolveFrom entry: ${entry}`);
213
+ }
214
+ }
215
+ return resolveFrom;
216
+ }
217
+ function normalizeWorkspaceItems(items) {
218
+ return Object.fromEntries(
219
+ Object.entries(items ?? {}).map(([workspaceId, item]) => [
220
+ workspaceId,
221
+ {
222
+ extends: Array.isArray(item?.extends) ? item.extends.map((entry) => entry.trim()).filter(Boolean) : item?.extends ? [item.extends.trim()].filter(Boolean) : [],
223
+ ...item?.globalId?.trim() ? { globalId: item.globalId.trim() } : {}
224
+ }
225
+ ])
226
+ );
227
+ }
228
+ function normalizeNamespaces(namespaces) {
229
+ const normalized = Object.fromEntries(
230
+ Object.entries(namespaces ?? {}).map(([namespace, definition]) => [
231
+ namespace,
232
+ {
233
+ kind: definition.kind ?? "data",
234
+ shareable: definition.shareable ?? false,
235
+ ...definition.sensitive !== void 0 ? { sensitive: definition.sensitive } : {},
236
+ ...definition.readonly !== void 0 ? { readonly: definition.readonly } : {},
237
+ ...definition.source ? { source: definition.source } : {}
238
+ }
239
+ ])
240
+ );
241
+ return {
242
+ ...DEFAULT_NAMESPACES,
243
+ ...normalized
244
+ };
245
+ }
246
+ function normalizeVaults(vaults) {
247
+ return Object.fromEntries(
248
+ Object.entries(vaults ?? {}).map(([name, definition]) => {
249
+ const provider = definition.provider?.trim();
250
+ if (!provider) {
251
+ throw new CnosManifestError(`Vault "${name}" requires a provider`);
252
+ }
253
+ return [
254
+ name,
255
+ {
256
+ provider,
257
+ ...definition.passphrase?.trim() ? {
258
+ passphrase: definition.passphrase.trim()
259
+ } : {}
260
+ }
261
+ ];
262
+ })
263
+ );
264
+ }
265
+ function normalizeManifest(manifest) {
266
+ const version = manifest.version ?? 1;
267
+ if (version !== 1) {
268
+ throw new CnosManifestError(`Unsupported CNOS manifest version: ${version}`);
269
+ }
270
+ const projectName = manifest.project?.name?.trim();
271
+ if (!projectName) {
272
+ throw new CnosManifestError("Manifest requires project.name");
273
+ }
274
+ const defaultProfile = manifest.profiles?.default?.trim() || "base";
275
+ const workspaceItems = normalizeWorkspaceItems(manifest.workspaces?.items);
276
+ const resolveFrom = validateResolveFrom(manifest.profiles?.resolveFrom ?? DEFAULT_RESOLVE_FROM);
277
+ const filesystemValues = {
278
+ root: "./",
279
+ format: "yaml",
280
+ ...manifest.sources?.["filesystem-values"] ?? {}
281
+ };
282
+ const filesystemSecrets = {
283
+ root: "./",
284
+ format: "yaml",
285
+ ...manifest.sources?.["filesystem-secrets"] ?? {}
286
+ };
287
+ const dotenv = {
288
+ root: "./env",
289
+ ...manifest.sources?.dotenv ?? {}
290
+ };
291
+ return {
292
+ version: 1,
293
+ project: {
294
+ name: projectName
295
+ },
296
+ workspaces: {
297
+ ...manifest.workspaces?.default?.trim() ? {
298
+ default: manifest.workspaces.default.trim()
299
+ } : {},
300
+ global: {
301
+ enabled: manifest.workspaces?.global?.enabled ?? false,
302
+ ...manifest.workspaces?.global?.root?.trim() ? {
303
+ root: manifest.workspaces.global.root.trim()
304
+ } : {},
305
+ allowWrite: manifest.workspaces?.global?.allowWrite ?? false
306
+ },
307
+ items: workspaceItems
308
+ },
309
+ profiles: {
310
+ default: defaultProfile,
311
+ resolveFrom
312
+ },
313
+ plugins: {
314
+ loaders: manifest.plugins?.loaders ?? DEFAULT_LOADERS,
315
+ resolver: manifest.plugins?.resolver ?? "profile-aware",
316
+ validators: manifest.plugins?.validators ?? DEFAULT_VALIDATORS,
317
+ exporters: manifest.plugins?.exporters ?? DEFAULT_EXPORTERS,
318
+ inspectors: manifest.plugins?.inspectors ?? DEFAULT_INSPECTORS
319
+ },
320
+ sources: {
321
+ ...manifest.sources ?? {},
322
+ "filesystem-values": filesystemValues,
323
+ "filesystem-secrets": filesystemSecrets,
324
+ dotenv
325
+ },
326
+ resolution: {
327
+ precedence: manifest.resolution?.precedence ?? [
328
+ "filesystem-values",
329
+ "filesystem-secrets",
330
+ "dotenv",
331
+ "process-env",
332
+ "cli-args"
333
+ ],
334
+ arrayPolicy: manifest.resolution?.arrayPolicy ?? "replace"
335
+ },
336
+ envMapping: {
337
+ ...manifest.envMapping?.convention ? {
338
+ convention: manifest.envMapping.convention
339
+ } : {},
340
+ explicit: manifest.envMapping?.explicit ?? {}
341
+ },
342
+ public: {
343
+ promote: manifest.public?.promote ?? [],
344
+ frameworks: {
345
+ ...DEFAULT_FRAMEWORK_PREFIXES,
346
+ ...manifest.public?.frameworks ?? {}
347
+ }
348
+ },
349
+ namespaces: normalizeNamespaces(manifest.namespaces),
350
+ vaults: normalizeVaults(manifest.vaults),
351
+ writePolicy: {
352
+ define: {
353
+ defaultProfile: manifest.writePolicy?.define?.defaultProfile ?? defaultProfile,
354
+ targets: {
355
+ value: manifest.writePolicy?.define?.targets?.value ?? "./values/app.yml",
356
+ secret: manifest.writePolicy?.define?.targets?.secret ?? "./secrets/app.yml"
357
+ }
358
+ }
359
+ },
360
+ schema: manifest.schema ?? {}
361
+ };
362
+ }
363
+
364
+ // ../core/src/manifest/loadManifest.ts
365
+ async function loadManifest(options = {}) {
366
+ const manifestRoot = await resolveManifestRoot(options.root);
367
+ const manifestPath = path2.join(manifestRoot, "cnos.yml");
368
+ let source;
369
+ try {
370
+ source = await readFile(manifestPath, "utf8");
371
+ } catch {
372
+ throw new CnosManifestError("Unable to read CNOS manifest", manifestPath);
373
+ }
374
+ const rawManifest = parseYaml(source);
375
+ if (!rawManifest || typeof rawManifest !== "object") {
376
+ throw new CnosManifestError("CNOS manifest must be a YAML object", manifestPath);
377
+ }
378
+ return {
379
+ manifestRoot,
380
+ repoRoot: path2.dirname(manifestRoot),
381
+ manifestPath,
382
+ manifest: normalizeManifest(rawManifest),
383
+ rawManifest
384
+ };
385
+ }
386
+
387
+ // ../core/src/promotions/validatePromotion.ts
388
+ var DEFAULT_DATA_NAMESPACE = {
389
+ kind: "data",
390
+ shareable: false
391
+ };
392
+ function getNamespaceNameForKey(key) {
393
+ const [namespace] = key.split(".");
394
+ if (!namespace || !key.includes(".")) {
395
+ throw new CnosManifestError(`Logical key must be namespace-qualified: ${key}`);
396
+ }
397
+ return namespace;
398
+ }
399
+ function getNamespaceDefinition(manifest, namespaceOrKey) {
400
+ const namespace = namespaceOrKey.includes(".") ? getNamespaceNameForKey(namespaceOrKey) : namespaceOrKey;
401
+ return manifest.namespaces[namespace] ?? DEFAULT_DATA_NAMESPACE;
402
+ }
403
+ function ensureProjectionAllowed(manifest, key, target) {
404
+ const namespace = getNamespaceNameForKey(key);
405
+ const definition = getNamespaceDefinition(manifest, namespace);
406
+ if (definition.kind !== "data") {
407
+ throw new CnosManifestError(
408
+ `Cannot promote ${key} to ${target} because namespace "${namespace}" is not a data namespace.`
409
+ );
410
+ }
411
+ if (definition.sensitive) {
412
+ throw new CnosSecurityError(
413
+ `Cannot promote ${key} to ${target} because namespace "${namespace}" is sensitive.`
414
+ );
415
+ }
416
+ if (!definition.shareable) {
417
+ throw new CnosSecurityError(
418
+ `Cannot promote ${key} to ${target} because namespace "${namespace}" is not shareable.`
419
+ );
420
+ }
421
+ }
422
+ function validateProjectionIssue(manifest, key, target) {
423
+ try {
424
+ ensureProjectionAllowed(manifest, key, target);
425
+ return void 0;
426
+ } catch (error) {
427
+ return {
428
+ code: target === "public" ? "public.invalid-promotion" : "env.invalid-mapping",
429
+ key,
430
+ message: error instanceof Error ? error.message : String(error)
431
+ };
432
+ }
433
+ }
434
+
435
+ // ../core/src/runtime/projection.ts
436
+ function setNestedValue(target, pathSegments, value) {
437
+ const [head, ...tail] = pathSegments;
438
+ if (!head) {
439
+ return;
440
+ }
441
+ if (tail.length === 0) {
442
+ target[head] = value;
443
+ return;
444
+ }
445
+ const current = target[head];
446
+ const nextTarget = current && typeof current === "object" && !Array.isArray(current) ? current : {};
447
+ target[head] = nextTarget;
448
+ setNestedValue(nextTarget, tail, value);
449
+ }
450
+ function toNamespaceObject(graph, namespace) {
451
+ const output = {};
452
+ const resolvedEntries = Array.from(graph.entries.values()).sort(
453
+ (left, right) => left.key.localeCompare(right.key)
454
+ );
455
+ for (const entry of resolvedEntries) {
456
+ if (namespace && entry.namespace !== namespace) {
457
+ continue;
458
+ }
459
+ const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
460
+ setNestedValue(output, valuePath.split("."), entry.value);
461
+ }
462
+ return output;
463
+ }
464
+
465
+ // ../core/src/runtime/read.ts
466
+ function readValue(graph, key) {
467
+ return graph.entries.get(key)?.value;
468
+ }
469
+
470
+ // ../core/src/runtime/readOr.ts
471
+ function readOrValue(graph, key, fallback) {
472
+ const value = readValue(graph, key);
473
+ return value === void 0 ? fallback : value;
474
+ }
475
+
476
+ // ../core/src/runtime/require.ts
477
+ function requireValue(graph, key) {
478
+ const value = readValue(graph, key);
479
+ if (value === void 0) {
480
+ throw new CnosKeyNotFoundError(key);
481
+ }
482
+ return value;
483
+ }
484
+
123
485
  // ../core/src/utils/secretStore.ts
124
486
  import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
125
- import { mkdir, readdir, readFile, writeFile } from "fs/promises";
126
- import path2 from "path";
487
+ import { mkdir, readdir, readFile as readFile2, writeFile } from "fs/promises";
488
+ import path3 from "path";
127
489
  function isObject(value) {
128
490
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
129
491
  }
@@ -131,13 +493,13 @@ function isSecretReference(value) {
131
493
  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));
132
494
  }
133
495
  function resolveSecretStoreRoot(processEnv = process.env) {
134
- return path2.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
496
+ return path3.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
135
497
  }
136
498
  function resolveSecretVaultFile(storeRoot, vault = "default") {
137
- return path2.join(storeRoot, "vaults", `${vault}.json`);
499
+ return path3.join(storeRoot, "vaults", `${vault}.json`);
138
500
  }
139
501
  function resolveSecretStoreFile(storeRoot, ref, vault = "default") {
140
- return path2.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
502
+ return path3.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
141
503
  }
142
504
  function deriveKey(passphrase, salt) {
143
505
  return scryptSync(passphrase, salt, 32);
@@ -146,6 +508,38 @@ function resolveSecretPassphrase(vault = "default", processEnv = process.env) {
146
508
  const vaultToken = vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
147
509
  return processEnv[`CNOS_SECRET_PASSPHRASE_${vaultToken}`] ?? processEnv.CNOS_SECRET_PASSPHRASE;
148
510
  }
511
+ function getVaultPassphraseEnvVar(vault = "default") {
512
+ const vaultToken = vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
513
+ return vaultToken && vaultToken !== "DEFAULT" ? `CNOS_SECRET_PASSPHRASE_${vaultToken}` : "CNOS_SECRET_PASSPHRASE";
514
+ }
515
+ function isPassphraseEnvRef(value) {
516
+ return typeof value === "string" && value.startsWith("env:") && value.length > 4;
517
+ }
518
+ function resolveConfiguredVaultPassphrase(definition, vault = "default", processEnv = process.env) {
519
+ if (definition?.provider !== "local") {
520
+ return void 0;
521
+ }
522
+ const passphraseRef = definition.passphrase;
523
+ if (typeof passphraseRef === "string" && passphraseRef.startsWith("env:") && passphraseRef.length > 4) {
524
+ return processEnv[passphraseRef.slice(4)];
525
+ }
526
+ if (passphraseRef) {
527
+ return passphraseRef;
528
+ }
529
+ return resolveSecretPassphrase(vault, processEnv);
530
+ }
531
+ function resolveVaultDefinition(vaults, vault = "default") {
532
+ const definition = vaults?.[vault];
533
+ const provider = definition?.provider ?? "local";
534
+ return {
535
+ name: vault,
536
+ provider,
537
+ ...definition?.passphrase ? {
538
+ passphrase: definition.passphrase
539
+ } : {},
540
+ requiresPassphrase: provider === "local"
541
+ };
542
+ }
149
543
  function encryptDocument(value, passphrase) {
150
544
  const salt = randomBytes(16);
151
545
  const iv = randomBytes(12);
@@ -176,7 +570,7 @@ function decryptDocument(document, passphrase) {
176
570
  async function createSecretVault(storeRoot, vault, passphrase) {
177
571
  const normalizedVault = vault.trim() || "default";
178
572
  const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
179
- await mkdir(path2.dirname(filePath), { recursive: true });
573
+ await mkdir(path3.dirname(filePath), { recursive: true });
180
574
  const document = {
181
575
  version: 1,
182
576
  name: normalizedVault,
@@ -190,7 +584,7 @@ async function ensureSecretVault(storeRoot, vault, passphrase) {
190
584
  const normalizedVault = vault.trim() || "default";
191
585
  const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
192
586
  try {
193
- await readFile(filePath, "utf8");
587
+ await readFile2(filePath, "utf8");
194
588
  return filePath;
195
589
  } catch (error) {
196
590
  if (error.code !== "ENOENT") {
@@ -200,7 +594,7 @@ async function ensureSecretVault(storeRoot, vault, passphrase) {
200
594
  return createSecretVault(storeRoot, normalizedVault, passphrase);
201
595
  }
202
596
  async function listSecretVaults(storeRoot) {
203
- const vaultRoot = path2.join(storeRoot, "vaults");
597
+ const vaultRoot = path3.join(storeRoot, "vaults");
204
598
  try {
205
599
  const entries = await readdir(vaultRoot, { withFileTypes: true });
206
600
  return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.replace(/\.json$/, "")).sort((left, right) => left.localeCompare(right));
@@ -211,7 +605,7 @@ async function listSecretVaults(storeRoot) {
211
605
  async function writeLocalSecret(storeRoot, ref, value, passphrase, vault = "default") {
212
606
  await ensureSecretVault(storeRoot, vault, passphrase);
213
607
  const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
214
- await mkdir(path2.dirname(filePath), { recursive: true });
608
+ await mkdir(path3.dirname(filePath), { recursive: true });
215
609
  await writeFile(filePath, JSON.stringify(encryptDocument(value, passphrase), null, 2), "utf8");
216
610
  return filePath;
217
611
  }
@@ -222,7 +616,7 @@ async function readLocalSecret(storeRoot, ref, passphrase, vault = "default") {
222
616
  );
223
617
  }
224
618
  const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
225
- const source = await readFile(filePath, "utf8");
619
+ const source = await readFile2(filePath, "utf8");
226
620
  const document = JSON.parse(source);
227
621
  if (document.version !== 1 || document.algorithm !== "aes-256-gcm" || typeof document.salt !== "string" || typeof document.iv !== "string" || typeof document.tag !== "string" || typeof document.ciphertext !== "string") {
228
622
  throw new CnosManifestError("Invalid local secret document", filePath);
@@ -254,6 +648,10 @@ function toEnv(graph, manifest, options = {}) {
254
648
  if (!entry) {
255
649
  continue;
256
650
  }
651
+ const namespaceDefinition = getNamespaceDefinition(manifest, entry.namespace);
652
+ if (namespaceDefinition.kind !== "data" || !namespaceDefinition.shareable || namespaceDefinition.sensitive) {
653
+ continue;
654
+ }
257
655
  if (entry.namespace === "secret" && !includeSecrets) {
258
656
  continue;
259
657
  }
@@ -265,64 +663,9 @@ function toEnv(graph, manifest, options = {}) {
265
663
  return output;
266
664
  }
267
665
 
268
- // ../core/src/utils/envNaming.ts
269
- function normalizeMappingConfig(config = {}) {
270
- return {
271
- convention: config.convention,
272
- explicit: config.explicit ?? {}
273
- };
274
- }
275
- function toScreamingSnakeSegment(segment) {
276
- return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
277
- }
278
- function toScreamingSnake(path8) {
279
- return path8.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
280
- }
281
- function fromScreamingSnake(path8) {
282
- return path8.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
283
- }
284
- function logicalKeyToEnvVar(key, config = {}) {
285
- const normalized = normalizeMappingConfig(config);
286
- const explicitEntry = Object.entries(normalized.explicit).find(([, logicalKey]) => logicalKey === key);
287
- if (explicitEntry) {
288
- return explicitEntry[0];
289
- }
290
- if (normalized.convention !== "SCREAMING_SNAKE") {
291
- return void 0;
292
- }
293
- if (key.startsWith("value.")) {
294
- return toScreamingSnake(key.slice("value.".length));
295
- }
296
- if (key.startsWith("secret.")) {
297
- return `SECRET_${toScreamingSnake(key.slice("secret.".length))}`;
298
- }
299
- return void 0;
300
- }
301
- function envVarToLogicalKey(envVar, config = {}) {
302
- const normalized = normalizeMappingConfig(config);
303
- const explicitMatch = normalized.explicit[envVar];
304
- if (explicitMatch) {
305
- return explicitMatch;
306
- }
307
- if (normalized.convention !== "SCREAMING_SNAKE") {
308
- return void 0;
309
- }
310
- if (envVar.startsWith("SECRET_")) {
311
- const stripped = envVar.slice("SECRET_".length);
312
- if (!stripped) {
313
- return void 0;
314
- }
315
- return `secret.${fromScreamingSnake(stripped)}`;
316
- }
317
- if (!/^[A-Z][A-Z0-9_]*$/.test(envVar)) {
318
- return void 0;
319
- }
320
- return `value.${fromScreamingSnake(envVar)}`;
321
- }
322
-
323
666
  // ../core/src/runtime/toPublicEnv.ts
324
- function fallbackValueEnvVar(key) {
325
- return key.replace(/^value\./, "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
667
+ function fallbackPublicEnvVar(valuePath) {
668
+ return valuePath.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
326
669
  }
327
670
  function normalizeEnvValue2(value) {
328
671
  if (value === void 0 || value === null) {
@@ -349,22 +692,12 @@ function resolvePublicPrefix(manifest, options) {
349
692
  }
350
693
  return configuredPrefix;
351
694
  }
352
- function ensurePublicPromotionKey(key) {
353
- if (!key.startsWith("value.")) {
354
- throw new CnosManifestError(`public.promote may only contain value.* keys: ${key}`);
355
- }
356
- }
357
695
  function toPublicEnv(graph, manifest, options = {}) {
358
696
  const prefix = resolvePublicPrefix(manifest, options);
359
697
  const output = {};
360
- const promotions = [...manifest.public.promote].sort((left, right) => left.localeCompare(right));
361
- for (const key of promotions) {
362
- ensurePublicPromotionKey(key);
363
- const resolved = graph.entries.get(key);
364
- if (!resolved) {
365
- continue;
366
- }
367
- const baseEnvVar = logicalKeyToEnvVar(key, manifest.envMapping) ?? fallbackValueEnvVar(key);
698
+ const promotions = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").sort((left, right) => left.key.localeCompare(right.key));
699
+ for (const resolved of promotions) {
700
+ const baseEnvVar = fallbackPublicEnvVar(stripNamespace(resolved.key));
368
701
  const envVar = prefix && !baseEnvVar.startsWith(prefix) ? `${prefix}${baseEnvVar}` : baseEnvVar;
369
702
  output[envVar] = normalizeEnvValue2(resolved.value);
370
703
  }
@@ -373,54 +706,22 @@ function toPublicEnv(graph, manifest, options = {}) {
373
706
 
374
707
  // ../core/src/runtime/dump.ts
375
708
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
376
- import path3 from "path";
377
-
378
- // ../core/src/runtime/projection.ts
379
- function setNestedValue(target, pathSegments, value) {
380
- const [head, ...tail] = pathSegments;
381
- if (!head) {
382
- return;
383
- }
384
- if (tail.length === 0) {
385
- target[head] = value;
386
- return;
387
- }
388
- const current = target[head];
389
- const nextTarget = current && typeof current === "object" && !Array.isArray(current) ? current : {};
390
- target[head] = nextTarget;
391
- setNestedValue(nextTarget, tail, value);
392
- }
393
- function toNamespaceObject(graph, namespace) {
394
- const output = {};
395
- const resolvedEntries = Array.from(graph.entries.values()).sort(
396
- (left, right) => left.key.localeCompare(right.key)
397
- );
398
- for (const entry of resolvedEntries) {
399
- if (namespace && entry.namespace !== namespace) {
400
- continue;
401
- }
402
- const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
403
- setNestedValue(output, valuePath.split("."), entry.value);
404
- }
405
- return output;
406
- }
407
-
408
- // ../core/src/runtime/dump.ts
709
+ import path4 from "path";
409
710
  function buildDumpFiles(graph, options = {}) {
410
- const basePath = options.flatten ? "" : path3.posix.join("workspaces", graph.workspace.workspaceId);
711
+ const basePath = options.flatten ? "" : path4.posix.join("workspaces", graph.workspace.workspaceId);
411
712
  const values = toNamespaceObject(graph, "value");
412
713
  const secrets = toNamespaceObject(graph, "secret");
413
714
  const files = [];
414
715
  if (Object.keys(values).length > 0) {
415
716
  files.push({
416
- path: path3.posix.join(basePath, "values", graph.profile, "app.yml"),
717
+ path: path4.posix.join(basePath, "values", graph.profile, "app.yml"),
417
718
  namespace: "value",
418
719
  content: stringifyYaml(values)
419
720
  });
420
721
  }
421
722
  if (Object.keys(secrets).length > 0) {
422
723
  files.push({
423
- path: path3.posix.join(basePath, "secrets", graph.profile, "app.yml"),
724
+ path: path4.posix.join(basePath, "secrets", graph.profile, "app.yml"),
424
725
  namespace: "secret",
425
726
  content: stringifyYaml(secrets)
426
727
  });
@@ -436,11 +737,11 @@ function planDump(graph, options = {}) {
436
737
  };
437
738
  }
438
739
  async function writeDump(graph, options) {
439
- const root = path3.resolve(options.to);
740
+ const root = path4.resolve(options.to);
440
741
  const plan = planDump(graph, options);
441
742
  for (const file of plan.files) {
442
- const destination = path3.join(root, file.path);
443
- await mkdir2(path3.dirname(destination), { recursive: true });
743
+ const destination = path4.join(root, file.path);
744
+ await mkdir2(path4.dirname(destination), { recursive: true });
444
745
  await writeFile2(destination, file.content, "utf8");
445
746
  }
446
747
  return {
@@ -457,9 +758,64 @@ function flattenObject(value, prefix = "") {
457
758
  Object.assign(accumulator, flattenObject(nestedValue, nextKey));
458
759
  return accumulator;
459
760
  }
460
- accumulator[nextKey] = nestedValue;
461
- return accumulator;
462
- }, {});
761
+ accumulator[nextKey] = nestedValue;
762
+ return accumulator;
763
+ }, {});
764
+ }
765
+
766
+ // ../core/src/utils/envNaming.ts
767
+ function normalizeMappingConfig(config = {}) {
768
+ return {
769
+ convention: config.convention,
770
+ explicit: config.explicit ?? {}
771
+ };
772
+ }
773
+ function toScreamingSnakeSegment(segment) {
774
+ return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
775
+ }
776
+ function toScreamingSnake(path8) {
777
+ return path8.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
778
+ }
779
+ function fromScreamingSnake(path8) {
780
+ return path8.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
781
+ }
782
+ function logicalKeyToEnvVar(key, config = {}) {
783
+ const normalized = normalizeMappingConfig(config);
784
+ const explicitEntry = Object.entries(normalized.explicit).find(([, logicalKey]) => logicalKey === key);
785
+ if (explicitEntry) {
786
+ return explicitEntry[0];
787
+ }
788
+ if (normalized.convention !== "SCREAMING_SNAKE") {
789
+ return void 0;
790
+ }
791
+ if (key.startsWith("value.")) {
792
+ return toScreamingSnake(key.slice("value.".length));
793
+ }
794
+ if (key.startsWith("secret.")) {
795
+ return `SECRET_${toScreamingSnake(key.slice("secret.".length))}`;
796
+ }
797
+ return void 0;
798
+ }
799
+ function envVarToLogicalKey(envVar, config = {}) {
800
+ const normalized = normalizeMappingConfig(config);
801
+ const explicitMatch = normalized.explicit[envVar];
802
+ if (explicitMatch) {
803
+ return explicitMatch;
804
+ }
805
+ if (normalized.convention !== "SCREAMING_SNAKE") {
806
+ return void 0;
807
+ }
808
+ if (envVar.startsWith("SECRET_")) {
809
+ const stripped = envVar.slice("SECRET_".length);
810
+ if (!stripped) {
811
+ return void 0;
812
+ }
813
+ return `secret.${fromScreamingSnake(stripped)}`;
814
+ }
815
+ if (!/^[A-Z][A-Z0-9_]*$/.test(envVar)) {
816
+ return void 0;
817
+ }
818
+ return `value.${fromScreamingSnake(envVar)}`;
463
819
  }
464
820
 
465
821
  // ../core/src/validation/envMapping.ts
@@ -475,7 +831,8 @@ function validateEnvMappingCollisions(manifest, graph) {
475
831
  ]);
476
832
  const collisions = /* @__PURE__ */ new Map();
477
833
  for (const key of candidates) {
478
- if (key.startsWith("meta.")) {
834
+ const definition = getNamespaceDefinition(manifest, key);
835
+ if (definition.kind !== "data") {
479
836
  continue;
480
837
  }
481
838
  const envVar = logicalKeyToEnvVar(key, manifest.envMapping) ?? (key.startsWith("value.") || key.startsWith("secret.") ? fallbackLogicalKeyToEnvVar(key) : void 0);
@@ -494,11 +851,7 @@ function validateEnvMappingCollisions(manifest, graph) {
494
851
 
495
852
  // ../core/src/validation/publicSafety.ts
496
853
  function validatePublicSafety(manifest) {
497
- return manifest.public.promote.filter((key) => !key.startsWith("value.")).map((key) => ({
498
- code: "public.invalid-promotion",
499
- key,
500
- message: `public.promote may only include value.* keys: ${key}`
501
- }));
854
+ return manifest.public.promote.map((key) => validateProjectionIssue(manifest, key, "public")).filter((issue) => Boolean(issue));
502
855
  }
503
856
 
504
857
  // ../core/src/validation/workspaceSafety.ts
@@ -564,39 +917,6 @@ async function validateRuntime(runtime) {
564
917
  };
565
918
  }
566
919
 
567
- // ../core/src/runtime/inspect.ts
568
- function inspectValue(graph, key) {
569
- const entry = graph.entries.get(key);
570
- if (!entry) {
571
- throw new CnosKeyNotFoundError(key);
572
- }
573
- return {
574
- key: entry.key,
575
- value: entry.value,
576
- namespace: entry.namespace,
577
- profile: graph.profile,
578
- profileSource: graph.profileSource,
579
- workspace: {
580
- id: graph.workspace.workspaceId,
581
- source: graph.workspace.workspaceSource,
582
- chain: graph.workspace.workspaceChain
583
- },
584
- winner: {
585
- sourceId: entry.winner.sourceId,
586
- pluginId: entry.winner.pluginId,
587
- workspaceId: entry.winner.workspaceId,
588
- ...entry.winner.origin ? { origin: entry.winner.origin } : {}
589
- },
590
- overridden: entry.overridden.map((override) => ({
591
- sourceId: override.sourceId,
592
- pluginId: override.pluginId,
593
- workspaceId: override.workspaceId,
594
- value: override.value,
595
- ...override.origin ? { origin: override.origin } : {}
596
- }))
597
- };
598
- }
599
-
600
920
  // ../core/src/inspectors/provenance.ts
601
921
  function createProvenanceInspector() {
602
922
  return {
@@ -608,167 +928,6 @@ function createProvenanceInspector() {
608
928
  };
609
929
  }
610
930
 
611
- // ../core/src/manifest/loadManifest.ts
612
- import { readFile as readFile2 } from "fs/promises";
613
- import path4 from "path";
614
-
615
- // ../core/src/manifest/normalizeManifest.ts
616
- var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
617
- var DEFAULT_LOADERS = [
618
- "filesystem-values",
619
- "filesystem-secrets",
620
- "dotenv",
621
- "process-env",
622
- "cli-args"
623
- ];
624
- var DEFAULT_VALIDATORS = ["basic-schema"];
625
- var DEFAULT_EXPORTERS = ["env", "public-env"];
626
- var DEFAULT_INSPECTORS = ["provenance"];
627
- var DEFAULT_FRAMEWORK_PREFIXES = {
628
- next: "NEXT_PUBLIC_",
629
- vite: "VITE_",
630
- nuxt: "NUXT_PUBLIC_"
631
- };
632
- function validateResolveFrom(resolveFrom) {
633
- const validValues = ["cli.profile", "env.CNOS_PROFILE", "default"];
634
- for (const entry of resolveFrom) {
635
- if (!validValues.includes(entry)) {
636
- throw new CnosManifestError(`Unsupported profiles.resolveFrom entry: ${entry}`);
637
- }
638
- }
639
- return resolveFrom;
640
- }
641
- function normalizeWorkspaceItems(items) {
642
- return Object.fromEntries(
643
- Object.entries(items ?? {}).map(([workspaceId, item]) => [
644
- workspaceId,
645
- {
646
- extends: Array.isArray(item?.extends) ? item.extends.map((entry) => entry.trim()).filter(Boolean) : item?.extends ? [item.extends.trim()].filter(Boolean) : [],
647
- ...item?.globalId?.trim() ? { globalId: item.globalId.trim() } : {}
648
- }
649
- ])
650
- );
651
- }
652
- function normalizeManifest(manifest) {
653
- const version = manifest.version ?? 1;
654
- if (version !== 1) {
655
- throw new CnosManifestError(`Unsupported CNOS manifest version: ${version}`);
656
- }
657
- const projectName = manifest.project?.name?.trim();
658
- if (!projectName) {
659
- throw new CnosManifestError("Manifest requires project.name");
660
- }
661
- const defaultProfile = manifest.profiles?.default?.trim() || "base";
662
- const workspaceItems = normalizeWorkspaceItems(manifest.workspaces?.items);
663
- const resolveFrom = validateResolveFrom(manifest.profiles?.resolveFrom ?? DEFAULT_RESOLVE_FROM);
664
- const filesystemValues = {
665
- root: "./",
666
- format: "yaml",
667
- ...manifest.sources?.["filesystem-values"] ?? {}
668
- };
669
- const filesystemSecrets = {
670
- root: "./",
671
- format: "yaml",
672
- ...manifest.sources?.["filesystem-secrets"] ?? {}
673
- };
674
- const dotenv = {
675
- root: "./env",
676
- ...manifest.sources?.dotenv ?? {}
677
- };
678
- return {
679
- version: 1,
680
- project: {
681
- name: projectName
682
- },
683
- workspaces: {
684
- ...manifest.workspaces?.default?.trim() ? {
685
- default: manifest.workspaces.default.trim()
686
- } : {},
687
- global: {
688
- enabled: manifest.workspaces?.global?.enabled ?? false,
689
- ...manifest.workspaces?.global?.root?.trim() ? {
690
- root: manifest.workspaces.global.root.trim()
691
- } : {},
692
- allowWrite: manifest.workspaces?.global?.allowWrite ?? false
693
- },
694
- items: workspaceItems
695
- },
696
- profiles: {
697
- default: defaultProfile,
698
- resolveFrom
699
- },
700
- plugins: {
701
- loaders: manifest.plugins?.loaders ?? DEFAULT_LOADERS,
702
- resolver: manifest.plugins?.resolver ?? "profile-aware",
703
- validators: manifest.plugins?.validators ?? DEFAULT_VALIDATORS,
704
- exporters: manifest.plugins?.exporters ?? DEFAULT_EXPORTERS,
705
- inspectors: manifest.plugins?.inspectors ?? DEFAULT_INSPECTORS
706
- },
707
- sources: {
708
- ...manifest.sources ?? {},
709
- "filesystem-values": filesystemValues,
710
- "filesystem-secrets": filesystemSecrets,
711
- dotenv
712
- },
713
- resolution: {
714
- precedence: manifest.resolution?.precedence ?? [
715
- "filesystem-values",
716
- "filesystem-secrets",
717
- "dotenv",
718
- "process-env",
719
- "cli-args"
720
- ],
721
- arrayPolicy: manifest.resolution?.arrayPolicy ?? "replace"
722
- },
723
- envMapping: {
724
- ...manifest.envMapping?.convention ? {
725
- convention: manifest.envMapping.convention
726
- } : {},
727
- explicit: manifest.envMapping?.explicit ?? {}
728
- },
729
- public: {
730
- promote: manifest.public?.promote ?? [],
731
- frameworks: {
732
- ...DEFAULT_FRAMEWORK_PREFIXES,
733
- ...manifest.public?.frameworks ?? {}
734
- }
735
- },
736
- writePolicy: {
737
- define: {
738
- defaultProfile: manifest.writePolicy?.define?.defaultProfile ?? defaultProfile,
739
- targets: {
740
- value: manifest.writePolicy?.define?.targets?.value ?? "./values/app.yml",
741
- secret: manifest.writePolicy?.define?.targets?.secret ?? "./secrets/app.yml"
742
- }
743
- }
744
- },
745
- schema: manifest.schema ?? {}
746
- };
747
- }
748
-
749
- // ../core/src/manifest/loadManifest.ts
750
- async function loadManifest(options = {}) {
751
- const manifestRoot = await resolveManifestRoot(options.root);
752
- const manifestPath = path4.join(manifestRoot, "cnos.yml");
753
- let source;
754
- try {
755
- source = await readFile2(manifestPath, "utf8");
756
- } catch {
757
- throw new CnosManifestError("Unable to read CNOS manifest", manifestPath);
758
- }
759
- const rawManifest = parseYaml(source);
760
- if (!rawManifest || typeof rawManifest !== "object") {
761
- throw new CnosManifestError("CNOS manifest must be a YAML object", manifestPath);
762
- }
763
- return {
764
- manifestRoot,
765
- repoRoot: path4.dirname(manifestRoot),
766
- manifestPath,
767
- manifest: normalizeManifest(rawManifest),
768
- rawManifest
769
- };
770
- }
771
-
772
931
  // ../core/src/manifest/loadWorkspaceFile.ts
773
932
  import { readFile as readFile3 } from "fs/promises";
774
933
  import path5 from "path";
@@ -936,6 +1095,50 @@ async function expandProfileChain(activeProfile, options = {}) {
936
1095
  };
937
1096
  }
938
1097
 
1098
+ // ../core/src/promotions/promoteToPublic.ts
1099
+ function toPublicKey(key) {
1100
+ const namespace = getNamespaceNameForKey(key);
1101
+ return namespace === "value" ? `public.${stripNamespace(key)}` : `public.${key}`;
1102
+ }
1103
+ function toPromotedConfigEntry(entry, key, promotedFrom) {
1104
+ return {
1105
+ ...entry,
1106
+ key,
1107
+ namespace: "public",
1108
+ sourceId: "public-promote",
1109
+ pluginId: "core",
1110
+ metadata: {
1111
+ ...entry.metadata ?? {},
1112
+ promotedFrom
1113
+ }
1114
+ };
1115
+ }
1116
+ function toPromotedResolvedEntry(entry) {
1117
+ const key = toPublicKey(entry.key);
1118
+ return {
1119
+ key,
1120
+ value: entry.value,
1121
+ namespace: "public",
1122
+ winner: toPromotedConfigEntry(entry.winner, key, entry.key),
1123
+ overridden: entry.overridden.map((override) => toPromotedConfigEntry(override, key, entry.key))
1124
+ };
1125
+ }
1126
+ function promoteToPublic(graph, manifest) {
1127
+ const entries = new Map(graph.entries);
1128
+ for (const key of manifest.public.promote) {
1129
+ ensureProjectionAllowed(manifest, key, "public");
1130
+ const resolved = graph.entries.get(key);
1131
+ if (!resolved) {
1132
+ continue;
1133
+ }
1134
+ entries.set(toPublicKey(key), toPromotedResolvedEntry(resolved));
1135
+ }
1136
+ return {
1137
+ ...graph,
1138
+ entries
1139
+ };
1140
+ }
1141
+
939
1142
  // ../core/src/profiles/resolveActiveProfile.ts
940
1143
  function resolveActiveProfile(manifest, options = {}) {
941
1144
  for (const source of manifest.profiles.resolveFrom) {
@@ -1370,26 +1573,6 @@ async function runPipeline(options) {
1370
1573
  return collectedEntries.flat();
1371
1574
  }
1372
1575
 
1373
- // ../core/src/runtime/read.ts
1374
- function readValue(graph, key) {
1375
- return graph.entries.get(key)?.value;
1376
- }
1377
-
1378
- // ../core/src/runtime/readOr.ts
1379
- function readOrValue(graph, key, fallback) {
1380
- const value = readValue(graph, key);
1381
- return value === void 0 ? fallback : value;
1382
- }
1383
-
1384
- // ../core/src/runtime/require.ts
1385
- function requireValue(graph, key) {
1386
- const value = readValue(graph, key);
1387
- if (value === void 0) {
1388
- throw new CnosKeyNotFoundError(key);
1389
- }
1390
- return value;
1391
- }
1392
-
1393
1576
  // ../core/src/orchestrator/runtime.ts
1394
1577
  function createRuntime(manifest, graph, plugins = []) {
1395
1578
  return {
@@ -1527,6 +1710,9 @@ function appendMetaEntries(graph, cnosVersion) {
1527
1710
  }
1528
1711
  async function createCnos(options = {}) {
1529
1712
  const loadedManifest = await loadManifest(options.root ? { root: options.root } : {});
1713
+ for (const key of loadedManifest.manifest.public.promote) {
1714
+ ensureProjectionAllowed(loadedManifest.manifest, key, "public");
1715
+ }
1530
1716
  const workspaceFile = await loadWorkspaceFile(loadedManifest.repoRoot);
1531
1717
  const workspace = await resolveWorkspaceContext(loadedManifest.manifest, {
1532
1718
  manifestRoot: loadedManifest.manifestRoot,
@@ -1566,10 +1752,11 @@ async function createCnos(options = {}) {
1566
1752
  workspace
1567
1753
  });
1568
1754
  const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
1755
+ const promotedGraph = promoteToPublic(schemaApplied.graph, loadedManifest.manifest);
1569
1756
  return createRuntime(
1570
1757
  loadedManifest.manifest,
1571
1758
  appendMetaEntries({
1572
- ...schemaApplied.graph,
1759
+ ...promotedGraph,
1573
1760
  profileSource: activeProfile.source
1574
1761
  }, options.cnosVersion),
1575
1762
  plugins
@@ -1578,28 +1765,42 @@ async function createCnos(options = {}) {
1578
1765
 
1579
1766
  export {
1580
1767
  CnosManifestError,
1768
+ CnosSecurityError,
1769
+ inspectValue,
1581
1770
  createProvenanceInspector,
1771
+ resolveManifestRoot,
1582
1772
  resolveWorkspaceScopedPath,
1583
1773
  resolveConfigDocumentPath,
1584
1774
  toPortablePath,
1585
1775
  joinConfigPath,
1776
+ toLogicalKey,
1586
1777
  parseYaml,
1587
1778
  stringifyYaml,
1779
+ loadManifest,
1780
+ ensureProjectionAllowed,
1588
1781
  applySchemaRules,
1782
+ toNamespaceObject,
1783
+ readValue,
1784
+ readOrValue,
1785
+ requireValue,
1589
1786
  isSecretReference,
1590
1787
  resolveSecretStoreRoot,
1591
1788
  resolveSecretVaultFile,
1592
1789
  resolveSecretPassphrase,
1790
+ getVaultPassphraseEnvVar,
1791
+ isPassphraseEnvRef,
1792
+ resolveConfiguredVaultPassphrase,
1793
+ resolveVaultDefinition,
1593
1794
  createSecretVault,
1594
1795
  listSecretVaults,
1595
1796
  writeLocalSecret,
1596
1797
  readLocalSecret,
1597
1798
  toEnv,
1598
- envVarToLogicalKey,
1599
1799
  toPublicEnv,
1600
1800
  createCnos,
1601
1801
  planDump,
1602
1802
  writeDump,
1803
+ envVarToLogicalKey,
1603
1804
  flattenObject,
1604
1805
  validateRuntime
1605
1806
  };