zyrk 0.5.4 → 0.5.5

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 -1
  2. package/VERSION +1 -1
  3. package/dist/install/import-npm-workspace.d.ts.map +1 -1
  4. package/dist/install/import-npm-workspace.js +1 -3
  5. package/dist/install/import-npm.d.ts.map +1 -1
  6. package/dist/install/import-npm.js +10 -28
  7. package/dist/install/lock.d.ts.map +1 -1
  8. package/dist/install/lock.js +8 -6
  9. package/dist/install/platform.d.ts +5 -0
  10. package/dist/install/platform.d.ts.map +1 -0
  11. package/dist/install/platform.js +97 -0
  12. package/dist/install/run.d.ts +3 -0
  13. package/dist/install/run.d.ts.map +1 -1
  14. package/dist/install/run.js +19 -48
  15. package/dist/install/workspace-graph.d.ts +1 -0
  16. package/dist/install/workspace-graph.d.ts.map +1 -1
  17. package/dist/install/workspace-graph.js +12 -3
  18. package/dist/install/workspace-install.d.ts.map +1 -1
  19. package/dist/install/workspace-install.js +5 -5
  20. package/dist/install/workspace-lock.d.ts +1 -1
  21. package/dist/install/workspace-lock.d.ts.map +1 -1
  22. package/dist/install/workspace-lock.js +11 -1
  23. package/dist/lockfile/fingerprints.js +0 -1
  24. package/dist/lockfile/read.d.ts +1 -1
  25. package/dist/lockfile/read.d.ts.map +1 -1
  26. package/dist/lockfile/read.js +11 -1
  27. package/dist/lockfile/types.d.ts +1 -0
  28. package/dist/lockfile/types.d.ts.map +1 -1
  29. package/dist/lockfile/types.js +1 -0
  30. package/dist/lockfile/write.d.ts.map +1 -1
  31. package/dist/lockfile/write.js +1 -0
  32. package/dist/resolve/resolver.d.ts +1 -21
  33. package/dist/resolve/resolver.d.ts.map +1 -1
  34. package/dist/resolve/resolver.js +13 -1
  35. package/dist/util/engines.d.ts +2 -0
  36. package/dist/util/engines.d.ts.map +1 -0
  37. package/dist/util/engines.js +23 -0
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -122,7 +122,10 @@ registry; private names never fall back to a public endpoint. Disabled TLS
122
122
  verification is rejected before lookup. Git sources and non-workspace local sources remain unsupported;
123
123
  they fail explicitly. Optional dependencies incompatible with the selected platform
124
124
  are omitted; missing packages, integrity failures, and other optional failures
125
- remain errors. Platform selection is recorded in the lock. macOS, Windows, and
125
+ remain errors. Locks retain exact platform-qualified optional variants; each machine
126
+ selects its compatible local closure without rewriting the lock or recording store
127
+ paths. Older platform-pruned locks need an intentional non-frozen refresh; incomplete
128
+ npm locks must be freshly resolved before portable adoption. macOS, Windows, and
126
129
  broad framework compatibility have not passed their release gates.
127
130
 
128
131
  ### Workspaces
package/VERSION CHANGED
@@ -1 +1 @@
1
- v0.5.4
1
+ v0.5.5
@@ -1 +1 @@
1
- {"version":3,"file":"import-npm-workspace.d.ts","sourceRoot":"","sources":["../../src/install/import-npm-workspace.ts"],"names":[],"mappings":"AASA,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;AA0V9B,oEAAoE;AACpE,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,CAWhB"}
1
+ {"version":3,"file":"import-npm-workspace.d.ts","sourceRoot":"","sources":["../../src/install/import-npm-workspace.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAOvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,sBAAsB,CAAC;AA6V9B,oEAAoE;AACpE,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,CAWhB"}
@@ -8,7 +8,6 @@ import { canonicalJson } from "../util/json.js";
8
8
  import { importNpmLock } from "./import-npm.js";
9
9
  import { lockMismatch, cleanUrl } from "./lock.js";
10
10
  import { ZyrkError } from "../errors.js";
11
- import { assertWorkspacePlatform } from "./workspace-graph.js";
12
11
  function importNpmWorkspaceLockPass(doc, project, origin, overrideState) {
13
12
  if (!doc ||
14
13
  typeof doc !== "object" ||
@@ -173,7 +172,6 @@ function importNpmWorkspaceLockPass(doc, project, origin, overrideState) {
173
172
  peers: {},
174
173
  optionalPeers: [],
175
174
  };
176
- assertWorkspacePlatform({ nodes: [node], importers: {}, omissions: [] });
177
175
  graph.nodes.push(node);
178
176
  locations.set(contextKey, node);
179
177
  contexts.set(node.key, selectedOverride.context);
@@ -230,7 +228,7 @@ function importNpmWorkspaceLockPass(doc, project, origin, overrideState) {
230
228
  continue;
231
229
  }
232
230
  if (requirement.kind === "optional")
233
- continue;
231
+ throw lockMismatch("npm workspace lock lacks an exact optional selection; restore a complete npm lock or intentionally resolve fresh without the pruned lock");
234
232
  throw lockMismatch("npm workspace lock is missing a required selection");
235
233
  }
236
234
  let target;
@@ -1 +1 @@
1
- {"version":3,"file":"import-npm.d.ts","sourceRoot":"","sources":["../../src/install/import-npm.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,yBAAyB,CAAC;AAIjC,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,EAC3C,SAAS,GAAE,cAAwC,GAClD,cAAc,CAyMhB"}
1
+ {"version":3,"file":"import-npm.d.ts","sourceRoot":"","sources":["../../src/install/import-npm.ts"],"names":[],"mappings":"AACA,qFAAqF;AACrF,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,yBAAyB,CAAC;AAIjC,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,EAC3C,SAAS,GAAE,cAAwC,GAClD,cAAc,CAkLhB"}
@@ -1,8 +1,9 @@
1
+ import { normalizeEngineConstraints } from "../util/engines.js";
1
2
  /** Adopt npm v2/v3 exact selections without asking the registry to pick versions. */
2
3
  import { createRootOverrides, } from "../resolve/overrides.js";
3
4
  import { validateLockDoc } from "../lockfile/read.js";
4
5
  import { canonicalStrongSri } from "../util/integrity.js";
5
- import { valid, validRange, satisfies } from "semver";
6
+ import { valid, satisfies } from "semver";
6
7
  import { parseRequirement } from "../resolve/spec.js";
7
8
  import { sourceIdOf, sha512Hex } from "../util/hash.js";
8
9
  import { cleanUrl, lockMismatch, packageName } from "./lock.js";
@@ -75,30 +76,10 @@ export function importNpmLock(doc, requirements, origin, overrides = createRootO
75
76
  edges: [],
76
77
  peerBindings: [],
77
78
  };
78
- if (entry.engines !== undefined) {
79
- if (Array.isArray(entry.engines)) {
80
- // Old npm manifests used ["node >= 0.2.0"] instead of an engine map.
81
- const engines = {};
82
- for (const value of entry.engines) {
83
- const match = typeof value === "string"
84
- ? /^([a-z][a-z0-9._-]*)\s+(.+)$/.exec(value)
85
- : null;
86
- if (!match ||
87
- Object.hasOwn(engines, match[1]) ||
88
- validRange(match[2]) === null)
89
- throw lockMismatch("invalid npm engine constraint");
90
- engines[match[1]] = match[2];
91
- }
92
- node.engines = engines;
93
- }
94
- else {
95
- if (typeof entry.engines !== "object" ||
96
- entry.engines === null ||
97
- Object.values(entry.engines).some((value) => typeof value !== "string"))
98
- throw lockMismatch("invalid npm engine constraint");
99
- node.engines = entry.engines;
100
- }
101
- }
79
+ if (entry.engines !== undefined)
80
+ node.engines = normalizeEngineConstraints(entry.engines, () => {
81
+ throw lockMismatch("invalid npm engine constraint");
82
+ });
102
83
  if (typeof entry.bin === "object" &&
103
84
  entry.bin !== null &&
104
85
  !Array.isArray(entry.bin)) {
@@ -141,11 +122,12 @@ export function importNpmLock(doc, requirements, origin, overrides = createRootO
141
122
  const meta = entry.peerDependenciesMeta;
142
123
  const optionalPeer = requirement.kind === "peer" && meta?.[dep]?.optional === true;
143
124
  if (!targetLocation) {
144
- if (requirement.kind === "optional" || optionalPeer) {
145
- if (optionalPeer)
146
- node.peerBindings.push({ name: dep, target: null, optional: true });
125
+ if (optionalPeer) {
126
+ node.peerBindings.push({ name: dep, target: null, optional: true });
147
127
  continue;
148
128
  }
129
+ if (requirement.kind === "optional")
130
+ throw lockMismatch("npm lock lacks an exact optional selection; restore a complete npm lock or intentionally resolve fresh without the pruned lock");
149
131
  throw lockMismatch("npm lock is missing a required dependency");
150
132
  }
151
133
  const target = load(targetLocation, dep, requirement.spec, selected.context);
@@ -1 +1 @@
1
- {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/install/lock.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMjD;AACD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAa/C;AACD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CASnD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,cAAc,CA6M3D;AAUD,kFAAkF;AAClF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAK,GAAG,IAAI,CAM3E"}
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/install/lock.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMjD;AACD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAa/C;AACD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CASnD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,cAAc,CA+M3D;AAYD,kFAAkF;AAClF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAK,GAAG,IAAI,CAM3E"}
@@ -39,6 +39,7 @@ export function lockedGraph(doc) {
39
39
  Object.keys(ext).some((key) => ![
40
40
  "version",
41
41
  "resolver",
42
+ "platformPolicy",
42
43
  "contextCanonicalization",
43
44
  "manifest",
44
45
  "scripts",
@@ -48,6 +49,7 @@ export function lockedGraph(doc) {
48
49
  ].includes(key)) ||
49
50
  ![ext.manifest, ext.scripts, ext.config].every((value) => typeof value === "string" && /^sha512-[A-Za-z0-9+/]{86}==$/.test(value)) ||
50
51
  ext.resolver !== ZYRK_RESOLVER_POLICY ||
52
+ ext.platformPolicy !== "portable-optional/1" ||
51
53
  ext.contextCanonicalization !== CONTEXT_CANONICALIZATION_VERSION ||
52
54
  !record(ext.nodes) ||
53
55
  !record(ext.roots) ||
@@ -180,7 +182,7 @@ export function lockedGraph(doc) {
180
182
  sourceId: raw.source,
181
183
  tarballUrl: raw.tarball,
182
184
  bin,
183
- engines,
185
+ ...(raw.engines === undefined ? {} : { engines }),
184
186
  platform,
185
187
  edges,
186
188
  peerBindings: peers,
@@ -204,11 +206,11 @@ export function lockedGraph(doc) {
204
206
  // npm publishes this canonical GitHub sponsorship link in funding metadata.
205
207
  // Keep source/archive URL validation query-free, and allow no other query here.
206
208
  function githubFundingUrl(value) {
207
- return /^https:\/\/github\.com\/[A-Za-z0-9_-]+\/[A-Za-z0-9_.-]+\?sponsor=1$/.test(value);
209
+ return (/^https:\/\/github\.com\/[A-Za-z0-9_-]+\/[A-Za-z0-9_.-]+\?sponsor=1$/.test(value) && new URL(value).href === value);
208
210
  }
209
211
  /** Preserved metadata is subject to the same portability boundary as new data. */
210
212
  export function assertPortableLockMetadata(value, field = "") {
211
- visitPortableLockMetadata(value, field, field === "funding" ? "entry" : undefined);
213
+ visitPortableLockMetadata(value, field, field === "funding" ? "funding" : undefined);
212
214
  }
213
215
  function visitPortableLockMetadata(value, field, funding) {
214
216
  if (typeof value === "string") {
@@ -222,7 +224,7 @@ function visitPortableLockMetadata(value, field, funding) {
222
224
  }
223
225
  if (Array.isArray(value)) {
224
226
  for (const item of value)
225
- visitPortableLockMetadata(item, field, funding === "entry" ? "entry" : undefined);
227
+ visitPortableLockMetadata(item, field, funding === "funding" ? "entry" : undefined);
226
228
  return;
227
229
  }
228
230
  if (value && typeof value === "object")
@@ -245,8 +247,8 @@ function visitPortableLockMetadata(value, field, funding) {
245
247
  ].includes(field))
246
248
  throw lockMismatch("portable metadata contains a credential field");
247
249
  visitPortableLockMetadata(item, key, key === "funding"
248
- ? "entry"
249
- : funding === "entry" && key === "url"
250
+ ? "funding"
251
+ : (funding === "funding" || funding === "entry") && key === "url"
250
252
  ? "url"
251
253
  : undefined);
252
254
  }
@@ -0,0 +1,5 @@
1
+ import { type RuntimePlatform, type FinalizedGraph } from "../resolve/resolver.ts";
2
+ import type { WorkspaceGraph } from "./workspace-graph.ts";
3
+ export declare function selectPlatformGraph(graph: FinalizedGraph, optionalRoots: ReadonlySet<string>, platform?: RuntimePlatform): FinalizedGraph;
4
+ export declare function selectWorkspacePlatform(graph: WorkspaceGraph, platform?: RuntimePlatform): WorkspaceGraph;
5
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/install/platform.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAuG3D,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,EACrB,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,EAClC,QAAQ,kBAAoB,GAC3B,cAAc,CAqBhB;AACD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EACrB,QAAQ,kBAAoB,GAC3B,cAAc,CAsBhB"}
@@ -0,0 +1,97 @@
1
+ /** Portable selections stay in the lock; only a compatible closure is realized. */
2
+ import { satisfies } from "semver";
3
+ import { ZyrkError } from "../errors.js";
4
+ import { currentPlatform, } from "../resolve/resolver.js";
5
+ import { lockMismatch } from "./lock.js";
6
+ function compatible(node, platform) {
7
+ return ([
8
+ [node.platform?.os, platform.os],
9
+ [node.platform?.cpu, platform.cpu],
10
+ [node.platform?.libc, platform.libc],
11
+ ].every(([list, actual]) => !list?.length ||
12
+ (!!actual &&
13
+ !list.includes(`!${actual}`) &&
14
+ (!list.some((v) => !v.startsWith("!")) ||
15
+ list.includes(actual) ||
16
+ list.includes("any")))) &&
17
+ (!node.engines?.node || satisfies(process.versions.node, node.engines.node)));
18
+ }
19
+ function optional(node, edge) {
20
+ return (edge.kind === "optional" ||
21
+ (edge.kind === "peer" &&
22
+ (node.optionalPeers?.includes(edge.name) === true ||
23
+ node.peerBindings?.some((p) => p.name === edge.name && p.optional) ===
24
+ true)));
25
+ }
26
+ function select(nodes, roots, platform) {
27
+ const byKey = new Map(nodes.map((n) => [n.key, n]));
28
+ const viable = new Set(nodes.filter((n) => compatible(n, platform)).map((n) => n.key));
29
+ // Propagate required incompatibility back to the nearest optional boundary.
30
+ let changed = true;
31
+ while (changed) {
32
+ changed = false;
33
+ for (const node of nodes)
34
+ if (viable.has(node.key) &&
35
+ node.edges.some((e) => !optional(node, e) && !viable.has(e.target))) {
36
+ viable.delete(node.key);
37
+ changed = true;
38
+ }
39
+ }
40
+ const active = new Set();
41
+ const omissions = [];
42
+ const visit = (name, target, isOptional, parent) => {
43
+ if (!byKey.has(target))
44
+ throw lockMismatch("missing platform selection");
45
+ if (!viable.has(target)) {
46
+ if (isOptional) {
47
+ omissions.push({ name, parent, reason: "platform" });
48
+ return;
49
+ }
50
+ throw new ZyrkError("ZYRK_PLATFORM_UNSUPPORTED", `Cannot install required dependency ${name} on the selected platform or Node.js runtime.`, {
51
+ remedy: "Select a compatible package version, platform, or Node.js runtime.",
52
+ });
53
+ }
54
+ if (active.has(target))
55
+ return;
56
+ active.add(target);
57
+ const node = byKey.get(target);
58
+ for (const edge of node.edges)
59
+ visit(edge.name, edge.target, optional(node, edge), node.key);
60
+ };
61
+ for (const root of roots)
62
+ visit(root.name, root.target, root.optional === true, "<root>");
63
+ return { active, viable, omissions };
64
+ }
65
+ export function selectPlatformGraph(graph, optionalRoots, platform = currentPlatform()) {
66
+ const { active, viable, omissions } = select(graph.nodes, graph.roots.map((r) => ({ ...r, optional: optionalRoots.has(r.name) })), platform);
67
+ return {
68
+ roots: graph.roots.filter((r) => active.has(r.target)),
69
+ omissions,
70
+ nodes: graph.nodes
71
+ .filter((n) => active.has(n.key))
72
+ .map((n) => ({
73
+ ...n,
74
+ edges: n.edges.filter((e) => viable.has(e.target)),
75
+ peerBindings: n.peerBindings.map((p) => p.target !== null && !viable.has(p.target)
76
+ ? { ...p, target: null }
77
+ : p),
78
+ })),
79
+ };
80
+ }
81
+ export function selectWorkspacePlatform(graph, platform = currentPlatform()) {
82
+ const { active, viable, omissions } = select(graph.nodes, Object.entries(graph.importers).map(([name, target]) => ({ name, target })), platform);
83
+ return {
84
+ ...graph,
85
+ omissions,
86
+ nodes: graph.nodes
87
+ .filter((n) => active.has(n.key))
88
+ .map((n) => ({
89
+ ...n,
90
+ edges: n.edges.filter((e) => viable.has(e.target)),
91
+ peers: Object.fromEntries(Object.entries(n.peers).map(([name, target]) => [
92
+ name,
93
+ target !== null && !viable.has(target) ? null : target,
94
+ ])),
95
+ })),
96
+ };
97
+ }
@@ -1,3 +1,4 @@
1
+ import type { RuntimePlatform } from "../resolve/resolver.ts";
1
2
  import { type BuildCandidate } from "./private.ts";
2
3
  import { RegistryClient } from "../fetch/registry.ts";
3
4
  import type { ResolverLimits } from "../resolve/resolver.ts";
@@ -11,6 +12,8 @@ export type InstallProgress = {
11
12
  export type InstallOptions = {
12
13
  onProgress?: (event: InstallProgress) => void;
13
14
  projectDir: string;
15
+ /** Target selection only; Store.open still checks the actual host. */
16
+ platform?: RuntimePlatform;
14
17
  store: Store;
15
18
  registry: RegistryClient;
16
19
  specs?: readonly string[];
@@ -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;AAYtB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAgC3C,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EACD,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,SAAS,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,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,aAAa,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1C,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;AA4GF,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAs0BxB"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/install/run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAK9D,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAYtB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AA+B3C,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EACD,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,SAAS,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,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,aAAa,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1C,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;AA4GF,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAoyBxB"}
@@ -1,3 +1,4 @@
1
+ import { selectPlatformGraph } from "./platform.js";
1
2
  import { findWorkspaceRoot } from "./workspaces.js";
2
3
  import { assertSupportedSourcePayload } from "./source-policy.js";
3
4
  import { prepareRepair } from "./repair.js";
@@ -23,7 +24,7 @@ import { Transaction } from "../store/txn.js";
23
24
  import { readSourceManifest, sourceManifestPath } from "../store/manifests.js";
24
25
  import { realizeGraph, selectRealizationDirs } from "../store/realize.js";
25
26
  import { createGraphDoc, graphHash } from "../store/graph.js";
26
- import { resolveRequirements, currentPlatform, } from "../resolve/resolver.js";
27
+ import { resolveRequirements, } from "../resolve/resolver.js";
27
28
  import { parseRequirement } from "../resolve/spec.js";
28
29
  import { readLockfile, assertFrozenCompatible } from "../lockfile/read.js";
29
30
  import { writeLockfile } from "../lockfile/write.js";
@@ -215,7 +216,6 @@ export async function installProject(options) {
215
216
  registry: options.registry.origin,
216
217
  registries: options.registry.scopedRegistries,
217
218
  linker: "shared",
218
- platform: currentPlatform(),
219
219
  ...(object(manifest.zyrk) &&
220
220
  Array.isArray(manifest.zyrk.mutablePackages)
221
221
  ? { mutablePackages: manifest.zyrk.mutablePackages }
@@ -224,7 +224,7 @@ export async function installProject(options) {
224
224
  }),
225
225
  });
226
226
  const lockPath = path.join(project, "package-lock.json");
227
- const existing = (await readLockfile(lockPath))?.doc;
227
+ const existing = (await readLockfile(lockPath, !options.frozen && !options.offline))?.doc;
228
228
  let resolved;
229
229
  if (options.importNpm && (!existing || existing.zyrk))
230
230
  throw lockMismatch("import --from npm requires an existing npm-only lockfile");
@@ -240,6 +240,8 @@ export async function installProject(options) {
240
240
  let compatible = true;
241
241
  try {
242
242
  assertFrozenCompatible(existing, fingerprints());
243
+ if (existing.zyrk?.platformPolicy !== "portable-optional/1")
244
+ throw lockMismatch("lock predates portable platform selections; refresh intentionally");
243
245
  }
244
246
  catch (cause) {
245
247
  if (options.frozen)
@@ -254,12 +256,15 @@ export async function installProject(options) {
254
256
  throw lockMismatch("missing compatible lockfile");
255
257
  if (options.offline)
256
258
  throw error("ZYRK_OFFLINE_MISSING", "Offline installation requires an existing compatible zyrk lockfile.");
257
- const prior = existing?.zyrk ? lockedGraph(existing) : undefined;
259
+ const prior = existing?.zyrk?.platformPolicy === "portable-optional/1"
260
+ ? lockedGraph(existing)
261
+ : undefined;
258
262
  const fresh = new Set(specs.map((spec) => npa(spec).name));
259
263
  options.onProgress?.({ phase: "resolving" });
260
264
  resolved = await resolveRequirements({
261
265
  overrides,
262
266
  limits: options.resolveBudget,
267
+ preservePlatformVariants: true,
263
268
  provider: {
264
269
  origin: options.registry.origin,
265
270
  originFor: (name) => options.registry.originFor(name),
@@ -366,49 +371,15 @@ export async function installProject(options) {
366
371
  node.origin !== options.registry.originFor(node.name))
367
372
  throw error("ZYRK_POLICY_DENIED", "Selected source has an unsupported or credential-bearing registry origin or archive URL.");
368
373
  }
369
- const selectedRoots = resolved.roots.filter((r) => !options.omitDev ||
370
- manifest.dependencies?.[r.name] !== undefined ||
371
- manifest.optionalDependencies?.[r.name] !== undefined);
372
- const byKey = new Map(resolved.nodes.map((n) => [n.key, n]));
373
- const activeKeys = new Set();
374
- const visit = (key) => {
375
- if (activeKeys.has(key))
376
- return;
377
- activeKeys.add(key);
378
- const n = byKey.get(key);
379
- if (!n)
380
- throw lockMismatch("missing selected node");
381
- for (const e of n.edges)
382
- visit(e.target);
383
- };
384
- for (const r of selectedRoots)
385
- visit(r.target);
386
- const activeNodes = resolved.nodes.filter((n) => activeKeys.has(n.key));
387
- for (const n of activeNodes) {
388
- for (const [list, current] of [
389
- [n.platform.os, process.platform],
390
- [n.platform.cpu, process.arch],
391
- ]) {
392
- if (list &&
393
- (list.includes(`!${current}`) ||
394
- (list.some((x) => !x.startsWith("!")) &&
395
- !list.includes(current) &&
396
- !list.includes("any"))))
397
- throw new ZyrkError("ZYRK_PLATFORM_UNSUPPORTED", `Cannot install ${n.name}@${n.version} on the selected platform.`, { remedy: "Select a package version supporting this OS and CPU." });
398
- }
399
- if (n.platform.libc?.length) {
400
- const libc = currentPlatform().libc;
401
- if (!libc ||
402
- n.platform.libc.includes(`!${libc}`) ||
403
- (n.platform.libc.some((v) => !v.startsWith("!")) &&
404
- !n.platform.libc.includes(libc)))
405
- throw new ZyrkError("ZYRK_PLATFORM_UNSUPPORTED", `Cannot install ${n.name}@${n.version} with this libc.`, { remedy: "Select a compatible platform or package version." });
406
- }
407
- if (n.engines?.node && !satisfies(process.versions.node, n.engines.node))
408
- throw new ZyrkError("ZYRK_PLATFORM_UNSUPPORTED", `Cannot install ${n.name}@${n.version} on this Node.js version.`, {
409
- remedy: "Use a Node.js version satisfying the package's engines.node range.",
410
- });
411
- }
374
+ const activeResolution = selectPlatformGraph({
375
+ ...resolved,
376
+ roots: resolved.roots.filter((r) => !options.omitDev ||
377
+ manifest.dependencies?.[r.name] !== undefined ||
378
+ manifest.optionalDependencies?.[r.name] !== undefined),
379
+ }, new Set(Object.keys(manifest.optionalDependencies ?? {})), options.platform);
380
+ const selectedRoots = activeResolution.roots;
381
+ const activeNodes = activeResolution.nodes;
382
+ const byKey = new Map(activeNodes.map((n) => [n.key, n]));
412
383
  barrier = await acquireLock(path.join(options.store.paths.locksDir, "liveness.lock"), { name: "store liveness" });
413
384
  txn = await Transaction.begin(options.store, "install");
414
385
  const candidateLock = path.join(txn.dir, "package-lock.json");
@@ -444,7 +415,7 @@ export async function installProject(options) {
444
415
  name: "package.json",
445
416
  contents: `${JSON.stringify(manifest, null, 2)}\n`,
446
417
  });
447
- const warnings = (resolved.omissions ?? []).map((item) => `${item.name}: omitted optional dependency incompatible with the selected platform.`);
418
+ const warnings = (activeResolution.omissions ?? []).map((item) => `${item.name}: omitted optional dependency incompatible with the selected platform.`);
448
419
  for (const stage of ["preinstall", "install", "postinstall"])
449
420
  if (manifest.scripts?.[stage])
450
421
  warnings.push(`Root ${stage} hook was not run; invoke it explicitly after installation.`);
@@ -50,6 +50,7 @@ declare function resolveWorkspaceGraphPass(project: WorkspaceProject, provider:
50
50
  previous?: WorkspaceGraph;
51
51
  fresh?: ReadonlySet<string>;
52
52
  platform?: RuntimePlatform;
53
+ preservePlatformVariants?: boolean;
53
54
  maxNodes?: number;
54
55
  maxDepth?: number;
55
56
  deadlineMs?: number;
@@ -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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"}
@@ -1,3 +1,4 @@
1
+ import { normalizeEngineConstraints } from "../util/engines.js";
1
2
  /** Multi-importer resolution. Live nodes are never registry sources or CAS inputs. */
2
3
  import { maxSatisfying, satisfies, valid } from "semver";
3
4
  import { expectedIntegrityFromDist, } from "../fetch/registry.js";
@@ -67,6 +68,11 @@ async function resolveWorkspaceGraphPass(project, provider, options = {}, overri
67
68
  ]).finally(() => clearTimeout(timer));
68
69
  };
69
70
  const compatible = (entry) => {
71
+ const engines = entry.engines === undefined
72
+ ? undefined
73
+ : normalizeEngineConstraints(entry.engines, () => fail("invalid npm engine constraint"));
74
+ if (options.preservePlatformVariants)
75
+ return;
70
76
  for (const [list, actual] of [
71
77
  [entry.os, platform.os],
72
78
  [entry.cpu, platform.cpu],
@@ -79,8 +85,7 @@ async function resolveWorkspaceGraphPass(project, provider, options = {}, overri
79
85
  !list.includes(actual) &&
80
86
  !list.includes("any"))))
81
87
  throw new PlatformMismatch();
82
- if (entry.engines?.node &&
83
- !satisfies(process.versions.node, entry.engines.node))
88
+ if (engines?.node && !satisfies(process.versions.node, engines.node))
84
89
  throw new PlatformMismatch();
85
90
  };
86
91
  const build = async (parent, name, spec, kind, ancestry, explicitLocal) => {
@@ -189,7 +194,11 @@ async function resolveWorkspaceGraphPass(project, provider, options = {}, overri
189
194
  ...(entry.cpu ? { cpu: entry.cpu } : {}),
190
195
  ...(entry.libc ? { libc: entry.libc } : {}),
191
196
  },
192
- ...(entry.engines ? { engines: entry.engines } : {}),
197
+ ...(entry.engines === undefined
198
+ ? {}
199
+ : {
200
+ engines: normalizeEngineConstraints(entry.engines, () => fail("invalid npm engine constraint")),
201
+ }),
193
202
  edges: [],
194
203
  peers: {},
195
204
  optionalPeers: [],
@@ -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,CA+qBxB"}
1
+ {"version":3,"file":"workspace-install.d.ts","sourceRoot":"","sources":["../../src/install/workspace-install.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAuH9D,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAkrBxB"}
@@ -1,9 +1,10 @@
1
+ import { selectWorkspacePlatform } from "./platform.js";
1
2
  /** Multi-importer live workspace installation with one publication journal. */
2
3
  import { chmod, copyFile, lstat, mkdir, readFile, realpath, rename, rm, symlink, } from "node:fs/promises";
3
4
  import { constants } from "node:fs";
4
5
  import * as path from "node:path";
5
6
  import { discoverWorkspaces, findWorkspaceRoot, assertNoLiveSourceBuilds, } from "./workspaces.js";
6
- import { resolveWorkspaceGraph, workspaceRegistryOccurrences, workspaceContextId, assertWorkspacePlatform, } from "./workspace-graph.js";
7
+ import { resolveWorkspaceGraph, workspaceRegistryOccurrences, workspaceContextId, } from "./workspace-graph.js";
7
8
  import { workspaceOverrides } from "./workspace-overrides.js";
8
9
  import { importNpmWorkspaceLock } from "./import-npm-workspace.js";
9
10
  import { readWorkspaceLock, workspaceLockDoc } from "./workspace-lock.js";
@@ -24,7 +25,6 @@ import { randomId } from "../util/ids.js";
24
25
  import { sha512Hex } from "../util/hash.js";
25
26
  import { canonicalJson } from "../util/json.js";
26
27
  import { configFingerprint, scriptPolicyFingerprint, } from "../lockfile/fingerprints.js";
27
- import { currentPlatform } from "../resolve/resolver.js";
28
28
  import { installProjection, installMetadata } from "../project/projection.js";
29
29
  import { prepareWorkspaceMutation } from "./workspace-mutation.js";
30
30
  import { loadProjectPatches, applyProjectPatches } from "../commands/patch.js";
@@ -135,7 +135,6 @@ export async function installWorkspaceProject(options) {
135
135
  registry: options.registry.origin,
136
136
  registries: options.registry.scopedRegistries,
137
137
  linker: "shared",
138
- platform: currentPlatform(),
139
138
  ...(mutable !== undefined
140
139
  ? { mutablePackages: mutable }
141
140
  : {}),
@@ -147,7 +146,7 @@ export async function installWorkspaceProject(options) {
147
146
  : undefined;
148
147
  let existing = options.importNpm
149
148
  ? null
150
- : await readWorkspaceLock(root, project, (name) => options.registry.originFor(name)), graph = imported;
149
+ : await readWorkspaceLock(root, project, (name) => options.registry.originFor(name), !options.frozen && !options.offline), graph = imported;
151
150
  if (existing) {
152
151
  const ext = existing.doc.zyrk;
153
152
  if (!mutation.changed &&
@@ -172,9 +171,9 @@ export async function installWorkspaceProject(options) {
172
171
  ...(existing ? { previous: existing.graph } : {}),
173
172
  fresh: mutation.fresh,
174
173
  ...options.resolveBudget,
174
+ preservePlatformVariants: true,
175
175
  });
176
176
  }
177
- assertWorkspacePlatform(graph);
178
177
  mutation.finish(graph);
179
178
  fp.manifest = project.manifestFingerprint;
180
179
  const manifestChanges = project.importers
@@ -190,6 +189,7 @@ export async function installWorkspaceProject(options) {
190
189
  : workspaceLockDoc(project, graph, fp), lockText = options.frozen
191
190
  ? await readFile(path.join(root, "package-lock.json"), "utf8")
192
191
  : JSON.stringify(doc, null, 2) + "\n";
192
+ graph = selectWorkspacePlatform(graph, options.platform);
193
193
  const warnings = graph.omissions.map((o) => `${o.name}: omitted incompatible optional workspace dependency.`);
194
194
  for (const importer of project.importers)
195
195
  for (const stage of ["preinstall", "install", "postinstall"])
@@ -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 | ((name: string) => string)): Promise<{
12
+ export declare function readWorkspaceLock(root: string, project?: WorkspaceProject, registryOrigin?: string | ((name: string) => string), allowPlatformRefresh?: boolean): 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,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"}
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,CA0CZ;AACD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAmTrE;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,EACpD,oBAAoB,UAAQ,GAC3B,OAAO,CAAC;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAAG,IAAI,CAAC,CAmD5D"}
@@ -54,6 +54,7 @@ export function workspaceLockDoc(project, graph, fp) {
54
54
  zyrk: {
55
55
  version: 2,
56
56
  resolver: ZYRK_RESOLVER_POLICY,
57
+ platformPolicy: "portable-optional/1",
57
58
  contextCanonicalization: CONTEXT_CANONICALIZATION_VERSION,
58
59
  ...fp,
59
60
  nodes: {},
@@ -71,6 +72,7 @@ export function validateWorkspaceLockDoc(doc) {
71
72
  if (Object.keys(e).some((k) => ![
72
73
  "version",
73
74
  "resolver",
75
+ "platformPolicy",
74
76
  "contextCanonicalization",
75
77
  "manifest",
76
78
  "scripts",
@@ -85,6 +87,7 @@ export function validateWorkspaceLockDoc(doc) {
85
87
  Object.keys(e.roots).length !== 0 ||
86
88
  e.version !== 2 ||
87
89
  e.resolver !== ZYRK_RESOLVER_POLICY ||
90
+ e.platformPolicy !== "portable-optional/1" ||
88
91
  e.contextCanonicalization !== CONTEXT_CANONICALIZATION_VERSION ||
89
92
  typeof e.manifest !== "string" ||
90
93
  !/^[a-f0-9]{128}$/.test(e.manifest) ||
@@ -249,6 +252,7 @@ export function validateWorkspaceLockDoc(doc) {
249
252
  zyrk: {
250
253
  version: 1,
251
254
  resolver: ZYRK_RESOLVER_POLICY,
255
+ platformPolicy: "portable-optional/1",
252
256
  contextCanonicalization: CONTEXT_CANONICALIZATION_VERSION,
253
257
  manifest: "sha512-" + "A".repeat(86) + "==",
254
258
  scripts: "sha512-" + "A".repeat(86) + "==",
@@ -300,7 +304,7 @@ export function validateWorkspaceLockDoc(doc) {
300
304
  }
301
305
  return g;
302
306
  }
303
- export async function readWorkspaceLock(root, project, registryOrigin) {
307
+ export async function readWorkspaceLock(root, project, registryOrigin, allowPlatformRefresh = false) {
304
308
  let text;
305
309
  try {
306
310
  text = await readFile(path.join(root, "package-lock.json"), "utf8");
@@ -317,6 +321,12 @@ export async function readWorkspaceLock(root, project, registryOrigin) {
317
321
  catch {
318
322
  throw lockMismatch("workspace lock is not valid JSON");
319
323
  }
324
+ if (allowPlatformRefresh &&
325
+ object(doc) &&
326
+ object(doc.zyrk) &&
327
+ doc.zyrk.version === 2 &&
328
+ doc.zyrk.platformPolicy === undefined)
329
+ return null;
320
330
  const graph = validateWorkspaceLockDoc(doc);
321
331
  if (project) {
322
332
  const expected = new Map(project.importers.map((i) => [i.id, i]));
@@ -72,7 +72,6 @@ export function configFingerprint(config) {
72
72
  : {}),
73
73
  linker: config.linker,
74
74
  ...(config.patches === undefined ? {} : { patches: config.patches }),
75
- ...(config.platform === undefined ? {} : { platform: config.platform }),
76
75
  ...(config.mutablePackages === undefined
77
76
  ? {}
78
77
  : { mutablePackages: [...config.mutablePackages].sort() }),
@@ -10,7 +10,7 @@ export type ReadLockResult = {
10
10
  path: string;
11
11
  doc: NpmLockDoc;
12
12
  };
13
- export declare function readLockfile(lockPath: string): Promise<ReadLockResult | null>;
13
+ export declare function readLockfile(lockPath: string, allowPlatformRefresh?: boolean): Promise<ReadLockResult | null>;
14
14
  export declare function validateLockDoc(doc: unknown, label: string): NpmLockDoc;
15
15
  export type FrozenFingerprints = {
16
16
  manifest: string;
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/lockfile/read.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC;CACjB,CAAC;AAEF,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAyBhC;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CA2DvE;AA4CD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,kBAAkB,GAC3B,IAAI,CAmCN"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/lockfile/read.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC;CACjB,CAAC;AAEF,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,oBAAoB,UAAQ,GAC3B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAmChC;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CA2DvE;AA4CD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,kBAAkB,GAC3B,IAAI,CAmCN"}
@@ -11,7 +11,7 @@ import { readFile } from "node:fs/promises";
11
11
  import { ZyrkError } from "../errors.js";
12
12
  import { isErrno, pathExists } from "../util/fsx.js";
13
13
  import { ZYRK_LOCK_EXTENSION_VERSION, } from "./types.js";
14
- export async function readLockfile(lockPath) {
14
+ export async function readLockfile(lockPath, allowPlatformRefresh = false) {
15
15
  if (!(await pathExists(lockPath)))
16
16
  return null;
17
17
  let raw;
@@ -34,6 +34,16 @@ export async function readLockfile(lockPath) {
34
34
  cause: error,
35
35
  });
36
36
  }
37
+ if (allowPlatformRefresh && typeof parsed === "object" && parsed !== null) {
38
+ const extension = parsed.zyrk;
39
+ if (extension?.version === 1 && extension.platformPolicy === undefined) {
40
+ // Validate old metadata without treating a platform-pruned graph as portable.
41
+ const checked = structuredClone(parsed);
42
+ checked.zyrk.platformPolicy = "portable-optional/1";
43
+ validateLockDoc(checked, lockPath);
44
+ return { path: lockPath, doc: parsed };
45
+ }
46
+ }
37
47
  return { path: lockPath, doc: validateLockDoc(parsed, lockPath) };
38
48
  }
39
49
  export function validateLockDoc(doc, label) {
@@ -15,6 +15,7 @@
15
15
  * manifest, policy, or configuration drift.
16
16
  */
17
17
  export declare const ZYRK_LOCK_EXTENSION_VERSION = 1;
18
+ export declare const ZYRK_PLATFORM_POLICY = "portable-optional/1";
18
19
  /** npm package metadata, interpreted during exact-selection import. */
19
20
  export type NpmPackageEntry = Record<string, unknown>;
20
21
  export type NpmLockDoc = {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lockfile/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,uEAAuE;AACvE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC;IACxD,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACrC,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,uBAAuB,EAAE,MAAM,CAAC;IAChC,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpC,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,oBAAoB,mBAAmB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lockfile/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAC7C,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D,uEAAuE;AACvE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC;IACxD,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACrC,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,uBAAuB,EAAE,MAAM,CAAC;IAChC,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpC,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,oBAAoB,mBAAmB,CAAC"}
@@ -15,4 +15,5 @@
15
15
  * manifest, policy, or configuration drift.
16
16
  */
17
17
  export const ZYRK_LOCK_EXTENSION_VERSION = 1;
18
+ export const ZYRK_PLATFORM_POLICY = "portable-optional/1";
18
19
  export const ZYRK_RESOLVER_POLICY = "zyrk-resolve/1";
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/lockfile/write.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,EAGL,KAAK,UAAU,EAGhB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,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,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC1D,QAAQ,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,mBAAmB,CAAC;IAChC,YAAY,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACzB,CAAC;AAEF,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAoOrB"}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/lockfile/write.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,EAGL,KAAK,UAAU,EAGhB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,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,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC1D,QAAQ,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,mBAAmB,CAAC;IAChC,YAAY,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACzB,CAAC;AAEF,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAqOrB"}
@@ -172,6 +172,7 @@ export async function writeLockfile(options) {
172
172
  const extension = {
173
173
  version: ZYRK_LOCK_EXTENSION_VERSION,
174
174
  resolver: ZYRK_RESOLVER_POLICY,
175
+ platformPolicy: "portable-optional/1",
175
176
  contextCanonicalization: CONTEXT_CANONICALIZATION_VERSION,
176
177
  manifest: options.fingerprints.manifest,
177
178
  scripts: options.fingerprints.scripts,
@@ -1,24 +1,3 @@
1
- /**
2
- * Registry-backed dependency resolver (SPEC 9).
3
- *
4
- * Turns requirement strings into an immutable resolved graph: exact name,
5
- * version, origin-qualified source identity, dependency edges, and peer
6
- * bindings. No package code runs here; no project files are touched.
7
- *
8
- * Scope of this slice: registry versions, ranges, tags, scoped names, and
9
- * npm aliases; prod and optional groups; required and optional peers with
10
- * explicit-consumer-context bindings; cycles; bundled subtrees (skipped,
11
- * never exposed). Dev groups need full packuments and arrive later, as do
12
- * overrides and workspace relationships. Platform omissions are reported
13
- * explicitly, and resource limits bound graph construction. Remote
14
- * tarballs, Git, and local sources fail explicitly (SPEC 9.2).
15
- *
16
- * Peer contexts (SPEC 9.3-9.4): one verified source may back several
17
- * dependency contexts. Occurrences that declare peers are instantiated per
18
- * requesting parent and keyed by a fingerprint of their resolved peer
19
- * closure, so identical bindings share one occurrence while differing
20
- * bindings stay distinct. Peerless occurrences share by name@version.
21
- */
22
1
  import { type Packument } from "../fetch/registry.ts";
23
2
  import { type OverridePolicy } from "./overrides.ts";
24
3
  export type MetadataProvider = {
@@ -70,6 +49,7 @@ export type ResolveOptions = {
70
49
  overrides?: OverridePolicy;
71
50
  limits?: Partial<ResolverLimits>;
72
51
  platform?: RuntimePlatform;
52
+ preservePlatformVariants?: boolean;
73
53
  };
74
54
  export type RuntimePlatform = {
75
55
  os: string;
@@ -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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"}
@@ -1,3 +1,4 @@
1
+ import { normalizeEngineConstraints } from "../util/engines.js";
1
2
  /**
2
3
  * Registry-backed dependency resolver (SPEC 9).
3
4
  *
@@ -75,6 +76,7 @@ class ResolverState {
75
76
  occurrences = [];
76
77
  limits;
77
78
  platform;
79
+ preservePlatformVariants;
78
80
  omissions = [];
79
81
  expires;
80
82
  peerExpansions = 0;
@@ -93,6 +95,7 @@ class ResolverState {
93
95
  if (!Number.isSafeInteger(value) || value <= 0)
94
96
  throw budgetError("invalid resolver limits");
95
97
  this.platform = options.platform ?? currentPlatform();
98
+ this.preservePlatformVariants = options.preservePlatformVariants === true;
96
99
  this.expires = Date.now() + this.limits.deadlineMs;
97
100
  }
98
101
  checkBudget(depth = 0, adding = false) {
@@ -104,6 +107,8 @@ class ResolverState {
104
107
  throw budgetError("resolved node limit exceeded");
105
108
  }
106
109
  checkPlatform(name, entry) {
110
+ if (this.preservePlatformVariants)
111
+ return;
107
112
  for (const [constraints, actual] of [
108
113
  [entry.os, this.platform.os],
109
114
  [entry.cpu, this.platform.cpu],
@@ -582,6 +587,13 @@ function assertMergeable(a, b, keys, origin) {
582
587
  }
583
588
  }
584
589
  function toResolved(occ, key, keys, origin) {
590
+ const engines = occ.entry.engines === undefined
591
+ ? undefined
592
+ : normalizeEngineConstraints(occ.entry.engines, () => {
593
+ throw new ZyrkError("ZYRK_RESOLUTION_FAILED", `Cannot resolve ${occ.name}: invalid engine constraints.`, {
594
+ remedy: "Select a package version with valid npm engine metadata.",
595
+ });
596
+ });
585
597
  const edgesByName = new Map();
586
598
  for (const link of occ.children) {
587
599
  const target = keys.get(link.child);
@@ -630,7 +642,7 @@ function toResolved(occ, key, keys, origin) {
630
642
  ...(occ.entry.cpu === undefined ? {} : { cpu: occ.entry.cpu }),
631
643
  ...(occ.entry.libc === undefined ? {} : { libc: occ.entry.libc }),
632
644
  },
633
- ...(occ.entry.engines === undefined ? {} : { engines: occ.entry.engines }),
645
+ ...(engines === undefined ? {} : { engines }),
634
646
  };
635
647
  }
636
648
  function sourceIdForOccurrence(occ, origin) {
@@ -0,0 +1,2 @@
1
+ export declare function normalizeEngineConstraints(value: unknown, invalid: () => never): Record<string, string>;
2
+ //# sourceMappingURL=engines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engines.d.ts","sourceRoot":"","sources":["../../src/util/engines.ts"],"names":[],"mappings":"AAGA,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,KAAK,GACnB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyBxB"}
@@ -0,0 +1,23 @@
1
+ /** Normalize npm's historical engine arrays without weakening modern map checks. */
2
+ import { validRange } from "semver";
3
+ export function normalizeEngineConstraints(value, invalid) {
4
+ if (Array.isArray(value)) {
5
+ const engines = {};
6
+ for (const item of value) {
7
+ const match = typeof item === "string"
8
+ ? /^([a-z][a-z0-9._-]*)\s+(.+)$/.exec(item)
9
+ : null;
10
+ if (!match ||
11
+ Object.hasOwn(engines, match[1]) ||
12
+ validRange(match[2]) === null)
13
+ return invalid();
14
+ engines[match[1]] = match[2];
15
+ }
16
+ return engines;
17
+ }
18
+ if (typeof value !== "object" ||
19
+ value === null ||
20
+ Object.values(value).some((item) => typeof item !== "string"))
21
+ return invalid();
22
+ return value;
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zyrk",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
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",