@kitsy/cnos 1.5.0 → 1.6.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 (62) hide show
  1. package/dist/build/index.cjs +333 -117
  2. package/dist/build/index.d.cts +3 -2
  3. package/dist/build/index.d.ts +3 -2
  4. package/dist/build/index.js +13 -8
  5. package/dist/{chunk-HMM76UYZ.js → chunk-BMAD24KC.js} +1 -1
  6. package/dist/{chunk-ZTPSFXWP.js → chunk-JYWQFMW5.js} +1 -1
  7. package/dist/{chunk-FWJC4Y2D.js → chunk-MW4OVAT3.js} +1 -1
  8. package/dist/chunk-QU5CXL47.js +577 -0
  9. package/dist/{chunk-APIU4GTB.js → chunk-S7H2UULC.js} +315 -107
  10. package/dist/{chunk-WCHX2QFY.js → chunk-UJBQS7CJ.js} +1 -1
  11. package/dist/{chunk-RYGSG3GR.js → chunk-UOKVLCFL.js} +10 -10
  12. package/dist/{chunk-T6Y57KTT.js → chunk-UR7CHHNN.js} +1 -1
  13. package/dist/{chunk-J4K4JUJL.js → chunk-VGZREX5D.js} +1 -1
  14. package/dist/{chunk-EQSKV3DP.js → chunk-XSUP7JKH.js} +23 -1
  15. package/dist/configure/index.cjs +332 -122
  16. package/dist/configure/index.d.cts +3 -3
  17. package/dist/configure/index.d.ts +3 -3
  18. package/dist/configure/index.js +8 -8
  19. package/dist/{envNaming-Dvm_LP2D.d.ts → envNaming-B7Mztkcf.d.ts} +1 -1
  20. package/dist/{envNaming-S4B-dHUx.d.cts → envNaming-gMVnPOfe.d.cts} +1 -1
  21. package/dist/index.cjs +754 -143
  22. package/dist/index.d.cts +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +10 -10
  25. package/dist/internal.cjs +229 -103
  26. package/dist/internal.d.cts +16 -28
  27. package/dist/internal.d.ts +16 -28
  28. package/dist/internal.js +11 -3
  29. package/dist/plugin/basic-schema.cjs +22 -15
  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.cjs +27 -18
  34. package/dist/plugin/cli-args.d.cts +1 -1
  35. package/dist/plugin/cli-args.d.ts +1 -1
  36. package/dist/plugin/cli-args.js +2 -2
  37. package/dist/plugin/dotenv.cjs +35 -26
  38. package/dist/plugin/dotenv.d.cts +2 -2
  39. package/dist/plugin/dotenv.d.ts +2 -2
  40. package/dist/plugin/dotenv.js +2 -2
  41. package/dist/plugin/env-export.cjs +34 -22
  42. package/dist/plugin/env-export.d.cts +2 -2
  43. package/dist/plugin/env-export.d.ts +2 -2
  44. package/dist/plugin/env-export.js +2 -2
  45. package/dist/plugin/filesystem.cjs +42 -33
  46. package/dist/plugin/filesystem.d.cts +1 -1
  47. package/dist/plugin/filesystem.d.ts +1 -1
  48. package/dist/plugin/filesystem.js +2 -2
  49. package/dist/plugin/process-env.cjs +24 -17
  50. package/dist/plugin/process-env.d.cts +2 -2
  51. package/dist/plugin/process-env.d.ts +2 -2
  52. package/dist/plugin/process-env.js +2 -2
  53. package/dist/{plugin-B4xwySxw.d.cts → plugin-CKrBlWGI.d.cts} +52 -3
  54. package/dist/{plugin-B4xwySxw.d.ts → plugin-CKrBlWGI.d.ts} +52 -3
  55. package/dist/runtime/index.cjs +752 -143
  56. package/dist/runtime/index.d.cts +19 -1
  57. package/dist/runtime/index.d.ts +19 -1
  58. package/dist/runtime/index.js +10 -10
  59. package/dist/{toPublicEnv-ggmphZFs.d.cts → toPublicEnv-CmBsy53P.d.cts} +1 -1
  60. package/dist/{toPublicEnv-CvhGAfsB.d.ts → toPublicEnv-q6VwWxXZ.d.ts} +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-TO76YYS4.js +0 -189
@@ -12,6 +12,11 @@ var CnosManifestError = class extends CnosError {
12
12
  }
13
13
  manifestPath;
14
14
  };
15
+ var CnosDiscoveryError = class extends CnosError {
16
+ constructor(message) {
17
+ super(message);
18
+ }
19
+ };
15
20
  var CnosSecurityError = class extends CnosError {
16
21
  constructor(message) {
17
22
  super(message);
@@ -169,29 +174,105 @@ async function writeKeychain(entry, value) {
169
174
  throw new CnosAuthenticationError(`OS keychain is not supported on platform "${process.platform}".`);
170
175
  }
171
176
 
177
+ // ../core/src/utils/yaml.ts
178
+ import { parse, stringify } from "yaml";
179
+ function parseYaml(source) {
180
+ return parse(source);
181
+ }
182
+ function stringifyYaml(value) {
183
+ return stringify(value);
184
+ }
185
+
172
186
  // ../core/src/utils/path.ts
173
- import { access } from "fs/promises";
187
+ import { access as access2 } from "fs/promises";
174
188
  import os from "os";
189
+ import path2 from "path";
190
+
191
+ // ../core/src/discovery/findCnosrc.ts
192
+ import { access, readFile } from "fs/promises";
175
193
  import path from "path";
194
+ async function exists(targetPath) {
195
+ try {
196
+ await access(targetPath);
197
+ return true;
198
+ } catch {
199
+ return false;
200
+ }
201
+ }
202
+ function validateCnosrc(value, filePath) {
203
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
204
+ throw new CnosManifestError(".cnosrc.yml must be a YAML object", filePath);
205
+ }
206
+ const root = typeof value.root === "string" ? value.root.trim() : "";
207
+ const workspace = typeof value.workspace === "string" ? value.workspace.trim() : void 0;
208
+ if (!root) {
209
+ throw new CnosManifestError(".cnosrc.yml requires root", filePath);
210
+ }
211
+ return {
212
+ root,
213
+ ...workspace ? { workspace } : {}
214
+ };
215
+ }
216
+ async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
217
+ let current = path.resolve(startDir);
218
+ for (let depth = 0; depth <= maxLevels; depth += 1) {
219
+ const candidate = path.join(current, ".cnosrc.yml");
220
+ if (await exists(candidate)) {
221
+ return candidate;
222
+ }
223
+ const parent = path.dirname(current);
224
+ if (parent === current) {
225
+ break;
226
+ }
227
+ current = parent;
228
+ }
229
+ return void 0;
230
+ }
231
+ async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3) {
232
+ const anchorPath = await findCnosrc(startDir, maxLevels);
233
+ if (!anchorPath) {
234
+ throw new CnosDiscoveryError(
235
+ "No .cnosrc.yml found. Run cnos init or create .cnosrc.yml in your package root."
236
+ );
237
+ }
238
+ const source = await readFile(anchorPath, "utf8");
239
+ const parsed = validateCnosrc(parseYaml(source), anchorPath);
240
+ const consumerRoot = path.dirname(anchorPath);
241
+ const manifestRoot = path.resolve(consumerRoot, parsed.root);
242
+ const manifestPath = path.join(manifestRoot, "cnos.yml");
243
+ if (!await exists(manifestPath)) {
244
+ throw new CnosDiscoveryError(
245
+ `.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`
246
+ );
247
+ }
248
+ return {
249
+ anchorPath,
250
+ consumerRoot,
251
+ manifestRoot,
252
+ ...parsed.workspace ? { workspace: parsed.workspace } : {}
253
+ };
254
+ }
255
+
256
+ // ../core/src/utils/path.ts
176
257
  var PRIMARY_CNOS_DIR = ".cnos";
177
258
  var LEGACY_CNOS_DIR = "cnos";
178
- async function exists(filePath) {
259
+ async function exists2(filePath) {
179
260
  try {
180
- await access(filePath);
261
+ await access2(filePath);
181
262
  return true;
182
263
  } catch {
183
264
  return false;
184
265
  }
185
266
  }
186
267
  async function resolveCnosRoot(root = process.cwd()) {
187
- const basePath = path.resolve(root);
268
+ const basePath = path2.resolve(root);
188
269
  const candidates = [
189
- path.join(basePath, PRIMARY_CNOS_DIR),
190
- path.join(basePath, LEGACY_CNOS_DIR),
270
+ path2.join(basePath, PRIMARY_CNOS_DIR),
271
+ path2.join(basePath, LEGACY_CNOS_DIR),
191
272
  basePath
192
273
  ];
193
274
  for (const candidate of candidates) {
194
- if (await exists(path.join(candidate, "cnos.yml"))) {
275
+ if (await exists2(path2.join(candidate, "cnos.yml"))) {
195
276
  return candidate;
196
277
  }
197
278
  }
@@ -199,8 +280,23 @@ async function resolveCnosRoot(root = process.cwd()) {
199
280
  `Could not locate .cnos/cnos.yml or cnos/cnos.yml from root: ${basePath}`
200
281
  );
201
282
  }
202
- async function resolveManifestRoot(root = process.cwd()) {
203
- return resolveCnosRoot(root);
283
+ async function resolveManifestRoot(options = {}) {
284
+ if (options.root) {
285
+ const manifestRoot = await resolveCnosRoot(options.root);
286
+ const resolvedRoot = path2.resolve(options.root);
287
+ const consumerRoot = path2.basename(manifestRoot) === PRIMARY_CNOS_DIR || path2.basename(manifestRoot) === LEGACY_CNOS_DIR ? path2.dirname(manifestRoot) : resolvedRoot;
288
+ return {
289
+ manifestRoot,
290
+ consumerRoot
291
+ };
292
+ }
293
+ const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd());
294
+ return {
295
+ manifestRoot: discovered.manifestRoot,
296
+ consumerRoot: discovered.consumerRoot,
297
+ anchorPath: discovered.anchorPath,
298
+ ...discovered.workspace ? { workspace: discovered.workspace } : {}
299
+ };
204
300
  }
205
301
  function interpolatePathTemplate(template, tokens) {
206
302
  return Object.entries(tokens).reduce(
@@ -213,7 +309,7 @@ function expandHomePath(targetPath) {
213
309
  return os.homedir();
214
310
  }
215
311
  if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
216
- return path.join(os.homedir(), targetPath.slice(2));
312
+ return path2.join(os.homedir(), targetPath.slice(2));
217
313
  }
218
314
  return targetPath;
219
315
  }
@@ -231,19 +327,19 @@ function stripWorkspaceTemplatePrefix(template) {
231
327
  function resolveWorkspaceScopedPath(workspaceRoot, template, tokens) {
232
328
  const relativeTemplate = stripWorkspaceTemplatePrefix(template);
233
329
  const interpolated = interpolatePathTemplate(relativeTemplate, tokens);
234
- return path.resolve(workspaceRoot, interpolated);
330
+ return path2.resolve(workspaceRoot, interpolated);
235
331
  }
236
332
  function resolveNamespaceDirectory(workspaceRoot, namespace, profile) {
237
333
  const rootFolder = namespace === "value" ? "values" : namespace === "secret" ? "secrets" : namespace;
238
334
  if (profile && profile !== "base") {
239
- return path.resolve(workspaceRoot, "profiles", profile, rootFolder);
335
+ return path2.resolve(workspaceRoot, "profiles", profile, rootFolder);
240
336
  }
241
- return path.resolve(workspaceRoot, rootFolder);
337
+ return path2.resolve(workspaceRoot, rootFolder);
242
338
  }
243
339
  function resolveConfigDocumentPath(workspaceRoot, namespace, configPath, profile) {
244
340
  const namespaceRoot = resolveNamespaceDirectory(workspaceRoot, namespace, profile);
245
341
  const fileName = `${configPath.split(".").shift() ?? "app"}.yml`;
246
- return path.resolve(namespaceRoot, fileName);
342
+ return path2.resolve(namespaceRoot, fileName);
247
343
  }
248
344
  function toPortablePath(targetPath) {
249
345
  return targetPath.replace(/\\/g, "/");
@@ -258,18 +354,9 @@ function stripNamespace(key) {
258
354
  return key.split(".").slice(1).join(".");
259
355
  }
260
356
 
261
- // ../core/src/utils/yaml.ts
262
- import { parse, stringify } from "yaml";
263
- function parseYaml(source) {
264
- return parse(source);
265
- }
266
- function stringifyYaml(value) {
267
- return stringify(value);
268
- }
269
-
270
357
  // ../core/src/manifest/loadManifest.ts
271
- import { readFile } from "fs/promises";
272
- import path2 from "path";
358
+ import { readFile as readFile2 } from "fs/promises";
359
+ import path3 from "path";
273
360
 
274
361
  // ../core/src/manifest/normalizeManifest.ts
275
362
  var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
@@ -286,7 +373,8 @@ var DEFAULT_INSPECTORS = ["provenance"];
286
373
  var DEFAULT_FRAMEWORK_PREFIXES = {
287
374
  next: "NEXT_PUBLIC_",
288
375
  vite: "VITE_",
289
- nuxt: "NUXT_PUBLIC_"
376
+ nuxt: "NUXT_PUBLIC_",
377
+ webpack: ""
290
378
  };
291
379
  var DEFAULT_NAMESPACES = {
292
380
  value: {
@@ -539,11 +627,15 @@ function normalizeManifest(manifest) {
539
627
 
540
628
  // ../core/src/manifest/loadManifest.ts
541
629
  async function loadManifest(options = {}) {
542
- const manifestRoot = await resolveManifestRoot(options.root);
543
- const manifestPath = path2.join(manifestRoot, "cnos.yml");
630
+ const resolved = await resolveManifestRoot({
631
+ ...options.root ? { root: options.root } : {},
632
+ ...options.cwd ? { cwd: options.cwd } : {}
633
+ });
634
+ const manifestRoot = resolved.manifestRoot;
635
+ const manifestPath = path3.join(manifestRoot, "cnos.yml");
544
636
  let source;
545
637
  try {
546
- source = await readFile(manifestPath, "utf8");
638
+ source = await readFile2(manifestPath, "utf8");
547
639
  } catch {
548
640
  throw new CnosManifestError("Unable to read CNOS manifest", manifestPath);
549
641
  }
@@ -553,7 +645,10 @@ async function loadManifest(options = {}) {
553
645
  }
554
646
  return {
555
647
  manifestRoot,
556
- repoRoot: path2.dirname(manifestRoot),
648
+ repoRoot: path3.dirname(manifestRoot),
649
+ consumerRoot: resolved.consumerRoot,
650
+ ...resolved.anchorPath ? { anchorPath: resolved.anchorPath } : {},
651
+ ...resolved.workspace ? { anchoredWorkspace: resolved.workspace } : {},
557
652
  manifestPath,
558
653
  manifest: normalizeManifest(rawManifest),
559
654
  rawManifest
@@ -609,17 +704,17 @@ function validateProjectionIssue(manifest, key, target) {
609
704
  }
610
705
 
611
706
  // ../core/src/secrets/sessionStore.ts
612
- import { mkdir, readFile as readFile2, readdir, rm, writeFile } from "fs/promises";
613
- import path3 from "path";
707
+ import { mkdir, readFile as readFile3, readdir, rm, writeFile } from "fs/promises";
708
+ import path4 from "path";
614
709
  function buildSessionRoot(processEnv = process.env) {
615
- return path3.join(path3.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
710
+ return path4.join(path4.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
616
711
  }
617
712
  function buildSessionPath(vault, processEnv) {
618
- return path3.join(buildSessionRoot(processEnv), `${vault}.json`);
713
+ return path4.join(buildSessionRoot(processEnv), `${vault}.json`);
619
714
  }
620
715
  async function writeVaultSessionKey(vault, derivedKey, processEnv) {
621
716
  const filePath = buildSessionPath(vault, processEnv);
622
- await mkdir(path3.dirname(filePath), { recursive: true });
717
+ await mkdir(path4.dirname(filePath), { recursive: true });
623
718
  const document = {
624
719
  version: 1,
625
720
  vault,
@@ -631,7 +726,7 @@ async function writeVaultSessionKey(vault, derivedKey, processEnv) {
631
726
  }
632
727
  async function readVaultSessionKey(vault, processEnv) {
633
728
  try {
634
- const source = await readFile2(buildSessionPath(vault, processEnv), "utf8");
729
+ const source = await readFile3(buildSessionPath(vault, processEnv), "utf8");
635
730
  const document = JSON.parse(source);
636
731
  if (document.version !== 1 || typeof document.derivedKey !== "string") {
637
732
  return void 0;
@@ -649,15 +744,15 @@ async function clearAllVaultSessionKeys(processEnv) {
649
744
  const root = buildSessionRoot(processEnv);
650
745
  try {
651
746
  const entries = await readdir(root);
652
- await Promise.all(entries.map((entry) => rm(path3.join(root, entry), { force: true })));
747
+ await Promise.all(entries.map((entry) => rm(path4.join(root, entry), { force: true })));
653
748
  } catch {
654
749
  }
655
750
  }
656
751
 
657
752
  // ../core/src/utils/secretStore.ts
658
753
  import { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from "crypto";
659
- import { mkdir as mkdir2, readdir as readdir2, readFile as readFile3, rm as rm2, stat, writeFile as writeFile2 } from "fs/promises";
660
- import path4 from "path";
754
+ import { mkdir as mkdir2, readdir as readdir2, readFile as readFile4, rm as rm2, stat, writeFile as writeFile2 } from "fs/promises";
755
+ import path5 from "path";
661
756
  var KEY_LENGTH = 32;
662
757
  var SALT_LENGTH = 32;
663
758
  var IV_LENGTH = 12;
@@ -674,7 +769,7 @@ function isSecretReference(value) {
674
769
  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));
675
770
  }
676
771
  function resolveSecretStoreRoot(processEnv = process.env) {
677
- return path4.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
772
+ return path5.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
678
773
  }
679
774
  function normalizeVaultToken(vault = "default") {
680
775
  return vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
@@ -709,19 +804,19 @@ function deriveVaultKey(passphrase, salt, iterations = PBKDF2_ITERATIONS) {
709
804
  return pbkdf2Sync(passphrase, salt, iterations, KEY_LENGTH, "sha512");
710
805
  }
711
806
  function buildMetaPath(storeRoot, vault = "default") {
712
- return path4.join(storeRoot, "vaults", vault, META_FILENAME);
807
+ return path5.join(storeRoot, "vaults", vault, META_FILENAME);
713
808
  }
714
809
  function resolveSecretVaultFile(storeRoot, vault = "default") {
715
810
  return buildMetaPath(storeRoot, vault);
716
811
  }
717
812
  function buildKeystorePath(storeRoot, vault = "default") {
718
- return path4.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
813
+ return path5.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
719
814
  }
720
815
  function buildLegacyVaultFile(storeRoot, vault = "default") {
721
- return path4.join(storeRoot, "vaults", `${vault}.json`);
816
+ return path5.join(storeRoot, "vaults", `${vault}.json`);
722
817
  }
723
818
  function buildLegacyVaultStoreRoot(storeRoot, vault = "default") {
724
- return path4.join(storeRoot, "vaults", vault, "store");
819
+ return path5.join(storeRoot, "vaults", vault, "store");
725
820
  }
726
821
  function assertVaultMetadata(value, filePath) {
727
822
  if (!isObject(value)) {
@@ -732,7 +827,7 @@ function assertVaultMetadata(value, filePath) {
732
827
  }
733
828
  return value;
734
829
  }
735
- async function exists2(targetPath) {
830
+ async function exists3(targetPath) {
736
831
  try {
737
832
  await stat(targetPath);
738
833
  return true;
@@ -743,10 +838,10 @@ async function exists2(targetPath) {
743
838
  async function detectLegacyVaultFormat(storeRoot, vault = "default") {
744
839
  const legacyFile = buildLegacyVaultFile(storeRoot, vault);
745
840
  const legacyStore = buildLegacyVaultStoreRoot(storeRoot, vault);
746
- if (await exists2(legacyFile)) {
841
+ if (await exists3(legacyFile)) {
747
842
  return legacyFile;
748
843
  }
749
- if (await exists2(legacyStore)) {
844
+ if (await exists3(legacyStore)) {
750
845
  return legacyStore;
751
846
  }
752
847
  return void 0;
@@ -818,7 +913,7 @@ function buildInitialPayload() {
818
913
  async function writeVaultFiles(storeRoot, vault, meta, payload, key) {
819
914
  const metaPath = buildMetaPath(storeRoot, vault);
820
915
  const keystorePath = buildKeystorePath(storeRoot, vault);
821
- await mkdir2(path4.dirname(metaPath), { recursive: true });
916
+ await mkdir2(path5.dirname(metaPath), { recursive: true });
822
917
  await writeFile2(metaPath, stringifyYaml(meta), "utf8");
823
918
  await writeFile2(keystorePath, encryptPayload(payload, key));
824
919
  }
@@ -826,7 +921,7 @@ async function readVaultMetadata(storeRoot, vault = "default") {
826
921
  await assertNoLegacyVaultFormat(storeRoot, vault);
827
922
  const metaPath = buildMetaPath(storeRoot, vault);
828
923
  try {
829
- const source = await readFile3(metaPath, "utf8");
924
+ const source = await readFile4(metaPath, "utf8");
830
925
  return assertVaultMetadata(parseYaml(source), metaPath);
831
926
  } catch (error) {
832
927
  if (error.code === "ENOENT") {
@@ -836,11 +931,11 @@ async function readVaultMetadata(storeRoot, vault = "default") {
836
931
  }
837
932
  }
838
933
  async function listSecretVaults(storeRoot) {
839
- const vaultRoot = path4.join(storeRoot, "vaults");
934
+ const vaultRoot = path5.join(storeRoot, "vaults");
840
935
  try {
841
936
  const entries = await readdir2(vaultRoot, { withFileTypes: true });
842
937
  const vaults = await Promise.all(
843
- entries.filter((entry) => entry.isDirectory()).map(async (entry) => await exists2(path4.join(vaultRoot, entry.name, META_FILENAME)) ? entry.name : void 0)
938
+ entries.filter((entry) => entry.isDirectory()).map(async (entry) => await exists3(path5.join(vaultRoot, entry.name, META_FILENAME)) ? entry.name : void 0)
844
939
  );
845
940
  return vaults.filter((value) => Boolean(value)).sort((left, right) => left.localeCompare(right));
846
941
  } catch {
@@ -929,7 +1024,7 @@ async function loadVaultPayload(storeRoot, vault, auth) {
929
1024
  if (!key) {
930
1025
  throw new CnosAuthenticationError(`Vault "${vault}" requires authentication before access.`);
931
1026
  }
932
- const buffer = await readFile3(buildKeystorePath(storeRoot, vault));
1027
+ const buffer = await readFile4(buildKeystorePath(storeRoot, vault));
933
1028
  return {
934
1029
  meta,
935
1030
  payload: decryptPayload(buffer, key),
@@ -1002,7 +1097,7 @@ function resolveVaultDefinition(vaults, vault = "default") {
1002
1097
  };
1003
1098
  }
1004
1099
  async function removeLocalVaultFiles(storeRoot, vault = "default") {
1005
- await rm2(path4.join(storeRoot, "vaults", vault), { recursive: true, force: true });
1100
+ await rm2(path5.join(storeRoot, "vaults", vault), { recursive: true, force: true });
1006
1101
  }
1007
1102
 
1008
1103
  // ../core/src/secrets/providers/github.ts
@@ -1062,10 +1157,10 @@ var GithubSecretsVaultProvider = class {
1062
1157
 
1063
1158
  // ../core/src/secrets/auditLog.ts
1064
1159
  import { appendFile, mkdir as mkdir3 } from "fs/promises";
1065
- import path5 from "path";
1160
+ import path6 from "path";
1066
1161
  async function appendAuditEvent(event, processEnv = process.env) {
1067
- const auditFile = processEnv.CNOS_AUDIT_FILE ?? path5.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
1068
- await mkdir3(path5.dirname(auditFile), { recursive: true });
1162
+ const auditFile = processEnv.CNOS_AUDIT_FILE ?? path6.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
1163
+ await mkdir3(path6.dirname(auditFile), { recursive: true });
1069
1164
  await appendFile(
1070
1165
  auditFile,
1071
1166
  `${JSON.stringify({
@@ -1389,11 +1484,14 @@ function resolvePublicPrefix(manifest, options) {
1389
1484
  if (!options.framework) {
1390
1485
  return "";
1391
1486
  }
1392
- const configuredPrefix = manifest.public.frameworks[options.framework];
1393
- if (!configuredPrefix) {
1487
+ const hasConfiguredPrefix = Object.prototype.hasOwnProperty.call(
1488
+ manifest.public.frameworks,
1489
+ options.framework
1490
+ );
1491
+ if (!hasConfiguredPrefix) {
1394
1492
  throw new CnosManifestError(`Unknown public framework prefix: ${options.framework}`);
1395
1493
  }
1396
- return configuredPrefix;
1494
+ return manifest.public.frameworks[options.framework] ?? "";
1397
1495
  }
1398
1496
  function toPublicEnv(graph, manifest, options = {}) {
1399
1497
  const prefix = resolvePublicPrefix(manifest, options);
@@ -1409,22 +1507,22 @@ function toPublicEnv(graph, manifest, options = {}) {
1409
1507
 
1410
1508
  // ../core/src/runtime/dump.ts
1411
1509
  import { mkdir as mkdir4, writeFile as writeFile3 } from "fs/promises";
1412
- import path6 from "path";
1510
+ import path7 from "path";
1413
1511
  function buildDumpFiles(graph, options = {}) {
1414
- const basePath = options.flatten ? "" : path6.posix.join("workspaces", graph.workspace.workspaceId);
1512
+ const basePath = options.flatten ? "" : path7.posix.join("workspaces", graph.workspace.workspaceId);
1415
1513
  const values = toNamespaceObject(graph, "value");
1416
1514
  const secrets = toNamespaceObject(graph, "secret");
1417
1515
  const files = [];
1418
1516
  if (Object.keys(values).length > 0) {
1419
1517
  files.push({
1420
- path: path6.posix.join(basePath, "values", graph.profile, "app.yml"),
1518
+ path: path7.posix.join(basePath, "values", graph.profile, "app.yml"),
1421
1519
  namespace: "value",
1422
1520
  content: stringifyYaml(values)
1423
1521
  });
1424
1522
  }
1425
1523
  if (Object.keys(secrets).length > 0) {
1426
1524
  files.push({
1427
- path: path6.posix.join(basePath, "secrets", graph.profile, "app.yml"),
1525
+ path: path7.posix.join(basePath, "secrets", graph.profile, "app.yml"),
1428
1526
  namespace: "secret",
1429
1527
  content: stringifyYaml(secrets)
1430
1528
  });
@@ -1440,11 +1538,11 @@ function planDump(graph, options = {}) {
1440
1538
  };
1441
1539
  }
1442
1540
  async function writeDump(graph, options) {
1443
- const root = path6.resolve(options.to);
1541
+ const root = path7.resolve(options.to);
1444
1542
  const plan = planDump(graph, options);
1445
1543
  for (const file of plan.files) {
1446
- const destination = path6.join(root, file.path);
1447
- await mkdir4(path6.dirname(destination), { recursive: true });
1544
+ const destination = path7.join(root, file.path);
1545
+ await mkdir4(path7.dirname(destination), { recursive: true });
1448
1546
  await writeFile3(destination, file.content, "utf8");
1449
1547
  }
1450
1548
  return {
@@ -1476,11 +1574,11 @@ function normalizeMappingConfig(config = {}) {
1476
1574
  function toScreamingSnakeSegment(segment) {
1477
1575
  return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
1478
1576
  }
1479
- function toScreamingSnake(path10) {
1480
- return path10.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
1577
+ function toScreamingSnake(path11) {
1578
+ return path11.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
1481
1579
  }
1482
- function fromScreamingSnake(path10) {
1483
- return path10.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
1580
+ function fromScreamingSnake(path11) {
1581
+ return path11.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
1484
1582
  }
1485
1583
  function logicalKeyToEnvVar(key, config = {}) {
1486
1584
  const normalized = normalizeMappingConfig(config);
@@ -1632,12 +1730,12 @@ function createProvenanceInspector() {
1632
1730
  }
1633
1731
 
1634
1732
  // ../core/src/manifest/loadWorkspaceFile.ts
1635
- import { readFile as readFile4 } from "fs/promises";
1636
- import path7 from "path";
1733
+ import { readFile as readFile5 } from "fs/promises";
1734
+ import path8 from "path";
1637
1735
  async function loadWorkspaceFile(repoRoot) {
1638
- const workspaceFilePath = path7.join(repoRoot, ".cnos-workspace.yml");
1736
+ const workspaceFilePath = path8.join(repoRoot, ".cnos-workspace.yml");
1639
1737
  try {
1640
- const source = await readFile4(workspaceFilePath, "utf8");
1738
+ const source = await readFile5(workspaceFilePath, "utf8");
1641
1739
  const parsed = parseYaml(source);
1642
1740
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1643
1741
  throw new CnosManifestError(".cnos-workspace.yml must be a YAML object", workspaceFilePath);
@@ -1660,11 +1758,11 @@ async function loadWorkspaceFile(repoRoot) {
1660
1758
  }
1661
1759
 
1662
1760
  // ../core/src/profiles/expandProfileChain.ts
1663
- import { access as access2, readFile as readFile5 } from "fs/promises";
1664
- import path8 from "path";
1761
+ import { access as access3, readFile as readFile6 } from "fs/promises";
1762
+ import path9 from "path";
1665
1763
  async function fileExists(targetPath) {
1666
1764
  try {
1667
- await access2(targetPath);
1765
+ await access3(targetPath);
1668
1766
  return true;
1669
1767
  } catch {
1670
1768
  return false;
@@ -1698,11 +1796,11 @@ async function loadProfileDefinition(profileName, options) {
1698
1796
  return normalizeProfileDefinition(profileName, void 0);
1699
1797
  }
1700
1798
  for (const workspaceRoot of [...workspaceRoots].reverse()) {
1701
- const profilePath = path8.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
1799
+ const profilePath = path9.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
1702
1800
  if (!await fileExists(profilePath)) {
1703
1801
  continue;
1704
1802
  }
1705
- const document = await readFile5(profilePath, "utf8");
1803
+ const document = await readFile6(profilePath, "utf8");
1706
1804
  const parsed = parseYaml(document);
1707
1805
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1708
1806
  throw new CnosManifestError("Profile definition must be a YAML object", profilePath);
@@ -1710,7 +1808,7 @@ async function loadProfileDefinition(profileName, options) {
1710
1808
  const definition = normalizeProfileDefinition(
1711
1809
  profileName,
1712
1810
  parsed,
1713
- options.manifestRoot ? toPortablePath(path8.relative(path8.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
1811
+ options.manifestRoot ? toPortablePath(path9.relative(path9.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
1714
1812
  );
1715
1813
  if (definition.name !== profileName) {
1716
1814
  throw new CnosManifestError(
@@ -1956,8 +2054,8 @@ function createProfileAwareResolver() {
1956
2054
  }
1957
2055
 
1958
2056
  // ../core/src/workspaces/resolveWorkspaceContext.ts
1959
- import { access as access3 } from "fs/promises";
1960
- import path9 from "path";
2057
+ import { access as access4 } from "fs/promises";
2058
+ import path10 from "path";
1961
2059
 
1962
2060
  // ../core/src/workspaces/expandWorkspaceChain.ts
1963
2061
  function expandWorkspaceChain(workspaceId, items) {
@@ -1994,31 +2092,31 @@ function expandWorkspaceChain(workspaceId, items) {
1994
2092
  }
1995
2093
 
1996
2094
  // ../core/src/workspaces/resolveWorkspaceContext.ts
1997
- async function exists3(targetPath) {
2095
+ async function exists4(targetPath) {
1998
2096
  try {
1999
- await access3(targetPath);
2097
+ await access4(targetPath);
2000
2098
  return true;
2001
2099
  } catch {
2002
2100
  return false;
2003
2101
  }
2004
2102
  }
2005
2103
  async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
2006
- const workspaceRoot = path9.join(manifestRoot, "workspaces", workspaceId);
2007
- if (await exists3(workspaceRoot)) {
2104
+ const workspaceRoot = path10.join(manifestRoot, "workspaces", workspaceId);
2105
+ if (await exists4(workspaceRoot)) {
2008
2106
  return workspaceRoot;
2009
2107
  }
2010
2108
  const customDataNamespaceRoots = Object.entries(manifest.namespaces).filter(
2011
2109
  ([namespace, definition]) => namespace !== "value" && namespace !== "secret" && definition.kind === "data" && !definition.sensitive
2012
2110
  ).map(([namespace]) => namespace);
2013
2111
  const legacyMarkers = ["values", "secrets", "env", "profiles", ...customDataNamespaceRoots].map(
2014
- (segment) => path9.join(manifestRoot, segment)
2112
+ (segment) => path10.join(manifestRoot, segment)
2015
2113
  );
2016
- if ((await Promise.all(legacyMarkers.map((marker) => exists3(marker)))).some(Boolean)) {
2114
+ if ((await Promise.all(legacyMarkers.map((marker) => exists4(marker)))).some(Boolean)) {
2017
2115
  return manifestRoot;
2018
2116
  }
2019
2117
  return workspaceRoot;
2020
2118
  }
2021
- function resolveWorkspaceSelection(manifest, workspaceFile, workspaceOption) {
2119
+ function resolveWorkspaceSelection(manifest, workspaceFile, anchoredWorkspace, workspaceOption) {
2022
2120
  if (workspaceOption) {
2023
2121
  return {
2024
2122
  workspaceId: workspaceOption,
@@ -2031,6 +2129,12 @@ function resolveWorkspaceSelection(manifest, workspaceFile, workspaceOption) {
2031
2129
  source: "workspace-file"
2032
2130
  };
2033
2131
  }
2132
+ if (anchoredWorkspace) {
2133
+ return {
2134
+ workspaceId: anchoredWorkspace,
2135
+ source: "anchor-file"
2136
+ };
2137
+ }
2034
2138
  if (manifest.workspaces.default) {
2035
2139
  return {
2036
2140
  workspaceId: manifest.workspaces.default,
@@ -2053,33 +2157,38 @@ function resolveGlobalRoot(manifest, workspaceFile, options) {
2053
2157
  }
2054
2158
  if (options.globalRoot) {
2055
2159
  return {
2056
- value: path9.resolve(expandHomePath(options.globalRoot)),
2160
+ value: path10.resolve(expandHomePath(options.globalRoot)),
2057
2161
  source: "cli"
2058
2162
  };
2059
2163
  }
2060
2164
  if (workspaceFile?.globalRoot) {
2061
2165
  return {
2062
- value: path9.resolve(expandHomePath(workspaceFile.globalRoot)),
2166
+ value: path10.resolve(expandHomePath(workspaceFile.globalRoot)),
2063
2167
  source: "workspace-file"
2064
2168
  };
2065
2169
  }
2066
2170
  if (manifest.workspaces.global.root) {
2067
2171
  return {
2068
- value: path9.resolve(expandHomePath(manifest.workspaces.global.root)),
2172
+ value: path10.resolve(expandHomePath(manifest.workspaces.global.root)),
2069
2173
  source: "manifest"
2070
2174
  };
2071
2175
  }
2072
2176
  const cnosHome = options.processEnv?.CNOS_HOME;
2073
2177
  if (cnosHome) {
2074
2178
  return {
2075
- value: path9.resolve(expandHomePath(cnosHome)),
2179
+ value: path10.resolve(expandHomePath(cnosHome)),
2076
2180
  source: "CNOS_HOME"
2077
2181
  };
2078
2182
  }
2079
2183
  return {};
2080
2184
  }
2081
2185
  async function resolveWorkspaceContext(manifest, options) {
2082
- const selectedWorkspace = resolveWorkspaceSelection(manifest, options.workspaceFile, options.workspace);
2186
+ const selectedWorkspace = resolveWorkspaceSelection(
2187
+ manifest,
2188
+ options.workspaceFile,
2189
+ options.anchoredWorkspace,
2190
+ options.workspace
2191
+ );
2083
2192
  const workspaceChain = expandWorkspaceChain(selectedWorkspace.workspaceId, manifest.workspaces.items);
2084
2193
  const globalRoot = resolveGlobalRoot(manifest, options.workspaceFile, options);
2085
2194
  const workspaceRoots = [];
@@ -2089,7 +2198,7 @@ async function resolveWorkspaceContext(manifest, options) {
2089
2198
  workspaceRoots.push({
2090
2199
  scope: "global",
2091
2200
  workspaceId: chainWorkspaceId,
2092
- path: path9.join(globalRoot.value, "workspaces", globalWorkspaceId)
2201
+ path: path10.join(globalRoot.value, "workspaces", globalWorkspaceId)
2093
2202
  });
2094
2203
  }
2095
2204
  }
@@ -2357,8 +2466,92 @@ function resolveSecretEntryValue(key, value, cache) {
2357
2466
  return cache.get(vaultId, value.ref) ?? value;
2358
2467
  }
2359
2468
 
2469
+ // ../core/src/runtime/toServerProjection.ts
2470
+ import { createHash } from "crypto";
2471
+ function stableSortObject(value) {
2472
+ return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
2473
+ }
2474
+ function stripValuePrefix(key) {
2475
+ return key.startsWith("value.") ? key.slice("value.".length) : key;
2476
+ }
2477
+ function configHash(values) {
2478
+ const serialized = JSON.stringify(stableSortObject(values));
2479
+ return createHash("sha256").update(serialized).digest("hex");
2480
+ }
2481
+ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
2482
+ const values = {};
2483
+ const secretRefs = {};
2484
+ const namespaces = /* @__PURE__ */ new Set();
2485
+ const publicKeys = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").map((entry) => entry.key.slice("public.".length)).sort((left, right) => left.localeCompare(right));
2486
+ for (const [key, entry] of graph.entries) {
2487
+ if (entry.namespace === "secret" && isSecretReference(entry.value)) {
2488
+ secretRefs[key.slice("secret.".length)] = {
2489
+ provider: entry.value.provider,
2490
+ vault: entry.value.vault ?? "default",
2491
+ ref: entry.value.ref
2492
+ };
2493
+ continue;
2494
+ }
2495
+ if (entry.namespace === "value") {
2496
+ values[stripValuePrefix(key)] = entry.value;
2497
+ continue;
2498
+ }
2499
+ const namespaceDefinition = manifest.namespaces[entry.namespace];
2500
+ if (namespaceDefinition && namespaceDefinition.kind === "data" && !namespaceDefinition.sensitive && entry.namespace !== "public") {
2501
+ values[key] = entry.value;
2502
+ namespaces.add(entry.namespace);
2503
+ }
2504
+ }
2505
+ return {
2506
+ version: 1,
2507
+ workspace: graph.workspace.workspaceId,
2508
+ profile: graph.profile,
2509
+ resolvedAt: graph.resolvedAt,
2510
+ configHash: configHash(values),
2511
+ values: stableSortObject(values),
2512
+ secretRefs: stableSortObject(secretRefs),
2513
+ publicKeys,
2514
+ meta: {
2515
+ workspace: graph.workspace.workspaceId,
2516
+ profile: graph.profile,
2517
+ cnos_version: cnosVersion,
2518
+ ...namespaces.size > 0 ? { namespaces: Array.from(namespaces).sort((left, right) => left.localeCompare(right)) } : {}
2519
+ }
2520
+ };
2521
+ }
2522
+
2360
2523
  // ../core/src/orchestrator/runtime.ts
2361
- function createRuntime(manifest, graph, plugins = [], secretCache) {
2524
+ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
2525
+ async function refreshSecretEntry(key) {
2526
+ const entry = graph.entries.get(key);
2527
+ if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
2528
+ return;
2529
+ }
2530
+ if (!secretCache) {
2531
+ return;
2532
+ }
2533
+ const vaultId = entry.value.vault ?? "default";
2534
+ const definition = manifest.vaults[vaultId] ?? {
2535
+ provider: entry.value.provider,
2536
+ auth: { passphrase: { from: [] } }
2537
+ };
2538
+ const provider = createSecretVaultProvider(vaultId, definition, processEnv);
2539
+ const auth = await resolveVaultAuth(vaultId, definition, processEnv);
2540
+ await provider.authenticate(auth);
2541
+ const value = await provider.get(entry.value.ref);
2542
+ if (value !== void 0) {
2543
+ secretCache.load(vaultId, /* @__PURE__ */ new Map([[entry.value.ref, value]]));
2544
+ }
2545
+ }
2546
+ async function refreshAllSecrets() {
2547
+ if (!secretCache) {
2548
+ return;
2549
+ }
2550
+ const secretKeys = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "secret" && isSecretReference(entry.value)).map((entry) => entry.key);
2551
+ for (const key of secretKeys) {
2552
+ await refreshSecretEntry(key);
2553
+ }
2554
+ }
2362
2555
  function readLogicalKey(key) {
2363
2556
  const entry = graph.entries.get(key);
2364
2557
  if (!entry) {
@@ -2386,14 +2579,14 @@ function createRuntime(manifest, graph, plugins = [], secretCache) {
2386
2579
  readOr(key, fallback) {
2387
2580
  return readOrValue(graph, key, fallback);
2388
2581
  },
2389
- value(path10) {
2390
- return readLogicalKey(toLogicalKey("value", path10));
2582
+ value(path11) {
2583
+ return readLogicalKey(toLogicalKey("value", path11));
2391
2584
  },
2392
- secret(path10) {
2393
- return readLogicalKey(toLogicalKey("secret", path10));
2585
+ secret(path11) {
2586
+ return readLogicalKey(toLogicalKey("secret", path11));
2394
2587
  },
2395
- meta(path10) {
2396
- return readLogicalKey(toLogicalKey("meta", path10));
2588
+ meta(path11) {
2589
+ return readLogicalKey(toLogicalKey("meta", path11));
2397
2590
  },
2398
2591
  inspect(key) {
2399
2592
  return inspectValue(graph, key);
@@ -2409,6 +2602,15 @@ function createRuntime(manifest, graph, plugins = [], secretCache) {
2409
2602
  },
2410
2603
  toPublicEnv(options) {
2411
2604
  return toPublicEnv(graph, manifest, options);
2605
+ },
2606
+ toServerProjection() {
2607
+ return toServerProjection(graph, manifest, cnosVersion);
2608
+ },
2609
+ async refreshSecrets() {
2610
+ await refreshAllSecrets();
2611
+ },
2612
+ async refreshSecret(key) {
2613
+ await refreshSecretEntry(key);
2412
2614
  }
2413
2615
  };
2414
2616
  }
@@ -2507,14 +2709,18 @@ function appendMetaEntries(graph, cnosVersion) {
2507
2709
  };
2508
2710
  }
2509
2711
  async function createCnos(options = {}) {
2510
- const loadedManifest = await loadManifest(options.root ? { root: options.root } : {});
2712
+ const loadedManifest = await loadManifest({
2713
+ ...options.root ? { root: options.root } : {},
2714
+ ...options.cwd ? { cwd: options.cwd } : {}
2715
+ });
2511
2716
  for (const key of loadedManifest.manifest.public.promote) {
2512
2717
  ensureProjectionAllowed(loadedManifest.manifest, key, "public");
2513
2718
  }
2514
- const workspaceFile = await loadWorkspaceFile(loadedManifest.repoRoot);
2719
+ const workspaceFile = await loadWorkspaceFile(loadedManifest.consumerRoot);
2515
2720
  const workspace = await resolveWorkspaceContext(loadedManifest.manifest, {
2516
2721
  manifestRoot: loadedManifest.manifestRoot,
2517
2722
  ...workspaceFile ? { workspaceFile: workspaceFile.config } : {},
2723
+ ...loadedManifest.anchoredWorkspace ? { anchoredWorkspace: loadedManifest.anchoredWorkspace } : {},
2518
2724
  ...options.workspace ? { workspace: options.workspace } : {},
2519
2725
  ...options.globalRoot ? { globalRoot: options.globalRoot } : {},
2520
2726
  ...options.processEnv ? { processEnv: options.processEnv } : {}
@@ -2559,7 +2765,9 @@ async function createCnos(options = {}) {
2559
2765
  profileSource: activeProfile.source
2560
2766
  }, options.cnosVersion),
2561
2767
  plugins,
2562
- secretCache
2768
+ secretCache,
2769
+ options.processEnv,
2770
+ options.cnosVersion
2563
2771
  );
2564
2772
  }
2565
2773
 
@@ -2571,14 +2779,14 @@ export {
2571
2779
  createProvenanceInspector,
2572
2780
  readKeychain,
2573
2781
  writeKeychain,
2782
+ parseYaml,
2783
+ stringifyYaml,
2574
2784
  resolveManifestRoot,
2575
2785
  resolveWorkspaceScopedPath,
2576
2786
  resolveConfigDocumentPath,
2577
2787
  toPortablePath,
2578
2788
  joinConfigPath,
2579
2789
  toLogicalKey,
2580
- parseYaml,
2581
- stringifyYaml,
2582
2790
  loadManifest,
2583
2791
  getNamespaceDefinition,
2584
2792
  ensureProjectionAllowed,