@vltpkg/graph 1.0.0-rc.3 → 1.0.0-rc.30

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 (227) hide show
  1. package/README.md +101 -22
  2. package/dist/{esm/actual → actual}/load.d.ts +8 -1
  3. package/dist/{esm/actual → actual}/load.js +57 -22
  4. package/dist/{esm/browser.d.ts → browser.d.ts} +0 -1
  5. package/dist/{esm/browser.js → browser.js} +0 -1
  6. package/dist/{esm/build.d.ts → build.d.ts} +0 -1
  7. package/dist/{esm/build.js → build.js} +0 -1
  8. package/dist/{esm/dependencies.d.ts → dependencies.d.ts} +0 -1
  9. package/dist/{esm/dependencies.js → dependencies.js} +0 -1
  10. package/dist/{esm/diff.d.ts → diff.d.ts} +4 -1
  11. package/dist/{esm/diff.js → diff.js} +5 -2
  12. package/dist/{esm/edge.d.ts → edge.d.ts} +1 -1
  13. package/dist/{esm/edge.js → edge.js} +4 -1
  14. package/dist/fixup-added-names.d.ts +18 -0
  15. package/dist/fixup-added-names.js +46 -0
  16. package/dist/{esm/graph.d.ts → graph.d.ts} +25 -5
  17. package/dist/{esm/graph.js → graph.js} +92 -43
  18. package/dist/ideal/append-nodes.d.ts +31 -0
  19. package/dist/ideal/append-nodes.js +560 -0
  20. package/dist/{esm/ideal → ideal}/build-ideal-from-starting-graph.d.ts +4 -5
  21. package/dist/ideal/build-ideal-from-starting-graph.js +69 -0
  22. package/dist/{esm/ideal → ideal}/build.d.ts +0 -1
  23. package/dist/ideal/build.js +84 -0
  24. package/dist/{esm/ideal → ideal}/get-importer-specs.d.ts +9 -3
  25. package/dist/{esm/ideal → ideal}/get-importer-specs.js +80 -6
  26. package/dist/ideal/peers.d.ts +160 -0
  27. package/dist/ideal/peers.js +696 -0
  28. package/dist/ideal/refresh-ideal-graph.d.ts +43 -0
  29. package/dist/ideal/refresh-ideal-graph.js +62 -0
  30. package/dist/{esm/ideal → ideal}/remove-satisfied-specs.d.ts +0 -1
  31. package/dist/{esm/ideal → ideal}/remove-satisfied-specs.js +8 -1
  32. package/dist/ideal/sorting.d.ts +45 -0
  33. package/dist/ideal/sorting.js +70 -0
  34. package/dist/ideal/types.d.ts +107 -0
  35. package/dist/ideal/types.js +1 -0
  36. package/dist/{esm/index.d.ts → index.d.ts} +1 -1
  37. package/dist/{esm/index.js → index.js} +1 -1
  38. package/dist/{esm/install.d.ts → install.d.ts} +3 -3
  39. package/dist/{esm/install.js → install.js} +49 -9
  40. package/dist/{esm/lockfile → lockfile}/load-edges.d.ts +0 -1
  41. package/dist/{esm/lockfile → lockfile}/load-edges.js +7 -4
  42. package/dist/{esm/lockfile → lockfile}/load-nodes.d.ts +0 -1
  43. package/dist/{esm/lockfile → lockfile}/load-nodes.js +10 -4
  44. package/dist/{esm/lockfile → lockfile}/load.d.ts +0 -5
  45. package/dist/{esm/lockfile → lockfile}/load.js +31 -33
  46. package/dist/{esm/lockfile → lockfile}/save.d.ts +1 -2
  47. package/dist/{esm/lockfile → lockfile}/save.js +8 -7
  48. package/dist/{esm/lockfile → lockfile}/types.d.ts +7 -1
  49. package/dist/{esm/lockfile → lockfile}/types.js +6 -1
  50. package/dist/{esm/modifiers.d.ts → modifiers.d.ts} +0 -1
  51. package/dist/{esm/modifiers.js → modifiers.js} +0 -1
  52. package/dist/{esm/node.d.ts → node.d.ts} +16 -1
  53. package/dist/{esm/node.js → node.js} +21 -1
  54. package/dist/{esm/non-empty-list.d.ts → non-empty-list.d.ts} +0 -1
  55. package/dist/{esm/non-empty-list.js → non-empty-list.js} +0 -1
  56. package/dist/{esm/reify → reify}/add-edge.d.ts +0 -1
  57. package/dist/{esm/reify → reify}/add-edge.js +10 -4
  58. package/dist/{esm/reify → reify}/add-edges.d.ts +1 -2
  59. package/dist/{esm/reify → reify}/add-edges.js +2 -2
  60. package/dist/{esm/reify → reify}/add-nodes.d.ts +0 -1
  61. package/dist/{esm/reify → reify}/add-nodes.js +0 -1
  62. package/dist/{esm/reify → reify}/bin-chmod.d.ts +0 -1
  63. package/dist/{esm/reify → reify}/bin-chmod.js +0 -1
  64. package/dist/{esm/reify → reify}/build.d.ts +0 -1
  65. package/dist/{esm/reify → reify}/build.js +12 -4
  66. package/dist/{esm/reify → reify}/calculate-save-value.d.ts +0 -1
  67. package/dist/{esm/reify → reify}/calculate-save-value.js +6 -1
  68. package/dist/{esm/reify → reify}/check-needed-build.d.ts +10 -1
  69. package/dist/reify/check-needed-build.js +71 -0
  70. package/dist/{esm/reify → reify}/delete-edge.d.ts +0 -1
  71. package/dist/{esm/reify → reify}/delete-edge.js +0 -1
  72. package/dist/{esm/reify → reify}/delete-edges.d.ts +0 -1
  73. package/dist/{esm/reify → reify}/delete-edges.js +0 -1
  74. package/dist/{esm/reify → reify}/delete-nodes.d.ts +0 -1
  75. package/dist/{esm/reify → reify}/delete-nodes.js +0 -1
  76. package/dist/{esm/reify → reify}/extract-node.d.ts +0 -1
  77. package/dist/{esm/reify → reify}/extract-node.js +10 -3
  78. package/dist/{esm/reify → reify}/index.d.ts +1 -1
  79. package/dist/{esm/reify → reify}/index.js +4 -4
  80. package/dist/{esm/reify → reify}/internal-hoist.d.ts +0 -1
  81. package/dist/{esm/reify → reify}/internal-hoist.js +0 -1
  82. package/dist/{esm/reify → reify}/optional-fail.d.ts +0 -1
  83. package/dist/{esm/reify → reify}/optional-fail.js +0 -1
  84. package/dist/{esm/reify → reify}/rollback.d.ts +0 -1
  85. package/dist/{esm/reify → reify}/rollback.js +0 -1
  86. package/dist/{esm/reify → reify}/update-importers-package-json.d.ts +1 -2
  87. package/dist/{esm/reify → reify}/update-importers-package-json.js +19 -17
  88. package/dist/{esm/remove-optional-subgraph.d.ts → remove-optional-subgraph.d.ts} +0 -1
  89. package/dist/{esm/remove-optional-subgraph.js → remove-optional-subgraph.js} +0 -1
  90. package/dist/{esm/resolve-save-type.d.ts → resolve-save-type.d.ts} +0 -1
  91. package/dist/{esm/resolve-save-type.js → resolve-save-type.js} +0 -1
  92. package/dist/{esm/stringify-node.d.ts → stringify-node.d.ts} +0 -1
  93. package/dist/{esm/stringify-node.js → stringify-node.js} +10 -2
  94. package/dist/{esm/transfer-data → transfer-data}/load.d.ts +0 -1
  95. package/dist/{esm/transfer-data → transfer-data}/load.js +5 -3
  96. package/dist/{esm/uninstall.d.ts → uninstall.d.ts} +0 -1
  97. package/dist/{esm/uninstall.js → uninstall.js} +27 -7
  98. package/dist/{esm/update.d.ts → update.d.ts} +0 -1
  99. package/dist/{esm/update.js → update.js} +11 -1
  100. package/dist/{esm/virtual-root.d.ts → virtual-root.d.ts} +0 -1
  101. package/dist/{esm/virtual-root.js → virtual-root.js} +0 -1
  102. package/dist/{esm/visualization → visualization}/human-readable-output.d.ts +0 -1
  103. package/dist/{esm/visualization → visualization}/human-readable-output.js +7 -3
  104. package/dist/{esm/visualization → visualization}/json-output.d.ts +2 -2
  105. package/dist/{esm/visualization → visualization}/json-output.js +2 -3
  106. package/dist/{esm/visualization → visualization}/mermaid-output.d.ts +2 -2
  107. package/dist/visualization/mermaid-output.js +170 -0
  108. package/dist/{esm/visualization → visualization}/object-like-output.d.ts +0 -1
  109. package/dist/{esm/visualization → visualization}/object-like-output.js +0 -1
  110. package/package.json +51 -63
  111. package/dist/esm/actual/load.d.ts.map +0 -1
  112. package/dist/esm/actual/load.js.map +0 -1
  113. package/dist/esm/browser.d.ts.map +0 -1
  114. package/dist/esm/browser.js.map +0 -1
  115. package/dist/esm/build.d.ts.map +0 -1
  116. package/dist/esm/build.js.map +0 -1
  117. package/dist/esm/dependencies.d.ts.map +0 -1
  118. package/dist/esm/dependencies.js.map +0 -1
  119. package/dist/esm/diff.d.ts.map +0 -1
  120. package/dist/esm/diff.js.map +0 -1
  121. package/dist/esm/edge.d.ts.map +0 -1
  122. package/dist/esm/edge.js.map +0 -1
  123. package/dist/esm/graph.d.ts.map +0 -1
  124. package/dist/esm/graph.js.map +0 -1
  125. package/dist/esm/ideal/add-nodes.d.ts +0 -34
  126. package/dist/esm/ideal/add-nodes.d.ts.map +0 -1
  127. package/dist/esm/ideal/add-nodes.js +0 -39
  128. package/dist/esm/ideal/add-nodes.js.map +0 -1
  129. package/dist/esm/ideal/append-nodes.d.ts +0 -19
  130. package/dist/esm/ideal/append-nodes.d.ts.map +0 -1
  131. package/dist/esm/ideal/append-nodes.js +0 -289
  132. package/dist/esm/ideal/append-nodes.js.map +0 -1
  133. package/dist/esm/ideal/build-ideal-from-starting-graph.d.ts.map +0 -1
  134. package/dist/esm/ideal/build-ideal-from-starting-graph.js +0 -55
  135. package/dist/esm/ideal/build-ideal-from-starting-graph.js.map +0 -1
  136. package/dist/esm/ideal/build.d.ts.map +0 -1
  137. package/dist/esm/ideal/build.js +0 -48
  138. package/dist/esm/ideal/build.js.map +0 -1
  139. package/dist/esm/ideal/get-importer-specs.d.ts.map +0 -1
  140. package/dist/esm/ideal/get-importer-specs.js.map +0 -1
  141. package/dist/esm/ideal/remove-nodes.d.ts +0 -7
  142. package/dist/esm/ideal/remove-nodes.d.ts.map +0 -1
  143. package/dist/esm/ideal/remove-nodes.js +0 -19
  144. package/dist/esm/ideal/remove-nodes.js.map +0 -1
  145. package/dist/esm/ideal/remove-satisfied-specs.d.ts.map +0 -1
  146. package/dist/esm/ideal/remove-satisfied-specs.js.map +0 -1
  147. package/dist/esm/ideal/types.d.ts +0 -35
  148. package/dist/esm/ideal/types.d.ts.map +0 -1
  149. package/dist/esm/ideal/types.js +0 -2
  150. package/dist/esm/ideal/types.js.map +0 -1
  151. package/dist/esm/index.d.ts.map +0 -1
  152. package/dist/esm/index.js.map +0 -1
  153. package/dist/esm/install.d.ts.map +0 -1
  154. package/dist/esm/install.js.map +0 -1
  155. package/dist/esm/lockfile/load-edges.d.ts.map +0 -1
  156. package/dist/esm/lockfile/load-edges.js.map +0 -1
  157. package/dist/esm/lockfile/load-nodes.d.ts.map +0 -1
  158. package/dist/esm/lockfile/load-nodes.js.map +0 -1
  159. package/dist/esm/lockfile/load.d.ts.map +0 -1
  160. package/dist/esm/lockfile/load.js.map +0 -1
  161. package/dist/esm/lockfile/save.d.ts.map +0 -1
  162. package/dist/esm/lockfile/save.js.map +0 -1
  163. package/dist/esm/lockfile/types.d.ts.map +0 -1
  164. package/dist/esm/lockfile/types.js.map +0 -1
  165. package/dist/esm/modifiers.d.ts.map +0 -1
  166. package/dist/esm/modifiers.js.map +0 -1
  167. package/dist/esm/node.d.ts.map +0 -1
  168. package/dist/esm/node.js.map +0 -1
  169. package/dist/esm/non-empty-list.d.ts.map +0 -1
  170. package/dist/esm/non-empty-list.js.map +0 -1
  171. package/dist/esm/package.json +0 -3
  172. package/dist/esm/reify/add-edge.d.ts.map +0 -1
  173. package/dist/esm/reify/add-edge.js.map +0 -1
  174. package/dist/esm/reify/add-edges.d.ts.map +0 -1
  175. package/dist/esm/reify/add-edges.js.map +0 -1
  176. package/dist/esm/reify/add-nodes.d.ts.map +0 -1
  177. package/dist/esm/reify/add-nodes.js.map +0 -1
  178. package/dist/esm/reify/bin-chmod.d.ts.map +0 -1
  179. package/dist/esm/reify/bin-chmod.js.map +0 -1
  180. package/dist/esm/reify/build.d.ts.map +0 -1
  181. package/dist/esm/reify/build.js.map +0 -1
  182. package/dist/esm/reify/calculate-save-value.d.ts.map +0 -1
  183. package/dist/esm/reify/calculate-save-value.js.map +0 -1
  184. package/dist/esm/reify/check-needed-build.d.ts.map +0 -1
  185. package/dist/esm/reify/check-needed-build.js +0 -50
  186. package/dist/esm/reify/check-needed-build.js.map +0 -1
  187. package/dist/esm/reify/delete-edge.d.ts.map +0 -1
  188. package/dist/esm/reify/delete-edge.js.map +0 -1
  189. package/dist/esm/reify/delete-edges.d.ts.map +0 -1
  190. package/dist/esm/reify/delete-edges.js.map +0 -1
  191. package/dist/esm/reify/delete-nodes.d.ts.map +0 -1
  192. package/dist/esm/reify/delete-nodes.js.map +0 -1
  193. package/dist/esm/reify/extract-node.d.ts.map +0 -1
  194. package/dist/esm/reify/extract-node.js.map +0 -1
  195. package/dist/esm/reify/index.d.ts.map +0 -1
  196. package/dist/esm/reify/index.js.map +0 -1
  197. package/dist/esm/reify/internal-hoist.d.ts.map +0 -1
  198. package/dist/esm/reify/internal-hoist.js.map +0 -1
  199. package/dist/esm/reify/optional-fail.d.ts.map +0 -1
  200. package/dist/esm/reify/optional-fail.js.map +0 -1
  201. package/dist/esm/reify/rollback.d.ts.map +0 -1
  202. package/dist/esm/reify/rollback.js.map +0 -1
  203. package/dist/esm/reify/update-importers-package-json.d.ts.map +0 -1
  204. package/dist/esm/reify/update-importers-package-json.js.map +0 -1
  205. package/dist/esm/remove-optional-subgraph.d.ts.map +0 -1
  206. package/dist/esm/remove-optional-subgraph.js.map +0 -1
  207. package/dist/esm/resolve-save-type.d.ts.map +0 -1
  208. package/dist/esm/resolve-save-type.js.map +0 -1
  209. package/dist/esm/stringify-node.d.ts.map +0 -1
  210. package/dist/esm/stringify-node.js.map +0 -1
  211. package/dist/esm/transfer-data/load.d.ts.map +0 -1
  212. package/dist/esm/transfer-data/load.js.map +0 -1
  213. package/dist/esm/uninstall.d.ts.map +0 -1
  214. package/dist/esm/uninstall.js.map +0 -1
  215. package/dist/esm/update.d.ts.map +0 -1
  216. package/dist/esm/update.js.map +0 -1
  217. package/dist/esm/virtual-root.d.ts.map +0 -1
  218. package/dist/esm/virtual-root.js.map +0 -1
  219. package/dist/esm/visualization/human-readable-output.d.ts.map +0 -1
  220. package/dist/esm/visualization/human-readable-output.js.map +0 -1
  221. package/dist/esm/visualization/json-output.d.ts.map +0 -1
  222. package/dist/esm/visualization/json-output.js.map +0 -1
  223. package/dist/esm/visualization/mermaid-output.d.ts.map +0 -1
  224. package/dist/esm/visualization/mermaid-output.js +0 -123
  225. package/dist/esm/visualization/mermaid-output.js.map +0 -1
  226. package/dist/esm/visualization/object-like-output.d.ts.map +0 -1
  227. package/dist/esm/visualization/object-like-output.js.map +0 -1
@@ -1,7 +1,7 @@
1
- import { getId, joinDepIDTuple } from '@vltpkg/dep-id';
1
+ import { getId, joinDepIDTuple, splitExtra } from '@vltpkg/dep-id';
2
2
  import { error } from '@vltpkg/error-cause';
3
3
  import { satisfies } from '@vltpkg/satisfies';
4
- import { Spec } from '@vltpkg/spec';
4
+ import { getOptions, Spec } from '@vltpkg/spec';
5
5
  import { inspect } from 'node:util';
6
6
  import { lockfileData } from "./lockfile/save.js";
7
7
  import { Edge } from "./edge.js";
@@ -17,7 +17,7 @@ const getMap = (m) => m ?? new Map();
17
17
  * Get a cache key for a resolution based on the
18
18
  * spec, location and query modifier.
19
19
  */
20
- const getResolutionCacheKey = (spec, location, queryModifier) => {
20
+ const getResolutionCacheKey = (spec, location, extra) => {
21
21
  const f = spec.final;
22
22
  // if it's a file: dep, then the fromNode location matters
23
23
  const fromPrefix = f.type === 'file' ? location + ' : ' : '';
@@ -29,7 +29,7 @@ const getResolutionCacheKey = (spec, location, queryModifier) => {
29
29
  : f.gitRemote ?
30
30
  `${cacheKeySeparator}git` + `${cacheKeySeparator}${f.gitRemote}`
31
31
  : `${cacheKeySeparator}${f.type}`;
32
- const modifierSuffix = `${cacheKeySeparator}${queryModifier}`;
32
+ const modifierSuffix = `${cacheKeySeparator}${extra}`;
33
33
  return fromPrefix + String(f) + typePrecisionKey + modifierSuffix;
34
34
  };
35
35
  export class Graph {
@@ -82,13 +82,40 @@ export class Graph {
82
82
  * The root of the project this graph represents
83
83
  */
84
84
  projectRoot;
85
+ /**
86
+ * The peer context sets used to resolve peer dependencies within this graph.
87
+ */
88
+ peerContexts;
89
+ /**
90
+ * Cache of forked peer contexts so identical fork operations can reuse
91
+ * previously created contexts instead of duplicating them.
92
+ *
93
+ * Key format is internal and constructed in `ideal/peers.ts`.
94
+ */
95
+ peerContextForkCache = new Map();
96
+ /**
97
+ * Tracks the current peer context index.
98
+ */
99
+ currentPeerContextIndex = 0;
85
100
  constructor(options) {
86
101
  const { mainManifest, monorepo } = options;
87
102
  this.#options = options;
103
+ // hydrate spec options to their full contents, including defaults
104
+ const specOptions = getOptions({
105
+ registry: options.registry,
106
+ registries: options.registries,
107
+ 'git-hosts': options['git-hosts'],
108
+ 'git-host-archives': options['git-host-archives'],
109
+ 'scoped-registries': options['scoped-registries'],
110
+ 'jsr-registries': options['jsr-registries'],
111
+ catalog: options.catalog,
112
+ catalogs: options.catalogs,
113
+ });
88
114
  this.manifests = getMap(options.manifests);
89
115
  this.projectRoot = options.projectRoot;
90
116
  this.#nodeOptions = {
91
117
  ...this.#options,
118
+ ...specOptions,
92
119
  graph: this,
93
120
  };
94
121
  // add the project root node
@@ -110,6 +137,12 @@ export class Graph {
110
137
  wsNode.setImporterLocation(`./${ws.path}`);
111
138
  if (wsNode.manifest) {
112
139
  this.manifests.set(wsNode.id, wsNode.manifest);
140
+ // set bins for workspace nodes so they can be linked
141
+ // when another importer depends on this workspace
142
+ /* c8 ignore next 3 - tested by integration tests */
143
+ if (wsNode.manifest.bin) {
144
+ wsNode.bins = wsNode.manifest.bin;
145
+ }
113
146
  }
114
147
  this.importers.add(wsNode);
115
148
  // creates a virtual edge to connect the workspaces to the root node
@@ -117,6 +150,16 @@ export class Graph {
117
150
  this.mainImporter.workspaces.set(wsNode.name, edge);
118
151
  }
119
152
  }
153
+ // initializes the peer context set collection
154
+ const initialPeerContext = new Map();
155
+ initialPeerContext.index = this.currentPeerContextIndex;
156
+ this.peerContexts = [initialPeerContext];
157
+ }
158
+ /**
159
+ * Get the next peer context index.
160
+ */
161
+ nextPeerContextIndex() {
162
+ return ++this.currentPeerContextIndex;
120
163
  }
121
164
  /**
122
165
  * Delete all nodes and edges that are unreachable from the importers.
@@ -191,9 +234,9 @@ export class Graph {
191
234
  /**
192
235
  * Find an existing node to satisfy a dependency
193
236
  */
194
- findResolution(spec, fromNode, queryModifier = '') {
237
+ findResolution(spec, fromNode, extra = '') {
195
238
  const f = spec.final;
196
- const sf = getResolutionCacheKey(f, fromNode.location, queryModifier);
239
+ const sf = getResolutionCacheKey(f, fromNode.location, extra);
197
240
  const cached = this.resolutions.get(sf);
198
241
  if (cached)
199
242
  return cached;
@@ -217,7 +260,10 @@ export class Graph {
217
260
  this.nodes.set(node.id, node);
218
261
  const nbn = this.nodesByName.get(node.name) ?? new Set();
219
262
  nbn.add(node);
220
- this.nodesByName.set(node.name, nbn);
263
+ // ensure the nodes by name set is always sorted, this will help
264
+ // keeping a deterministic graph resolution when reusing nodes
265
+ const newByNameSet = new Set([...nbn].sort((a, b) => a.id.localeCompare(b.id)));
266
+ this.nodesByName.set(node.name, newByNameSet);
221
267
  if (manifest) {
222
268
  this.manifests.set(node.id, manifest);
223
269
  }
@@ -261,8 +307,21 @@ export class Graph {
261
307
  this.addEdge(depType, spec, fromNode, toFoundNode);
262
308
  // the current only stays dev/optional if this dep lets it remain so
263
309
  // if it's not already, we don't make it dev or optional.
310
+ toFoundNode.detached = false;
264
311
  toFoundNode.dev &&= flags.dev;
265
312
  toFoundNode.optional &&= flags.optional;
313
+ // Hydrate manifest and integrity on existing nodes (e.g. loaded
314
+ // from a lockfile without manifest data). Without this, nodes
315
+ // that already have `resolved` set from the lockfile will never
316
+ // get their integrity populated because `setResolved()` is
317
+ // skipped when `resolved` is already present.
318
+ if (manifest) {
319
+ if (!toFoundNode.manifest) {
320
+ toFoundNode.manifest = manifest;
321
+ this.manifests.set(toFoundNode.id, manifest);
322
+ }
323
+ toFoundNode.integrity ??= manifest.dist?.integrity;
324
+ }
266
325
  return toFoundNode;
267
326
  }
268
327
  // creates a new node and edges to its parent
@@ -270,12 +329,17 @@ export class Graph {
270
329
  toNode.registry = spec.registry;
271
330
  toNode.dev = flags.dev;
272
331
  toNode.optional = flags.optional;
273
- toNode.modifier = extra;
332
+ // split extra into modifier and peerSetHash
333
+ if (extra) {
334
+ const { modifier, peerSetHash } = splitExtra(extra);
335
+ toNode.modifier = modifier;
336
+ toNode.peerSetHash = peerSetHash;
337
+ }
274
338
  // add extra manifest info if available
275
339
  if (manifest) {
276
- const { bin, engines, os, cpu } = manifest;
340
+ const { bin, engines, os, cpu, libc } = manifest;
277
341
  // add platform info if available
278
- if (engines || os || cpu) {
342
+ if (engines || os || cpu || libc) {
279
343
  const platform = {};
280
344
  if (engines)
281
345
  platform.engines = engines;
@@ -283,6 +347,8 @@ export class Graph {
283
347
  platform.os = os;
284
348
  if (cpu)
285
349
  platform.cpu = cpu;
350
+ if (libc)
351
+ platform.libc = libc;
286
352
  toNode.platform = platform;
287
353
  }
288
354
  // add bin info if available
@@ -343,9 +409,9 @@ export class Graph {
343
409
  /**
344
410
  * Removes the resolved node of a given edge.
345
411
  */
346
- removeEdgeResolution(edge, queryModifier = '') {
412
+ removeEdgeResolution(edge, extra = '') {
347
413
  const node = edge.to;
348
- const resolutionKey = getResolutionCacheKey(edge.spec, edge.from.location, queryModifier);
414
+ const resolutionKey = getResolutionCacheKey(edge.spec, edge.from.location, extra);
349
415
  if (node) {
350
416
  edge.to = undefined;
351
417
  this.resolutions.delete(resolutionKey);
@@ -358,38 +424,22 @@ export class Graph {
358
424
  }
359
425
  }
360
426
  /**
361
- * Reset resolution cache data.
427
+ * Remove all edges from the graph while preserving nodes and resolution caches.
428
+ * This allows the graph to be reconstructed efficiently using the existing nodes.
362
429
  */
363
- resetResolution() {
364
- // Clear all cache structures
365
- this.resolutions.clear();
366
- this.resolutionsReverse.clear();
367
- this.nodesByName.clear();
368
- // Rebuild nodesByName from all nodes
430
+ resetEdges() {
431
+ // Clear the global edges set
432
+ this.edges.clear();
433
+ // Clear all node edge relationships
369
434
  for (const node of this.nodes.values()) {
370
- const nbn = this.nodesByName.get(node.name) ?? new Set();
371
- nbn.add(node);
372
- this.nodesByName.set(node.name, nbn);
373
- }
374
- // Rebuild resolution caches from all edges that have resolved targets
375
- const seenNodes = new Set();
376
- for (const edge of this.edges) {
377
- const { to: node } = edge;
378
- if (!node)
379
- continue; // Skip unresolved edges
380
- // Only process each node once to avoid duplicate cache entries
381
- if (seenNodes.has(node))
382
- continue;
383
- seenNodes.add(node);
384
- // Initialize resolutionsReverse entry for this node if it doesn't exist
385
- if (!this.resolutionsReverse.has(node)) {
386
- this.resolutionsReverse.set(node, new Set());
387
- }
388
- // Get the modifier if the node has one associated to it
389
- const queryModifier = node.modifier || '';
390
- const resolutionKey = getResolutionCacheKey(edge.spec.final, edge.from.location, queryModifier);
391
- this.resolutions.set(resolutionKey, node);
392
- this.resolutionsReverse.get(node)?.add(resolutionKey);
435
+ // Mark nodes as detached so ideal rebuild treats them as candidates
436
+ // that must be (re)placed during traversal. Detached nodes with a
437
+ // manifest can skip refetch; detached nodes without a manifest must
438
+ // fetch from package-info during ideal rebuild.
439
+ node.detached = true;
440
+ // detaches all edges from this node
441
+ node.edgesOut.clear();
442
+ node.edgesIn.clear();
393
443
  }
394
444
  }
395
445
  toJSON() {
@@ -404,4 +454,3 @@ export class Graph {
404
454
  return `${this[Symbol.toStringTag]} ${inspect(data, options)}`;
405
455
  }
406
456
  }
407
- //# sourceMappingURL=graph.js.map
@@ -0,0 +1,31 @@
1
+ import type { DepID } from '@vltpkg/dep-id';
2
+ import type { PackageInfoClient } from '@vltpkg/package-info';
3
+ import type { SpecOptions } from '@vltpkg/spec';
4
+ import type { PathScurry } from 'path-scurry';
5
+ import type { Dependency } from '../dependencies.ts';
6
+ import type { Graph } from '../graph.ts';
7
+ import type { Node } from '../node.ts';
8
+ import type { GraphModifier, ModifierActiveEntry } from '../modifiers.ts';
9
+ import type { ExtractResult } from '../reify/extract-node.ts';
10
+ import type { RollbackRemove } from '@vltpkg/rollback-remove';
11
+ import type { TransientAddMap, TransientRemoveMap } from './types.ts';
12
+ /**
13
+ * Append new nodes in the given `graph` for dependencies specified at `add`
14
+ * and missing dependencies from the `deps` parameter.
15
+ *
16
+ * Uses **breadth-first traversal** (BFS) with **deterministic ordering** to
17
+ * ensure reproducible builds. The algorithm:
18
+ *
19
+ * 1. Process all deps at the current level in parallel
20
+ * 2. After each level, run `postPlacementPeerCheck` to handle peer contexts
21
+ * 3. Collect child deps for the next level
22
+ * 4. Repeat until no more deps to process
23
+ *
24
+ * **Peer Context Isolation**: Each workspace importer gets its own peer context
25
+ * to prevent cross-workspace leakage. Without this, `react@^18` from workspace A
26
+ * could incorrectly satisfy `react@^19` peer deps in workspace B.
27
+ *
28
+ * **Early Extraction**: When `actual` graph is provided, nodes are extracted
29
+ * to the vlt store during graph construction (not after), improving performance.
30
+ */
31
+ export declare const appendNodes: (packageInfo: PackageInfoClient, graph: Graph, fromNode: Node, deps: Dependency[], scurry: PathScurry, options: SpecOptions, seen: Set<DepID>, add?: Map<string, Dependency>, modifiers?: GraphModifier, modifierRefs?: Map<string, ModifierActiveEntry>, extractPromises?: Promise<ExtractResult>[], actual?: Graph, seenExtracted?: Set<DepID>, remover?: RollbackRemove, transientAdd?: TransientAddMap, transientRemove?: TransientRemoveMap) => Promise<void>;