zyrk 0.5.0 → 0.5.1

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 (38) hide show
  1. package/README.md +4 -2
  2. package/VERSION +1 -1
  3. package/dist/commands/deploy.d.ts.map +1 -1
  4. package/dist/commands/deploy.js +7 -11
  5. package/dist/commands/maintenance.d.ts.map +1 -1
  6. package/dist/commands/maintenance.js +22 -2
  7. package/dist/fetch/package.d.ts.map +1 -1
  8. package/dist/fetch/package.js +2 -1
  9. package/dist/fetch/registry.d.ts +5 -0
  10. package/dist/fetch/registry.d.ts.map +1 -1
  11. package/dist/fetch/registry.js +84 -10
  12. package/dist/install/import-npm-workspace.d.ts +1 -1
  13. package/dist/install/import-npm-workspace.d.ts.map +1 -1
  14. package/dist/install/import-npm-workspace.js +1 -1
  15. package/dist/install/import-npm.d.ts +1 -1
  16. package/dist/install/import-npm.d.ts.map +1 -1
  17. package/dist/install/import-npm.js +3 -2
  18. package/dist/install/registry-policy.d.ts +9 -0
  19. package/dist/install/registry-policy.d.ts.map +1 -0
  20. package/dist/install/registry-policy.js +30 -0
  21. package/dist/install/registry.d.ts.map +1 -1
  22. package/dist/install/registry.js +18 -13
  23. package/dist/install/run.d.ts.map +1 -1
  24. package/dist/install/run.js +11 -3
  25. package/dist/install/workspace-graph.d.ts.map +1 -1
  26. package/dist/install/workspace-graph.js +4 -3
  27. package/dist/install/workspace-install.d.ts.map +1 -1
  28. package/dist/install/workspace-install.js +12 -3
  29. package/dist/install/workspace-lock.d.ts +1 -1
  30. package/dist/install/workspace-lock.d.ts.map +1 -1
  31. package/dist/install/workspace-lock.js +5 -1
  32. package/dist/lockfile/fingerprints.d.ts +1 -0
  33. package/dist/lockfile/fingerprints.d.ts.map +1 -1
  34. package/dist/lockfile/fingerprints.js +3 -0
  35. package/dist/resolve/resolver.d.ts +1 -0
  36. package/dist/resolve/resolver.d.ts.map +1 -1
  37. package/dist/resolve/resolver.js +2 -2
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -116,8 +116,10 @@ Default registry and authentication settings are loaded from user/project
116
116
  token placeholders are supported. Credentials are restricted to their configured
117
117
  scheme, host, port, and path; redirects cannot expand that scope. Use
118
118
  `--registry=https://your-registry.example/` on install for an explicit registry.
119
- Mixed scoped routing and disabled TLS verification are rejected before public
120
- lookup. Git sources, non-workspace local sources, and overrides remain unsupported;
119
+ Scoped registries route metadata, exact sources, imports and tool commands by
120
+ the real package name, including aliases. Advisory requests are partitioned by
121
+ registry; private names never fall back to a public endpoint. Disabled TLS
122
+ verification is rejected before lookup. Git sources, non-workspace local sources, and overrides remain unsupported;
121
123
  they fail explicitly. Optional dependencies incompatible with the selected platform
122
124
  are omitted; missing packages, integrity failures, and other optional failures
123
125
  remain errors. Platform selection is recorded in the lock. macOS, Windows, and
package/VERSION CHANGED
@@ -1 +1 @@
1
- v0.5.0
1
+ v0.5.1
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAmEA,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAwEF,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CA0ZjB"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAoEA,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAwEF,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAqZjB"}
@@ -1,3 +1,4 @@
1
+ import { installedRegistryConfig } from "../install/registry-policy.js";
1
2
  /** Self-contained runtime deployment and explicit local Docker commands. */
2
3
  import { constants } from "node:fs";
3
4
  import { open, copyFile, chmod, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rename, rm, symlink, writeFile, } from "node:fs/promises";
@@ -141,16 +142,14 @@ export async function runDeployCommand(options) {
141
142
  manifestFingerprint(manifest))
142
143
  throw error("ZYRK_LOCK_MISMATCH", "Deployment manifest, lock, and installed generation disagree.");
143
144
  if (resolved.nodes.length) {
144
- const origins = new Set(resolved.nodes.map((node) => node.origin));
145
- if (origins.size !== 1)
146
- throw error("ZYRK_DEPLOY_NONRELOCATABLE", "Mixed-origin deployment requires a validated registry adapter.");
145
+ const registryConfig = installedRegistryConfig(state, resolved.nodes);
147
146
  const patches = await loadProjectPatches(project);
148
147
  const policy = object(manifest.zyrk) ? manifest.zyrk : {};
149
148
  assertFrozenCompatible(doc, {
150
149
  manifest: manifestFingerprint(manifest),
151
150
  scripts: scriptPolicyFingerprint(policy.scripts),
152
151
  config: configFingerprint({
153
- registry: [...origins][0],
152
+ ...registryConfig,
154
153
  linker: "shared",
155
154
  platform: currentPlatform(),
156
155
  ...(Array.isArray(policy.mutablePackages)
@@ -800,15 +799,12 @@ async function exportWorkspace(options, project, manifest, state, out, parent, f
800
799
  const policy = object(manifest.zyrk) ? manifest.zyrk : {};
801
800
  if (locked.doc.zyrk.scripts !== scriptPolicyFingerprint(policy.scripts))
802
801
  throw error("ZYRK_LOCK_MISMATCH", "Workspace deployment build policy changed after installation.");
803
- const origins = new Set(locked.graph.nodes
804
- .filter((n) => n.kind === "registry")
805
- .map((n) => n.origin));
806
- if (origins.size > 1)
807
- throw error("ZYRK_DEPLOY_NONRELOCATABLE", "Mixed-origin workspace export requires a validated registry adapter.");
808
- if (origins.size === 1) {
802
+ const registryNodesForPolicy = locked.graph.nodes.filter((n) => n.kind === "registry");
803
+ if (registryNodesForPolicy.length || state.registryConfig !== undefined) {
804
+ const registryConfig = installedRegistryConfig(state, registryNodesForPolicy);
809
805
  const patches = await loadProjectPatches(project);
810
806
  const expected = configFingerprint({
811
- registry: [...origins][0],
807
+ ...registryConfig,
812
808
  linker: "shared",
813
809
  platform: currentPlatform(),
814
810
  ...(Array.isArray(policy.mutablePackages)
@@ -1 +1 @@
1
- {"version":3,"file":"maintenance.d.ts","sourceRoot":"","sources":["../../src/commands/maintenance.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AASvE,QAAA,MAAM,UAAU,YAAI,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC;AAC5E,KAAK,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,aAAa,CAAC;IAChD,UAAU,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,QAAQ,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAUF,wBAAsB,qBAAqB,CAAC,OAAO,EAAE;IACnD,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;IACtC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC,aAAa,GAAG,WAAW,CAAC,CAwOvC"}
1
+ {"version":3,"file":"maintenance.d.ts","sourceRoot":"","sources":["../../src/commands/maintenance.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AASvE,QAAA,MAAM,UAAU,YAAI,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC;AAC5E,KAAK,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,aAAa,CAAC;IAChD,UAAU,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,QAAQ,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAUF,wBAAsB,qBAAqB,CAAC,OAAO,EAAE;IACnD,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;IACtC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC,aAAa,GAAG,WAAW,CAAC,CAgQvC"}
@@ -126,6 +126,7 @@ export async function runMaintenanceCommand(options) {
126
126
  scripts: scriptPolicyFingerprint(object(manifest.zyrk) ? manifest.zyrk.scripts : undefined),
127
127
  config: configFingerprint({
128
128
  registry: options.registry.origin,
129
+ registries: options.registry.scopedRegistries,
129
130
  linker: "shared",
130
131
  platform: currentPlatform(),
131
132
  ...(object(manifest.zyrk) && Array.isArray(manifest.zyrk.mutablePackages)
@@ -146,7 +147,7 @@ export async function runMaintenanceCommand(options) {
146
147
  : lockedGraph(lock.doc).nodes;
147
148
  const packages = Object.create(null);
148
149
  for (const node of graphNodes) {
149
- if (node.origin !== options.registry.origin)
150
+ if (node.origin !== options.registry.originFor(node.name))
150
151
  throw new ZyrkError("ZYRK_POLICY_DENIED", "Cannot audit a graph from a different registry origin.", {
151
152
  remedy: "Select the registry recorded by the lockfile before sending dependency names.",
152
153
  });
@@ -158,7 +159,26 @@ export async function runMaintenanceCommand(options) {
158
159
  return base;
159
160
  let response;
160
161
  try {
161
- response = await options.registry.auditAdvisories(packages);
162
+ const groups = new Map();
163
+ for (const [name, versions] of Object.entries(packages)) {
164
+ const client = options.registry.forPackage(name);
165
+ let selected = groups.get(client);
166
+ if (!selected) {
167
+ selected = Object.create(null);
168
+ groups.set(client, selected);
169
+ }
170
+ selected[name] = versions;
171
+ }
172
+ const replies = await Promise.all([...groups].map(async ([client, selected]) => {
173
+ const reply = await client.auditAdvisories(selected);
174
+ if (!object(reply) ||
175
+ Object.keys(reply).some((name) => !Object.hasOwn(selected, name)))
176
+ return null;
177
+ return reply;
178
+ }));
179
+ response = replies.some((reply) => reply === null)
180
+ ? null
181
+ : Object.assign({}, ...replies);
162
182
  }
163
183
  catch {
164
184
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"package.d.ts","sourceRoot":"","sources":["../../src/fetch/package.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,EAA0B,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAA6B,MAAM,eAAe,CAAC;AAE1E;;2EAE2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,IAAI,IAAI,CAAC;IACnB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAgB,oBAAoB,CAClC,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACjB,GACL;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAAC,KAAK,IAAI,IAAI,CAAA;CAAE,CAuDzE;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACnC,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wEAAwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED,MAAM,WAAW,aAAc,SAAQ,eAAe;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CA+IxB"}
1
+ {"version":3,"file":"package.d.ts","sourceRoot":"","sources":["../../src/fetch/package.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,EAA0B,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAA6B,MAAM,eAAe,CAAC;AAE1E;;2EAE2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,IAAI,IAAI,CAAC;IACnB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAgB,oBAAoB,CAClC,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACjB,GACL;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAAC,KAAK,IAAI,IAAI,CAAA;CAAE,CAuDzE;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACnC,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wEAAwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED,MAAM,WAAW,aAAc,SAAQ,eAAe;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAgJxB"}
@@ -72,7 +72,8 @@ export function createFetchOperation(options = {}) {
72
72
  * Callers resolve the version first; this function never guesses.
73
73
  */
74
74
  export async function fetchAndCommitSource(options) {
75
- const { store, registry, txn, name, version } = options;
75
+ const { store, txn, name, version } = options;
76
+ const registry = options.registry.forPackage(name);
76
77
  const label = `${name}@${version}`;
77
78
  // ---- 1. Metadata: exact version entry for the resolved identity ----
78
79
  options.operation?.checkpoint();
@@ -48,6 +48,7 @@ export interface Packument {
48
48
  modified?: string;
49
49
  }
50
50
  export interface RegistryClientOptions {
51
+ scopedRegistries?: Readonly<Record<string, string>>;
51
52
  /** Registry base URL; must be http(s). Trailing slash optional. */
52
53
  registry: string;
53
54
  userAgent: string;
@@ -83,6 +84,10 @@ export declare class RegistryClient {
83
84
  /** Credential-free registry origin; participates in source identity (§8.1). */
84
85
  get origin(): string;
85
86
  get registry(): string;
87
+ /** Routing always follows the real package name, including npm aliases. */
88
+ forPackage(name: string): RegistryClient;
89
+ originFor(name: string): string;
90
+ get scopedRegistries(): Readonly<Record<string, string>>;
86
91
  /** Fetch the (abbreviated) packument for an exact package name. */
87
92
  packument(name: string, options?: {
88
93
  signal?: AbortSignal;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/fetch/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/fetch/registry.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,8 @@ export const DEFAULT_REGISTRY = "https://registry.npmjs.org/";
22
22
  /** npm's abbreviated packument media type, used for installs. */
23
23
  const INSTALL_V1_ACCEPT = "application/vnd.npm.install-v1+json";
24
24
  export class RegistryClient {
25
+ #routeBoundaries = [];
26
+ #scopedClients = new Map();
25
27
  #registry;
26
28
  #origin;
27
29
  #userAgent;
@@ -30,7 +32,7 @@ export class RegistryClient {
30
32
  #maxTarballBytes;
31
33
  #maxMetadataBytes;
32
34
  #maxTotalMetadataBytes;
33
- #totalMetadataBytes = 0;
35
+ #metadataBudget = { bytes: 0 };
34
36
  #maxMetadataVersions;
35
37
  #requestDeadlineMs;
36
38
  #signal;
@@ -59,13 +61,51 @@ export class RegistryClient {
59
61
  base.timeout = options.timeoutMs;
60
62
  const parsed = safeTransportOptions(options.fetchOptions ?? {}, registry);
61
63
  this.#fetchOptions = { ...base, ...parsed.transport, strictSSL: true };
62
- this.#credentials = parsed.credentials;
64
+ const boundary = new URL(registry);
65
+ this.#credentials = parsed.credentials.filter(({ scope }) => scope.origin === boundary.origin &&
66
+ (scope.pathname.startsWith(boundary.pathname) ||
67
+ boundary.pathname.startsWith(scope.pathname)));
63
68
  this.#maxMetadataBytes = positiveLimit(options.maxMetadataBytes ?? 32 * 1024 * 1024, "maxMetadataBytes");
64
69
  this.#maxTotalMetadataBytes = positiveLimit(options.maxTotalMetadataBytes ?? 128 * 1024 * 1024, "maxTotalMetadataBytes");
65
70
  this.#maxMetadataVersions = positiveLimit(options.maxMetadataVersions ?? 100_000, "maxMetadataVersions");
66
71
  this.#requestDeadlineMs = positiveLimit(options.requestDeadlineMs ?? 120_000, "requestDeadlineMs");
67
72
  positiveLimit(this.#maxTarballBytes, "maxTarballBytes");
68
73
  this.#signal = options.signal;
74
+ const { scopedRegistries, ...baseOptions } = options;
75
+ for (const [scope, selected] of Object.entries(scopedRegistries ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
76
+ if (!/^@[a-z0-9][a-z0-9._-]*$/.test(scope))
77
+ throw new ZyrkError("ZYRK_POLICY_DENIED", "Invalid scoped registry name.", { remedy: "Use an npm @scope registry setting." });
78
+ const { headers, ...childFetchOptions } = options.fetchOptions ?? {};
79
+ const client = new RegistryClient({
80
+ ...baseOptions,
81
+ fetchOptions: childFetchOptions,
82
+ registry: selected,
83
+ });
84
+ // Raw Authorization headers are scoped once to the original registry.
85
+ // Cloning must never reinterpret them as credentials for a child host.
86
+ for (const authorization of Object.values((headers ?? {}))) {
87
+ const originalScope = new URL(registry), childScope = new URL(client.registry);
88
+ if (originalScope.origin === childScope.origin &&
89
+ (originalScope.pathname.startsWith(childScope.pathname) ||
90
+ childScope.pathname.startsWith(originalScope.pathname)))
91
+ client.#credentials.push({ scope: originalScope, authorization });
92
+ }
93
+ client.#credentials.sort((a, b) => b.scope.pathname.length - a.scope.pathname.length);
94
+ client.#metadataBudget = this.#metadataBudget;
95
+ this.#scopedClients.set(scope, client);
96
+ }
97
+ // A containing public registry must not borrow a credential belonging to a
98
+ // narrower configured private registry on the same host. Explicit broad
99
+ // credentials retain their declared scope, including use by child routes.
100
+ const clients = [this, ...this.#scopedClients.values()];
101
+ const boundaries = clients.map((client) => new URL(client.registry));
102
+ for (const client of clients) {
103
+ const own = new URL(client.registry);
104
+ client.#routeBoundaries = boundaries;
105
+ client.#credentials = client.#credentials.filter(({ scope }) => !boundaries.some((boundary) => boundary.origin === scope.origin &&
106
+ boundary.pathname.length > own.pathname.length &&
107
+ scope.pathname.startsWith(boundary.pathname)));
108
+ }
69
109
  }
70
110
  /** Credential-free registry origin; participates in source identity (§8.1). */
71
111
  get origin() {
@@ -74,9 +114,24 @@ export class RegistryClient {
74
114
  get registry() {
75
115
  return this.#registry;
76
116
  }
117
+ /** Routing always follows the real package name, including npm aliases. */
118
+ forPackage(name) {
119
+ validateRegistryPackageName(name);
120
+ return name.startsWith("@")
121
+ ? (this.#scopedClients.get(name.slice(0, name.indexOf("/"))) ?? this)
122
+ : this;
123
+ }
124
+ originFor(name) {
125
+ return this.forPackage(name).origin;
126
+ }
127
+ get scopedRegistries() {
128
+ return Object.fromEntries([...this.#scopedClients].map(([scope, client]) => [scope, client.origin]));
129
+ }
77
130
  /** Fetch the (abbreviated) packument for an exact package name. */
78
131
  async packument(name, options = {}) {
79
- validateRegistryPackageName(name);
132
+ const selected = this.forPackage(name);
133
+ if (selected !== this)
134
+ return selected.packument(name, options);
80
135
  const url = `${this.#registry}${escapePackageName(name)}`;
81
136
  this.#logger?.debug("fetching packument", { name, url });
82
137
  let raw;
@@ -96,6 +151,14 @@ export class RegistryClient {
96
151
  versions.some((version) => typeof version !== "string"))
97
152
  throw new ZyrkError("ZYRK_POLICY_DENIED", "Invalid registry advisory package versions.");
98
153
  }
154
+ const routes = new Set(Object.keys(packages).map((name) => this.forPackage(name)));
155
+ if (routes.size > 1)
156
+ throw new ZyrkError("ZYRK_POLICY_DENIED", "Mixed-registry audit requests must be partitioned by registry.", {
157
+ remedy: "Audit each selected registry independently so private names are never disclosed across origins.",
158
+ });
159
+ const selected = [...routes][0];
160
+ if (selected && selected !== this)
161
+ return selected.auditAdvisories(packages, options);
99
162
  const body = JSON.stringify(packages);
100
163
  if (Buffer.byteLength(body) > this.#maxMetadataBytes)
101
164
  throw resourceLimit("advisory request bytes", this.#maxMetadataBytes, "maxMetadataBytes");
@@ -107,10 +170,10 @@ export class RegistryClient {
107
170
  }
108
171
  }
109
172
  #countMetadataBytes(bytes, responseBytes) {
110
- this.#totalMetadataBytes += bytes;
173
+ this.#metadataBudget.bytes += bytes;
111
174
  if (responseBytes > this.#maxMetadataBytes)
112
175
  throw resourceLimit("metadata bytes", this.#maxMetadataBytes, "maxMetadataBytes");
113
- if (this.#totalMetadataBytes > this.#maxTotalMetadataBytes)
176
+ if (this.#metadataBudget.bytes > this.#maxTotalMetadataBytes)
114
177
  throw resourceLimit("total metadata bytes", this.#maxTotalMetadataBytes, "maxTotalMetadataBytes");
115
178
  }
116
179
  async #readMetadata(response) {
@@ -226,6 +289,15 @@ export class RegistryClient {
226
289
  throw mapFetchError(error, `download tarball for ${options.label}`);
227
290
  }
228
291
  }
292
+ #insideAdvisoryBoundary(url) {
293
+ const registryScope = new URL(this.#registry);
294
+ return (url.origin === registryScope.origin &&
295
+ url.pathname.startsWith(registryScope.pathname) &&
296
+ !/%(?:2f|5c|2e)/i.test(url.pathname) &&
297
+ !this.#routeBoundaries.some((boundary) => boundary.origin === url.origin &&
298
+ boundary.pathname.length > registryScope.pathname.length &&
299
+ url.pathname.startsWith(boundary.pathname)));
300
+ }
229
301
  async #withRequest(url, accept, consume, signal, request = {}) {
230
302
  const controller = new AbortController();
231
303
  let active;
@@ -246,6 +318,10 @@ export class RegistryClient {
246
318
  cancel();
247
319
  try {
248
320
  let current = parseTarballUrl(url, "registry request");
321
+ if (request.method === "POST" && !this.#insideAdvisoryBoundary(current))
322
+ throw new ZyrkError("ZYRK_FETCH_REFUSED", "Registry advisory endpoint overlaps another configured registry or has an ambiguous path.", {
323
+ remedy: "Use a distinct advisory endpoint within the selected registry's own route.",
324
+ });
249
325
  let crossedBoundary = false;
250
326
  for (let hop = 0; hop <= 10; hop++) {
251
327
  if (controller.signal.aborted)
@@ -317,10 +393,8 @@ export class RegistryClient {
317
393
  if (current.protocol === "https:" && next.protocol !== "https:")
318
394
  throw new ZyrkError("ZYRK_FETCH_REFUSED", "Registry HTTPS downgrade redirect refused.", { remedy: "Use HTTPS for every registry redirect." });
319
395
  if (request.method === "POST") {
320
- const registryScope = new URL(this.#registry);
321
396
  if (![307, 308].includes(active.status) ||
322
- next.origin !== registryScope.origin ||
323
- !next.pathname.startsWith(registryScope.pathname))
397
+ !this.#insideAdvisoryBoundary(next))
324
398
  throw new ZyrkError("ZYRK_FETCH_REFUSED", "Registry advisory redirect crosses its authorized endpoint boundary or changes POST semantics.", {
325
399
  remedy: "Configure the advisory service directly within the selected registry; private package names are never forwarded outside that boundary.",
326
400
  });
@@ -421,8 +495,8 @@ export function validateRegistryPackageName(name) {
421
495
  // eslint-disable-next-line no-control-regex
422
496
  if (/[\u0000-\u0020\u007f]/.test(name))
423
497
  bad("control or whitespace character");
424
- if (!/^(?:@[^/@]+\/)?[^/@]+$/.test(name))
425
- bad("shape is not `name` or `@scope/name`");
498
+ if (!/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(name))
499
+ bad("name must use supported lowercase npm package characters");
426
500
  for (const segment of name.split("/")) {
427
501
  if (segment === "." || segment === "..")
428
502
  bad("path-like segment");
@@ -1,5 +1,5 @@
1
1
  import type { NpmLockDoc } from "../lockfile/types.ts";
2
2
  import type { WorkspaceProject } from "./workspaces.ts";
3
3
  import type { WorkspaceGraph } from "./workspace-graph.ts";
4
- export declare function importNpmWorkspaceLock(doc: NpmLockDoc, project: WorkspaceProject, origin: string): WorkspaceGraph;
4
+ export declare function importNpmWorkspaceLock(doc: NpmLockDoc, project: WorkspaceProject, origin: string | ((name: string) => string)): WorkspaceGraph;
5
5
  //# sourceMappingURL=import-npm-workspace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"import-npm-workspace.d.ts","sourceRoot":"","sources":["../../src/install/import-npm-workspace.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAQvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,sBAAsB,CAAC;AAE9B,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,GACb,cAAc,CAyThB"}
1
+ {"version":3,"file":"import-npm-workspace.d.ts","sourceRoot":"","sources":["../../src/install/import-npm-workspace.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAQvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,sBAAsB,CAAC;AAE9B,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,GAC1C,cAAc,CAyThB"}
@@ -62,7 +62,7 @@ export function importNpmWorkspaceLock(doc, project, origin) {
62
62
  if (doc.zyrk ||
63
63
  ![2, 3].includes(doc.lockfileVersion ?? 0) ||
64
64
  !doc.packages ||
65
- !cleanUrl(origin))
65
+ (typeof origin === "string" && !cleanUrl(origin)))
66
66
  throw lockMismatch("workspace adoption needs an unannotated npm v2/v3 lock");
67
67
  const packages = doc.packages;
68
68
  const graph = { nodes: [], importers: {}, omissions: [] };
@@ -1,4 +1,4 @@
1
1
  import type { NpmLockDoc } from "../lockfile/types.ts";
2
2
  import type { FinalizedGraph } from "../resolve/resolver.ts";
3
- export declare function importNpmLock(doc: NpmLockDoc, requirements: Record<string, string>, origin: string): FinalizedGraph;
3
+ export declare function importNpmLock(doc: NpmLockDoc, requirements: Record<string, string>, origin: string | ((name: string) => string)): FinalizedGraph;
4
4
  //# sourceMappingURL=import-npm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"import-npm.d.ts","sourceRoot":"","sources":["../../src/install/import-npm.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,MAAM,EAAE,MAAM,GACb,cAAc,CA0KhB"}
1
+ {"version":3,"file":"import-npm.d.ts","sourceRoot":"","sources":["../../src/install/import-npm.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,GAC1C,cAAc,CA4KhB"}
@@ -32,6 +32,7 @@ export function importNpmLock(doc, requirements, origin) {
32
32
  if (!entry || entry.link === true || entry.inBundle === true)
33
33
  throw lockMismatch("npm lock contains an unsupported linked or bundled selection");
34
34
  const request = parseRequirement(edgeName, spec);
35
+ const selectedOrigin = typeof origin === "string" ? origin : origin(request.realName);
35
36
  const name = typeof entry.name === "string" ? entry.name : request.realName;
36
37
  const integrity = typeof entry.integrity === "string"
37
38
  ? canonicalStrongSri(entry.integrity)
@@ -55,13 +56,13 @@ export function importNpmLock(doc, requirements, origin) {
55
56
  key: `${name}@${entry.version}#${sha512Hex(location).slice(0, 16)}`,
56
57
  name,
57
58
  version: entry.version,
58
- origin,
59
+ origin: selectedOrigin,
59
60
  integrity,
60
61
  sourceId: sourceIdOf({
61
62
  sourceType: "registry",
62
63
  name,
63
64
  version: entry.version,
64
- origin,
65
+ origin: selectedOrigin,
65
66
  integrity,
66
67
  }),
67
68
  tarballUrl: entry.resolved,
@@ -0,0 +1,9 @@
1
+ export type InstalledRegistryConfig = {
2
+ registry: string;
3
+ registries?: Readonly<Record<string, string>>;
4
+ };
5
+ export declare function installedRegistryConfig(state: Record<string, unknown>, nodes: readonly {
6
+ name: string;
7
+ origin: string;
8
+ }[]): InstalledRegistryConfig;
9
+ //# sourceMappingURL=registry-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-policy.d.ts","sourceRoot":"","sources":["../../src/install/registry-policy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC/C,CAAC;AACF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,GACjD,uBAAuB,CAqCzB"}
@@ -0,0 +1,30 @@
1
+ /** Credential-free routing captured with the exact installed generation. */
2
+ import { cleanUrl, lockMismatch } from "./lock.js";
3
+ export function installedRegistryConfig(state, nodes) {
4
+ const object = (x) => !!x && typeof x === "object" && !Array.isArray(x);
5
+ const raw = state.registryConfig;
6
+ if (raw === undefined) {
7
+ const origins = new Set(nodes.map((n) => n.origin));
8
+ if (origins.size !== 1)
9
+ throw lockMismatch("legacy installed state has no exact registry routing");
10
+ return { registry: [...origins][0] };
11
+ }
12
+ if (!object(raw) ||
13
+ Object.keys(raw).some((k) => !["registry", "registries"].includes(k)) ||
14
+ typeof raw.registry !== "string" ||
15
+ !cleanUrl(raw.registry) ||
16
+ !object(raw.registries) ||
17
+ Object.entries(raw.registries).some(([scope, url]) => !/^@[a-z0-9][a-z0-9._-]*$/.test(scope) ||
18
+ typeof url !== "string" ||
19
+ !cleanUrl(url)))
20
+ throw lockMismatch("installed registry routing is malformed");
21
+ const registries = raw.registries;
22
+ for (const node of nodes) {
23
+ const expected = node.name.startsWith("@")
24
+ ? (registries[node.name.slice(0, node.name.indexOf("/"))] ?? raw.registry)
25
+ : raw.registry;
26
+ if (node.origin !== expected)
27
+ throw lockMismatch("installed registry routing disagrees with selected sources");
28
+ }
29
+ return { registry: raw.registry, registries };
30
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/install/registry.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAoB,MAAM,sBAAsB,CAAC;AAKxE,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,cAAc,CAAC,CAwI1B"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/install/registry.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAoB,MAAM,sBAAsB,CAAC;AAKxE,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,cAAc,CAAC,CAuI1B"}
@@ -11,6 +11,7 @@ import { cleanUrl } from "./lock.js";
11
11
  export async function installRegistry(options) {
12
12
  let registry = DEFAULT_REGISTRY;
13
13
  const auth = {};
14
+ const scopedRegistries = {};
14
15
  const home = options.env.HOME ?? os.homedir();
15
16
  const project = (await findWorkspaceRoot(options.cwd)) ??
16
17
  (await findProjectBoundary(options.cwd)) ??
@@ -64,9 +65,7 @@ export async function installRegistry(options) {
64
65
  if (key === "registry")
65
66
  registry = value;
66
67
  if (/^@.+:registry$/.test(key))
67
- throw new ZyrkError("ZYRK_POLICY_DENIED", "Scoped registry routing is not supported by native commands yet.", {
68
- remedy: "Use npm for mixed-registry projects; zyrk will not silently fetch a private scope from a public registry.",
69
- });
68
+ scopedRegistries[key.slice(0, -9)] = value;
70
69
  if (key === "strict-ssl" && value === "false")
71
70
  throw new ZyrkError("ZYRK_POLICY_DENIED", "Disabling registry TLS verification is not supported.", {
72
71
  remedy: "Configure a trusted HTTPS registry with valid TLS certificates.",
@@ -80,18 +79,24 @@ export async function installRegistry(options) {
80
79
  options.env.npm_config_registry ??
81
80
  options.env.NPM_CONFIG_REGISTRY ??
82
81
  registry;
83
- if (!cleanUrl(registry))
84
- throw new ZyrkError("ZYRK_POLICY_DENIED", "Registry URL must be HTTP(S) without credentials, query parameters, or fragments.", {
85
- remedy: "Use a credential-free registry URL and configure URL-scoped credentials separately in .npmrc.",
86
- });
87
- const url = new URL(registry);
88
- if (url.protocol !== "https:" &&
89
- !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname))
90
- throw new ZyrkError("ZYRK_POLICY_DENIED", "Remote registries require HTTPS.", {
91
- remedy: "Select an HTTPS registry; HTTP is limited to loopback development registries.",
92
- });
82
+ const validate = (registry) => {
83
+ if (!cleanUrl(registry))
84
+ throw new ZyrkError("ZYRK_POLICY_DENIED", "Registry URL must be HTTP(S) without credentials, query parameters, or fragments.", {
85
+ remedy: "Use a credential-free registry URL and configure URL-scoped credentials separately in .npmrc.",
86
+ });
87
+ const url = new URL(registry);
88
+ if (url.protocol !== "https:" &&
89
+ !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname))
90
+ throw new ZyrkError("ZYRK_POLICY_DENIED", "Remote registries require HTTPS.", {
91
+ remedy: "Select an HTTPS registry; HTTP is limited to loopback development registries.",
92
+ });
93
+ };
94
+ validate(registry);
95
+ for (const selected of Object.values(scopedRegistries))
96
+ validate(selected);
93
97
  return new RegistryClient({
94
98
  registry,
99
+ scopedRegistries,
95
100
  userAgent: `zyrk/${options.version}`,
96
101
  fetchOptions: auth,
97
102
  });
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/install/run.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAWtB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAgC3C,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE;QACZ,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC;AACF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EACL,OAAO,GACP,uBAAuB,GACvB,eAAe,GACf,SAAS,GACT,cAAc,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AA6GF,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CA4wBxB"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/install/run.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAWtB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAgC3C,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE;QACZ,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC;AACF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EACL,OAAO,GACP,uBAAuB,GACvB,eAAe,GACf,SAAS,GACT,cAAc,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AA6GF,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAsxBxB"}
@@ -197,6 +197,7 @@ export async function installProject(options) {
197
197
  scripts: scriptPolicyFingerprint(scriptPolicy(manifest)),
198
198
  config: configFingerprint({
199
199
  registry: options.registry.origin,
200
+ registries: options.registry.scopedRegistries,
200
201
  linker: "shared",
201
202
  platform: currentPlatform(),
202
203
  ...(object(manifest.zyrk) &&
@@ -214,7 +215,7 @@ export async function installProject(options) {
214
215
  if (existing && !existing.zyrk) {
215
216
  if (options.frozen || options.offline || specs.length)
216
217
  throw lockMismatch("npm-only lockfile requires a non-frozen adoption install before adding packages");
217
- resolved = importNpmLock(existing, allDeps, options.registry.origin);
218
+ resolved = importNpmLock(existing, allDeps, (name) => options.registry.originFor(name));
218
219
  }
219
220
  if (existing?.zyrk &&
220
221
  specs.length === 0 &&
@@ -242,6 +243,7 @@ export async function installProject(options) {
242
243
  resolved = await resolveRequirements({
243
244
  provider: {
244
245
  origin: options.registry.origin,
246
+ originFor: (name) => options.registry.originFor(name),
245
247
  packument: (name) => options.registry.packument(name, {
246
248
  signal: operation.operation.signal,
247
249
  }),
@@ -342,7 +344,7 @@ export async function installProject(options) {
342
344
  if (!packageName(node.name) ||
343
345
  !cleanUrl(node.origin) ||
344
346
  !cleanUrl(node.tarballUrl) ||
345
- node.origin !== options.registry.origin)
347
+ node.origin !== options.registry.originFor(node.name))
346
348
  throw error("ZYRK_POLICY_DENIED", "Selected source has an unsupported or credential-bearing registry origin or archive URL.");
347
349
  }
348
350
  const selectedRoots = resolved.roots.filter((r) => !options.omitDev ||
@@ -458,7 +460,9 @@ export async function installProject(options) {
458
460
  if (options.offline)
459
461
  throw error("ZYRK_OFFLINE_MISSING", `Verified source for ${node.name}@${node.version} is missing from the store.`);
460
462
  const tarball = path.join(txn.dir, `${node.sourceId}.tgz`);
461
- const download = await options.registry.downloadTarball({
463
+ const download = await options.registry
464
+ .forPackage(node.name)
465
+ .downloadTarball({
462
466
  signal: operation.operation.signal,
463
467
  onBytes: operation.operation.consumeArchiveBytes,
464
468
  url: node.tarballUrl,
@@ -680,6 +684,10 @@ export async function installProject(options) {
680
684
  instances: registration.instances,
681
685
  activeContexts: registration.contexts,
682
686
  lockDigest: sha512Hex(canonicalJson(doc)),
687
+ registryConfig: {
688
+ registry: options.registry.origin,
689
+ registries: options.registry.scopedRegistries,
690
+ },
683
691
  graphDigest: digest,
684
692
  platform: process.platform,
685
693
  arch: process.arch,
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-graph.d.ts","sourceRoot":"","sources":["../../src/install/workspace-graph.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workspace-graph.d.ts","sourceRoot":"","sources":["../../src/install/workspace-graph.ts"],"names":[],"mappings":"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"}
@@ -151,7 +151,8 @@ export async function resolveWorkspaceGraph(project, provider, options = {}) {
151
151
  const key = `${requirement.realName}@${version}#${sha512Hex(parent.key + "\0" + name).slice(0, 16)}`;
152
152
  if (byKey.has(key))
153
153
  return key;
154
- if (!cleanUrl(provider.origin) || !cleanUrl(entry.dist.tarball))
154
+ const origin = provider.originFor?.(requirement.realName) ?? provider.origin;
155
+ if (!cleanUrl(origin) || !cleanUrl(entry.dist.tarball))
155
156
  fail("unsafe registry source metadata");
156
157
  const bin = typeof entry.bin === "string"
157
158
  ? { [requirement.realName.split("/").at(-1)]: entry.bin }
@@ -165,10 +166,10 @@ export async function resolveWorkspaceGraph(project, provider, options = {}) {
165
166
  sourceType: "registry",
166
167
  name: requirement.realName,
167
168
  version,
168
- origin: provider.origin,
169
+ origin,
169
170
  integrity,
170
171
  }),
171
- origin: provider.origin,
172
+ origin,
172
173
  integrity,
173
174
  tarballUrl: entry.dist.tarball,
174
175
  bin,
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-install.d.ts","sourceRoot":"","sources":["../../src/install/workspace-install.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyH9D,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAopBxB"}
1
+ {"version":3,"file":"workspace-install.d.ts","sourceRoot":"","sources":["../../src/install/workspace-install.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAwH9D,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CA+pBxB"}
@@ -61,7 +61,7 @@ async function readNpmWorkspaceImport(root, project, options) {
61
61
  catch {
62
62
  throw lockMismatch("npm workspace adoption needs an existing readable JSON lock");
63
63
  }
64
- const graph = importNpmWorkspaceLock(npmDoc, project, options.registry.origin);
64
+ const graph = importNpmWorkspaceLock(npmDoc, project, (name) => options.registry.originFor(name));
65
65
  // Prove the complete graph and ordinary npm projection are representable
66
66
  // before any project state is created. Actual policy fingerprints are added
67
67
  // under the install lock after policy validation.
@@ -70,6 +70,7 @@ async function readNpmWorkspaceImport(root, project, options) {
70
70
  scripts: scriptPolicyFingerprint(undefined),
71
71
  config: configFingerprint({
72
72
  registry: options.registry.origin,
73
+ registries: options.registry.scopedRegistries,
73
74
  linker: "shared",
74
75
  }),
75
76
  });
@@ -131,6 +132,7 @@ export async function installWorkspaceProject(options) {
131
132
  scripts: scriptPolicyFingerprint(policy),
132
133
  config: configFingerprint({
133
134
  registry: options.registry.origin,
135
+ registries: options.registry.scopedRegistries,
134
136
  linker: "shared",
135
137
  platform: currentPlatform(),
136
138
  ...(mutable !== undefined
@@ -144,7 +146,7 @@ export async function installWorkspaceProject(options) {
144
146
  : undefined;
145
147
  let existing = options.importNpm
146
148
  ? null
147
- : await readWorkspaceLock(root, project, options.registry.origin), graph = imported;
149
+ : await readWorkspaceLock(root, project, (name) => options.registry.originFor(name)), graph = imported;
148
150
  if (existing) {
149
151
  const ext = existing.doc.zyrk;
150
152
  if (!mutation.changed &&
@@ -160,6 +162,7 @@ export async function installWorkspaceProject(options) {
160
162
  throw lockMismatch("offline/frozen workspace install needs a compatible lock");
161
163
  graph = await resolveWorkspaceGraph(project, {
162
164
  origin: options.registry.origin,
165
+ originFor: (name) => options.registry.originFor(name),
163
166
  packument: (name) => options.registry.packument(name, {
164
167
  signal: operation.operation.signal,
165
168
  }),
@@ -264,7 +267,9 @@ export async function installWorkspaceProject(options) {
264
267
  throw new ZyrkError("ZYRK_OFFLINE_MISSING", `Verified workspace dependency ${node.name}@${node.version} is missing.`, {
265
268
  remedy: "Fetch the exact locked sources online before retrying offline.",
266
269
  });
267
- const archive = path.join(txn.dir, `${node.sourceId}.tgz`), download = await options.registry.downloadTarball({
270
+ const archive = path.join(txn.dir, `${node.sourceId}.tgz`), download = await options.registry
271
+ .forPackage(node.name)
272
+ .downloadTarball({
268
273
  url: node.tarballUrl,
269
274
  expectedIntegrity: node.integrity,
270
275
  destPath: archive,
@@ -508,6 +513,10 @@ export async function installWorkspaceProject(options) {
508
513
  instances: registration.instances,
509
514
  activeContexts: registration.contexts,
510
515
  lockDigest: sha512Hex(canonicalJson(doc)),
516
+ registryConfig: {
517
+ registry: options.registry.origin,
518
+ registries: options.registry.scopedRegistries,
519
+ },
511
520
  graphDigest: graphHash(sourceGraph),
512
521
  platform: process.platform,
513
522
  arch: process.arch,
@@ -9,7 +9,7 @@ export type WorkspaceFingerprints = {
9
9
  export declare function safeImporter(id: unknown): id is string;
10
10
  export declare function workspaceLockDoc(project: WorkspaceProject, graph: WorkspaceGraph, fp: WorkspaceFingerprints): NpmLockDoc;
11
11
  export declare function validateWorkspaceLockDoc(doc: unknown): WorkspaceGraph;
12
- export declare function readWorkspaceLock(root: string, project?: WorkspaceProject, registryOrigin?: string): Promise<{
12
+ export declare function readWorkspaceLock(root: string, project?: WorkspaceProject, registryOrigin?: string | ((name: string) => string)): Promise<{
13
13
  doc: NpmLockDoc;
14
14
  graph: WorkspaceGraph;
15
15
  } | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-lock.d.ts","sourceRoot":"","sources":["../../src/install/workspace-lock.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AASvD,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,wBAAgB,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,MAAM,CAqBtD;AACD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,cAAc,EACrB,EAAE,EAAE,qBAAqB,GACxB,UAAU,CAyCZ;AACD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAgTrE;AACD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,gBAAgB,EAC1B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAAG,IAAI,CAAC,CAsC5D"}
1
+ {"version":3,"file":"workspace-lock.d.ts","sourceRoot":"","sources":["../../src/install/workspace-lock.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AASvD,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,wBAAgB,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,MAAM,CAqBtD;AACD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,cAAc,EACrB,EAAE,EAAE,qBAAqB,GACxB,UAAU,CAyCZ;AACD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAgTrE;AACD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,gBAAgB,EAC1B,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,GACnD,OAAO,CAAC;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAAG,IAAI,CAAC,CA2C5D"}
@@ -333,7 +333,11 @@ export async function readWorkspaceLock(root, project, registryOrigin) {
333
333
  throw lockMismatch("workspace importer is missing");
334
334
  }
335
335
  if (registryOrigin &&
336
- graph.nodes.some((n) => n.kind === "registry" && n.origin !== registryOrigin))
336
+ graph.nodes.some((n) => n.kind === "registry" &&
337
+ n.origin !==
338
+ (typeof registryOrigin === "string"
339
+ ? registryOrigin
340
+ : registryOrigin(n.name))))
337
341
  throw lockMismatch("workspace registry origin differs");
338
342
  return { doc: doc, graph };
339
343
  }
@@ -32,6 +32,7 @@ export declare function scriptPolicyFingerprint(policy: unknown): string;
32
32
  export type ResolutionConfig = {
33
33
  /** Credential-free registry origin. */
34
34
  registry: string;
35
+ registries?: Readonly<Record<string, string>>;
35
36
  linker: "shared" | "local";
36
37
  patches?: string;
37
38
  mutablePackages?: readonly string[];
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprints.d.ts","sourceRoot":"","sources":["../../src/lockfile/fingerprints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CA2BzE;AAED,eAAO,MAAM,qBAAqB;IAAK,OAAO;IAAU,KAAK;IAAM,IAAI;CAAM,CAAC;AAE9E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAG/D;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvD,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAUlE"}
1
+ {"version":3,"file":"fingerprints.d.ts","sourceRoot":"","sources":["../../src/lockfile/fingerprints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CA2BzE;AAED,eAAO,MAAM,qBAAqB;IAAK,OAAO;IAAU,KAAK;IAAM,IAAI;CAAM,CAAC;AAE9E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAG/D;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvD,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAalE"}
@@ -55,6 +55,9 @@ export function scriptPolicyFingerprint(policy) {
55
55
  export function configFingerprint(config) {
56
56
  return fingerprintOf({
57
57
  registry: config.registry,
58
+ ...(config.registries && Object.keys(config.registries).length
59
+ ? { registries: config.registries }
60
+ : {}),
58
61
  linker: config.linker,
59
62
  ...(config.patches === undefined ? {} : { patches: config.patches }),
60
63
  ...(config.platform === undefined ? {} : { platform: config.platform }),
@@ -22,6 +22,7 @@
22
22
  import { type Packument } from "../fetch/registry.ts";
23
23
  export type MetadataProvider = {
24
24
  readonly origin: string;
25
+ originFor?(name: string): string;
25
26
  packument(name: string): Promise<Packument>;
26
27
  };
27
28
  export type EdgeKind = "prod" | "optional" | "peer";
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/resolve/resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/resolve/resolver.ts"],"names":[],"mappings":"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"}
@@ -381,14 +381,14 @@ class ResolverState {
381
381
  throw internal("missing finalized key");
382
382
  const existing = byKey.get(key);
383
383
  if (existing !== undefined) {
384
- assertMergeable(existing, occ, keys, this.provider.origin);
384
+ assertMergeable(existing, occ, keys, this.provider.originFor?.(occ.name) ?? this.provider.origin);
385
385
  continue;
386
386
  }
387
387
  byKey.set(key, occ);
388
388
  }
389
389
  const nodes = [...byKey.entries()]
390
390
  .sort((a, b) => compareStrings(a[0], b[0]))
391
- .map(([key, occ]) => toResolved(occ, key, keys, this.provider.origin));
391
+ .map(([key, occ]) => toResolved(occ, key, keys, this.provider.originFor?.(occ.name) ?? this.provider.origin));
392
392
  const roots = rootLinks.map((link) => {
393
393
  const target = keys.get(link.child);
394
394
  if (target === undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zyrk",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Storage-efficient Node package manager: one verified store per user, shared across projects through links.",
5
5
  "license": "MIT",
6
6
  "type": "module",