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.
- package/{access-YSLEWR2C.js → access-LNHKSCBO.js} +5 -5
- package/{bugs-S6CRUEA2.js → bugs-PSOZGCKG.js} +15 -14
- package/{build-SG3KPX3W.js → build-GBIF54BN.js} +11 -11
- package/{cache-HA77ROM7.js → cache-XOYAGCIO.js} +10 -8
- package/cache-unzip-src-unzip.js +190 -3
- package/chunk-24DWRCPS.js +79 -0
- package/chunk-2CFNQ4QB.js +77 -0
- package/{chunk-AEVT3CHK.js → chunk-3RYVF2GG.js} +2 -2
- package/{chunk-IHERL3TA.js → chunk-3UDBYFAH.js} +95 -8
- package/{chunk-ZJE3OTP3.js → chunk-6BD4RCTR.js} +40 -13
- package/{chunk-Y5PA7DVK.js → chunk-6ETYWCJN.js} +197 -1
- package/{chunk-KURQHX54.js → chunk-6ISFYONV.js} +2 -2
- package/{chunk-VGPLFOJO.js → chunk-AQJR7QDA.js} +1 -1
- package/{chunk-JZXNHIQE.js → chunk-BGOXKLQ6.js} +1 -1
- package/{chunk-MSWOR3FV.js → chunk-C75GDQFE.js} +9 -2
- package/{chunk-WMMKUVAT.js → chunk-FRX5IFFY.js} +4 -4
- package/{chunk-EMTGRCSE.js → chunk-GJMDZJPJ.js} +1 -1
- package/{chunk-M242QVJS.js → chunk-HHSPE2DS.js} +1 -1
- package/{chunk-AHLBPSGQ.js → chunk-JASG7RHB.js} +2 -2
- package/{chunk-W24SBFY5.js → chunk-JNPVOACH.js} +4 -4
- package/{chunk-OWL5G4K4.js → chunk-JYYIWXJX.js} +1 -1
- package/{chunk-5Q2HSLVV.js → chunk-L65CG5LE.js} +1 -1
- package/{chunk-PDWPFR5T.js → chunk-LEMHGORE.js} +1 -1
- package/{chunk-JV5XR5JQ.js → chunk-MCQTGFJY.js} +1 -1
- package/{chunk-O6MQ7NN6.js → chunk-N4SU52H5.js} +1 -1
- package/{chunk-Q2UEILN6.js → chunk-NB7QVWHU.js} +84 -16
- package/{chunk-N6HV7JWC.js → chunk-QFPAFVRR.js} +39 -67
- package/{chunk-DXED4ARV.js → chunk-QGLGNPCQ.js} +2 -2
- package/{chunk-3E3ISOYM.js → chunk-QGUQZURY.js} +2 -2
- package/{chunk-L3ZF7OYM.js → chunk-TGPL6YRK.js} +2 -2
- package/{chunk-C4RJ4NNS.js → chunk-TQBSL35R.js} +5 -5
- package/{chunk-6XVW7CWJ.js → chunk-XWA55GAN.js} +3 -3
- package/{chunk-BQMHDAYL.js → chunk-XWVEIWTT.js} +1 -1
- package/{chunk-4UAIPIAV.js → chunk-Y53EROVE.js} +5 -5
- package/{chunk-NO53Y3QO.js → chunk-Z63CXYQF.js} +1 -1
- package/{chunk-B6RIGNEO.js → chunk-ZESNN24A.js} +11 -1
- package/{ci-GVLL72SS.js → ci-XSH7DZGD.js} +13 -13
- package/cli-package.json +1 -1
- package/{config-KH6AEMHI.js → config-6XFBWC3U.js} +7 -6
- package/{config-TIPKOPYS.js → config-C73FLGQV.js} +7 -6
- package/{create-SKNEZEZY.js → create-UNCQKKBS.js} +16 -15
- package/{deprecate-RFRLJZVL.js → deprecate-HCVFAVZD.js} +9 -8
- package/{dist-tag-LVYOTJHJ.js → dist-tag-WXLJRWFJ.js} +5 -5
- package/{docs-INXRFEGY.js → docs-5EFY7ZHN.js} +15 -14
- package/{exec-5MA5XRPZ.js → exec-EC5D5GE3.js} +16 -15
- package/{exec-cache-7GS4KLWJ.js → exec-cache-EMUFVFCJ.js} +14 -13
- package/{exec-local-RE4KVTMN.js → exec-local-L5H4M37T.js} +13 -13
- package/{help-JHLP565L.js → help-FUHVZ6UH.js} +1 -1
- package/{init-4UFHO67B.js → init-63M6W7N4.js} +11 -11
- package/{install-Z33YVCDK.js → install-IHQRULIE.js} +20 -19
- package/{list-XAMKR6TL.js → list-EDXNWJJR.js} +16 -16
- package/{login-6NXUO5FF.js → login-OD7E5AO5.js} +10 -9
- package/{logout-6P7LWTAY.js → logout-V2WJTQV2.js} +5 -5
- package/{outdated-YNUSWZJD.js → outdated-7N7NGSSR.js} +15 -14
- package/{pack-LMQYH75V.js → pack-TKJW7AEB.js} +12 -12
- package/package.json +1 -1
- package/{ping-VLFZ3WCY.js → ping-PVWRNSCX.js} +5 -5
- package/{pkg-JMPBHKSW.js → pkg-PDP4XR5S.js} +12 -12
- package/{profile-PJJAA2YM.js → profile-BP5EALWS.js} +5 -5
- package/{publish-33RFJ2HJ.js → publish-HCICK5LY.js} +14 -14
- package/{query-LUUOK57K.js → query-TZ3BPC4B.js} +16 -16
- package/registry-client-src-revalidate.js +304 -44
- package/{repo-VLHLQP2S.js → repo-BYOSXG5J.js} +15 -14
- package/{reporter-SNSM2TDC.js → reporter-S6DDAHQL.js} +12 -11
- package/{run-USWK7R3N.js → run-JAVVTY7B.js} +13 -13
- package/{run-exec-PHE44AWW.js → run-exec-GGENQDEW.js} +13 -13
- package/security-archive-src-update-expired.js +1 -1
- package/{setup-JMY47ERY.js → setup-I6GLYILV.js} +13 -12
- package/{skills-YMMV6TMN.js → skills-5V6HKMA7.js} +14 -13
- package/{skills-7PYMTDER.js → skills-QOFA6XMM.js} +6 -6
- package/{src-2ZS4VHJP.js → src-74IKO7PC.js} +12 -8
- package/src-GY57R4DK.js +659 -0
- package/{src-A5ZJNOHN.js → src-REZNPR2X.js} +5 -5
- package/tar-src-placement-worker.js +6426 -0
- package/{token-YKHELNVQ.js → token-JEAMCRK6.js} +5 -5
- package/{uninstall-Q46HWR5S.js → uninstall-WA4FJFVA.js} +14 -14
- package/{unpublish-LBANPSJ5.js → unpublish-SG3J524L.js} +5 -5
- package/{update-B2EGLZHI.js → update-Y3KY2DZD.js} +15 -14
- package/{version-IEOBL3NN.js → version-QBEPMA7Q.js} +11 -11
- package/{view-JCA5VT6F.js → view-FYRF3SLJ.js} +8 -7
- package/vlr.js +1 -1
- package/vlrx.js +1 -1
- package/vlt.js +1 -1
- package/vlx.js +1 -1
- package/vlxl.js +1 -1
- package/{whoami-OWJUPO3X.js → whoami-XSQ6SOIC.js} +5 -5
- package/chunk-N3V6EK5I.js +0 -77
- package/src-W2VQULRG.js +0 -285
package/src-GY57R4DK.js
ADDED
|
@@ -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-
|
|
32
|
+
} from "./chunk-NB7QVWHU.js";
|
|
33
33
|
import "./chunk-QNHBAGXQ.js";
|
|
34
34
|
import {
|
|
35
35
|
userAgent
|
|
36
|
-
} from "./chunk-
|
|
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-
|
|
44
|
+
import "./chunk-ZESNN24A.js";
|
|
45
45
|
import "./chunk-XNLSTHDK.js";
|
|
46
|
-
import "./chunk-
|
|
47
|
-
import "./chunk-
|
|
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";
|