@vltpkg/cli-js 1.3.2 → 1.3.4

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 (76) hide show
  1. package/{access-M5BOAKLX.js → access-AY2CIGVN.js} +4 -4
  2. package/{bugs-QZ5NURDC.js → bugs-6PTC6V7S.js} +12 -12
  3. package/{build-CEAMZG7H.js → build-R6OJNJDU.js} +6 -6
  4. package/{cache-ILCET6EY.js → cache-NVLCCVWQ.js} +6 -6
  5. package/{chunk-NAVFU65Z.js → chunk-4XTUCYBW.js} +1 -1
  6. package/{chunk-MC6CESRA.js → chunk-AFUXQ3P4.js} +1 -1
  7. package/{chunk-4FHGRT4J.js → chunk-B5AKQ5TS.js} +3 -3
  8. package/{chunk-CU752KW7.js → chunk-BCANUHR3.js} +1 -1
  9. package/{chunk-EJFGJ543.js → chunk-BFR3XHEM.js} +3 -3
  10. package/{chunk-HBB2ECAT.js → chunk-CYN4ADWK.js} +2 -2
  11. package/{chunk-USLE2NXK.js → chunk-D4KNFORN.js} +1 -1
  12. package/{chunk-4QYSZZZQ.js → chunk-DK6HGJCF.js} +4 -4
  13. package/chunk-DM2XRLCS.js +75 -0
  14. package/{chunk-O63K3ZP6.js → chunk-GCLZEI3R.js} +173 -50
  15. package/{chunk-BUKZHMMK.js → chunk-INEKXXUQ.js} +1 -0
  16. package/{chunk-I6QGYSB4.js → chunk-LHIDMYN2.js} +1 -1
  17. package/{chunk-4WQ76RJD.js → chunk-MVD5AUNS.js} +1 -1
  18. package/{chunk-E53Z7AF6.js → chunk-MWAWPY3P.js} +3 -3
  19. package/chunk-OFHNSAQ5.js +2155 -0
  20. package/{chunk-2UW4UIVL.js → chunk-QEWKCTQY.js} +4 -4
  21. package/{chunk-IIXKXSLE.js → chunk-QGFDMXDH.js} +313 -171
  22. package/{chunk-QX6KMBTX.js → chunk-QZIC3WVP.js} +3 -3
  23. package/{chunk-ZWKI5OSF.js → chunk-SRWDPPLX.js} +0 -1377
  24. package/{chunk-ZMRJRQDK.js → chunk-TL5SYXSC.js} +292 -45
  25. package/{chunk-CSZTT7QN.js → chunk-TOKUDCSW.js} +2 -2
  26. package/{chunk-3NWCWTIU.js → chunk-WXRS5PRL.js} +1 -1
  27. package/{chunk-ENSGPOLR.js → chunk-XU5WNX4S.js} +3 -1
  28. package/{ci-4AI6XHRE.js → ci-FEZ6B33S.js} +7 -7
  29. package/cli-package.json +1 -1
  30. package/{config-PJVA5HZQ.js → config-EV5S74AA.js} +5 -5
  31. package/{config-UHPA5FHX.js → config-VVPVV36W.js} +6 -6
  32. package/{create-NQNFYWOC.js → create-VGCARZLU.js} +13 -13
  33. package/{deprecate-35D4AZFD.js → deprecate-3E27QREJ.js} +7 -7
  34. package/{dist-tag-W3AJECYB.js → dist-tag-ZIDIGEIM.js} +4 -4
  35. package/{docs-OFRPTPOG.js → docs-GESU73FF.js} +12 -12
  36. package/{exec-UTWGYF3B.js → exec-3SE4PRXY.js} +13 -13
  37. package/{exec-cache-VLPJMK7E.js → exec-cache-7QOIKCYP.js} +11 -11
  38. package/{exec-local-JKBHBKJZ.js → exec-local-EVAI6IYM.js} +10 -10
  39. package/{help-YRQQVODA.js → help-H54DUW2F.js} +4 -4
  40. package/{init-2QZ5TITF.js → init-JOAMKEKV.js} +7 -7
  41. package/{install-QBVAEHTO.js → install-WHOVSLKH.js} +12 -12
  42. package/{list-P4UQWDX7.js → list-7X2RIDA4.js} +12 -12
  43. package/{login-6KPWMFG4.js → login-P5NRTQDS.js} +8 -8
  44. package/{logout-KCYMUY6H.js → logout-5PCTGCJZ.js} +4 -4
  45. package/{pack-WQLFLOE2.js → pack-MLOVKXJZ.js} +9 -9
  46. package/package.json +1 -1
  47. package/{ping-GYFPW4F5.js → ping-6D6EEICV.js} +4 -4
  48. package/{pkg-KVQ6QMQH.js → pkg-HC6N3DDH.js} +8 -8
  49. package/{profile-APD6X27T.js → profile-C3MNVMAE.js} +4 -4
  50. package/{publish-EYKECRD3.js → publish-3KUMQXKT.js} +12 -12
  51. package/{query-3N5D2ZZW.js → query-HNBW2ZGX.js} +12 -12
  52. package/{registry-MXAA4HVJ.js → registry-PY2L5ZWC.js} +2 -2
  53. package/registry-client-src-revalidate.js +173 -50
  54. package/{repo-6B5W7Q2C.js → repo-VWEPCUXK.js} +12 -12
  55. package/{reporter-ZEDO2YIG.js → reporter-UUDMEN4E.js} +6 -6
  56. package/{run-INZMUBF2.js → run-OFW4MPAV.js} +10 -10
  57. package/{run-exec-RVYS73II.js → run-exec-ACGX23HX.js} +10 -10
  58. package/security-archive-src-update-expired.js +1 -1
  59. package/{setup-Q7JD6XJV.js → setup-5C56O3S3.js} +10 -10
  60. package/{src-EJSVFFXB.js → src-3MEJQYBG.js} +21 -7
  61. package/{src-3UQFZRM3.js → src-LH2HZ6FT.js} +2 -2
  62. package/{src-527GIT4Y.js → src-SI5YMOJI.js} +9 -9
  63. package/{token-5HFD3COV.js → token-RPQP6BV5.js} +4 -4
  64. package/{uninstall-4R7Z2FD7.js → uninstall-HDUNLNAD.js} +8 -8
  65. package/{unpublish-RBRQE53F.js → unpublish-SB647KPY.js} +4 -4
  66. package/{update-7LXJAEJN.js → update-PAIZPQPH.js} +11 -11
  67. package/{version-UHRS2KJX.js → version-5O2P2ROI.js} +7 -7
  68. package/{view-BNQKJF5L.js → view-3YVL4M7Z.js} +7 -7
  69. package/vlr.js +1 -1
  70. package/vlrx.js +1 -1
  71. package/vlt.js +1 -1
  72. package/vlx.js +1 -1
  73. package/vlxl.js +1 -1
  74. package/{whoami-GYAT6NWM.js → whoami-KFXNKZOX.js} +4 -4
  75. package/chunk-KH3ERNCA.js +0 -783
  76. package/chunk-TGOC27YZ.js +0 -75
@@ -10,9 +10,8 @@ globalThis.clearInterval = _vlt_clearInterval;
10
10
  import {createRequire as _vlt_createRequire} from "node:module";
11
11
  var require = _vlt_createRequire(import.meta.filename);
12
12
  import {
13
- Qn,
14
- require_lib
15
- } from "./chunk-ZWKI5OSF.js";
13
+ Qn
14
+ } from "./chunk-SRWDPPLX.js";
16
15
  import {
17
16
  Monorepo,
18
17
  PackageJson,
@@ -20,7 +19,7 @@ import {
20
19
  pickManifest,
21
20
  resolve,
22
21
  revs
23
- } from "./chunk-BUKZHMMK.js";
22
+ } from "./chunk-INEKXXUQ.js";
24
23
  import {
25
24
  Spec
26
25
  } from "./chunk-64VFL4WI.js";
@@ -44,12 +43,66 @@ import {
44
43
  import {
45
44
  error
46
45
  } from "./chunk-WZWDS3W4.js";
47
- import {
48
- __toESM
49
- } from "./chunk-PZLD7RTK.js";
46
+
47
+ // ../../src/package-info/src/resolve-batch.ts
48
+ import { createInterface } from "node:readline";
49
+ var fetchResolve = async (client, registry, request, onRecord) => {
50
+ if (!request.roots.length) return;
51
+ let body;
52
+ try {
53
+ const response = await client.requestStream(
54
+ new URL("-/vlt/resolve", registry),
55
+ {
56
+ // POST, not QUERY: CloudFront's allowed-method sets are fixed and
57
+ // none includes QUERY. The registry answers both.
58
+ method: "POST",
59
+ headers: {
60
+ "content-type": "application/json",
61
+ accept: "application/x-ndjson"
62
+ },
63
+ body: JSON.stringify(request)
64
+ }
65
+ );
66
+ if (response.statusCode !== 207) {
67
+ response.body.resume();
68
+ return;
69
+ }
70
+ body = response.body;
71
+ } catch {
72
+ return;
73
+ }
74
+ try {
75
+ for await (const line of createInterface({ input: body })) {
76
+ const record = parseRecord(line);
77
+ if (record) onRecord(record);
78
+ }
79
+ } catch {
80
+ body.destroy();
81
+ }
82
+ };
83
+ var parseRecord = (l) => {
84
+ let record;
85
+ try {
86
+ record = JSON.parse(l);
87
+ } catch {
88
+ return;
89
+ }
90
+ const { status, name, requested, manifest } = record;
91
+ if (status !== 200 || typeof name !== "string") return;
92
+ if (!Array.isArray(requested) || !requested.every((s) => typeof s === "string"))
93
+ return;
94
+ if (typeof manifest !== "object" || manifest === null) return;
95
+ const mani = manifest;
96
+ if (mani.name !== name || typeof mani.version !== "string") return;
97
+ return {
98
+ name,
99
+ version: mani.version,
100
+ requested,
101
+ manifest: mani
102
+ };
103
+ };
50
104
 
51
105
  // ../../src/package-info/src/index.ts
52
- var import_ssri = __toESM(require_lib(), 1);
53
106
  import { createHash, randomBytes } from "node:crypto";
54
107
  import {
55
108
  mkdir,
@@ -66,6 +119,7 @@ import {
66
119
  resolve as pathResolve,
67
120
  relative
68
121
  } from "node:path";
122
+ import { setTimeout } from "node:timers/promises";
69
123
  import { debuglog } from "node:util";
70
124
 
71
125
  // ../../src/package-info/src/capabilities.ts
@@ -147,18 +201,32 @@ var delimiter = "~";
147
201
  var VLT_PACKUMENT_MIME = "application/vnd.vlt.packument-v1+json";
148
202
  var VLT_PACKUMENT_V2_MIME = "application/vnd.vlt.packument-v2+json";
149
203
  var PACKUMENT_ACCEPT = `${VLT_PACKUMENT_V2_MIME}; q=1.0, ${VLT_PACKUMENT_MIME}; q=0.9, application/json; q=0.8, */*; q=0.1`;
204
+ var resolveWaitMs = () => {
205
+ const configured = Number(process.env.VLT_BATCH_RESOLVE_WAIT_MS);
206
+ return Number.isFinite(configured) && configured >= 0 ? configured : 1e3;
207
+ };
208
+ var stalled = /* @__PURE__ */ Symbol("stalled");
209
+ var SELECTION_OPTIONS = [
210
+ "before",
211
+ "os",
212
+ "arch",
213
+ "libc",
214
+ "node-version"
215
+ ];
150
216
  var manifestCacheMaxAge = 5 * 60 * 1e3;
151
217
  var noRegistryError = (spec) => error(
152
218
  'No registry configured to resolve this spec. Set "registry" in vlt.json, pass --registry, or run `vlt login --registry=<url>`. See https://docs.vlt.sh/cli',
153
219
  { code: "ECONFIG", spec }
154
220
  );
155
221
  var isMovingSelector = (f) => !!(f.distTag || f.range?.isAny);
222
+ var revalidateMode = (f, options) => !isMovingSelector(f) ? void 0 : options.backgroundRevalidate ? "background" : true;
156
223
  var isStableSelector = (f) => {
157
224
  const { range } = f;
158
225
  if (!range) return false;
159
226
  return !range.isAny && !range.raw.includes("-");
160
227
  };
161
228
  var storeLinkers = /* @__PURE__ */ new Set(["auto", "hardlink", "copy"]);
229
+ var storedIntegrity = (response) => !response.fromCache ? response.integrityActual : !response.contentType ? void 0 : response.integrity ?? (response.isGzip ? response.integrityActual : void 0);
162
230
  var PackageInfoClient = class {
163
231
  #registryClient;
164
232
  #projectRoot;
@@ -191,8 +259,8 @@ var PackageInfoClient = class {
191
259
  // In-flight coalescing key is `${registry}${name}` — no representation
192
260
  // component. Safe only because every caller requests the same full
193
261
  // packument (see #fetchPackument). The one thing that does vary per
194
- // caller is forceRevalidate, so record it and let a moving selector
195
- // reuse a forced promise but never a non-forced one (see packument()).
262
+ // caller is forceRevalidate, so record how hard it revalidates and
263
+ // never let a request ride a weaker one (see #packument()).
196
264
  #packumentPromises = /* @__PURE__ */ new Map();
197
265
  // unique temp file names for atomic manifest cache writes
198
266
  #manifestWriteRandom = randomBytes(6).toString("hex");
@@ -203,11 +271,31 @@ var PackageInfoClient = class {
203
271
  // needed. entries are removed when the on-disk file is invalidated
204
272
  // so the refreshed manifest can be written again.
205
273
  #manifestWritePaths = /* @__PURE__ */ new Set();
274
+ // Manifests a resolve batch delivered, keyed both as
275
+ // `${registry}${name}@${range}` for every spec that chose a version and
276
+ // `${registry}${name}@${version}` for the version itself.
277
+ #resolvedManifests = /* @__PURE__ */ new Map();
278
+ // The resolves still streaming, per registry, each settling when its
279
+ // stream ends. The requests overlap whatever the graph build does before
280
+ // it asks for its first manifest.
281
+ #resolveInflight = /* @__PURE__ */ new Map();
282
+ // Requests already sent, so the same ask is not repeated. Keyed on the
283
+ // request rather than the registry: a later step asking for a different
284
+ // root set is a different question.
285
+ #resolveSent = /* @__PURE__ */ new Set();
286
+ // Keys `manifest()` is waiting for, each woken by the record that carries
287
+ // it. Waiting per key rather than on the whole response is what lets a
288
+ // build place level N while the server still walks level N+1.
289
+ #resolveWaiters = /* @__PURE__ */ new Map();
290
+ // When each registry's resolve last delivered a record, which is what a
291
+ // waiter checks to tell a stream that is still coming from one that has
292
+ // stalled.
293
+ #resolveLastRecordAt = /* @__PURE__ */ new Map();
206
294
  #registryClientPromise;
207
295
  #tarPoolPromise;
208
296
  async getRegistryClient() {
209
297
  if (this.#registryClient) return this.#registryClient;
210
- this.#registryClientPromise ??= import("./src-3UQFZRM3.js").then(({ RegistryClient }) => {
298
+ this.#registryClientPromise ??= import("./src-LH2HZ6FT.js").then(({ RegistryClient }) => {
211
299
  this.#registryClient = new RegistryClient(this.options);
212
300
  return this.#registryClient;
213
301
  });
@@ -247,7 +335,7 @@ var PackageInfoClient = class {
247
335
  }
248
336
  async getTarPool() {
249
337
  if (this.#tarPool) return this.#tarPool;
250
- this.#tarPoolPromise ??= import("./src-EJSVFFXB.js").then(
338
+ this.#tarPoolPromise ??= import("./src-3MEJQYBG.js").then(
251
339
  ({ Pool }) => {
252
340
  this.#tarPool = new Pool();
253
341
  return this.#tarPool;
@@ -297,8 +385,7 @@ var PackageInfoClient = class {
297
385
  from = this.#projectRoot,
298
386
  integrity,
299
387
  resolved,
300
- fromLockfile = false,
301
- installScripts = false
388
+ fromLockfile = false
302
389
  } = options;
303
390
  const f = spec.final;
304
391
  const brotli = !!resolved && tarballFormat(resolved) === "brotli";
@@ -344,7 +431,7 @@ var PackageInfoClient = class {
344
431
  const pool = await this.getTarPool();
345
432
  const format = tarballFormat(r.resolved);
346
433
  const storeOn = f.type === "registry" && this.#storeLinker !== "unpack";
347
- const copy = this.#storeLinker === "copy" || installScripts;
434
+ const copy = this.#storeLinker === "copy";
348
435
  const hex = !storeOn ? void 0 : r.integrity ? integrityHex(r.integrity) : integrityHex(
349
436
  (await this.getRegistryClient()).cachedIntegrity(
350
437
  r.resolved
@@ -466,30 +553,71 @@ var PackageInfoClient = class {
466
553
  return r;
467
554
  }
468
555
  case "remote": {
469
- const response = await (await this.getRegistryClient()).request(r.resolved);
470
- if (response.statusCode !== 200) {
471
- throw this.#resolveError(
472
- spec,
473
- options,
474
- `failed to fetch remote tarball: ${registryErrorMessage(response)}`,
475
- {
476
- url: r.resolved,
477
- response
556
+ const rc = await this.getRegistryClient();
557
+ const { CacheEntry: Entry, cacheKey } = await import("./src-LH2HZ6FT.js");
558
+ const key = cacheKey("GET", new URL(r.resolved));
559
+ const unzipped = (entry) => {
560
+ try {
561
+ return entry.unzippedIntegrity() === r.integrity;
562
+ } catch {
563
+ return false;
564
+ }
565
+ };
566
+ const fetchTarball = async (readCache) => {
567
+ let response2;
568
+ try {
569
+ response2 = await rc.request(r.resolved, {
570
+ integrity: r.integrity,
571
+ ...readCache === false ? { readCache } : {}
572
+ });
573
+ } catch (er) {
574
+ const cause = er.cause;
575
+ if (cause?.code !== "EINTEGRITY" || !(cause.response instanceof Entry) || !unzipped(cause.response)) {
576
+ throw er;
478
577
  }
479
- );
578
+ response2 = cause.response;
579
+ r.integrity = response2.integrityActual;
580
+ response2.labelArtifact();
581
+ rc.cache.set(key, response2.encode(), {
582
+ integrity: r.integrity
583
+ });
584
+ }
585
+ if (response2.statusCode !== 200) {
586
+ throw this.#resolveError(
587
+ spec,
588
+ options,
589
+ `failed to fetch remote tarball: ${registryErrorMessage(response2)}`,
590
+ {
591
+ url: r.resolved,
592
+ response: response2
593
+ }
594
+ );
595
+ }
596
+ return response2;
597
+ };
598
+ let response = await fetchTarball();
599
+ let found = storedIntegrity(response);
600
+ if (response.fromCache && found && r.integrity && r.integrity !== found && unzipped(response)) {
601
+ r.integrity = found;
480
602
  }
481
- const buf = response.buffer();
482
- const computed = import_ssri.default.fromData(buf, { algorithms: ["sha512"] }).toString();
483
- if (r.integrity && r.integrity !== computed) {
603
+ if (response.fromCache && (!found || r.integrity && r.integrity !== found)) {
604
+ rc.cache.delete(key, true, found);
605
+ if (r.integrity) rc.cache.delete(key, true, r.integrity);
606
+ await rc.cache.promise();
607
+ response = await fetchTarball(false);
608
+ found = storedIntegrity(response);
609
+ }
610
+ if (!found || r.integrity && r.integrity !== found) {
484
611
  throw error("Integrity check failure", {
485
612
  code: "EINTEGRITY",
486
613
  spec,
487
614
  url: r.resolved,
488
615
  wanted: r.integrity,
489
- found: computed
616
+ found
490
617
  });
491
618
  }
492
- r.integrity = computed;
619
+ r.integrity = found;
620
+ const buf = response.buffer();
493
621
  try {
494
622
  await (await this.getTarPool()).unpack(buf, target);
495
623
  } catch (er) {
@@ -759,6 +887,110 @@ var PackageInfoClient = class {
759
887
  }
760
888
  }
761
889
  }
890
+ /**
891
+ * Start a server-side resolve for `request` against `registry` and
892
+ * return without waiting. `manifest()` answers from what has arrived,
893
+ * and blocks on the request only when it needs a key that has not.
894
+ *
895
+ * A no-op unless the registry says it serves the endpoint. Anything it
896
+ * does not deliver is left to `manifest()`.
897
+ */
898
+ prefetchResolve(registry, request) {
899
+ if (!request.roots.length) return;
900
+ if (!registry.endsWith("/")) registry += "/";
901
+ const sent = `${registry}\0${JSON.stringify(request)}`;
902
+ if (this.#resolveSent.has(sent)) return;
903
+ this.#resolveSent.add(sent);
904
+ const promise = this.#runResolve(registry, request);
905
+ let inflight = this.#resolveInflight.get(registry);
906
+ if (!inflight)
907
+ this.#resolveInflight.set(registry, inflight = /* @__PURE__ */ new Set());
908
+ inflight.add(promise);
909
+ const clear = () => inflight.delete(promise);
910
+ promise.then(clear, clear);
911
+ }
912
+ /** Never rejects: a resolve that fails leaves every spec to manifest(). */
913
+ async #runResolve(registry, request) {
914
+ try {
915
+ if ((await this.capabilities(registry)).resolve === void 0)
916
+ return;
917
+ const client = await this.getRegistryClient();
918
+ this.#resolveLastRecordAt.set(registry, Date.now());
919
+ await fetchResolve(client, registry, request, (record) => {
920
+ this.#resolveLastRecordAt.set(registry, Date.now());
921
+ absolutizeTarball(
922
+ record.manifest,
923
+ `${registry}${record.name}/-/`
924
+ );
925
+ this.#vltPackuments.add(`${registry}${record.name}`);
926
+ for (const spec of record.requested) {
927
+ this.#deliverResolved(
928
+ `${registry}${record.name}@${spec}`,
929
+ record.manifest
930
+ );
931
+ }
932
+ this.#deliverResolved(
933
+ `${registry}${record.name}@${record.version}`,
934
+ record.manifest
935
+ );
936
+ });
937
+ } catch {
938
+ }
939
+ }
940
+ /** Record an arrived manifest and wake whoever was waiting for it. */
941
+ #deliverResolved(key, manifest) {
942
+ debug("resolve delivered %s", key);
943
+ this.#resolvedManifests.set(key, manifest);
944
+ const waiters = this.#resolveWaiters.get(key);
945
+ if (waiters) {
946
+ this.#resolveWaiters.delete(key);
947
+ for (const wake of waiters) wake(manifest);
948
+ }
949
+ }
950
+ /**
951
+ * The manifest an in-flight resolve is expected to carry for `key`, or
952
+ * undefined once waiting stopped being worth it: every request settled
953
+ * without the key, or no record of any kind arrived for a whole wait.
954
+ *
955
+ * A stream that is still delivering is worth waiting on, since its records
956
+ * come in the order the build needs them; one that has stalled is not, and
957
+ * the packument fetch was the alternative anyway.
958
+ */
959
+ async #awaitResolved(registry, key) {
960
+ const inflight = this.#resolveInflight.get(registry);
961
+ if (!inflight?.size) return void 0;
962
+ let wake;
963
+ const arrival = new Promise((res) => {
964
+ wake = res;
965
+ });
966
+ let waiters = this.#resolveWaiters.get(key);
967
+ if (!waiters) this.#resolveWaiters.set(key, waiters = /* @__PURE__ */ new Set());
968
+ waiters.add(wake);
969
+ const settled = Promise.all([...inflight]).then(
970
+ () => this.#resolvedManifests.get(key)
971
+ );
972
+ const waitMs = resolveWaitMs();
973
+ try {
974
+ for (; ; ) {
975
+ const outcome = await Promise.race([
976
+ arrival,
977
+ settled,
978
+ // unref'd: a pending wait must never be what keeps the process up
979
+ setTimeout(waitMs, stalled, { ref: false })
980
+ ]);
981
+ if (outcome !== stalled) return outcome;
982
+ const lastRecordAt = this.#resolveLastRecordAt.get(registry) ?? 0;
983
+ if (Date.now() - lastRecordAt >= waitMs) return void 0;
984
+ }
985
+ } finally {
986
+ waiters.delete(wake);
987
+ if (!waiters.size) this.#resolveWaiters.delete(key);
988
+ }
989
+ }
990
+ /** How many manifests resolve batches have delivered. For tests. */
991
+ get resolvedManifestCount() {
992
+ return this.#resolvedManifests.size;
993
+ }
762
994
  async manifest(spec, options = {}) {
763
995
  const { from = this.#projectRoot } = options;
764
996
  if (typeof spec === "string")
@@ -766,6 +998,16 @@ var PackageInfoClient = class {
766
998
  const f = spec.final;
767
999
  switch (f.type) {
768
1000
  case "registry": {
1001
+ if (!SELECTION_OPTIONS.some((k) => options[k] !== void 0)) {
1002
+ const key = `${f.registry ?? ""}${f.name}@${f.bareSpec}`;
1003
+ const resolved = this.#resolvedManifests.get(key);
1004
+ if (resolved) return resolved;
1005
+ if (f.registry) {
1006
+ const arrived = await this.#awaitResolved(f.registry, key);
1007
+ if (arrived) return arrived;
1008
+ debug("resolve miss %s", key);
1009
+ }
1010
+ }
769
1011
  const cachePath = this._manifestCachePath(spec, options);
770
1012
  if (cachePath) {
771
1013
  try {
@@ -848,7 +1090,7 @@ var PackageInfoClient = class {
848
1090
  );
849
1091
  }
850
1092
  const buf = response.buffer();
851
- const computed = import_ssri.default.fromData(buf, { algorithms: ["sha512"] }).toString();
1093
+ const integrity = storedIntegrity(response);
852
1094
  try {
853
1095
  await (await this.getTarPool()).unpack(buf, dir);
854
1096
  } catch (er) {
@@ -860,7 +1102,7 @@ var PackageInfoClient = class {
860
1102
  );
861
1103
  }
862
1104
  const mani = this.#readExtracted(dir, s, options);
863
- mani.dist = { integrity: computed };
1105
+ if (integrity) mani.dist = { integrity };
864
1106
  return mani;
865
1107
  });
866
1108
  }
@@ -948,19 +1190,19 @@ var PackageInfoClient = class {
948
1190
  );
949
1191
  const fullKey = `${registry}${name}`;
950
1192
  const packumentKey = stable ? `${fullKey}?stable` : fullKey;
951
- const forced = isMovingSelector(f);
1193
+ const mode = revalidateMode(f, options);
1194
+ const rank = mode === true ? 2 : mode ? 1 : 0;
952
1195
  const inflight = this.#packumentPromises.get(packumentKey) ?? // the full packument is a superset of the stable one, so an
953
1196
  // in-flight full request answers a stable ask too, and a package
954
1197
  // wanted both ways is still fetched once
955
1198
  (stable ? this.#packumentPromises.get(fullKey) : void 0);
956
- if (inflight && (!forced || inflight.forced))
957
- return inflight.promise;
1199
+ if (inflight && inflight.rank >= rank) return inflight.promise;
958
1200
  const pakuURL = new URL(
959
1201
  stable ? `${name}?stable` : name,
960
1202
  registry
961
1203
  );
962
1204
  const promise = this.#fetchPackument(spec, options, pakuURL);
963
- const record = { promise, forced };
1205
+ const record = { promise, rank };
964
1206
  this.#packumentPromises.set(packumentKey, record);
965
1207
  const clear = () => {
966
1208
  if (this.#packumentPromises.get(packumentKey) === record) {
@@ -973,15 +1215,17 @@ var PackageInfoClient = class {
973
1215
  }
974
1216
  }
975
1217
  async #fetchPackument(spec, options, pakuURL, useCache) {
1218
+ const mode = revalidateMode(spec.final, options);
976
1219
  const response = await (await this.getRegistryClient()).request(pakuURL, {
977
1220
  headers: {
978
1221
  accept: options.full ? "application/json" : PACKUMENT_ACCEPT
979
1222
  },
980
1223
  ...useCache === false || options.full ? { useCache: false } : {},
981
- // costs a conditional GET per moving selector on an otherwise warm
982
- // cache, install included. 304s are cheap but not free; the
983
- // alternative is serving a dist tag that moved (#1656).
984
- ...isMovingSelector(spec.final) ? { forceRevalidate: true } : {}
1224
+ // a moving selector pays a conditional GET before use, so a moved
1225
+ // dist tag is seen at once (#1656). with backgroundRevalidate a
1226
+ // packument still within max-age is served and revalidated after
1227
+ // exit instead.
1228
+ ...mode === void 0 ? {} : { forceRevalidate: mode }
985
1229
  });
986
1230
  if (response.statusCode !== 200) {
987
1231
  throw this.#resolveError(
@@ -1176,11 +1420,14 @@ var PackageInfoClient = class {
1176
1420
  }
1177
1421
  };
1178
1422
  var absolutizeTarballs = (paku, base) => {
1179
- for (const { dist } of Object.values(paku.versions)) {
1180
- const tarball = dist?.tarball;
1181
- if (tarball && !/^[a-z][a-z0-9+.-]*:/i.test(tarball)) {
1182
- dist.tarball = String(new URL(tarball, base));
1183
- }
1423
+ for (const manifest of Object.values(paku.versions)) {
1424
+ absolutizeTarball(manifest, base);
1425
+ }
1426
+ };
1427
+ var absolutizeTarball = (manifest, base) => {
1428
+ const dist = manifest.dist;
1429
+ if (dist?.tarball && !/^[a-z][a-z0-9+.-]*:/i.test(dist.tarball)) {
1430
+ dist.tarball = String(new URL(dist.tarball, base));
1184
1431
  }
1185
1432
  };
1186
1433
 
@@ -12,7 +12,7 @@ var require = _vlt_createRequire(import.meta.filename);
12
12
  import {
13
13
  generateDefaultHelp,
14
14
  generateFullHelp
15
- } from "./chunk-CU752KW7.js";
15
+ } from "./chunk-BCANUHR3.js";
16
16
  import {
17
17
  flush,
18
18
  trackCommand,
@@ -38,7 +38,7 @@ import {
38
38
  } from "./chunk-JIQBZ2UT.js";
39
39
  import {
40
40
  defaultView
41
- } from "./chunk-ENSGPOLR.js";
41
+ } from "./chunk-XU5WNX4S.js";
42
42
  import {
43
43
  emitter
44
44
  } from "./chunk-U7TEQCBN.js";
@@ -14,7 +14,7 @@ var require = _vlt_createRequire(import.meta.filename);
14
14
  var package_default = {
15
15
  name: "@vltpkg/user-agent",
16
16
  description: "The User-Agent string that vlt sends with every outbound request",
17
- version: "1.3.2",
17
+ version: "1.3.4",
18
18
  repository: {
19
19
  type: "git",
20
20
  url: "git+https://github.com/vltpkg/vltpkg.git",
@@ -1383,7 +1383,9 @@ var definition = j2.heading("Configuration").description(
1383
1383
  - unpack: Unpack each package tarball, skipping the
1384
1384
  global store.
1385
1385
 
1386
- Packages with install scripts are always copied.
1386
+ A package is copied right before its install
1387
+ scripts run, so they don't change its files in the
1388
+ store.
1387
1389
  An invalid \`VLT_STORE_LINKER\` warns and uses
1388
1390
  \`unpack\`.`,
1389
1391
  validOptions: storeLinkers,
@@ -11,20 +11,20 @@ import {createRequire as _vlt_createRequire} from "node:module";
11
11
  var require = _vlt_createRequire(import.meta.filename);
12
12
  import {
13
13
  install
14
- } from "./chunk-IIXKXSLE.js";
15
- import "./chunk-4WQ76RJD.js";
14
+ } from "./chunk-QGFDMXDH.js";
15
+ import "./chunk-MVD5AUNS.js";
16
16
  import {
17
17
  commandUsage
18
- } from "./chunk-I6QGYSB4.js";
19
- import "./chunk-BUKZHMMK.js";
18
+ } from "./chunk-LHIDMYN2.js";
19
+ import "./chunk-INEKXXUQ.js";
20
20
  import {
21
21
  lazyView
22
22
  } from "./chunk-4KCU2KZL.js";
23
23
  import "./chunk-JIQBZ2UT.js";
24
24
  import "./chunk-64VFL4WI.js";
25
- import "./chunk-ENSGPOLR.js";
25
+ import "./chunk-XU5WNX4S.js";
26
26
  import "./chunk-HTOTG4TS.js";
27
- import "./chunk-3NWCWTIU.js";
27
+ import "./chunk-WXRS5PRL.js";
28
28
  import "./chunk-U7TEQCBN.js";
29
29
  import "./chunk-XNLSTHDK.js";
30
30
  import "./chunk-PDWPFR5T.js";
@@ -63,7 +63,7 @@ var usage = () => commandUsage({
63
63
  var views = {
64
64
  json: (i) => i.graph.toJSON(),
65
65
  human: lazyView(
66
- async () => (await import("./reporter-ZEDO2YIG.js")).InstallReporter
66
+ async () => (await import("./reporter-UUDMEN4E.js")).InstallReporter
67
67
  )
68
68
  };
69
69
  var command = async (conf) => {
package/cli-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vltpkg/cli-sdk",
3
3
  "description": "The source for the vlt CLI",
4
- "version": "1.3.2",
4
+ "version": "1.3.4",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
@@ -16,10 +16,10 @@ import {
16
16
  kCustomInspect,
17
17
  pairsToRecords,
18
18
  recordsToPairs
19
- } from "./chunk-4FHGRT4J.js";
20
- import "./chunk-ZMRJRQDK.js";
21
- import "./chunk-ZWKI5OSF.js";
22
- import "./chunk-BUKZHMMK.js";
19
+ } from "./chunk-B5AKQ5TS.js";
20
+ import "./chunk-TL5SYXSC.js";
21
+ import "./chunk-SRWDPPLX.js";
22
+ import "./chunk-INEKXXUQ.js";
23
23
  import "./chunk-JIQBZ2UT.js";
24
24
  import "./chunk-64VFL4WI.js";
25
25
  import {
@@ -27,7 +27,7 @@ import {
27
27
  definition,
28
28
  isRecordField,
29
29
  recordFields
30
- } from "./chunk-ENSGPOLR.js";
30
+ } from "./chunk-XU5WNX4S.js";
31
31
  import "./chunk-HTOTG4TS.js";
32
32
  import "./chunk-PBBULTAG.js";
33
33
  import "./chunk-U7TEQCBN.js";
@@ -19,19 +19,19 @@ import {
19
19
  import {
20
20
  pairsToRecords,
21
21
  recordsToPairs
22
- } from "./chunk-4FHGRT4J.js";
23
- import "./chunk-ZMRJRQDK.js";
24
- import "./chunk-ZWKI5OSF.js";
22
+ } from "./chunk-B5AKQ5TS.js";
23
+ import "./chunk-TL5SYXSC.js";
24
+ import "./chunk-SRWDPPLX.js";
25
25
  import {
26
26
  commandUsage
27
- } from "./chunk-I6QGYSB4.js";
28
- import "./chunk-BUKZHMMK.js";
27
+ } from "./chunk-LHIDMYN2.js";
28
+ import "./chunk-INEKXXUQ.js";
29
29
  import "./chunk-JIQBZ2UT.js";
30
30
  import "./chunk-64VFL4WI.js";
31
31
  import {
32
32
  getSortedKeys,
33
33
  isRecordField
34
- } from "./chunk-ENSGPOLR.js";
34
+ } from "./chunk-XU5WNX4S.js";
35
35
  import {
36
36
  find,
37
37
  load