@antongolub/lockfile 0.0.0-snapshot.67 → 0.0.0-snapshot.69

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.
package/dist/complete.js CHANGED
@@ -58,6 +58,25 @@ function resolveFindUp(graph, consumerId, name, range, depKind) {
58
58
  }
59
59
  return void 0;
60
60
  }
61
+ function bestExistingSatisfying(graph, name, range) {
62
+ const candidates = [];
63
+ for (const id of graph.byName(name)) {
64
+ const node = graph.getNode(id);
65
+ if (node === void 0) continue;
66
+ if (node.peerContext.length > 0) continue;
67
+ if (node.patch !== void 0) continue;
68
+ if (node.source !== void 0) continue;
69
+ if (node.workspacePath !== void 0) continue;
70
+ if (safeSatisfies(node.version, range)) candidates.push(node);
71
+ }
72
+ if (candidates.length === 0) return void 0;
73
+ candidates.sort((a, b) => {
74
+ const v = semverRcompareSafe(a.version, b.version);
75
+ if (v !== 0) return v;
76
+ return cmpStr2(a.id, b.id);
77
+ });
78
+ return candidates[0].id;
79
+ }
61
80
  function safeSatisfies(version, range) {
62
81
  try {
63
82
  return semver.satisfies(version, range);
@@ -212,6 +231,22 @@ async function completeTransitives(graph, registry, options = {}) {
212
231
  if (!visited.has(targetId)) frontier.push(targetId);
213
232
  continue;
214
233
  }
234
+ if (kind !== "peer") {
235
+ const reuseId = bestExistingSatisfying(currentGraph, depName, depRange);
236
+ if (reuseId !== void 0 && reuseId !== nodeId) {
237
+ const triple2 = { src: nodeId, dst: reuseId, kind };
238
+ const resolvedDiag = completionEdgeResolved(triple2);
239
+ const result2 = currentGraph.mutate((m) => {
240
+ m.addEdge(nodeId, reuseId, kind, { range: depRange });
241
+ m.diagnostic(resolvedDiag);
242
+ });
243
+ currentGraph = result2.graph;
244
+ wired.push(triple2);
245
+ emit(resolvedDiag);
246
+ if (!visited.has(reuseId)) frontier.push(reuseId);
247
+ continue;
248
+ }
249
+ }
215
250
  const resolved = await registry.resolve(depName, depRange);
216
251
  if (resolved === void 0) {
217
252
  if (kind === "peer") {
@@ -0,0 +1,34 @@
1
+ import { D as Diagnostic, N as NodeId, G as Graph } from './graph-CPo-SvS2.js';
2
+
3
+ /** Supplies the npm tarball bytes for recompute (ADR-0034 §3) — a CacheAdapter
4
+ * or a registry-backed fetch wired by the orchestrator. */
5
+ interface TarballSource {
6
+ tarball(name: string, version: string): Promise<Uint8Array | undefined>;
7
+ }
8
+ interface RefurbishOptions {
9
+ /** Stream diagnostics as they fire (ADR-0024 §3). */
10
+ onDiagnostic?: (d: Diagnostic) => void;
11
+ /** Bound the fill to these NodeIds (the modifier's recently-changed set);
12
+ * absent ⇒ scan every non-workspace node. */
13
+ seed?: ReadonlySet<NodeId>;
14
+ }
15
+ interface RefurbishResult {
16
+ graph: Graph;
17
+ /** NodeIds that gained ≥1 field. */
18
+ enriched: NodeId[];
19
+ /** All diagnostics this call emitted, in emission order. */
20
+ unresolved: Diagnostic[];
21
+ }
22
+ /**
23
+ * Fill install-required fields the graph's own format needs (v1: the yarn-berry
24
+ * `checksum`). `format` is the lock's own format (caller-supplied, from
25
+ * `detect()`); `source` supplies tarball bytes for recompute.
26
+ */
27
+ declare function refurbish(graph: Graph, format: string, source: TarballSource, opts?: RefurbishOptions): Promise<RefurbishResult>;
28
+
29
+ type EnrichDiagnosticCode = 'ENRICH_FIELD_FILLED' | 'ENRICH_CHECKSUM_DEFERRED' | 'ENRICH_NOOP';
30
+ interface EnrichDiagnostic extends Diagnostic {
31
+ code: EnrichDiagnosticCode;
32
+ }
33
+
34
+ export { type EnrichDiagnostic, type EnrichDiagnosticCode, type RefurbishOptions, type RefurbishResult, type TarballSource, refurbish };
package/dist/enrich.js ADDED
@@ -0,0 +1,245 @@
1
+ import zlib, { gunzipSync } from 'zlib';
2
+ import { createHash } from 'crypto';
3
+
4
+ // src/main/ts/recipe/integrity.ts
5
+ function emptyIntegrity() {
6
+ return { hashes: [] };
7
+ }
8
+ function emitBerryChecksum(i) {
9
+ var _a;
10
+ return (_a = i.hashes.find((h) => h.algorithm === "sha512" && h.origin === "berry-zip")) == null ? void 0 : _a.digest;
11
+ }
12
+ function mergeIntegrity(a, b) {
13
+ const seen = /* @__PURE__ */ new Set();
14
+ const hashes = [];
15
+ for (const h of [...a.hashes, ...b.hashes]) {
16
+ const key = `${h.algorithm} ${h.origin} ${h.digest}`;
17
+ if (seen.has(key)) continue;
18
+ seen.add(key);
19
+ hashes.push(h);
20
+ }
21
+ return { hashes };
22
+ }
23
+ var DOS_TIME = 44608;
24
+ var DOS_DATE = 2262;
25
+ var MADE_BY = 831;
26
+ var EMPTY = Buffer.alloc(0);
27
+ var CRC_TABLE = (() => {
28
+ const t = new Uint32Array(256);
29
+ for (let n = 0; n < 256; n++) {
30
+ let c = n;
31
+ for (let k = 0; k < 8; k++) c = (c & 1) !== 0 ? 3988292384 ^ c >>> 1 : c >>> 1;
32
+ t[n] = c >>> 0;
33
+ }
34
+ return t;
35
+ })();
36
+ function crc32Table(buf) {
37
+ let c = 4294967295;
38
+ for (let i = 0; i < buf.length; i++) c = (CRC_TABLE[(c ^ buf[i]) & 255] ^ c >>> 8) >>> 0;
39
+ return (c ^ 4294967295) >>> 0;
40
+ }
41
+ var nativeCrc32 = zlib.crc32;
42
+ var crc32 = typeof nativeCrc32 === "function" ? (buf) => nativeCrc32(buf) >>> 0 : crc32Table;
43
+ var tarField = (b, off, len) => {
44
+ const slice = b.subarray(off, off + len);
45
+ const nul = slice.indexOf(0);
46
+ return slice.toString("latin1", 0, nul === -1 ? len : nul);
47
+ };
48
+ function parseTar(tar) {
49
+ const out = [];
50
+ for (let o = 0; o + 512 <= tar.length; ) {
51
+ const header = tar.subarray(o, o + 512);
52
+ let allZero = true;
53
+ for (let i = 0; i < 512; i++) if (header[i] !== 0) {
54
+ allZero = false;
55
+ break;
56
+ }
57
+ if (allZero) break;
58
+ const prefix = tarField(header, 345, 155);
59
+ const rawName = tarField(header, 0, 100);
60
+ const name = prefix !== "" ? `${prefix}/${rawName}` : rawName;
61
+ const size = parseInt(tarField(header, 124, 12).trim() || "0", 8) || 0;
62
+ const mode = parseInt(tarField(header, 100, 8).trim() || "0", 8) || 0;
63
+ const type = String.fromCharCode(header[156] ?? 0);
64
+ o += 512;
65
+ if (type === "0" || type === "\0" || type === "") out.push({ name, mode, data: tar.subarray(o, o + size) });
66
+ o += Math.ceil(size / 512) * 512;
67
+ }
68
+ return out;
69
+ }
70
+ function buildStoreZip(entries) {
71
+ const parts = [];
72
+ const central = [];
73
+ let off = 0;
74
+ for (const e of entries) {
75
+ const nm = Buffer.from(e.name, "latin1");
76
+ const data = e.dir ? EMPTY : e.data;
77
+ const crc = e.dir ? 0 : crc32(data);
78
+ const vn = e.dir ? 20 : 10;
79
+ const ext = e.dir ? 1106051072 : (e.mode & 73) !== 0 ? 2179792896 : 2175008768;
80
+ const lh = Buffer.alloc(30);
81
+ lh.writeUInt32LE(67324752, 0);
82
+ lh.writeUInt16LE(vn, 4);
83
+ lh.writeUInt16LE(0, 6);
84
+ lh.writeUInt16LE(0, 8);
85
+ lh.writeUInt16LE(DOS_TIME, 10);
86
+ lh.writeUInt16LE(DOS_DATE, 12);
87
+ lh.writeUInt32LE(crc, 14);
88
+ lh.writeUInt32LE(data.length, 18);
89
+ lh.writeUInt32LE(data.length, 22);
90
+ lh.writeUInt16LE(nm.length, 26);
91
+ lh.writeUInt16LE(0, 28);
92
+ parts.push(lh, nm, data);
93
+ central.push({ name: nm, crc, size: data.length, vn, ext, off });
94
+ off += 30 + nm.length + data.length;
95
+ }
96
+ const cdStart = off;
97
+ for (const c of central) {
98
+ const h = Buffer.alloc(46);
99
+ h.writeUInt32LE(33639248, 0);
100
+ h.writeUInt16LE(MADE_BY, 4);
101
+ h.writeUInt16LE(c.vn, 6);
102
+ h.writeUInt16LE(0, 8);
103
+ h.writeUInt16LE(0, 10);
104
+ h.writeUInt16LE(DOS_TIME, 12);
105
+ h.writeUInt16LE(DOS_DATE, 14);
106
+ h.writeUInt32LE(c.crc, 16);
107
+ h.writeUInt32LE(c.size, 20);
108
+ h.writeUInt32LE(c.size, 24);
109
+ h.writeUInt16LE(c.name.length, 28);
110
+ h.writeUInt16LE(0, 30);
111
+ h.writeUInt16LE(0, 32);
112
+ h.writeUInt16LE(0, 34);
113
+ h.writeUInt16LE(0, 36);
114
+ h.writeUInt32LE(c.ext, 38);
115
+ h.writeUInt32LE(c.off, 42);
116
+ parts.push(h, c.name);
117
+ off += 46 + c.name.length;
118
+ }
119
+ const eocd = Buffer.alloc(22);
120
+ eocd.writeUInt32LE(101010256, 0);
121
+ eocd.writeUInt16LE(central.length, 8);
122
+ eocd.writeUInt16LE(central.length, 10);
123
+ eocd.writeUInt32LE(off - cdStart, 12);
124
+ eocd.writeUInt32LE(cdStart, 16);
125
+ parts.push(eocd);
126
+ return Buffer.concat(parts);
127
+ }
128
+ function cacheKeyCompressionLevel(cacheKey) {
129
+ const m = /c(\d)$/.exec(cacheKey);
130
+ return m ? Number(m[1]) : -1;
131
+ }
132
+ function computeBerryChecksum(tgz, ident, cacheKey) {
133
+ if (cacheKeyCompressionLevel(cacheKey) !== 0)
134
+ throw new Error(`computeBerryChecksum: only STORE (cacheKey ending 'c0') is supported; got '${cacheKey}'`);
135
+ const tar = gunzipSync(Buffer.from(tgz));
136
+ const prefix = `node_modules/${ident}/`;
137
+ const entries = [];
138
+ const seen = /* @__PURE__ */ new Set();
139
+ for (const f of parseTar(tar)) {
140
+ const rel = f.name.split("/").slice(1).join("/");
141
+ if (rel === "") continue;
142
+ const full = prefix + rel;
143
+ const segs = full.split("/");
144
+ segs.pop();
145
+ let cur = "";
146
+ for (const s of segs) {
147
+ cur += `${s}/`;
148
+ if (!seen.has(cur)) {
149
+ seen.add(cur);
150
+ entries.push({ name: cur, dir: true, mode: 493, data: EMPTY });
151
+ }
152
+ }
153
+ entries.push({ name: full, dir: false, mode: f.mode, data: f.data });
154
+ }
155
+ return createHash("sha512").update(buildStoreZip(entries)).digest("hex");
156
+ }
157
+
158
+ // src/main/ts/enrich/diagnostics.ts
159
+ function enrichFieldFilled(nodeId, field, rung) {
160
+ return {
161
+ code: "ENRICH_FIELD_FILLED",
162
+ severity: "info",
163
+ subject: nodeId,
164
+ message: `enrich: filled ${field} on ${nodeId} (rung: ${rung})`
165
+ };
166
+ }
167
+ function enrichChecksumDeferred(nodeId) {
168
+ return {
169
+ code: "ENRICH_CHECKSUM_DEFERRED",
170
+ severity: "warning",
171
+ subject: nodeId,
172
+ message: `enrich: berry checksum for ${nodeId} not recomputable (DEFLATE cacheKey or tarball bytes unavailable) \u2014 line omitted; plain \`yarn install\` recovers it, \`yarn install --immutable\` will reject this node`
173
+ };
174
+ }
175
+ function enrichNoop() {
176
+ return {
177
+ code: "ENRICH_NOOP",
178
+ severity: "info",
179
+ // 'graph' literal per ADR-0023 §7.3 — per-call event; NodeId is `string`.
180
+ subject: "graph",
181
+ message: "enrich: nothing to fill"
182
+ };
183
+ }
184
+
185
+ // src/main/ts/enrich/refurbish.ts
186
+ var isBerryFormat = (format) => format.startsWith("yarn-berry");
187
+ function berryCacheKeyFor(graph) {
188
+ var _a;
189
+ for (const node of graph.nodes()) {
190
+ const ck = (_a = graph.tarballOf(node.id)) == null ? void 0 : _a.berryChecksumCacheKey;
191
+ if (ck !== void 0) return ck;
192
+ }
193
+ return "10c0";
194
+ }
195
+ async function refurbish(graph, format, source, opts = {}) {
196
+ const unresolved = [];
197
+ const enriched = [];
198
+ let next = graph;
199
+ const record = (d) => {
200
+ next = next.mutate((m) => {
201
+ m.diagnostic(d);
202
+ }).graph;
203
+ unresolved.push(d);
204
+ if (opts.onDiagnostic !== void 0) opts.onDiagnostic(d);
205
+ };
206
+ if (!isBerryFormat(format)) {
207
+ record(enrichNoop());
208
+ return { graph: next, enriched, unresolved };
209
+ }
210
+ const cacheKey = berryCacheKeyFor(graph);
211
+ const isStore = cacheKeyCompressionLevel(cacheKey) === 0;
212
+ for (const node of graph.nodes()) {
213
+ if (opts.seed !== void 0 && !opts.seed.has(node.id)) continue;
214
+ if (node.workspacePath !== void 0) continue;
215
+ const payload = graph.tarballOf(node.id) ?? {};
216
+ if (emitBerryChecksum(payload.integrity ?? emptyIntegrity()) !== void 0) continue;
217
+ if (!isStore) {
218
+ record(enrichChecksumDeferred(node.id));
219
+ continue;
220
+ }
221
+ const tgz = await source.tarball(node.name, node.version);
222
+ if (tgz === void 0) {
223
+ record(enrichChecksumDeferred(node.id));
224
+ continue;
225
+ }
226
+ const hex = computeBerryChecksum(tgz, node.name, cacheKey);
227
+ const integrity = mergeIntegrity(
228
+ payload.integrity ?? emptyIntegrity(),
229
+ { hashes: [{ algorithm: "sha512", digest: hex, origin: "berry-zip" }] }
230
+ );
231
+ const merged = { ...payload, integrity, berryChecksumCacheKey: cacheKey };
232
+ const diag = enrichFieldFilled(node.id, "berryChecksum", "recompute");
233
+ next = next.mutate((m) => {
234
+ m.setTarball({ name: node.name, version: node.version, patch: node.patch }, merged);
235
+ m.diagnostic(diag);
236
+ }).graph;
237
+ enriched.push(node.id);
238
+ unresolved.push(diag);
239
+ if (opts.onDiagnostic !== void 0) opts.onDiagnostic(diag);
240
+ }
241
+ if (unresolved.length === 0) record(enrichNoop());
242
+ return { graph: next, enriched, unresolved };
243
+ }
244
+
245
+ export { refurbish };
@@ -2490,7 +2490,7 @@ function withUnresolvedDepRefs(liveBlock, refs) {
2490
2490
  function emittedRangeOfEdge(kind, range, config, aliased = false) {
2491
2491
  if (kind === "peer") return range;
2492
2492
  if (aliased) return range;
2493
- return range;
2493
+ return entryKeyRangeOf(range);
2494
2494
  }
2495
2495
  var DEFAULT_CACHEKEY_V8_V9 = "10c0";
2496
2496
  function checksumOfPayload(payload, config, cacheKey, nodeId, emitDiagnostic) {
@@ -2490,7 +2490,7 @@ function withUnresolvedDepRefs(liveBlock, refs) {
2490
2490
  function emittedRangeOfEdge(kind, range, config, aliased = false) {
2491
2491
  if (kind === "peer") return range;
2492
2492
  if (aliased) return range;
2493
- return range;
2493
+ return entryKeyRangeOf(range);
2494
2494
  }
2495
2495
  function checksumOfPayload(payload, config, cacheKey, nodeId, emitDiagnostic) {
2496
2496
  const integrity = payload == null ? void 0 : payload.integrity;
@@ -2490,7 +2490,7 @@ function withUnresolvedDepRefs(liveBlock, refs) {
2490
2490
  function emittedRangeOfEdge(kind, range, config, aliased = false) {
2491
2491
  if (kind === "peer") return range;
2492
2492
  if (aliased) return range;
2493
- return range;
2493
+ return entryKeyRangeOf(range);
2494
2494
  }
2495
2495
  var DEFAULT_CACHEKEY_V8_V9 = "10c0";
2496
2496
  function checksumOfPayload(payload, config, cacheKey, nodeId, emitDiagnostic) {
@@ -2490,7 +2490,7 @@ function withUnresolvedDepRefs(liveBlock, refs) {
2490
2490
  function emittedRangeOfEdge(kind, range, config, aliased = false) {
2491
2491
  if (kind === "peer") return range;
2492
2492
  if (aliased) return range;
2493
- return range;
2493
+ return entryKeyRangeOf(range);
2494
2494
  }
2495
2495
  var DEFAULT_CACHEKEY_V8_V9 = "10c0";
2496
2496
  function checksumOfPayload(payload, config, cacheKey, nodeId, emitDiagnostic) {
package/dist/index.js CHANGED
@@ -7111,7 +7111,7 @@ function withUnresolvedDepRefs(liveBlock, refs) {
7111
7111
  function emittedRangeOfEdge(kind, range, config, aliased = false) {
7112
7112
  if (kind === "peer") return range;
7113
7113
  if (aliased) return range;
7114
- if (config.rangeEmit !== "bare") return range;
7114
+ if (config.rangeEmit !== "bare") return entryKeyRangeOf(range);
7115
7115
  return range.startsWith("npm:") ? range.slice("npm:".length) : range;
7116
7116
  }
7117
7117
  var DEFAULT_CACHEKEY_V8_V9 = "10c0";
@@ -10564,6 +10564,12 @@ async function replaceVersion(graph, selector, toRange, context, options = {}) {
10564
10564
  currentGraph = currentGraph.mutate((m) => {
10565
10565
  m.setTarball({ name: target.name, version: target.version, patch: node.patch }, payload);
10566
10566
  }).graph;
10567
+ const staleOut = [...currentGraph.out(targetId)].filter((e) => e.kind === "dep" || e.kind === "optional");
10568
+ if (staleOut.length > 0) {
10569
+ currentGraph = currentGraph.mutate((m) => {
10570
+ for (const e of staleOut) m.removeEdge(targetId, e.dst, e.kind);
10571
+ }).graph;
10572
+ }
10567
10573
  replaced.push({ from: node.id, to: targetId });
10568
10574
  recentlyAdded.add(targetId);
10569
10575
  added.push(targetId);
package/dist/modify.js CHANGED
@@ -623,6 +623,12 @@ async function replaceVersion(graph, selector, toRange, context, options = {}) {
623
623
  currentGraph = currentGraph.mutate((m) => {
624
624
  m.setTarball({ name: target.name, version: target.version, patch: node.patch }, payload);
625
625
  }).graph;
626
+ const staleOut = [...currentGraph.out(targetId)].filter((e) => e.kind === "dep" || e.kind === "optional");
627
+ if (staleOut.length > 0) {
628
+ currentGraph = currentGraph.mutate((m) => {
629
+ for (const e of staleOut) m.removeEdge(targetId, e.dst, e.kind);
630
+ }).graph;
631
+ }
626
632
  replaced.push({ from: node.id, to: targetId });
627
633
  recentlyAdded.add(targetId);
628
634
  added.push(targetId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antongolub/lockfile",
3
- "version": "0.0.0-snapshot.67",
3
+ "version": "0.0.0-snapshot.69",
4
4
  "private": false,
5
5
  "description": "Universal lockfile model and converter for npm, yarn, pnpm, bun",
6
6
  "type": "module",
@@ -27,6 +27,10 @@
27
27
  "types": "./dist/registry.d.ts",
28
28
  "default": "./dist/registry.js"
29
29
  },
30
+ "./enrich": {
31
+ "types": "./dist/enrich.d.ts",
32
+ "default": "./dist/enrich.js"
33
+ },
30
34
  "./formats/bun-text": {
31
35
  "types": "./dist/formats/bun-text.d.ts",
32
36
  "default": "./dist/formats/bun-text.js"
@@ -92,6 +96,16 @@
92
96
  "default": "./dist/formats/lockgraph.js"
93
97
  }
94
98
  },
99
+ "typesVersions": {
100
+ "*": {
101
+ "modify": ["./dist/modify.d.ts"],
102
+ "complete": ["./dist/complete.d.ts"],
103
+ "optimize": ["./dist/optimize.d.ts"],
104
+ "registry": ["./dist/registry.d.ts"],
105
+ "enrich": ["./dist/enrich.d.ts"],
106
+ "formats/*": ["./dist/formats/*.d.ts"]
107
+ }
108
+ },
95
109
  "files": [
96
110
  "dist",
97
111
  "README.md",