@clef-sh/core 0.1.23 → 0.1.24-beta.169

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.
@@ -1 +1 @@
1
- {"version":3,"file":"packer.d.ts","sourceRoot":"","sources":["../../src/artifact/packer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAiB,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkB,MAAM,SAAS,CAAC;AAMjE;;;;;;GAMG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAFJ,UAAU,EAAE,iBAAiB,EAC7B,aAAa,EAAE,aAAa,EAC5B,GAAG,CAAC,EAAE,WAAW,YAAA;IAGpC;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CAiI9F"}
1
+ {"version":3,"file":"packer.d.ts","sourceRoot":"","sources":["../../src/artifact/packer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAiB,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkB,MAAM,SAAS,CAAC;AAMjE;;;;;;GAMG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAFJ,UAAU,EAAE,iBAAiB,EAC7B,aAAa,EAAE,aAAa,EAC5B,GAAG,CAAC,EAAE,WAAW,YAAA;IAGpC;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CA0I9F"}
@@ -1,9 +1,13 @@
1
1
  import { ClefManifest, EncryptionBackend, ServiceIdentityDefinition, ServiceIdentityEnvironmentConfig } from "../types";
2
2
  import { MatrixManager } from "../matrix/manager";
3
- /** Resolved identity secrets: merged key/value map plus metadata. */
3
+ /** Resolved identity secrets: namespace keyvalue, plus metadata. */
4
4
  export interface ResolvedSecrets {
5
- /** Flat key/value map (namespace-prefixed if multi-namespace). */
6
- values: Record<string, string>;
5
+ /**
6
+ * Nested map keyed by namespace, then by key name. The on-the-wire ciphertext
7
+ * payload uses this exact shape — namespace structure stays inside the
8
+ * encrypted blob, never in clear metadata.
9
+ */
10
+ values: Record<string, Record<string, string>>;
7
11
  /** The matched service identity definition. */
8
12
  identity: ServiceIdentityDefinition;
9
13
  /** Age public key for the target environment (undefined for KMS identities). */
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/artifact/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,yBAAyB,EACzB,gCAAgC,EACjC,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,+CAA+C;IAC/C,QAAQ,EAAE,yBAAyB,CAAC;IACpC,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,SAAS,EAAE,gCAAgC,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,iBAAiB,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,eAAe,CAAC,CA+C1B"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/artifact/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,yBAAyB,EACzB,gCAAgC,EACjC,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,+CAA+C;IAC/C,QAAQ,EAAE,yBAAyB,CAAC;IACpC,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,SAAS,EAAE,gCAAgC,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,iBAAiB,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,eAAe,CAAC,CA0C1B"}
@@ -117,6 +117,23 @@ export declare class GitIntegration {
117
117
  * @throws {@link GitOperationError} On failure.
118
118
  */
119
119
  getDiff(repoRoot: string): Promise<string>;
120
+ /**
121
+ * Of the given paths, return those that exist on disk but are untracked by git.
122
+ *
123
+ * Used by {@link TransactionManager} to refuse mutations whose declared paths
124
+ * include untracked-but-existing files. Rollback uses `git reset --hard` to
125
+ * restore content, which can only restore files that exist in a commit. An
126
+ * untracked file in the declared paths would be silently destroyed by the
127
+ * rollback's `git clean` — so we refuse upfront.
128
+ *
129
+ * @param repoRoot - Working directory for the git command.
130
+ * @param paths - Paths to check (relative to repoRoot).
131
+ * @returns Subset of `paths` that are untracked. Non-existent paths are
132
+ * excluded; tracked paths are excluded; directories are reported by
133
+ * their porcelain entry (with trailing slash if untracked-as-dir).
134
+ * @throws {@link GitOperationError} On failure.
135
+ */
136
+ getUntrackedAmongPaths(repoRoot: string, paths: string[]): Promise<string[]>;
120
137
  /**
121
138
  * Parse `git status --porcelain` into staged, unstaged, and untracked lists.
122
139
  *
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../src/git/integration.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAqB,SAAS,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA8CrF;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAErD;;;;;;OAMG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAatE;;;;;;;;OAQG;IACG,MAAM,CACV,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7D,OAAO,CAAC,MAAM,CAAC;IAqBlB;;;;;;OAMG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAahD;;;;;;;;;;OAUG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW7D;;;;;;;OAOG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAelE;;;;;;OAMG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBjD;;;;;;;OAOG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,GAAG,QAAQ,CAAA;KAAE,CAAC;IAsBpF;;;;;OAKG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKhD;;;;;;OAMG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAe1F;;;;;;;OAOG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IA6B1F;;;;;;OAMG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUhD;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IA8CrD;;;;;;;;;;;;OAYG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCzD;;;;;;;OAOG;IACG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAChD,SAAS,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,OAAO,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,qBAAqB,EAAE,OAAO,CAAC;KAChC,CAAC;YAqBY,mBAAmB;IAyBjC;;;;;;OAMG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAgB5D"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../src/git/integration.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAqB,SAAS,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA8CrF;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAErD;;;;;;OAMG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAatE;;;;;;;;OAQG;IACG,MAAM,CACV,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7D,OAAO,CAAC,MAAM,CAAC;IAqBlB;;;;;;OAMG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAahD;;;;;;;;;;OAUG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW7D;;;;;;;OAOG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAelE;;;;;;OAMG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBjD;;;;;;;OAOG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,GAAG,QAAQ,CAAA;KAAE,CAAC;IAsBpF;;;;;OAKG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKhD;;;;;;OAMG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAe1F;;;;;;;OAOG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IA6B1F;;;;;;OAMG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUhD;;;;;;;;;;;;;;;OAeG;IACG,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBlF;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IA8CrD;;;;;;;;;;;;OAYG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCzD;;;;;;;OAOG;IACG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAChD,SAAS,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,OAAO,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,qBAAqB,EAAE,OAAO,CAAC;KAChC,CAAC;YAqBY,mBAAmB;IAyBjC;;;;;;OAMG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAgB5D"}
@@ -30,7 +30,7 @@ export interface SpawnKeyserviceOptions {
30
30
  * Spawn a clef-keyservice sidecar and wait for it to report its port.
31
31
  *
32
32
  * @throws If neither `pin` nor `pinFile` is provided, if startup exceeds
33
- * {@link STARTUP_TIMEOUT_MS}, or if the child exits before reporting `PORT=`.
33
+ * the 5s startup timeout, or if the child exits before reporting `PORT=`.
34
34
  */
35
35
  export declare function spawnKeyservice(options: SpawnKeyserviceOptions): Promise<KeyserviceHandle>;
36
36
  //# sourceMappingURL=keyservice.d.ts.map
package/dist/index.js CHANGED
@@ -11732,6 +11732,7 @@ function keyPreview(key) {
11732
11732
  var CLEF_MANIFEST_FILENAME = "clef.yaml";
11733
11733
  var VALID_BACKENDS = ["age", "awskms", "gcpkms", "azurekv", "pgp", "hsm"];
11734
11734
  var PKCS11_URI_PATTERN = /^pkcs11:[a-zA-Z][a-zA-Z0-9_-]*=[^;]+/;
11735
+ var AWS_KMS_ARN_PATTERN = /^arn:aws(?:-[a-z]+)*:kms:[a-z0-9-]+:\d+:(key|alias)\/.+$/;
11735
11736
  var VALID_TOP_LEVEL_KEYS = [
11736
11737
  "version",
11737
11738
  "environments",
@@ -12254,11 +12255,22 @@ var ManifestParser = class {
12254
12255
  "service_identities"
12255
12256
  );
12256
12257
  }
12258
+ if (kmsObj.provider === "aws" && !AWS_KMS_ARN_PATTERN.test(kmsObj.keyId)) {
12259
+ throw new ManifestValidationError(
12260
+ `Service identity '${siName}' environment '${envName}': kms.keyId must be a full AWS KMS ARN (e.g. arn:aws:kms:us-east-1:123456789012:key/abcd-1234), got '${kmsObj.keyId}'.`,
12261
+ "service_identities"
12262
+ );
12263
+ }
12264
+ if (Object.prototype.hasOwnProperty.call(kmsObj, "region")) {
12265
+ throw new ManifestValidationError(
12266
+ `Service identity '${siName}' environment '${envName}': kms.region is no longer accepted; the region is read from the AWS KMS key ARN. Remove this field.`,
12267
+ "service_identities"
12268
+ );
12269
+ }
12257
12270
  parsedEnvs[envName] = {
12258
12271
  kms: {
12259
12272
  provider: kmsObj.provider,
12260
- keyId: kmsObj.keyId,
12261
- region: typeof kmsObj.region === "string" ? kmsObj.region : void 0
12273
+ keyId: kmsObj.keyId
12262
12274
  }
12263
12275
  };
12264
12276
  }
@@ -12903,11 +12915,17 @@ var MatrixManager = class {
12903
12915
  await sopsClient.encrypt(cell.filePath, {}, manifest, cell.environment);
12904
12916
  }
12905
12917
  /**
12906
- * Decrypt each cell and return key counts, pending counts, and cross-environment issues.
12918
+ * Read each cell and return key counts, pending counts, and cross-environment issues.
12919
+ *
12920
+ * The SOPS client parameter is currently unused — keys are read from the
12921
+ * plaintext YAML structure directly, no decryption needed. It is retained
12922
+ * in the signature for back-compat with callers that may need to swap to a
12923
+ * decrypt-based implementation later (e.g. for backends that don't expose
12924
+ * key names without decryption).
12907
12925
  *
12908
12926
  * @param manifest - Parsed manifest.
12909
12927
  * @param repoRoot - Absolute path to the repository root.
12910
- * @param sopsClient - SOPS client used to decrypt each cell.
12928
+ * @param _sopsClient - Reserved for future use; pass any `EncryptionBackend`.
12911
12929
  */
12912
12930
  async getMatrixStatus(manifest, repoRoot, _sopsClient) {
12913
12931
  const cells = this.resolveMatrix(manifest, repoRoot);
@@ -13664,6 +13682,42 @@ var GitIntegration = class {
13664
13682
  }
13665
13683
  return result.stdout;
13666
13684
  }
13685
+ /**
13686
+ * Of the given paths, return those that exist on disk but are untracked by git.
13687
+ *
13688
+ * Used by {@link TransactionManager} to refuse mutations whose declared paths
13689
+ * include untracked-but-existing files. Rollback uses `git reset --hard` to
13690
+ * restore content, which can only restore files that exist in a commit. An
13691
+ * untracked file in the declared paths would be silently destroyed by the
13692
+ * rollback's `git clean` — so we refuse upfront.
13693
+ *
13694
+ * @param repoRoot - Working directory for the git command.
13695
+ * @param paths - Paths to check (relative to repoRoot).
13696
+ * @returns Subset of `paths` that are untracked. Non-existent paths are
13697
+ * excluded; tracked paths are excluded; directories are reported by
13698
+ * their porcelain entry (with trailing slash if untracked-as-dir).
13699
+ * @throws {@link GitOperationError} On failure.
13700
+ */
13701
+ async getUntrackedAmongPaths(repoRoot, paths) {
13702
+ if (paths.length === 0) return [];
13703
+ const result = await this.runner.run("git", ["status", "--porcelain", "--", ...paths], {
13704
+ cwd: repoRoot
13705
+ });
13706
+ if (result.exitCode !== 0) {
13707
+ throw new GitOperationError(
13708
+ `Failed to check tracked status: ${result.stderr.trim()}`,
13709
+ "Inspect with 'git status' and resolve any repository errors."
13710
+ );
13711
+ }
13712
+ const untracked = [];
13713
+ for (const line of result.stdout.split("\n")) {
13714
+ if (line === "") continue;
13715
+ if (line[0] === "?") {
13716
+ untracked.push(line.substring(3));
13717
+ }
13718
+ }
13719
+ return untracked;
13720
+ }
13667
13721
  /**
13668
13722
  * Parse `git status --porcelain` into staged, unstaged, and untracked lists.
13669
13723
  *
@@ -13938,6 +13992,14 @@ var TransactionManager = class {
13938
13992
  "Commit or stash your changes first, or pass --allow-dirty to proceed (rollback will be best-effort)."
13939
13993
  );
13940
13994
  }
13995
+ const untrackedDeclared = await this.git.getUntrackedAmongPaths(repoRoot, opts.paths);
13996
+ if (untrackedDeclared.length > 0) {
13997
+ throw new TransactionPreflightError(
13998
+ "untracked-paths",
13999
+ `Refusing to mutate: the following declared paths are untracked and would not survive rollback: ${untrackedDeclared.join(", ")}`,
14000
+ "Commit these files first (`git add` + `git commit`), then retry. Rollback can only restore content that exists in a commit."
14001
+ );
14002
+ }
13941
14003
  try {
13942
14004
  await opts.mutate();
13943
14005
  } catch (mutateErr) {
@@ -17656,23 +17718,18 @@ async function resolveIdentitySecrets(identityName, environment, manifest, repoR
17656
17718
  const cells = matrixManager.resolveMatrix(manifest, repoRoot).filter(
17657
17719
  (c) => c.exists && identity.namespaces.includes(c.namespace) && c.environment === environment
17658
17720
  );
17659
- const isMultiNamespace = identity.namespaces.length > 1;
17660
- const collisions = [];
17661
17721
  for (const cell of cells) {
17662
17722
  const decrypted = await encryption.decrypt(cell.filePath);
17723
+ const bucket = allValues[cell.namespace] ??= {};
17663
17724
  for (const [key, value] of Object.entries(decrypted.values)) {
17664
- const qualifiedKey = isMultiNamespace ? `${cell.namespace}__${key}` : key;
17665
- if (qualifiedKey in allValues && allValues[qualifiedKey] !== value) {
17666
- collisions.push(qualifiedKey);
17725
+ if (key in bucket && bucket[key] !== value) {
17726
+ throw new Error(
17727
+ `Key collision in namespace '${cell.namespace}': '${key}' set to different values.`
17728
+ );
17667
17729
  }
17668
- allValues[qualifiedKey] = value;
17730
+ bucket[key] = value;
17669
17731
  }
17670
17732
  }
17671
- if (collisions.length > 0) {
17672
- throw new Error(
17673
- `Key collision detected in bundle: ${collisions.join(", ")}. Keys with the same name but different values exist across namespaces.`
17674
- );
17675
- }
17676
17733
  return {
17677
17734
  values: allValues,
17678
17735
  identity,
@@ -17915,7 +17972,12 @@ var ArtifactPacker = class {
17915
17972
  const json = JSON.stringify(artifact, null, 2);
17916
17973
  const output = config.output ?? new FilePackOutput(config.outputPath ?? "artifact.json");
17917
17974
  await output.write(artifact, json);
17918
- const keys = Object.keys(resolved.values);
17975
+ const keys = [];
17976
+ for (const [ns, bucket] of Object.entries(resolved.values)) {
17977
+ for (const k of Object.keys(bucket)) {
17978
+ keys.push(`${ns}__${k}`);
17979
+ }
17980
+ }
17919
17981
  return {
17920
17982
  outputPath: config.outputPath ?? "",
17921
17983
  namespaceCount: resolved.identity.namespaces.length,