vlt 1.6.1 → 1.6.2

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 (88) hide show
  1. package/{access-YSLEWR2C.js → access-LNHKSCBO.js} +5 -5
  2. package/{bugs-S6CRUEA2.js → bugs-PSOZGCKG.js} +15 -14
  3. package/{build-SG3KPX3W.js → build-GBIF54BN.js} +11 -11
  4. package/{cache-HA77ROM7.js → cache-XOYAGCIO.js} +10 -8
  5. package/cache-unzip-src-unzip.js +190 -3
  6. package/chunk-24DWRCPS.js +79 -0
  7. package/chunk-2CFNQ4QB.js +77 -0
  8. package/{chunk-AEVT3CHK.js → chunk-3RYVF2GG.js} +2 -2
  9. package/{chunk-IHERL3TA.js → chunk-3UDBYFAH.js} +95 -8
  10. package/{chunk-ZJE3OTP3.js → chunk-6BD4RCTR.js} +40 -13
  11. package/{chunk-Y5PA7DVK.js → chunk-6ETYWCJN.js} +197 -1
  12. package/{chunk-KURQHX54.js → chunk-6ISFYONV.js} +2 -2
  13. package/{chunk-VGPLFOJO.js → chunk-AQJR7QDA.js} +1 -1
  14. package/{chunk-JZXNHIQE.js → chunk-BGOXKLQ6.js} +1 -1
  15. package/{chunk-MSWOR3FV.js → chunk-C75GDQFE.js} +9 -2
  16. package/{chunk-WMMKUVAT.js → chunk-FRX5IFFY.js} +4 -4
  17. package/{chunk-EMTGRCSE.js → chunk-GJMDZJPJ.js} +1 -1
  18. package/{chunk-M242QVJS.js → chunk-HHSPE2DS.js} +1 -1
  19. package/{chunk-AHLBPSGQ.js → chunk-JASG7RHB.js} +2 -2
  20. package/{chunk-W24SBFY5.js → chunk-JNPVOACH.js} +4 -4
  21. package/{chunk-OWL5G4K4.js → chunk-JYYIWXJX.js} +1 -1
  22. package/{chunk-5Q2HSLVV.js → chunk-L65CG5LE.js} +1 -1
  23. package/{chunk-PDWPFR5T.js → chunk-LEMHGORE.js} +1 -1
  24. package/{chunk-JV5XR5JQ.js → chunk-MCQTGFJY.js} +1 -1
  25. package/{chunk-O6MQ7NN6.js → chunk-N4SU52H5.js} +1 -1
  26. package/{chunk-Q2UEILN6.js → chunk-NB7QVWHU.js} +84 -16
  27. package/{chunk-N6HV7JWC.js → chunk-QFPAFVRR.js} +39 -67
  28. package/{chunk-DXED4ARV.js → chunk-QGLGNPCQ.js} +2 -2
  29. package/{chunk-3E3ISOYM.js → chunk-QGUQZURY.js} +2 -2
  30. package/{chunk-L3ZF7OYM.js → chunk-TGPL6YRK.js} +2 -2
  31. package/{chunk-C4RJ4NNS.js → chunk-TQBSL35R.js} +5 -5
  32. package/{chunk-6XVW7CWJ.js → chunk-XWA55GAN.js} +3 -3
  33. package/{chunk-BQMHDAYL.js → chunk-XWVEIWTT.js} +1 -1
  34. package/{chunk-4UAIPIAV.js → chunk-Y53EROVE.js} +5 -5
  35. package/{chunk-NO53Y3QO.js → chunk-Z63CXYQF.js} +1 -1
  36. package/{chunk-B6RIGNEO.js → chunk-ZESNN24A.js} +11 -1
  37. package/{ci-GVLL72SS.js → ci-XSH7DZGD.js} +13 -13
  38. package/cli-package.json +1 -1
  39. package/{config-KH6AEMHI.js → config-6XFBWC3U.js} +7 -6
  40. package/{config-TIPKOPYS.js → config-C73FLGQV.js} +7 -6
  41. package/{create-SKNEZEZY.js → create-UNCQKKBS.js} +16 -15
  42. package/{deprecate-RFRLJZVL.js → deprecate-HCVFAVZD.js} +9 -8
  43. package/{dist-tag-LVYOTJHJ.js → dist-tag-WXLJRWFJ.js} +5 -5
  44. package/{docs-INXRFEGY.js → docs-5EFY7ZHN.js} +15 -14
  45. package/{exec-5MA5XRPZ.js → exec-EC5D5GE3.js} +16 -15
  46. package/{exec-cache-7GS4KLWJ.js → exec-cache-EMUFVFCJ.js} +14 -13
  47. package/{exec-local-RE4KVTMN.js → exec-local-L5H4M37T.js} +13 -13
  48. package/{help-JHLP565L.js → help-FUHVZ6UH.js} +1 -1
  49. package/{init-4UFHO67B.js → init-63M6W7N4.js} +11 -11
  50. package/{install-Z33YVCDK.js → install-IHQRULIE.js} +20 -19
  51. package/{list-XAMKR6TL.js → list-EDXNWJJR.js} +16 -16
  52. package/{login-6NXUO5FF.js → login-OD7E5AO5.js} +10 -9
  53. package/{logout-6P7LWTAY.js → logout-V2WJTQV2.js} +5 -5
  54. package/{outdated-YNUSWZJD.js → outdated-7N7NGSSR.js} +15 -14
  55. package/{pack-LMQYH75V.js → pack-TKJW7AEB.js} +12 -12
  56. package/package.json +1 -1
  57. package/{ping-VLFZ3WCY.js → ping-PVWRNSCX.js} +5 -5
  58. package/{pkg-JMPBHKSW.js → pkg-PDP4XR5S.js} +12 -12
  59. package/{profile-PJJAA2YM.js → profile-BP5EALWS.js} +5 -5
  60. package/{publish-33RFJ2HJ.js → publish-HCICK5LY.js} +14 -14
  61. package/{query-LUUOK57K.js → query-TZ3BPC4B.js} +16 -16
  62. package/registry-client-src-revalidate.js +304 -44
  63. package/{repo-VLHLQP2S.js → repo-BYOSXG5J.js} +15 -14
  64. package/{reporter-SNSM2TDC.js → reporter-S6DDAHQL.js} +12 -11
  65. package/{run-USWK7R3N.js → run-JAVVTY7B.js} +13 -13
  66. package/{run-exec-PHE44AWW.js → run-exec-GGENQDEW.js} +13 -13
  67. package/security-archive-src-update-expired.js +1 -1
  68. package/{setup-JMY47ERY.js → setup-I6GLYILV.js} +13 -12
  69. package/{skills-YMMV6TMN.js → skills-5V6HKMA7.js} +14 -13
  70. package/{skills-7PYMTDER.js → skills-QOFA6XMM.js} +6 -6
  71. package/{src-2ZS4VHJP.js → src-74IKO7PC.js} +12 -8
  72. package/src-GY57R4DK.js +659 -0
  73. package/{src-A5ZJNOHN.js → src-REZNPR2X.js} +5 -5
  74. package/tar-src-placement-worker.js +6426 -0
  75. package/{token-YKHELNVQ.js → token-JEAMCRK6.js} +5 -5
  76. package/{uninstall-Q46HWR5S.js → uninstall-WA4FJFVA.js} +14 -14
  77. package/{unpublish-LBANPSJ5.js → unpublish-SG3J524L.js} +5 -5
  78. package/{update-B2EGLZHI.js → update-Y3KY2DZD.js} +15 -14
  79. package/{version-IEOBL3NN.js → version-QBEPMA7Q.js} +11 -11
  80. package/{view-JCA5VT6F.js → view-FYRF3SLJ.js} +8 -7
  81. package/vlr.js +1 -1
  82. package/vlrx.js +1 -1
  83. package/vlt.js +1 -1
  84. package/vlx.js +1 -1
  85. package/vlxl.js +1 -1
  86. package/{whoami-OWJUPO3X.js → whoami-XSQ6SOIC.js} +5 -5
  87. package/chunk-N3V6EK5I.js +0 -77
  88. package/src-W2VQULRG.js +0 -285
@@ -0,0 +1,659 @@
1
+ var global = globalThis;
2
+ import {Buffer} from "node:buffer";
3
+ import {setTimeout as _vlt_setTimeout,clearTimeout as _vlt_clearTimeout,setImmediate as _vlt_setImmediate,clearImmediate as _vlt_clearImmediate,setInterval as _vlt_setInterval,clearInterval as _vlt_clearInterval} from "node:timers";
4
+ globalThis.setTimeout = _vlt_setTimeout;
5
+ globalThis.clearTimeout = _vlt_clearTimeout;
6
+ globalThis.setImmediate = _vlt_setImmediate;
7
+ globalThis.clearImmediate = _vlt_clearImmediate;
8
+ globalThis.setInterval = _vlt_setInterval;
9
+ globalThis.clearInterval = _vlt_clearInterval;
10
+ import {createRequire as _vlt_createRequire} from "node:module";
11
+ var require = _vlt_createRequire(import.meta.filename);
12
+ import {
13
+ cacheEntryBody,
14
+ markStoreEntryCopied,
15
+ removeStoreEntry,
16
+ storeCopiedPath,
17
+ storeEntryCopied,
18
+ storeEntryLastCopied,
19
+ storeEntryLinked,
20
+ storeEntryNames,
21
+ storeEntryTime,
22
+ tmpName,
23
+ unpack,
24
+ unpackCacheEntryParallel,
25
+ unpackCacheEntrySync,
26
+ unpackFileParallel,
27
+ unpackFileSync,
28
+ unpackParallel,
29
+ unpackSync,
30
+ unpackToStoreSync,
31
+ verifyStoreEntry
32
+ } from "./chunk-QFPAFVRR.js";
33
+ import {
34
+ cloneAvailable,
35
+ cloneDir
36
+ } from "./chunk-6IF3RJND.js";
37
+ import {
38
+ readStoreIndex,
39
+ storeIndexPath
40
+ } from "./chunk-24DWRCPS.js";
41
+ import {
42
+ rimrafSync
43
+ } from "./chunk-LEMHGORE.js";
44
+ import {
45
+ lane,
46
+ trace
47
+ } from "./chunk-6ETYWCJN.js";
48
+ import "./chunk-BF5DRGRZ.js";
49
+ import "./chunk-WZWDS3W4.js";
50
+ import "./chunk-PZLD7RTK.js";
51
+
52
+ // ../../src/tar/src/link-tree.ts
53
+ import {
54
+ chmodSync,
55
+ linkSync,
56
+ lstatSync,
57
+ mkdirSync,
58
+ readdirSync,
59
+ readFileSync,
60
+ renameSync,
61
+ statSync,
62
+ writeFileSync
63
+ } from "node:fs";
64
+ import { dirname, sep } from "node:path";
65
+ import { debuglog } from "node:util";
66
+ var debug = debuglog("vlt");
67
+ var noThrow = { throwIfNoEntry: false };
68
+ var verify = process.env.VLT_STORE_VERIFY === "1";
69
+ var copyAll = false;
70
+ var downgrade = (code) => {
71
+ copyAll = true;
72
+ debug("global store: linking failed, copying from now on", code);
73
+ };
74
+ var cloneNone = false;
75
+ var native = (p) => sep === "/" ? p : p.replaceAll("/", sep);
76
+ var cloneEntry = (storeEntry, tmp) => {
77
+ const res = cloneDir(storeEntry, tmp);
78
+ if (res === true) return true;
79
+ if (res === "ENOTSUP" || res === "EXDEV" || res === "EPERM" || res === "EACCES") {
80
+ cloneNone = true;
81
+ debug("global store: cloning failed, unpacking from now on", res);
82
+ }
83
+ return false;
84
+ };
85
+ var checkClone = (tmp, index) => {
86
+ const counts = /* @__PURE__ */ new Map([["", 0]]);
87
+ for (const d of index.dirs) counts.set(d, 0);
88
+ for (const p of [...index.dirs, ...index.files.map((f) => f[0])]) {
89
+ const i = p.lastIndexOf("/");
90
+ const d = i === -1 ? "" : p.slice(0, i);
91
+ const n = counts.get(d);
92
+ if (n === void 0) return "damaged";
93
+ counts.set(d, n + 1);
94
+ }
95
+ for (const [d, n] of counts) {
96
+ let names;
97
+ try {
98
+ names = readdirSync(d ? tmp + sep + native(d) : tmp);
99
+ } catch {
100
+ return "damaged";
101
+ }
102
+ if (names.length !== n) return "damaged";
103
+ }
104
+ const pj = index.files.find((f) => f[0] === "package.json");
105
+ if (verify && pj && statSync(tmp + sep + "package.json").size !== pj[1]) {
106
+ return "damaged";
107
+ }
108
+ };
109
+ var place = (src, dst, exec, copy) => {
110
+ if (!copy && !copyAll) {
111
+ try {
112
+ linkSync(src, dst);
113
+ return "link";
114
+ } catch (er) {
115
+ const { code = "" } = er;
116
+ if (code === "ENOENT") {
117
+ if (!lstatSync(src, noThrow)) return false;
118
+ if (!lstatSync(dirname(dst), noThrow)) throw er;
119
+ downgrade(code);
120
+ } else if (code === "EXDEV" || code === "EPERM" || code === "EACCES" || code === "ENOTSUP") {
121
+ downgrade(code);
122
+ } else if (code !== "EMLINK") {
123
+ throw er;
124
+ }
125
+ }
126
+ }
127
+ let body;
128
+ try {
129
+ body = readFileSync(src);
130
+ } catch (er) {
131
+ if (er.code === "ENOENT") return false;
132
+ throw er;
133
+ }
134
+ writeFileSync(dst, body, { mode: exec ? 511 : 438, flag: "wx" });
135
+ if (exec) chmodSync(dst, statSync(src).mode & 511);
136
+ return "copy";
137
+ };
138
+ var fill = (storeEntry, tmp, index, copy) => {
139
+ const put = ([p, , exec]) => place(
140
+ storeEntry + sep + native(p),
141
+ tmp + sep + native(p),
142
+ exec,
143
+ copy
144
+ );
145
+ try {
146
+ for (const d of index.dirs) mkdirSync(tmp + sep + native(d));
147
+ let pj;
148
+ let linked = false;
149
+ for (const f of index.files) {
150
+ if (f[0] === "package.json") {
151
+ pj = f;
152
+ continue;
153
+ }
154
+ const how2 = put(f);
155
+ if (!how2) return "damaged";
156
+ if (how2 === "link") linked = true;
157
+ }
158
+ if (!pj) return;
159
+ const how = put(pj);
160
+ if (!how) return "damaged";
161
+ if (how === "copy" && linked) return "mixed";
162
+ if (verify && statSync(tmp + sep + pj[0]).size !== pj[1]) {
163
+ return "damaged";
164
+ }
165
+ } catch (er) {
166
+ if (er.code === "EEXIST")
167
+ return "clash";
168
+ throw er;
169
+ }
170
+ };
171
+ var linkFromStore = (storeEntry, target, { copy = false, clone = false } = {}) => {
172
+ if (clone && cloneNone) return false;
173
+ const index = readStoreIndex(storeEntry);
174
+ if (!index || !lstatSync(storeEntry, noThrow)?.isDirectory()) {
175
+ return false;
176
+ }
177
+ const parent = lstatSync(dirname(target), noThrow);
178
+ if (parent?.isSymbolicLink()) return false;
179
+ if (!parent) mkdirSync(dirname(target), { recursive: true });
180
+ const tmp = tmpName(target);
181
+ const og = tmp + ".ORIGINAL";
182
+ let succeeded = false;
183
+ try {
184
+ if (clone && !cloneEntry(storeEntry, tmp)) return false;
185
+ let copied = !clone && copy;
186
+ if (!clone) mkdirSync(tmp);
187
+ let miss = clone ? checkClone(tmp, index) : fill(storeEntry, tmp, index, copied);
188
+ if (miss === "mixed") {
189
+ rimrafSync(tmp);
190
+ mkdirSync(tmp);
191
+ copied = true;
192
+ miss = fill(storeEntry, tmp, index, copied);
193
+ }
194
+ if (miss === "clash") {
195
+ debug("global store: name clash in target", storeEntry);
196
+ return false;
197
+ }
198
+ if (miss) {
199
+ debug("global store: removing damaged entry", storeEntry);
200
+ try {
201
+ removeStoreEntry(storeEntry);
202
+ } catch {
203
+ }
204
+ return false;
205
+ }
206
+ const targetExists = !!lstatSync(target, noThrow);
207
+ if (targetExists) renameSync(target, og);
208
+ renameSync(tmp, target);
209
+ if (targetExists) rimrafSync(og);
210
+ if (clone || copied || copyAll || index.scripts) {
211
+ markStoreEntryCopied(storeEntry);
212
+ }
213
+ succeeded = true;
214
+ return {
215
+ how: clone ? "clone" : copied || copyAll ? "copy" : "link",
216
+ index
217
+ };
218
+ } finally {
219
+ if (!succeeded) {
220
+ if (lstatSync(og, noThrow)) {
221
+ rimrafSync(target);
222
+ renameSync(og, target);
223
+ }
224
+ rimrafSync(tmp);
225
+ }
226
+ }
227
+ };
228
+
229
+ // ../../src/tar/src/placement-pool.ts
230
+ import { availableParallelism } from "node:os";
231
+ import { Worker } from "node:worker_threads";
232
+
233
+ // ../../src/tar/src/placement-worker.ts
234
+ import { resolve } from "node:path";
235
+ var __CODE_SPLIT_SCRIPT_NAME = resolve(import.meta.dirname, "tar-src-placement-worker.js");
236
+
237
+ // ../../src/tar/src/placement-pool.ts
238
+ var placementThreads = () => {
239
+ const env = process.env.VLT_PLACEMENT_THREADS;
240
+ if (env !== void 0 && env !== "") {
241
+ const n = Number(env);
242
+ return Number.isInteger(n) && n >= 1 ? n : 1;
243
+ }
244
+ return Math.min(Math.max(availableParallelism() - 1, 1), 8);
245
+ };
246
+ var DEFAULT_PLACEMENT_MIN_JOBS = 100;
247
+ var DEFAULT_HELD_BYTES = 64 * 1024 * 1024;
248
+ var PlacementPool = class {
249
+ #size;
250
+ #minJobs;
251
+ #heldMax;
252
+ #workers = [];
253
+ #ready = /* @__PURE__ */ new Set();
254
+ #idle = [];
255
+ #queue = [];
256
+ #pending = /* @__PURE__ */ new Map();
257
+ #seq = 0;
258
+ #seen = 0;
259
+ #started = false;
260
+ #threaded = false;
261
+ #closed = false;
262
+ #booting = [];
263
+ #held = 0;
264
+ #room = [];
265
+ #busy = 0;
266
+ #queued = 0;
267
+ constructor(size = placementThreads(), minJobs = DEFAULT_PLACEMENT_MIN_JOBS, heldMax = DEFAULT_HELD_BYTES) {
268
+ this.#size = size;
269
+ this.#minJobs = minJobs;
270
+ this.#heldMax = heldMax;
271
+ }
272
+ /** True when placement runs inline, with no worker threads. */
273
+ get inline() {
274
+ return this.#size < 2;
275
+ }
276
+ /** True once the workers were started and placement goes to them. */
277
+ get threaded() {
278
+ return this.#threaded;
279
+ }
280
+ // Whether a placement arriving now runs on the main thread: no
281
+ // workers at all, closed, or not (or no longer) threaded. A method,
282
+ // not a getter, so a re-check after an await is not narrowed away.
283
+ #inlineNow() {
284
+ return this.inline || this.#closed || !this.#threaded;
285
+ }
286
+ /** Number of worker threads spawned so far (for tests). */
287
+ get workerCount() {
288
+ return this.#workers.length;
289
+ }
290
+ /** Number of workers that have booted and can take jobs (for tests). */
291
+ get readyCount() {
292
+ return this.#ready.size;
293
+ }
294
+ /** Compressed bytes downloaded and waiting for, or in, an unpack. */
295
+ get heldBytes() {
296
+ return this.#held;
297
+ }
298
+ /**
299
+ * Start the workers for an install that will place `jobs` packages,
300
+ * so they boot now rather than when the first placement arrives.
301
+ * Starts nothing, leaving placement inline, when the pool is inline
302
+ * or closed, when it was already warmed, or when `jobs` is below the
303
+ * minimum. Resolves once every worker it started is ready or gone; it
304
+ * never rejects, so a caller may fire and forget it.
305
+ */
306
+ async warm(jobs) {
307
+ if (this.inline || this.#closed || this.#threaded || jobs < this.#minJobs) {
308
+ return;
309
+ }
310
+ this.#threaded = true;
311
+ this.#started = true;
312
+ try {
313
+ while (this.#workers.length < this.#size) this.#spawn();
314
+ } catch {
315
+ if (!this.#workers.length) {
316
+ this.#threaded = false;
317
+ return;
318
+ }
319
+ }
320
+ await new Promise((resolve2) => {
321
+ this.#booting.push(resolve2);
322
+ this.#checkBooted();
323
+ });
324
+ }
325
+ // A pool nobody warmed starts itself once enough placements have
326
+ // come through to pay for the boot. The placements before that ran
327
+ // inline; the ones from here on queue for the workers. Workers that
328
+ // were started once and all died are not started again: the pool
329
+ // stays inline, as it would after a `warm`.
330
+ #maybeAutoWarm() {
331
+ if (this.#started || this.#closed || this.inline) return;
332
+ if (++this.#seen < this.#minJobs) return;
333
+ void this.warm(this.#seen);
334
+ }
335
+ // Every live worker is ready, or none is left: settle any warm() that
336
+ // is waiting on the boot.
337
+ #checkBooted() {
338
+ if (this.#ready.size < this.#workers.length) return;
339
+ const waiters = this.#booting;
340
+ this.#booting = [];
341
+ for (const resolve2 of waiters) resolve2();
342
+ }
343
+ /**
344
+ * Unpack `tarData` into `target`: on a worker once the pool is
345
+ * threaded, inline otherwise (inflating on libuv's threadpool and
346
+ * writing on the main thread, as before this pool existed). Resolves
347
+ * when the files are in place.
348
+ *
349
+ * The bytes are copied before they go to a worker: the caller may
350
+ * still hold them (the registry client caches its response bodies),
351
+ * and a transfer would detach them for everyone. For a tarball that
352
+ * is already on disk, {@link unpackCacheEntry} avoids the copy.
353
+ */
354
+ async unpack(tarData, target, format) {
355
+ this.#maybeAutoWarm();
356
+ if (this.#inlineNow())
357
+ return unpackParallel(tarData, target, format);
358
+ const bytes = tarData.byteLength;
359
+ await this.#reserve(bytes);
360
+ if (this.#inlineNow()) {
361
+ this.#release(bytes);
362
+ return unpackParallel(tarData, target, format);
363
+ }
364
+ const copy = new Uint8Array(bytes);
365
+ copy.set(tarData);
366
+ await this.#submit(
367
+ {
368
+ kind: "unpack",
369
+ id: this.#seq++,
370
+ buffer: copy.buffer,
371
+ byteOffset: 0,
372
+ byteLength: bytes,
373
+ target,
374
+ format
375
+ },
376
+ bytes
377
+ );
378
+ }
379
+ /**
380
+ * Unpack the tarball in the vlt cache entry `file` into `target`. A
381
+ * worker reads the file itself, so the main thread neither reads nor
382
+ * copies the body, and nothing is held against the byte cap. Inline
383
+ * when the pool is not threaded, like {@link unpack}.
384
+ */
385
+ async unpackCacheEntry(file, target, format) {
386
+ this.#maybeAutoWarm();
387
+ if (this.#inlineNow()) {
388
+ return unpackCacheEntryParallel(file, target, format);
389
+ }
390
+ await this.#submit(
391
+ { kind: "cacheEntry", id: this.#seq++, file, target, format },
392
+ 0
393
+ );
394
+ }
395
+ // Wait until `bytes` more may be held. Nothing waits while nothing is
396
+ // held, so one oversized tarball never deadlocks.
397
+ async #reserve(bytes) {
398
+ while (this.#held > 0 && this.#held + bytes > this.#heldMax) {
399
+ await new Promise((resolve2) => this.#room.push(resolve2));
400
+ }
401
+ this.#held += bytes;
402
+ }
403
+ #release(bytes) {
404
+ this.#held -= bytes;
405
+ const waiters = this.#room;
406
+ this.#room = [];
407
+ for (const resolve2 of waiters) resolve2();
408
+ }
409
+ // Queue the job, or hand it to a free worker. A ready worker is free:
410
+ // use it. Otherwise queue; a worker takes the next queued job as it
411
+ // finishes, or as it finishes booting. Placing inline while the
412
+ // workers boot was measured and rejected: on a machine with few cores
413
+ // the main thread's placement contends with the boots, and the install
414
+ // comes out slower than either.
415
+ #submit(job, bytes) {
416
+ return new Promise((resolve2, reject) => {
417
+ this.#pending.set(job.id, { bytes, resolve: resolve2, reject });
418
+ const worker = this.#idle.pop();
419
+ if (worker) this.#assign(worker, job);
420
+ else {
421
+ this.#queue.push(job);
422
+ this.#queued++;
423
+ this.#trace();
424
+ }
425
+ });
426
+ }
427
+ #trace() {
428
+ lane("unpack", this.#busy, this.#queued);
429
+ }
430
+ #spawn() {
431
+ trace("pool:spawn", { workers: this.#workers.length + 1 });
432
+ const worker = new Worker(__CODE_SPLIT_SCRIPT_NAME);
433
+ worker.on(
434
+ "message",
435
+ (reply) => this.#onMessage(worker, reply)
436
+ );
437
+ worker.on("error", (er) => this.#onLost(worker, er));
438
+ worker.on(
439
+ "exit",
440
+ () => this.#onLost(worker, new Error("placement worker exited"))
441
+ );
442
+ this.#workers.push(worker);
443
+ }
444
+ #assign(worker, job) {
445
+ const pending = this.#pending.get(job.id);
446
+ if (pending) pending.worker = worker;
447
+ this.#busy++;
448
+ this.#trace();
449
+ worker.ref();
450
+ worker.postMessage(job, job.kind === "unpack" ? [job.buffer] : []);
451
+ }
452
+ // Hand the worker the next queued job, or park it idle.
453
+ #park(worker) {
454
+ const next = this.#queue.shift();
455
+ if (next) {
456
+ this.#queued--;
457
+ this.#assign(worker, next);
458
+ } else {
459
+ worker.unref();
460
+ this.#idle.push(worker);
461
+ }
462
+ }
463
+ #settle(id, pending) {
464
+ if (pending.worker) {
465
+ this.#busy--;
466
+ this.#trace();
467
+ }
468
+ this.#release(pending.bytes);
469
+ this.#pending.delete(id);
470
+ }
471
+ #onMessage(worker, reply) {
472
+ if ("ready" in reply) {
473
+ this.#ready.add(worker);
474
+ trace("pool:ready", { ready: this.#ready.size });
475
+ this.#park(worker);
476
+ this.#checkBooted();
477
+ return;
478
+ }
479
+ const pending = this.#pending.get(reply.id);
480
+ if (pending) this.#settle(reply.id, pending);
481
+ this.#park(worker);
482
+ if (!pending) return;
483
+ if ("result" in reply) pending.resolve();
484
+ else {
485
+ const er = new Error(reply.error);
486
+ er.stack = reply.stack ?? er.stack;
487
+ if (reply.code !== void 0) er.code = reply.code;
488
+ pending.reject(er);
489
+ }
490
+ }
491
+ // A worker died outright, not a job that threw (that comes back as a
492
+ // reply). Drop it, reject the one job it was running, and keep the
493
+ // queue moving so no placement promise is left hanging. 'error' and
494
+ // 'exit' both land here, so the first call drops the worker and the
495
+ // second returns.
496
+ #onLost(worker, er) {
497
+ if (!this.#workers.includes(worker)) return;
498
+ this.#workers = this.#workers.filter((w) => w !== worker);
499
+ this.#idle = this.#idle.filter((w) => w !== worker);
500
+ this.#ready.delete(worker);
501
+ for (const [id, pending] of this.#pending) {
502
+ if (pending.worker === worker) {
503
+ this.#settle(id, pending);
504
+ pending.reject(er);
505
+ }
506
+ }
507
+ this.#checkBooted();
508
+ if (this.#workers.length) return;
509
+ this.#threaded = false;
510
+ this.#rejectQueued(er);
511
+ }
512
+ #rejectQueued(er) {
513
+ const queued = this.#queue;
514
+ this.#queue = [];
515
+ for (const job of queued) {
516
+ this.#queued--;
517
+ const pending = this.#pending.get(job.id);
518
+ if (pending) {
519
+ this.#settle(job.id, pending);
520
+ pending.reject(er);
521
+ }
522
+ }
523
+ }
524
+ /**
525
+ * Terminate every worker. Safe to call more than once. Any placement
526
+ * still assigned or queued is rejected rather than left hanging, since
527
+ * terminating a worker stops it before it can reply, and a `warm()`
528
+ * still waiting on the boot is released.
529
+ */
530
+ async close() {
531
+ this.#closed = true;
532
+ this.#threaded = false;
533
+ const workers = this.#workers;
534
+ this.#workers = [];
535
+ this.#idle = [];
536
+ this.#ready.clear();
537
+ const er = new Error("placement pool closed");
538
+ this.#rejectQueued(er);
539
+ for (const [id, pending] of this.#pending) {
540
+ this.#settle(id, pending);
541
+ pending.reject(er);
542
+ }
543
+ this.#checkBooted();
544
+ await Promise.all(workers.map((w) => w.terminate()));
545
+ }
546
+ };
547
+
548
+ // ../../src/tar/src/pool.ts
549
+ import { readFile } from "node:fs/promises";
550
+ var mode = process.env.VLT_TAR_SYNC;
551
+ var Pool = class {
552
+ #placement;
553
+ get #pool() {
554
+ this.#placement ??= new PlacementPool();
555
+ return this.#placement;
556
+ }
557
+ /**
558
+ * Provide the tardata to be unpacked, and the location where it's to be
559
+ * placed. Resolves when the tarball has been extracted. See
560
+ * {@link PlacementPool.unpack}.
561
+ */
562
+ async unpack(tarData, target, format) {
563
+ if (mode === "0") return unpack(tarData, target, format);
564
+ if (mode === "1") return unpackSync(tarData, target, format);
565
+ return this.#pool.unpack(tarData, target, format);
566
+ }
567
+ /**
568
+ * Unpack the tarball in the vlt cache entry `file`, whose first 4
569
+ * bytes are the big-endian length of the head before the body. On a
570
+ * worker the file is read there, so the main thread never holds the
571
+ * body. See {@link PlacementPool.unpackCacheEntry}.
572
+ */
573
+ async unpackCacheEntry(file, target, format) {
574
+ if (mode === "0") {
575
+ return unpack(
576
+ cacheEntryBody(await readFile(file)),
577
+ target,
578
+ format
579
+ );
580
+ }
581
+ if (mode === "1")
582
+ return unpackCacheEntrySync(file, target, format);
583
+ return this.#pool.unpackCacheEntry(file, target, format);
584
+ }
585
+ /**
586
+ * Same, reading the tarball from a file and skipping `offset` leading
587
+ * bytes, so a cache entry is unpacked without loading it into the
588
+ * registry client's in-memory cache.
589
+ */
590
+ async unpackFile(file, target, offset = 0, format) {
591
+ if (mode === "0") {
592
+ return unpack(
593
+ (await readFile(file)).subarray(offset),
594
+ target,
595
+ format
596
+ );
597
+ }
598
+ if (mode === "1") {
599
+ return unpackFileSync(file, target, offset, format);
600
+ }
601
+ return unpackFileParallel(file, target, offset, format);
602
+ }
603
+ /**
604
+ * Hardlink (or copy) a global store entry into `target`. Resolves
605
+ * how, with the index, or false on a store miss. See
606
+ * {@link linkFromStore}.
607
+ */
608
+ async linkFromStore(storeEntry, target, opts) {
609
+ return linkFromStore(storeEntry, target, opts);
610
+ }
611
+ /**
612
+ * Start the unpack workers for an install about to unpack `jobs`
613
+ * tarballs, so they boot while the first packages are fetched rather
614
+ * than on the first placement. Never rejects. See
615
+ * {@link PlacementPool.warm}.
616
+ */
617
+ async warm(jobs) {
618
+ if (mode !== void 0) return;
619
+ await this.#pool.warm(jobs);
620
+ }
621
+ /**
622
+ * Terminate the placement worker threads, if any were started. The
623
+ * pool works without this -- idle workers do not keep the process
624
+ * alive -- but reify calls it when an install's placement is done, to
625
+ * free the threads promptly.
626
+ */
627
+ async close() {
628
+ await this.#placement?.close();
629
+ }
630
+ /**
631
+ * Explode a tarball into `dir` for the global store. See
632
+ * {@link unpackToStoreSync}.
633
+ */
634
+ async unpackToStore(tarData, dir, format) {
635
+ return unpackToStoreSync(tarData, dir, format);
636
+ }
637
+ };
638
+ export {
639
+ DEFAULT_HELD_BYTES,
640
+ DEFAULT_PLACEMENT_MIN_JOBS,
641
+ PlacementPool,
642
+ Pool,
643
+ cloneAvailable,
644
+ linkFromStore,
645
+ markStoreEntryCopied,
646
+ placementThreads,
647
+ readStoreIndex,
648
+ removeStoreEntry,
649
+ storeCopiedPath,
650
+ storeEntryCopied,
651
+ storeEntryLastCopied,
652
+ storeEntryLinked,
653
+ storeEntryNames,
654
+ storeEntryTime,
655
+ storeIndexPath,
656
+ unpack,
657
+ unpackToStoreSync,
658
+ verifyStoreEntry
659
+ };
@@ -29,11 +29,11 @@ import {
29
29
  runtimeTokens,
30
30
  setRuntimeToken,
31
31
  setToken
32
- } from "./chunk-Q2UEILN6.js";
32
+ } from "./chunk-NB7QVWHU.js";
33
33
  import "./chunk-QNHBAGXQ.js";
34
34
  import {
35
35
  userAgent
36
- } from "./chunk-M242QVJS.js";
36
+ } from "./chunk-HHSPE2DS.js";
37
37
  import {
38
38
  assertOk,
39
39
  registryErrorMessage,
@@ -41,10 +41,10 @@ import {
41
41
  storeRoot
42
42
  } from "./chunk-4GMNWW4C.js";
43
43
  import "./chunk-SUU2WETN.js";
44
- import "./chunk-B6RIGNEO.js";
44
+ import "./chunk-ZESNN24A.js";
45
45
  import "./chunk-XNLSTHDK.js";
46
- import "./chunk-PDWPFR5T.js";
47
- import "./chunk-Y5PA7DVK.js";
46
+ import "./chunk-LEMHGORE.js";
47
+ import "./chunk-6ETYWCJN.js";
48
48
  import "./chunk-BF5DRGRZ.js";
49
49
  import "./chunk-WZWDS3W4.js";
50
50
  import "./chunk-PZLD7RTK.js";