@kitsy/cnos 1.10.0 → 1.11.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 (61) hide show
  1. package/dist/build/index.cjs +331 -63
  2. package/dist/build/index.d.cts +1 -1
  3. package/dist/build/index.d.ts +1 -1
  4. package/dist/build/index.js +13 -15
  5. package/dist/{chunk-A5U7EZCJ.js → chunk-2DMCB3PK.js} +1 -1
  6. package/dist/{chunk-RTHKUGJV.js → chunk-5JGNRADB.js} +1 -1
  7. package/dist/{chunk-3EZGPQCE.js → chunk-DPC2BV3S.js} +1 -1
  8. package/dist/{chunk-FHXLOWAB.js → chunk-KJ57PF47.js} +1 -1
  9. package/dist/{chunk-CSA4L64V.js → chunk-NFGPS7VJ.js} +10 -10
  10. package/dist/{chunk-ESBHCFC6.js → chunk-NU25VFA2.js} +1 -1
  11. package/dist/{chunk-UGLATJJD.js → chunk-RNTTPI5S.js} +1 -1
  12. package/dist/{chunk-UKNL2Y4N.js → chunk-T3E57MSQ.js} +1 -1
  13. package/dist/{chunk-MQ4WG3K6.js → chunk-WPB4HB2K.js} +320 -49
  14. package/dist/{chunk-EIK7OUFP.js → chunk-XGK6DXQL.js} +157 -37
  15. package/dist/configure/index.cjs +329 -59
  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/{core-Ud1o2MBn.d.cts → core-BW8SLnRx.d.cts} +34 -2
  20. package/dist/{core-Ud1o2MBn.d.ts → core-BW8SLnRx.d.ts} +34 -2
  21. package/dist/{envNaming-DxxqiGKN.d.cts → envNaming-1rk7BR0e.d.cts} +1 -1
  22. package/dist/{envNaming-CPwXl4I6.d.ts → envNaming-CjL28IeH.d.ts} +1 -1
  23. package/dist/index.cjs +480 -91
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +10 -10
  27. package/dist/internal.cjs +89 -23
  28. package/dist/internal.d.cts +3 -3
  29. package/dist/internal.d.ts +3 -3
  30. package/dist/internal.js +2 -2
  31. package/dist/plugin/basic-schema.cjs +4 -1
  32. package/dist/plugin/basic-schema.d.cts +1 -1
  33. package/dist/plugin/basic-schema.d.ts +1 -1
  34. package/dist/plugin/basic-schema.js +2 -2
  35. package/dist/plugin/cli-args.cjs +4 -1
  36. package/dist/plugin/cli-args.d.cts +1 -1
  37. package/dist/plugin/cli-args.d.ts +1 -1
  38. package/dist/plugin/cli-args.js +2 -2
  39. package/dist/plugin/dotenv.cjs +6 -3
  40. package/dist/plugin/dotenv.d.cts +2 -2
  41. package/dist/plugin/dotenv.d.ts +2 -2
  42. package/dist/plugin/dotenv.js +2 -2
  43. package/dist/plugin/env-export.cjs +5 -2
  44. package/dist/plugin/env-export.d.cts +2 -2
  45. package/dist/plugin/env-export.d.ts +2 -2
  46. package/dist/plugin/env-export.js +2 -2
  47. package/dist/plugin/filesystem.cjs +13 -10
  48. package/dist/plugin/filesystem.d.cts +1 -1
  49. package/dist/plugin/filesystem.d.ts +1 -1
  50. package/dist/plugin/filesystem.js +2 -2
  51. package/dist/plugin/process-env.cjs +4 -1
  52. package/dist/plugin/process-env.d.cts +2 -2
  53. package/dist/plugin/process-env.d.ts +2 -2
  54. package/dist/plugin/process-env.js +2 -2
  55. package/dist/runtime/index.cjs +480 -91
  56. package/dist/runtime/index.d.cts +13 -6
  57. package/dist/runtime/index.d.ts +13 -6
  58. package/dist/runtime/index.js +10 -10
  59. package/dist/{toPublicEnv-fUZMRUOz.d.cts → toPublicEnv-CZzpvhGg.d.cts} +1 -1
  60. package/dist/{toPublicEnv-C9wPSpRo.d.ts → toPublicEnv-CmydGcxg.d.ts} +1 -1
  61. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1603,11 +1603,19 @@ function normalizeVaults(vaults) {
1603
1603
  throw new CnosManifestError(`Vault "${name}" requires a provider`);
1604
1604
  }
1605
1605
  const normalizedAuth = normalizeVaultAuth(name, provider, definition.auth);
1606
- const normalizedMapping = Object.fromEntries(
1607
- Object.entries(definition.mapping ?? {}).filter(
1608
- (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
1609
- ).map(([envVar, logicalRef]) => [envVar.trim(), logicalRef.trim()]).filter(([envVar, logicalRef]) => envVar.length > 0 && logicalRef.length > 0)
1610
- );
1606
+ const normalizedMapping = normalizeVaultMapping(definition.mapping);
1607
+ const fallback = (definition.fallback ?? []).map((entry, index) => {
1608
+ const fallbackProvider = entry.provider?.trim();
1609
+ if (!fallbackProvider) {
1610
+ throw new CnosManifestError(`Vault "${name}" fallback ${index + 1} requires a provider`);
1611
+ }
1612
+ const fallbackMapping = normalizeVaultMapping(entry.mapping);
1613
+ return {
1614
+ provider: fallbackProvider,
1615
+ auth: normalizeVaultAuth(name, fallbackProvider, entry.auth),
1616
+ ...Object.keys(fallbackMapping).length > 0 ? { mapping: fallbackMapping } : {}
1617
+ };
1618
+ });
1611
1619
  return [
1612
1620
  name,
1613
1621
  {
@@ -1615,12 +1623,20 @@ function normalizeVaults(vaults) {
1615
1623
  auth: normalizedAuth,
1616
1624
  ...Object.keys(normalizedMapping).length > 0 ? {
1617
1625
  mapping: normalizedMapping
1618
- } : {}
1626
+ } : {},
1627
+ ...fallback.length > 0 ? { fallback } : {}
1619
1628
  }
1620
1629
  ];
1621
1630
  })
1622
1631
  );
1623
1632
  }
1633
+ function normalizeVaultMapping(mapping) {
1634
+ return Object.fromEntries(
1635
+ Object.entries(mapping ?? {}).filter(
1636
+ (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
1637
+ ).map(([envVar, logicalRef]) => [envVar.trim(), logicalRef.trim()]).filter(([envVar, logicalRef]) => envVar.length > 0 && logicalRef.length > 0)
1638
+ );
1639
+ }
1624
1640
  function normalizeAuthSources(value) {
1625
1641
  if (!value || typeof value !== "object" || Array.isArray(value)) {
1626
1642
  return void 0;
@@ -2568,7 +2584,7 @@ function isObject(value) {
2568
2584
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2569
2585
  }
2570
2586
  function isSecretReference(value) {
2571
- 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));
2587
+ return isObject(value) && (value.provider === void 0 || 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));
2572
2588
  }
2573
2589
  function resolveSecretStoreRoot(processEnv = process.env) {
2574
2590
  return import_node_path11.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
@@ -2915,6 +2931,23 @@ var SecretCache = class {
2915
2931
  get(vaultId, ref) {
2916
2932
  return this.cache.get(`${vaultId}:${ref}`);
2917
2933
  }
2934
+ delete(vaultId, ref) {
2935
+ this.cache.delete(`${vaultId}:${ref}`);
2936
+ }
2937
+ replace(vaultId, secrets) {
2938
+ this.clear(vaultId);
2939
+ this.load(vaultId, secrets);
2940
+ }
2941
+ entriesForVault(vaultId) {
2942
+ const entries = /* @__PURE__ */ new Map();
2943
+ for (const [key, value] of this.cache) {
2944
+ const prefix = `${vaultId}:`;
2945
+ if (key.startsWith(prefix)) {
2946
+ entries.set(key.slice(prefix.length), value);
2947
+ }
2948
+ }
2949
+ return entries;
2950
+ }
2918
2951
  clear(vaultId) {
2919
2952
  if (!vaultId) {
2920
2953
  this.cache.clear();
@@ -3080,7 +3113,7 @@ var LocalSecretVaultProvider = class _LocalSecretVaultProvider {
3080
3113
  };
3081
3114
 
3082
3115
  // ../core/src/secrets/providers/registry.ts
3083
- function createSecretVaultProvider(vaultId, definition, processEnv) {
3116
+ function createSecretVaultProvider(vaultId, definition, processEnv, factories = []) {
3084
3117
  if (definition.provider === "local") {
3085
3118
  return new LocalSecretVaultProvider(vaultId, definition, processEnv);
3086
3119
  }
@@ -3090,9 +3123,30 @@ function createSecretVaultProvider(vaultId, definition, processEnv) {
3090
3123
  if (definition.provider === "github-secrets") {
3091
3124
  return new GithubSecretsVaultProvider(vaultId, definition, processEnv);
3092
3125
  }
3126
+ const factory = factories.find((candidate) => candidate.provider === definition.provider);
3127
+ if (factory) {
3128
+ return factory.create(vaultId, definition, processEnv);
3129
+ }
3093
3130
  throw new CnosManifestError(`Unsupported vault provider: ${definition.provider}`);
3094
3131
  }
3095
3132
 
3133
+ // ../core/src/secrets/providerCompatibility.ts
3134
+ function assertSecretRefVaultProviderCompatible(manifest, ref, logicalKey = "secret ref") {
3135
+ if (!ref.vault || !ref.provider) {
3136
+ return;
3137
+ }
3138
+ const definition = manifest.vaults[ref.vault];
3139
+ if (!definition || definition.provider === ref.provider) {
3140
+ return;
3141
+ }
3142
+ throw new CnosManifestError(
3143
+ `Secret ref "${logicalKey}" declares provider "${ref.provider}" but vault "${ref.vault}" uses provider "${definition.provider}". Remove the ref provider or use a matching vault.`
3144
+ );
3145
+ }
3146
+
3147
+ // ../core/src/secrets/resolveAuth.ts
3148
+ var import_promises12 = require("fs/promises");
3149
+
3096
3150
  // ../core/src/secrets/prompt.ts
3097
3151
  var import_node_readline = __toESM(require("readline"), 1);
3098
3152
  var import_node_stream = require("stream");
@@ -3133,6 +3187,23 @@ function toAuthError(vaultId, sources) {
3133
3187
  `Cannot authenticate to vault "${vaultId}". Tried: ${sources.join(", ")}. Set ${getVaultPassphraseEnvVar(vaultId)} or run cnos vault auth ${vaultId}.`
3134
3188
  );
3135
3189
  }
3190
+ async function resolveTokenFromSource(source, processEnv) {
3191
+ if (source.startsWith("env:")) {
3192
+ return processEnv[source.slice(4)] || void 0;
3193
+ }
3194
+ if (source.startsWith("file:")) {
3195
+ try {
3196
+ const value = await (0, import_promises12.readFile)(expandHomePath(source.slice("file:".length)), "utf8");
3197
+ return value.trim() || void 0;
3198
+ } catch {
3199
+ return void 0;
3200
+ }
3201
+ }
3202
+ if (source.startsWith("keychain:")) {
3203
+ return readKeychain(source.slice("keychain:".length));
3204
+ }
3205
+ return void 0;
3206
+ }
3136
3207
  async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
3137
3208
  const sessionKey = await resolveVaultSessionKey(vaultId, processEnv);
3138
3209
  if (sessionKey) {
@@ -3148,6 +3219,32 @@ async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
3148
3219
  ...definition.auth?.config ? { config: definition.auth.config } : {}
3149
3220
  };
3150
3221
  }
3222
+ if (definition.auth?.method === "iam") {
3223
+ return {
3224
+ method: "iam",
3225
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
3226
+ };
3227
+ }
3228
+ if (definition.auth?.method === "environment") {
3229
+ return {
3230
+ method: "environment",
3231
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
3232
+ };
3233
+ }
3234
+ const tokenSources = definition.auth?.token?.from ?? [];
3235
+ for (const source of tokenSources) {
3236
+ const token = await resolveTokenFromSource(source, processEnv);
3237
+ if (token) {
3238
+ return {
3239
+ token,
3240
+ method: "token",
3241
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
3242
+ };
3243
+ }
3244
+ }
3245
+ if (definition.auth?.method === "token") {
3246
+ throw toAuthError(vaultId, [getVaultSessionKeyEnvVar(vaultId), ...tokenSources]);
3247
+ }
3151
3248
  const sources = definition.auth?.passphrase?.from ?? [getVaultPassphraseEnvVar(vaultId)];
3152
3249
  for (const source of sources) {
3153
3250
  if (source.startsWith("env:")) {
@@ -3199,22 +3296,76 @@ function collectSecretDescriptors(graph) {
3199
3296
  ref: entry.value
3200
3297
  }));
3201
3298
  }
3202
- async function batchResolveSecrets(graph, manifest, processEnv = process.env) {
3299
+ function secretGroupKey(manifest, descriptor) {
3300
+ assertSecretRefVaultProviderCompatible(manifest, descriptor.ref, descriptor.logicalKey);
3301
+ const vaultId = descriptor.ref.vault ?? "default";
3302
+ const provider = descriptor.ref.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
3303
+ return `${vaultId}\0${provider}`;
3304
+ }
3305
+ function vaultDefinitionForRef(manifest, ref) {
3306
+ assertSecretRefVaultProviderCompatible(manifest, ref);
3307
+ const vaultId = ref.vault ?? "default";
3308
+ const base = manifest.vaults[vaultId] ?? { provider: "local", auth: { passphrase: { from: [] } } };
3309
+ if (!ref.provider || ref.provider === base.provider) {
3310
+ return base;
3311
+ }
3312
+ return {
3313
+ ...base,
3314
+ provider: ref.provider
3315
+ };
3316
+ }
3317
+ async function resolveFromDefinition(vaultId, definition, refs, processEnv, factories) {
3318
+ const runtimeDefinition = {
3319
+ provider: definition.provider,
3320
+ ...definition.auth ? { auth: definition.auth } : {},
3321
+ ...definition.mapping ? { mapping: definition.mapping } : {}
3322
+ };
3323
+ const provider = createSecretVaultProvider(vaultId, runtimeDefinition, processEnv, factories);
3324
+ const auth = await resolveVaultAuth(vaultId, runtimeDefinition, processEnv);
3325
+ await provider.authenticate(auth);
3326
+ return provider.batchGet(refs.map((entry) => entry.ref.ref));
3327
+ }
3328
+ async function batchResolveSecrets(graph, manifest, processEnv = process.env, factories = []) {
3203
3329
  const cache = new SecretCache();
3204
3330
  const descriptors = collectSecretDescriptors(graph);
3205
3331
  const grouped = descriptors.reduce((accumulator, descriptor) => {
3206
- const vaultId = descriptor.ref.vault ?? "default";
3207
- const bucket = accumulator.get(vaultId) ?? [];
3332
+ const key = secretGroupKey(manifest, descriptor);
3333
+ const bucket = accumulator.get(key) ?? [];
3208
3334
  bucket.push(descriptor);
3209
- accumulator.set(vaultId, bucket);
3335
+ accumulator.set(key, bucket);
3210
3336
  return accumulator;
3211
3337
  }, /* @__PURE__ */ new Map());
3212
- for (const [vaultId, refs] of grouped) {
3213
- const definition = manifest.vaults[vaultId] ?? { provider: "local", auth: { passphrase: { from: [] } } };
3214
- const provider = createSecretVaultProvider(vaultId, definition, processEnv);
3215
- const auth = await resolveVaultAuth(vaultId, definition, processEnv);
3216
- await provider.authenticate(auth);
3217
- const resolved = await provider.batchGet(refs.map((entry) => entry.ref.ref));
3338
+ for (const refs of grouped.values()) {
3339
+ const first = refs[0];
3340
+ if (!first) {
3341
+ continue;
3342
+ }
3343
+ const vaultId = first.ref.vault ?? "default";
3344
+ const definition = vaultDefinitionForRef(manifest, first.ref);
3345
+ const definitions = [definition, ...definition.fallback ?? []];
3346
+ const resolved = /* @__PURE__ */ new Map();
3347
+ let remaining = refs;
3348
+ let lastError;
3349
+ for (const candidate of definitions) {
3350
+ try {
3351
+ const candidateValues = await resolveFromDefinition(vaultId, candidate, remaining, processEnv, factories);
3352
+ for (const descriptor of remaining) {
3353
+ const value = candidateValues.get(descriptor.ref.ref);
3354
+ if (value !== void 0) {
3355
+ resolved.set(descriptor.ref.ref, value);
3356
+ }
3357
+ }
3358
+ remaining = remaining.filter((descriptor) => !resolved.has(descriptor.ref.ref));
3359
+ if (remaining.length === 0) {
3360
+ break;
3361
+ }
3362
+ } catch (error) {
3363
+ lastError = error;
3364
+ }
3365
+ }
3366
+ if (resolved.size === 0 && lastError) {
3367
+ throw lastError;
3368
+ }
3218
3369
  cache.load(vaultId, resolved);
3219
3370
  await appendAuditEvent(
3220
3371
  {
@@ -3235,7 +3386,11 @@ function resolveSecretEntryValue(key, value, cache) {
3235
3386
  return value;
3236
3387
  }
3237
3388
  const vaultId = value.vault ?? "default";
3238
- return cache.get(vaultId, value.ref) ?? value;
3389
+ const resolved = cache.get(vaultId, value.ref);
3390
+ if (resolved !== void 0 || cache.isVaultAuthenticated(vaultId)) {
3391
+ return resolved;
3392
+ }
3393
+ return value;
3239
3394
  }
3240
3395
 
3241
3396
  // ../core/src/runtime/projection.ts
@@ -3338,19 +3493,117 @@ function configHash(values) {
3338
3493
  function shouldProjectResolvedValue(sourceId) {
3339
3494
  return sourceId !== "process-env";
3340
3495
  }
3496
+ var SAFE_PROJECTED_CONFIG_KEYS = /* @__PURE__ */ new Set([
3497
+ "address",
3498
+ "audience",
3499
+ "clientid",
3500
+ "endpoint",
3501
+ "mount",
3502
+ "namespace",
3503
+ "path",
3504
+ "projectid",
3505
+ "region",
3506
+ "scope",
3507
+ "scopes",
3508
+ "serviceaccountemail",
3509
+ "tenant",
3510
+ "tenantid",
3511
+ "url",
3512
+ "version",
3513
+ "vaulturl"
3514
+ ]);
3515
+ function isSafeProjectedConfigKey(key) {
3516
+ return SAFE_PROJECTED_CONFIG_KEYS.has(key.replace(/[^A-Za-z0-9]/g, "").toLowerCase());
3517
+ }
3518
+ function sanitizeProjectedConfigValue(value) {
3519
+ if (Array.isArray(value)) {
3520
+ return value.map((item) => sanitizeProjectedConfigValue(item));
3521
+ }
3522
+ if (!value || typeof value !== "object") {
3523
+ return value;
3524
+ }
3525
+ return stableSortObject(
3526
+ Object.fromEntries(
3527
+ Object.entries(value).map(([key, item]) => [key, sanitizeProjectedConfigValue(item)]).filter(([key, item]) => {
3528
+ if (item && typeof item === "object" && !Array.isArray(item)) {
3529
+ return Object.keys(item).length > 0;
3530
+ }
3531
+ return isSafeProjectedConfigKey(key);
3532
+ })
3533
+ )
3534
+ );
3535
+ }
3536
+ function sanitizeProjectedConfig(config) {
3537
+ const sanitized = sanitizeProjectedConfigValue(config);
3538
+ if (!sanitized || typeof sanitized !== "object" || Array.isArray(sanitized)) {
3539
+ return void 0;
3540
+ }
3541
+ return Object.keys(sanitized).length > 0 ? sanitized : void 0;
3542
+ }
3543
+ function projectVaultAuth(definition) {
3544
+ const auth = definition.auth;
3545
+ if (!auth) {
3546
+ return void 0;
3547
+ }
3548
+ const config = auth.config ? sanitizeProjectedConfig(auth.config) : void 0;
3549
+ const projected = {
3550
+ ...auth.method ? { method: auth.method } : {},
3551
+ ...auth.passphrase?.from ? {
3552
+ passphrase: {
3553
+ from: [...auth.passphrase.from]
3554
+ }
3555
+ } : {},
3556
+ ...auth.token?.from ? {
3557
+ token: {
3558
+ from: [...auth.token.from]
3559
+ }
3560
+ } : {},
3561
+ ...config ? { config } : {}
3562
+ };
3563
+ return Object.keys(projected).length > 0 ? projected : void 0;
3564
+ }
3565
+ function projectVaultDefinition(definition) {
3566
+ const auth = projectVaultAuth(definition);
3567
+ const mapping = definition.mapping ? stableSortObject(definition.mapping) : void 0;
3568
+ const fallback = definition.fallback?.map((entry) => projectVaultDefinition({
3569
+ provider: entry.provider,
3570
+ ...entry.auth ? { auth: entry.auth } : {},
3571
+ ...entry.mapping ? { mapping: entry.mapping } : {}
3572
+ }));
3573
+ return {
3574
+ provider: definition.provider,
3575
+ ...auth ? { auth } : {},
3576
+ ...mapping && Object.keys(mapping).length > 0 ? { mapping } : {},
3577
+ ...fallback && fallback.length > 0 ? { fallback } : {}
3578
+ };
3579
+ }
3580
+ function projectReferencedVaults(manifest, vaultIds) {
3581
+ const projected = {};
3582
+ for (const vaultId of Array.from(vaultIds).sort((left, right) => left.localeCompare(right))) {
3583
+ const definition = manifest.vaults[vaultId];
3584
+ if (definition) {
3585
+ projected[vaultId] = projectVaultDefinition(definition);
3586
+ }
3587
+ }
3588
+ return Object.keys(projected).length > 0 ? projected : void 0;
3589
+ }
3341
3590
  function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
3342
3591
  const values = {};
3343
3592
  const derived = {};
3344
3593
  const secretRefs = {};
3594
+ const referencedVaultIds = /* @__PURE__ */ new Set();
3345
3595
  const namespaces = /* @__PURE__ */ new Set();
3346
3596
  const runtimeNamespaces = /* @__PURE__ */ new Set();
3347
3597
  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));
3348
3598
  for (const [key, entry] of graph.entries) {
3349
3599
  if (entry.namespace === "secret" && isSecretReference(entry.value)) {
3600
+ assertSecretRefVaultProviderCompatible(manifest, entry.value, key);
3350
3601
  const vaultId = entry.value.vault ?? "default";
3602
+ const provider = entry.value.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
3351
3603
  const envVar = resolveProjectedEnvVar(manifest, vaultId, entry.value.ref);
3604
+ referencedVaultIds.add(vaultId);
3352
3605
  secretRefs[key.slice("secret.".length)] = {
3353
- provider: entry.value.provider,
3606
+ provider,
3354
3607
  vault: vaultId,
3355
3608
  ref: entry.value.ref,
3356
3609
  ...envVar ? {
@@ -3396,6 +3649,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
3396
3649
  namespaces.add(entry.namespace);
3397
3650
  }
3398
3651
  }
3652
+ const vaults = projectReferencedVaults(manifest, referencedVaultIds);
3399
3653
  return {
3400
3654
  version: 1,
3401
3655
  workspace: graph.workspace.workspaceId,
@@ -3405,6 +3659,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
3405
3659
  values: stableSortObject(values),
3406
3660
  derived: stableSortObject(derived),
3407
3661
  secretRefs: stableSortObject(secretRefs),
3662
+ ...vaults ? { vaults } : {},
3408
3663
  publicKeys,
3409
3664
  runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
3410
3665
  meta: {
@@ -3519,9 +3774,10 @@ function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
3519
3774
  }
3520
3775
 
3521
3776
  // ../core/src/orchestrator/runtime.ts
3522
- function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
3777
+ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev", secretVaultProviders = []) {
3523
3778
  const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
3524
3779
  const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
3780
+ let activeSecretCache = secretCache;
3525
3781
  function resolveProjectedSourceKey(key) {
3526
3782
  if (!key.startsWith("public.")) {
3527
3783
  return key;
@@ -3538,30 +3794,38 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
3538
3794
  if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
3539
3795
  return;
3540
3796
  }
3541
- if (!secretCache) {
3797
+ if (!activeSecretCache) {
3542
3798
  return;
3543
3799
  }
3544
3800
  const vaultId = entry.value.vault ?? "default";
3545
- const definition = manifest.vaults[vaultId] ?? {
3546
- provider: entry.value.provider,
3547
- auth: { passphrase: { from: [] } }
3548
- };
3549
- const provider = createSecretVaultProvider(vaultId, definition, processEnv);
3550
- const auth = await resolveVaultAuth(vaultId, definition, processEnv);
3551
- await provider.authenticate(auth);
3552
- const value = await provider.get(entry.value.ref);
3553
- if (value !== void 0) {
3554
- secretCache.load(vaultId, /* @__PURE__ */ new Map([[entry.value.ref, value]]));
3801
+ const refreshed = await batchResolveSecrets(
3802
+ {
3803
+ ...graph,
3804
+ entries: /* @__PURE__ */ new Map([[key, entry]])
3805
+ },
3806
+ manifest,
3807
+ processEnv,
3808
+ secretVaultProviders
3809
+ );
3810
+ const resolved = refreshed.get(vaultId, entry.value.ref);
3811
+ const existing = activeSecretCache.entriesForVault(vaultId);
3812
+ existing.delete(entry.value.ref);
3813
+ if (resolved !== void 0) {
3814
+ existing.set(entry.value.ref, resolved);
3555
3815
  }
3816
+ activeSecretCache.replace(vaultId, existing);
3556
3817
  }
3557
3818
  async function refreshAllSecrets() {
3558
- if (!secretCache) {
3819
+ if (!activeSecretCache) {
3559
3820
  return;
3560
3821
  }
3561
- const secretKeys = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "secret" && isSecretReference(entry.value)).map((entry) => entry.key);
3562
- for (const key of secretKeys) {
3563
- await refreshSecretEntry(key);
3564
- }
3822
+ const refreshed = await batchResolveSecrets(
3823
+ graph,
3824
+ manifest,
3825
+ processEnv,
3826
+ secretVaultProviders
3827
+ );
3828
+ activeSecretCache = refreshed;
3565
3829
  }
3566
3830
  function readLogicalKey2(key) {
3567
3831
  const resolved = derivedSupport.read(key, (ref) => {
@@ -3569,10 +3833,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
3569
3833
  if (!entry2) {
3570
3834
  return void 0;
3571
3835
  }
3572
- if (!secretCache) {
3836
+ if (!activeSecretCache) {
3573
3837
  return entry2.value;
3574
3838
  }
3575
- return resolveSecretEntryValue(ref, entry2.value, secretCache);
3839
+ return resolveSecretEntryValue(ref, entry2.value, activeSecretCache);
3576
3840
  });
3577
3841
  if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
3578
3842
  return resolved;
@@ -3581,10 +3845,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
3581
3845
  if (!entry) {
3582
3846
  return void 0;
3583
3847
  }
3584
- if (!secretCache) {
3848
+ if (!activeSecretCache) {
3585
3849
  return entry.value;
3586
3850
  }
3587
- return resolveSecretEntryValue(key, entry.value, secretCache);
3851
+ return resolveSecretEntryValue(key, entry.value, activeSecretCache);
3588
3852
  }
3589
3853
  return {
3590
3854
  manifest,
@@ -3621,10 +3885,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
3621
3885
  if (!entry) {
3622
3886
  return void 0;
3623
3887
  }
3624
- if (!secretCache) {
3888
+ if (!activeSecretCache) {
3625
3889
  return entry.value;
3626
3890
  }
3627
- return resolveSecretEntryValue(candidate, entry.value, secretCache);
3891
+ return resolveSecretEntryValue(candidate, entry.value, activeSecretCache);
3628
3892
  })
3629
3893
  });
3630
3894
  },
@@ -3815,7 +4079,12 @@ async function createCnos(options = {}) {
3815
4079
  });
3816
4080
  const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
3817
4081
  const promotedGraph = promoteToPublic(schemaApplied.graph, loadedManifest.manifest);
3818
- const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(promotedGraph, loadedManifest.manifest, options.processEnv);
4082
+ const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(
4083
+ promotedGraph,
4084
+ loadedManifest.manifest,
4085
+ options.processEnv,
4086
+ options.secretVaultProviders
4087
+ );
3819
4088
  return createRuntime(
3820
4089
  loadedManifest.manifest,
3821
4090
  appendMetaEntries({
@@ -3825,12 +4094,13 @@ async function createCnos(options = {}) {
3825
4094
  plugins,
3826
4095
  secretCache,
3827
4096
  options.processEnv,
3828
- options.cnosVersion
4097
+ options.cnosVersion,
4098
+ options.secretVaultProviders
3829
4099
  );
3830
4100
  }
3831
4101
 
3832
4102
  // ../core/src/runtime/dump.ts
3833
- var import_promises12 = require("fs/promises");
4103
+ var import_promises13 = require("fs/promises");
3834
4104
  var import_node_path13 = __toESM(require("path"), 1);
3835
4105
 
3836
4106
  // ../core/src/utils/envNaming.ts
@@ -3868,7 +4138,7 @@ function envVarToLogicalKey(envVar, config = {}) {
3868
4138
  // package.json
3869
4139
  var package_default = {
3870
4140
  name: "@kitsy/cnos",
3871
- version: "1.10.0",
4141
+ version: "1.11.0",
3872
4142
  description: "Batteries-included CNOS runtime package wired with the official plugins.",
3873
4143
  type: "module",
3874
4144
  main: "./dist/index.cjs",
@@ -4067,7 +4337,7 @@ function createCliArgsPlugin() {
4067
4337
  }
4068
4338
 
4069
4339
  // ../../plugins/dotenv/src/index.ts
4070
- var import_promises13 = require("fs/promises");
4340
+ var import_promises14 = require("fs/promises");
4071
4341
  var import_node_path14 = __toESM(require("path"), 1);
4072
4342
  var DOTENV_PLUGIN_ID = "@kitsy/cnos/plugins/dotenv";
4073
4343
  function parseDoubleQuoted(value) {
@@ -4154,7 +4424,7 @@ function dotenvEntriesFromObject(values, mapping = {}, originFile, workspaceId =
4154
4424
  }
4155
4425
  async function readIfPresent(filePath) {
4156
4426
  try {
4157
- return await (0, import_promises13.readFile)(filePath, "utf8");
4427
+ return await (0, import_promises14.readFile)(filePath, "utf8");
4158
4428
  } catch {
4159
4429
  return void 0;
4160
4430
  }
@@ -4220,16 +4490,16 @@ function createPublicEnvExportPlugin() {
4220
4490
  }
4221
4491
 
4222
4492
  // ../../plugins/filesystem/src/filesystemSecretsReader.ts
4223
- var import_promises15 = require("fs/promises");
4493
+ var import_promises16 = require("fs/promises");
4224
4494
 
4225
4495
  // ../../plugins/filesystem/src/helpers.ts
4226
- var import_promises14 = require("fs/promises");
4496
+ var import_promises15 = require("fs/promises");
4227
4497
  var import_node_path15 = __toESM(require("path"), 1);
4228
4498
  var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
4229
4499
  var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
4230
4500
  async function existsDirectory(targetPath) {
4231
4501
  try {
4232
- const stat2 = await (0, import_promises14.readdir)(targetPath);
4502
+ const stat2 = await (0, import_promises15.readdir)(targetPath);
4233
4503
  void stat2;
4234
4504
  return true;
4235
4505
  } catch {
@@ -4237,7 +4507,7 @@ async function existsDirectory(targetPath) {
4237
4507
  }
4238
4508
  }
4239
4509
  async function collectYamlFiles(root) {
4240
- const entries = await (0, import_promises14.readdir)(root, { withFileTypes: true });
4510
+ const entries = await (0, import_promises15.readdir)(root, { withFileTypes: true });
4241
4511
  const results = [];
4242
4512
  for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
4243
4513
  const absolutePath = import_node_path15.default.join(root, entry.name);
@@ -4339,7 +4609,7 @@ function createFilesystemSecretsPlugin() {
4339
4609
  );
4340
4610
  const entries = [];
4341
4611
  for (const file of files) {
4342
- const document = await (0, import_promises15.readFile)(file.absolutePath, "utf8");
4612
+ const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
4343
4613
  const fileEntries = filesystemSecretsReader(file.relativePath, document, file.workspaceId);
4344
4614
  for (const entry of fileEntries) {
4345
4615
  const metadata = toSecretReferenceMetadata(entry.value);
@@ -4355,7 +4625,7 @@ function createFilesystemSecretsPlugin() {
4355
4625
  }
4356
4626
 
4357
4627
  // ../../plugins/filesystem/src/filesystemValuesReader.ts
4358
- var import_promises16 = require("fs/promises");
4628
+ var import_promises17 = require("fs/promises");
4359
4629
  function filesystemValuesReader(filePath, document, workspaceId = "default") {
4360
4630
  return yamlObjectToEntries(document, filePath, "value", "filesystem-values", workspaceId);
4361
4631
  }
@@ -4376,7 +4646,7 @@ function createFilesystemValuesPlugin() {
4376
4646
  ).map(([namespace]) => namespace);
4377
4647
  const entries = [];
4378
4648
  for (const file of files) {
4379
- const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
4649
+ const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
4380
4650
  entries.push(...filesystemValuesReader(file.relativePath, document, file.workspaceId));
4381
4651
  }
4382
4652
  for (const namespace of customNamespaces) {
@@ -4391,7 +4661,7 @@ function createFilesystemValuesPlugin() {
4391
4661
  layers
4392
4662
  );
4393
4663
  for (const file of namespaceFiles) {
4394
- const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
4664
+ const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
4395
4665
  entries.push(...yamlObjectToEntries(document, file.relativePath, namespace, "filesystem-values", file.workspaceId));
4396
4666
  }
4397
4667
  }
@@ -4647,6 +4917,19 @@ function graphRequiresSecretHydration(graph) {
4647
4917
 
4648
4918
  // src/runtime/index.ts
4649
4919
  var NOT_READY_MESSAGE = "CNOS not initialized. Call await cnos.ready() or use cnos run.";
4920
+ var bootstrappedProjection;
4921
+ var singletonRuntimeProviders = /* @__PURE__ */ new Map();
4922
+ var singletonSecretVaultProviders = /* @__PURE__ */ new Map();
4923
+ function registerSingletonSecretVaultProvider(factory) {
4924
+ singletonSecretVaultProviders.set(factory.provider, factory);
4925
+ }
4926
+ function mergeSecretVaultProviders(factories = []) {
4927
+ const merged = new Map(singletonSecretVaultProviders);
4928
+ for (const factory of factories) {
4929
+ merged.set(factory.provider, factory);
4930
+ }
4931
+ return Array.from(merged.values());
4932
+ }
4650
4933
  function getRuntimeOrThrow() {
4651
4934
  const runtime = getSingletonRuntime();
4652
4935
  if (!runtime) {
@@ -4710,6 +4993,7 @@ function attachBootstrappedGraph(graph) {
4710
4993
  if (getSingletonRuntime()) {
4711
4994
  return;
4712
4995
  }
4996
+ bootstrappedProjection = void 0;
4713
4997
  const bootstrappedManifest = {
4714
4998
  version: 1,
4715
4999
  project: {
@@ -4780,6 +5064,9 @@ function attachBootstrappedGraph(graph) {
4780
5064
  schema: {}
4781
5065
  };
4782
5066
  const runtimeProviders = createDefaultRuntimeProviders(bootstrappedManifest, process.env);
5067
+ for (const [namespace, provider] of singletonRuntimeProviders) {
5068
+ registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
5069
+ }
4783
5070
  const derivedSupport = createDerivedRuntimeSupport(graph, bootstrappedManifest, runtimeProviders);
4784
5071
  const resolveProjectedSourceKey = (key) => {
4785
5072
  if (!key.startsWith("public.")) {
@@ -4848,6 +5135,7 @@ function attachBootstrappedGraph(graph) {
4848
5135
  },
4849
5136
  registerRuntimeProvider(namespace, provider) {
4850
5137
  registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
5138
+ singletonRuntimeProviders.set(namespace, provider);
4851
5139
  },
4852
5140
  async refreshSecrets() {
4853
5141
  return;
@@ -4859,7 +5147,7 @@ function attachBootstrappedGraph(graph) {
4859
5147
  setSingletonRuntime(runtime);
4860
5148
  setBootstrappedSecretHydrationRequired(graphRequiresSecretHydration(graph));
4861
5149
  }
4862
- function toBootstrappedManifest(graph, runtimeNamespaces = []) {
5150
+ function toBootstrappedManifest(graph, runtimeNamespaces = [], vaults = {}) {
4863
5151
  return {
4864
5152
  version: 1,
4865
5153
  project: {
@@ -4920,7 +5208,7 @@ function toBootstrappedManifest(graph, runtimeNamespaces = []) {
4920
5208
  ])
4921
5209
  )
4922
5210
  },
4923
- vaults: {},
5211
+ vaults,
4924
5212
  writePolicy: {
4925
5213
  define: {
4926
5214
  defaultProfile: graph.profile,
@@ -5055,14 +5343,34 @@ function graphFromProjection(projection) {
5055
5343
  }
5056
5344
  };
5057
5345
  }
5058
- function attachBootstrappedProjection(projection, force = false) {
5346
+ function vaultDefinitionFromProjection(manifest, projection, key, ref) {
5347
+ assertSecretRefVaultProviderCompatible(manifest, ref, key);
5348
+ const vaultId = ref.vault ?? "default";
5349
+ const projected = projection.vaults?.[vaultId];
5350
+ const mapping = {
5351
+ ...projected?.mapping ?? {},
5352
+ ...ref.envVar ? { [ref.envVar]: ref.ref } : {}
5353
+ };
5354
+ return {
5355
+ provider: projected?.provider ?? ref.provider ?? "local",
5356
+ ...projected?.auth ? { auth: projected.auth } : {},
5357
+ ...Object.keys(mapping).length > 0 ? { mapping } : {},
5358
+ ...projected?.fallback ? { fallback: projected.fallback } : {}
5359
+ };
5360
+ }
5361
+ function attachBootstrappedProjection(projection, force = false, options = {}) {
5059
5362
  if (getSingletonRuntime() && !force) {
5060
5363
  return;
5061
5364
  }
5365
+ bootstrappedProjection = projection;
5062
5366
  const graph = graphFromProjection(projection);
5063
- const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces);
5367
+ const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces, projection.vaults ?? {});
5064
5368
  const hydratedSecrets = /* @__PURE__ */ new Map();
5369
+ const secretVaultProviders = mergeSecretVaultProviders(options.secretVaultProviders);
5065
5370
  const runtimeProviders = createDefaultRuntimeProviders(manifest, process.env);
5371
+ for (const [namespace, provider] of singletonRuntimeProviders) {
5372
+ registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
5373
+ }
5066
5374
  const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
5067
5375
  const resolveProjectedSourceKey = (key) => {
5068
5376
  if (!key.startsWith("public.")) {
@@ -5075,32 +5383,95 @@ function attachBootstrappedProjection(projection, force = false) {
5075
5383
  const fallback = `value.${key.slice("public.".length)}`;
5076
5384
  return graph.entries.has(fallback) ? fallback : key;
5077
5385
  };
5078
- const resolveSecretValue = async (key) => {
5386
+ const projectedDescriptorForKey = (key) => {
5079
5387
  const entry = graph.entries.get(key);
5080
5388
  if (!entry || entry.namespace !== "secret") {
5081
- return entry?.value;
5082
- }
5083
- if (hydratedSecrets.has(key)) {
5084
- return hydratedSecrets.get(key);
5389
+ return void 0;
5085
5390
  }
5086
5391
  const ref = projection.secretRefs[key.slice("secret.".length)];
5087
5392
  if (!ref) {
5088
5393
  return void 0;
5089
5394
  }
5090
- const definition = {
5091
- provider: ref.provider,
5092
- ...ref.envVar ? {
5093
- mapping: {
5094
- [ref.envVar]: ref.ref
5095
- }
5096
- } : {}
5395
+ const definition = vaultDefinitionFromProjection(manifest, projection, key, ref);
5396
+ return {
5397
+ key,
5398
+ ref,
5399
+ vaultId: ref.vault ?? "default",
5400
+ definitions: [definition, ...definition.fallback ?? []]
5097
5401
  };
5098
- const provider = createSecretVaultProvider(ref.vault ?? "default", definition, process.env);
5099
- const auth = await resolveVaultAuth(ref.vault ?? "default", definition, process.env);
5100
- await provider.authenticate(auth);
5101
- const value = await provider.get(ref.ref);
5102
- hydratedSecrets.set(key, value);
5103
- return value;
5402
+ };
5403
+ const runtimeDefinitionForCandidate = (candidate) => ({
5404
+ provider: candidate.provider,
5405
+ ...candidate.auth ? { auth: candidate.auth } : {},
5406
+ ...candidate.mapping ? { mapping: candidate.mapping } : {}
5407
+ });
5408
+ const hydrateProjectedSecrets = async (keys) => {
5409
+ const requestedKeys = keys ?? Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`);
5410
+ let remaining = requestedKeys.filter((key) => !hydratedSecrets.has(key)).map((key) => projectedDescriptorForKey(key)).filter((descriptor) => Boolean(descriptor));
5411
+ const lastErrors = /* @__PURE__ */ new Map();
5412
+ let candidateIndex = 0;
5413
+ while (remaining.length > 0) {
5414
+ const grouped = /* @__PURE__ */ new Map();
5415
+ const exhausted = [];
5416
+ for (const descriptor of remaining) {
5417
+ const candidate = descriptor.definitions[candidateIndex];
5418
+ if (!candidate) {
5419
+ exhausted.push(descriptor);
5420
+ continue;
5421
+ }
5422
+ const groupKey = `${descriptor.vaultId}\0${candidate.provider}`;
5423
+ const group = grouped.get(groupKey) ?? {
5424
+ vaultId: descriptor.vaultId,
5425
+ definition: candidate,
5426
+ descriptors: []
5427
+ };
5428
+ group.descriptors.push(descriptor);
5429
+ grouped.set(groupKey, group);
5430
+ }
5431
+ if (grouped.size === 0) {
5432
+ remaining = exhausted;
5433
+ break;
5434
+ }
5435
+ const unresolved = [...exhausted];
5436
+ for (const group of grouped.values()) {
5437
+ const runtimeDefinition = runtimeDefinitionForCandidate(group.definition);
5438
+ try {
5439
+ const provider = createSecretVaultProvider(
5440
+ group.vaultId,
5441
+ runtimeDefinition,
5442
+ process.env,
5443
+ secretVaultProviders
5444
+ );
5445
+ const auth = await resolveVaultAuth(group.vaultId, runtimeDefinition, process.env);
5446
+ await provider.authenticate(auth);
5447
+ const refs = Array.from(new Set(group.descriptors.map((descriptor) => descriptor.ref.ref))).sort((left, right) => left.localeCompare(right));
5448
+ const values = await provider.batchGet(refs);
5449
+ for (const descriptor of group.descriptors) {
5450
+ const value = values.get(descriptor.ref.ref);
5451
+ if (value !== void 0) {
5452
+ hydratedSecrets.set(descriptor.key, value);
5453
+ lastErrors.delete(descriptor.key);
5454
+ } else {
5455
+ unresolved.push(descriptor);
5456
+ }
5457
+ }
5458
+ } catch (error) {
5459
+ for (const descriptor of group.descriptors) {
5460
+ lastErrors.set(descriptor.key, error);
5461
+ unresolved.push(descriptor);
5462
+ }
5463
+ }
5464
+ }
5465
+ remaining = unresolved.filter((descriptor) => !hydratedSecrets.has(descriptor.key));
5466
+ candidateIndex += 1;
5467
+ }
5468
+ for (const descriptor of remaining) {
5469
+ const error = lastErrors.get(descriptor.key);
5470
+ if (error) {
5471
+ throw error;
5472
+ }
5473
+ hydratedSecrets.set(descriptor.key, void 0);
5474
+ }
5104
5475
  };
5105
5476
  const runtime = {
5106
5477
  manifest,
@@ -5170,14 +5541,14 @@ function attachBootstrappedProjection(projection, force = false) {
5170
5541
  toNamespace(namespace) {
5171
5542
  return toNamespaceObject(graph, namespace, (key) => this.read(key));
5172
5543
  },
5173
- toEnv(options) {
5174
- return toEnv(graph, manifest, options, {
5544
+ toEnv(options2) {
5545
+ return toEnv(graph, manifest, options2, {
5175
5546
  read: (key) => this.read(key),
5176
5547
  isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
5177
5548
  });
5178
5549
  },
5179
- toPublicEnv(options) {
5180
- return toPublicEnv(graph, manifest, options, {
5550
+ toPublicEnv(options2) {
5551
+ return toPublicEnv(graph, manifest, options2, {
5181
5552
  read: (key) => derivedSupport.toConcreteValue(
5182
5553
  resolveProjectedSourceKey(key),
5183
5554
  (ref) => {
@@ -5200,16 +5571,18 @@ function attachBootstrappedProjection(projection, force = false) {
5200
5571
  },
5201
5572
  registerRuntimeProvider(namespace, provider) {
5202
5573
  registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
5574
+ singletonRuntimeProviders.set(namespace, provider);
5203
5575
  },
5204
5576
  async refreshSecrets() {
5205
- for (const key of Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`)) {
5577
+ const keys = Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`);
5578
+ for (const key of keys) {
5206
5579
  hydratedSecrets.delete(key);
5207
- await resolveSecretValue(key);
5208
5580
  }
5581
+ await hydrateProjectedSecrets(keys);
5209
5582
  },
5210
5583
  async refreshSecret(key) {
5211
5584
  hydratedSecrets.delete(key);
5212
- await resolveSecretValue(key);
5585
+ await hydrateProjectedSecrets([key]);
5213
5586
  }
5214
5587
  };
5215
5588
  setSingletonRuntime(runtime);
@@ -5316,14 +5689,23 @@ var cnos = Object.assign(
5316
5689
  console.log(formatted);
5317
5690
  return formatted;
5318
5691
  },
5319
- async loadProjection(source) {
5692
+ async loadProjection(source, options = {}) {
5320
5693
  const resolvedSource = import_node_path16.default.resolve(source);
5321
5694
  const projection = deserializeServerProjection((0, import_node_fs.readFileSync)(resolvedSource, "utf8"));
5322
- attachBootstrappedProjection(projection, true);
5695
+ attachBootstrappedProjection(projection, true, options);
5323
5696
  setBootstrappedSecretHydrationRequired(Object.keys(projection.secretRefs).length > 0);
5324
5697
  },
5325
5698
  registerRuntimeProvider(namespace, provider) {
5326
5699
  getRuntimeOrThrow().registerRuntimeProvider(namespace, provider);
5700
+ singletonRuntimeProviders.set(namespace, provider);
5701
+ },
5702
+ registerSecretVaultProvider(factory) {
5703
+ registerSingletonSecretVaultProvider(factory);
5704
+ },
5705
+ registerSecretVaultProviders(factories) {
5706
+ for (const factory of factories) {
5707
+ registerSingletonSecretVaultProvider(factory);
5708
+ }
5327
5709
  },
5328
5710
  async refreshSecrets() {
5329
5711
  await getRuntimeOrThrow().refreshSecrets();
@@ -5332,10 +5714,14 @@ var cnos = Object.assign(
5332
5714
  async refreshSecret(key) {
5333
5715
  await getRuntimeOrThrow().refreshSecret(key);
5334
5716
  },
5335
- async ready() {
5717
+ async ready(options = {}) {
5336
5718
  const runtime = getSingletonRuntime();
5719
+ const secretVaultProviders = mergeSecretVaultProviders(options.secretVaultProviders);
5337
5720
  if (runtime && getBootstrappedSecretHydrationRequired()) {
5338
- await runtime.refreshSecrets();
5721
+ const runtimeToHydrate = bootstrappedProjection && secretVaultProviders.length > 0 ? (attachBootstrappedProjection(bootstrappedProjection, true, {
5722
+ secretVaultProviders
5723
+ }), getRuntimeOrThrow()) : runtime;
5724
+ await runtimeToHydrate.refreshSecrets();
5339
5725
  setBootstrappedSecretHydrationRequired(false);
5340
5726
  return;
5341
5727
  }
@@ -5347,7 +5733,10 @@ var cnos = Object.assign(
5347
5733
  await existing;
5348
5734
  return;
5349
5735
  }
5350
- const readyPromise = createCnos2().then((runtime2) => {
5736
+ const readyPromise = createCnos2({
5737
+ ...options,
5738
+ secretVaultProviders
5739
+ }).then((runtime2) => {
5351
5740
  setSingletonRuntime(runtime2);
5352
5741
  setBootstrappedSecretHydrationRequired(false);
5353
5742
  return runtime2;