@antongolub/lockfile 0.0.0-snapshot.67 → 0.0.0-snapshot.68
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/enrich.d.ts +34 -0
- package/dist/enrich.js +245 -0
- package/package.json +15 -1
package/dist/enrich.d.ts
ADDED
|
@@ -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 };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antongolub/lockfile",
|
|
3
|
-
"version": "0.0.0-snapshot.
|
|
3
|
+
"version": "0.0.0-snapshot.68",
|
|
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",
|