@vltpkg/cli-js 1.0.9 → 1.1.0

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 (77) hide show
  1. package/{access-5DJJIIGD.js → access-GLWBGQLN.js} +41 -10
  2. package/{bugs-NRHU4ENC.js → bugs-OCQYFWFE.js} +18 -18
  3. package/{build-5VZJTEBD.js → build-CPWGNTCM.js} +7 -8
  4. package/{cache-QZ5XII4U.js → cache-SL7DQMY2.js} +20 -14
  5. package/chunk-2IMBYPYC.js +190 -0
  6. package/{chunk-5JFRXIK2.js → chunk-2PWSMJD7.js} +20 -1
  7. package/{chunk-LHMEJF6J.js → chunk-47M7IZ5P.js} +94 -39
  8. package/{chunk-6NQBG3ZR.js → chunk-6LEMBT22.js} +30 -5
  9. package/chunk-A75UYRJC.js +75 -0
  10. package/{chunk-HAYXR3MW.js → chunk-APMYKJI2.js} +1 -1
  11. package/{chunk-A6TBJ4AB.js → chunk-BUXPKRYB.js} +4 -4
  12. package/{chunk-PTR5IGFQ.js → chunk-CBASIDQH.js} +1 -1
  13. package/{chunk-XISRK3R5.js → chunk-CEHPRPGQ.js} +38 -0
  14. package/{chunk-KCXN2GTX.js → chunk-CF5EGH4W.js} +12 -2
  15. package/{chunk-HRY5MJCA.js → chunk-CTQSUNNE.js} +35 -19
  16. package/{chunk-ATYE2HQV.js → chunk-GJGQTRAT.js} +165 -30
  17. package/{chunk-YAIKXFLN.js → chunk-HYCYL4RX.js} +1 -1
  18. package/{chunk-EBXBZ2Y5.js → chunk-J2XWQVDK.js} +98 -6
  19. package/{chunk-SBEZ7RUC.js → chunk-JSQUYHU7.js} +5 -5
  20. package/{chunk-GKCU7R4B.js → chunk-S6Y57MUS.js} +4 -4
  21. package/chunk-SNOBGFNM.js +129 -0
  22. package/{chunk-MXCWH7WC.js → chunk-TNEMFBP5.js} +41 -10
  23. package/{chunk-USRMYD4F.js → chunk-TUXWDPCQ.js} +1 -1
  24. package/{chunk-2HDWM6AD.js → chunk-TXTK2PKN.js} +2 -2
  25. package/{chunk-LPIBYUMT.js → chunk-U7TEQCBN.js} +27 -1
  26. package/{chunk-XFI4THXZ.js → chunk-WE2TQN32.js} +1 -1
  27. package/{chunk-USTJECVS.js → chunk-X2AWQGYG.js} +1 -1
  28. package/{chunk-6WMR7BLF.js → chunk-YKCGWKUE.js} +3 -3
  29. package/{chunk-2YJ5MESP.js → chunk-ZDQJWRCU.js} +1 -1
  30. package/{ci-MBYD4AGJ.js → ci-O2RSLTBX.js} +9 -10
  31. package/cli-package.json +1 -1
  32. package/{config-DTZ7EWQF.js → config-ZBIF32GS.js} +11 -11
  33. package/{config-RQKPUW5B.js → config-ZPH7V77F.js} +8 -6
  34. package/{create-CYTNZ66Z.js → create-2JX4RV5U.js} +17 -17
  35. package/{deprecate-H3L4MPZS.js → deprecate-XJLP2TUW.js} +21 -18
  36. package/{dist-tag-CZHTW7C6.js → dist-tag-F6ZFWGQU.js} +23 -25
  37. package/{docs-Z76UCNLH.js → docs-IJCZZ4V6.js} +18 -18
  38. package/{exec-PGPFYCAM.js → exec-IWSS2LUA.js} +17 -17
  39. package/{exec-cache-HPILZWUY.js → exec-cache-AG77OOEE.js} +15 -15
  40. package/{exec-local-VKDC6XAQ.js → exec-local-QXPWC4QG.js} +13 -14
  41. package/{help-QPZESL4Y.js → help-TGNDNWLP.js} +4 -4
  42. package/{init-MMQV6UC5.js → init-WU7BRPKR.js} +7 -8
  43. package/{install-KZPDV66V.js → install-74XKB5N7.js} +37 -14
  44. package/{list-PJ2U4FE7.js → list-TOEC6Q3A.js} +41 -29
  45. package/{login-L3D5FQGT.js → login-WJYMAFSL.js} +11 -11
  46. package/{logout-SRZ574SQ.js → logout-MTRQWI3L.js} +7 -7
  47. package/{pack-OI5JLA3R.js → pack-FFWGLSNC.js} +11 -12
  48. package/package.json +1 -1
  49. package/{ping-VQ662NAP.js → ping-DWUVTCJB.js} +7 -7
  50. package/{pkg-HNPRMTWV.js → pkg-KNZW5FIA.js} +10 -11
  51. package/{profile-Z7IOODZ4.js → profile-6W2ABNXL.js} +20 -7
  52. package/{publish-KTUUX25U.js → publish-HGNUONU3.js} +35 -65
  53. package/{query-MV5HKRIT.js → query-FSCYPETX.js} +35 -23
  54. package/{registry-BMWXMQS4.js → registry-YTJZ3AQD.js} +3 -3
  55. package/registry-client-package.json +6 -1
  56. package/registry-client-src-revalidate.js +241 -43
  57. package/{repo-ZBCD65WE.js → repo-OVIKYYWA.js} +18 -18
  58. package/{reporter-SDMDYYMJ.js → reporter-ZW7OMRZT.js} +23 -1
  59. package/{run-QJK5LA6Q.js → run-UPV3RPQJ.js} +13 -14
  60. package/{run-exec-EAASMT5O.js → run-exec-YJSMWMMP.js} +13 -14
  61. package/{setup-Q7NTAV26.js → setup-7DPMAPUY.js} +20 -19
  62. package/{src-YVODDQYK.js → src-BNCFK4FH.js} +15 -15
  63. package/{src-MEEFRFWA.js → src-XJT4IJSV.js} +11 -4
  64. package/{token-NQRHTTKG.js → token-GA73ER5V.js} +8 -8
  65. package/{uninstall-E2SVGYI3.js → uninstall-E3VKSC3B.js} +11 -11
  66. package/{unpublish-IE4KYVM4.js → unpublish-Q6MQHBPQ.js} +43 -40
  67. package/{update-KZOWARII.js → update-4CC44TR5.js} +34 -12
  68. package/{version-T6PTPZPR.js → version-CRZBXNDG.js} +23 -18
  69. package/{view-MVYV7YZ2.js → view-ILUULGSO.js} +9 -9
  70. package/vlr.js +1 -1
  71. package/vlrx.js +1 -1
  72. package/vlt.js +1 -1
  73. package/vlx.js +1 -1
  74. package/vlxl.js +1 -1
  75. package/{whoami-A5RM2Z7Z.js → whoami-Z4TSLYTR.js} +28 -12
  76. package/chunk-UBLFPJHV.js +0 -40
  77. package/chunk-XEPCV7DP.js +0 -75
@@ -20,13 +20,16 @@ import {
20
20
  pickManifest,
21
21
  resolve,
22
22
  revs
23
- } from "./chunk-USTJECVS.js";
23
+ } from "./chunk-X2AWQGYG.js";
24
24
  import {
25
25
  Spec
26
26
  } from "./chunk-XKVU23NC.js";
27
+ import {
28
+ registryErrorMessage
29
+ } from "./chunk-SNOBGFNM.js";
27
30
  import {
28
31
  logRequest
29
- } from "./chunk-UBLFPJHV.js";
32
+ } from "./chunk-U7TEQCBN.js";
30
33
  import {
31
34
  asPackument
32
35
  } from "./chunk-VFBCWAOC.js";
@@ -83,11 +86,13 @@ var rename = platform !== "win32" ? fsRename : (async function(oldPath, newPath)
83
86
  var debug = debuglog("vlt");
84
87
  var xdg = new XDG("vlt");
85
88
  var delimiter = "~";
89
+ var PACKUMENT_ACCEPT = "application/vnd.vlt.packument-v1+json; q=1.0, application/json; q=0.8, */*; q=0.1";
86
90
  var manifestCacheMaxAge = 5 * 60 * 1e3;
87
91
  var noRegistryError = (spec) => error(
88
92
  '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',
89
93
  { code: "ECONFIG", spec }
90
94
  );
95
+ var isMovingSelector = (f) => !!(f.distTag || f.range?.isAny);
91
96
  var PackageInfoClient = class {
92
97
  #registryClient;
93
98
  #projectRoot;
@@ -101,7 +106,9 @@ var PackageInfoClient = class {
101
106
  #cachePath;
102
107
  // In-flight coalescing key is `${registry}${name}` — no representation
103
108
  // component. Safe only because every caller requests the same full
104
- // packument (see #fetchPackument).
109
+ // packument (see #fetchPackument). The one thing that does vary per
110
+ // caller is forceRevalidate, so record it and let a moving selector
111
+ // reuse a forced promise but never a non-forced one (see packument()).
105
112
  #packumentPromises = /* @__PURE__ */ new Map();
106
113
  // unique temp file names for atomic manifest cache writes
107
114
  #manifestWriteRandom = randomBytes(6).toString("hex");
@@ -116,7 +123,7 @@ var PackageInfoClient = class {
116
123
  #tarPoolPromise;
117
124
  async getRegistryClient() {
118
125
  if (this.#registryClient) return this.#registryClient;
119
- this.#registryClientPromise ??= import("./src-MEEFRFWA.js").then(({ RegistryClient }) => {
126
+ this.#registryClientPromise ??= import("./src-XJT4IJSV.js").then(({ RegistryClient }) => {
120
127
  this.#registryClient = new RegistryClient(this.options);
121
128
  return this.#registryClient;
122
129
  });
@@ -225,7 +232,7 @@ var PackageInfoClient = class {
225
232
  throw this.#resolveError(
226
233
  spec,
227
234
  options,
228
- `Registry returned HTTP ${response.statusCode} when fetching the tarball for ${spec}. The resolved version may have been unpublished, or the registry may be misconfigured or unreachable.`,
235
+ `${registryErrorMessage(response)} when fetching the tarball for ${spec}. The resolved version may have been unpublished, or the registry may be misconfigured or unreachable.`,
229
236
  {
230
237
  url: r.resolved,
231
238
  response
@@ -283,7 +290,7 @@ var PackageInfoClient = class {
283
290
  throw this.#resolveError(
284
291
  spec,
285
292
  options,
286
- "failed to fetch remote tarball",
293
+ `failed to fetch remote tarball: ${registryErrorMessage(response)}`,
287
294
  {
288
295
  url: r.resolved,
289
296
  response
@@ -398,7 +405,7 @@ var PackageInfoClient = class {
398
405
  return;
399
406
  }
400
407
  const f = spec.final;
401
- if (f.distTag || f.range?.isAny) {
408
+ if (isMovingSelector(f)) {
402
409
  return;
403
410
  }
404
411
  const key = this.#manifestCacheKey(f, options);
@@ -459,7 +466,7 @@ var PackageInfoClient = class {
459
466
  throw this.#resolveError(
460
467
  spec,
461
468
  options,
462
- `Registry returned HTTP ${response.statusCode} when fetching the tarball for ${spec} at ${tarball}. The version may have been unpublished, or the registry may be misconfigured or unreachable.`,
469
+ `${registryErrorMessage(response)} when fetching the tarball for ${spec} at ${tarball}. The version may have been unpublished, or the registry may be misconfigured or unreachable.`,
463
470
  { response, url: tarball }
464
471
  );
465
472
  }
@@ -539,7 +546,7 @@ var PackageInfoClient = class {
539
546
  throw this.#resolveError(
540
547
  spec,
541
548
  options,
542
- "failed to fetch URL",
549
+ `failed to fetch URL: ${registryErrorMessage(response)}`,
543
550
  { response, url: remoteURL }
544
551
  );
545
552
  }
@@ -642,7 +649,7 @@ var PackageInfoClient = class {
642
649
  throw this.#resolveError(
643
650
  s,
644
651
  options,
645
- "failed to fetch URL",
652
+ `failed to fetch URL: ${registryErrorMessage(response)}`,
646
653
  { response, url: remoteURL }
647
654
  );
648
655
  }
@@ -732,29 +739,38 @@ var PackageInfoClient = class {
732
739
  const { registry, name } = f;
733
740
  if (!registry) throw noRegistryError(spec);
734
741
  const packumentKey = `${registry}${name}`;
742
+ const forced = isMovingSelector(f);
735
743
  const inflight = this.#packumentPromises.get(packumentKey);
736
- if (inflight) return inflight;
744
+ if (inflight && (!forced || inflight.forced))
745
+ return inflight.promise;
737
746
  const pakuURL = new URL(name, registry);
738
747
  const promise = this.#fetchPackument(spec, options, pakuURL);
739
- this.#packumentPromises.set(packumentKey, promise);
740
- promise.then(
741
- () => this.#packumentPromises.delete(packumentKey),
742
- () => this.#packumentPromises.delete(packumentKey)
743
- );
748
+ const record = { promise, forced };
749
+ this.#packumentPromises.set(packumentKey, record);
750
+ const clear = () => {
751
+ if (this.#packumentPromises.get(packumentKey) === record) {
752
+ this.#packumentPromises.delete(packumentKey);
753
+ }
754
+ };
755
+ promise.then(clear, clear);
744
756
  return promise;
745
757
  }
746
758
  }
747
759
  }
748
760
  async #fetchPackument(spec, options, pakuURL, useCache) {
749
761
  const response = await (await this.getRegistryClient()).request(pakuURL, {
750
- headers: { accept: "application/json" },
751
- ...useCache === false ? { useCache } : {}
762
+ headers: { accept: PACKUMENT_ACCEPT },
763
+ ...useCache === false ? { useCache } : {},
764
+ // costs a conditional GET per moving selector on an otherwise warm
765
+ // cache, install included. 304s are cheap but not free; the
766
+ // alternative is serving a dist tag that moved (#1656).
767
+ ...isMovingSelector(spec.final) ? { forceRevalidate: true } : {}
752
768
  });
753
769
  if (response.statusCode !== 200) {
754
770
  throw this.#resolveError(
755
771
  spec,
756
772
  options,
757
- "failed to fetch packument",
773
+ `failed to fetch packument: ${registryErrorMessage(response)}`,
758
774
  {
759
775
  url: pakuURL,
760
776
  response
@@ -11,16 +11,18 @@ import {createRequire as _vlt_createRequire} from "node:module";
11
11
  var require = _vlt_createRequire(import.meta.filename);
12
12
  import {
13
13
  urlOpen
14
- } from "./chunk-HAYXR3MW.js";
14
+ } from "./chunk-APMYKJI2.js";
15
+ import {
16
+ assertOk,
17
+ registryErrorMessage
18
+ } from "./chunk-SNOBGFNM.js";
15
19
  import {
16
20
  loadPackageJson
17
21
  } from "./chunk-E74WGW5C.js";
18
22
  import {
19
- I
20
- } from "./chunk-LPIBYUMT.js";
21
- import {
23
+ I,
22
24
  logRequest
23
- } from "./chunk-UBLFPJHV.js";
25
+ } from "./chunk-U7TEQCBN.js";
24
26
  import {
25
27
  asError
26
28
  } from "./chunk-VFBCWAOC.js";
@@ -1074,7 +1076,7 @@ var require_util = __commonJS({
1074
1076
  return new BodyAsyncIterable(body);
1075
1077
  } else if (body && isFormDataLike(body)) {
1076
1078
  return body;
1077
- } else if (body && typeof body !== "string" && !ArrayBuffer.isView(body) && isIterable2(body)) {
1079
+ } else if (body && typeof body !== "string" && !ArrayBuffer.isView(body) && isIterable3(body)) {
1078
1080
  return new BodyAsyncIterable(body);
1079
1081
  } else {
1080
1082
  return body;
@@ -1195,7 +1197,7 @@ var require_util = __commonJS({
1195
1197
  function isAsyncIterable(obj) {
1196
1198
  return !!(obj != null && typeof obj[Symbol.asyncIterator] === "function");
1197
1199
  }
1198
- function isIterable2(obj) {
1200
+ function isIterable3(obj) {
1199
1201
  return !!(obj != null && (typeof obj[Symbol.iterator] === "function" || typeof obj[Symbol.asyncIterator] === "function"));
1200
1202
  }
1201
1203
  function hasSafeIterator(obj) {
@@ -1806,7 +1808,7 @@ var require_util = __commonJS({
1806
1808
  parseURL,
1807
1809
  getServerName,
1808
1810
  isStream,
1809
- isIterable: isIterable2,
1811
+ isIterable: isIterable3,
1810
1812
  hasSafeIterator,
1811
1813
  isAsyncIterable,
1812
1814
  isDestroyed,
@@ -2115,7 +2117,7 @@ var require_request = __commonJS({
2115
2117
  destroy,
2116
2118
  isBuffer,
2117
2119
  isFormDataLike,
2118
- isIterable: isIterable2,
2120
+ isIterable: isIterable3,
2119
2121
  hasSafeIterator,
2120
2122
  isBlobLike,
2121
2123
  serializePathWithQuery,
@@ -2230,7 +2232,7 @@ var require_request = __commonJS({
2230
2232
  this.body = body.byteLength ? Buffer.from(body) : null;
2231
2233
  } else if (typeof body === "string") {
2232
2234
  this.body = body.length ? Buffer.from(body) : null;
2233
- } else if (isFormDataLike(body) || isIterable2(body) || isBlobLike(body)) {
2235
+ } else if (isFormDataLike(body) || isIterable3(body) || isBlobLike(body)) {
2234
2236
  this.body = body;
2235
2237
  } else {
2236
2238
  throw new InvalidArgumentError("body must be a string, a Buffer, a Readable stream, an iterable, or an async iterable");
@@ -26601,6 +26603,19 @@ var CacheEntry = class _CacheEntry {
26601
26603
  get statusCode() {
26602
26604
  return this.#statusCode;
26603
26605
  }
26606
+ /**
26607
+ * True when the registry answered with a 2xx.
26608
+ *
26609
+ * `RegistryClient.request()` resolves for every status, so this is how
26610
+ * code holding a real CacheEntry asks "did it work?".
26611
+ *
26612
+ * Note this is the strict form. Use it only where a genuine CacheEntry
26613
+ * is guaranteed; `assertOk` uses the loose range check because it is
26614
+ * also handed duck-typed responses.
26615
+ */
26616
+ get ok() {
26617
+ return this.#statusCode >= 200 && this.#statusCode < 300;
26618
+ }
26604
26619
  get headers() {
26605
26620
  return this.#headers;
26606
26621
  }
@@ -26953,9 +26968,9 @@ var __CODE_SPLIT_SCRIPT_NAME2 = resolve3(import.meta.dirname, "registry-client-s
26953
26968
  var isDeno2 = globalThis.Deno != void 0;
26954
26969
  var didProcessBeforeExitHook2 = false;
26955
26970
  var registered2 = /* @__PURE__ */ new Map();
26956
- var register2 = (path, method, url) => {
26971
+ var register2 = (path, method, url, accept) => {
26957
26972
  const r = registered2.get(path) ?? /* @__PURE__ */ new Set();
26958
- const key = `${method} ${url}`;
26973
+ const key = `${method} ${url}${accept ? ` ${String(accept)}` : ""}`;
26959
26974
  r.add(key);
26960
26975
  registered2.set(path, r);
26961
26976
  if (!didProcessBeforeExitHook2) {
@@ -27005,6 +27020,33 @@ var bun = isBun ? proc.versions.bun : void 0;
27005
27020
  var deno = isDeno3 ? proc.versions.deno : void 0;
27006
27021
  var node = isNode ? proc.versions.node : void 0;
27007
27022
 
27023
+ // ../../src/registry-client/src/get-header.ts
27024
+ var isIterable2 = (o) => !!o && typeof o === "object" && Symbol.iterator in o;
27025
+ var getHeader = (headers, key) => {
27026
+ if (!headers) return void 0;
27027
+ key = key.toLowerCase();
27028
+ if (Array.isArray(headers)) {
27029
+ if (!headers.length) return void 0;
27030
+ if (Array.isArray(headers[0])) {
27031
+ for (const [k, v] of headers) {
27032
+ if (k.toLowerCase() === key) return v;
27033
+ }
27034
+ } else if (headers.length % 2 === 0) {
27035
+ for (let i = 0; i < headers.length; i += 2) {
27036
+ if (headers[i]?.toLowerCase() === key) return headers[i + 1];
27037
+ }
27038
+ }
27039
+ } else if (isIterable2(headers)) {
27040
+ for (const [k, v] of headers) {
27041
+ if (k.toLowerCase() === key) return v;
27042
+ }
27043
+ } else {
27044
+ for (const [k, v] of Object.entries(headers)) {
27045
+ if (k.toLowerCase() === key) return v;
27046
+ }
27047
+ }
27048
+ };
27049
+
27008
27050
  // ../../src/registry-client/src/handle-304-response.ts
27009
27051
  var handleCacheHitResponse = (resp, entry) => {
27010
27052
  if (resp.statusCode !== 304 && resp.statusCode !== 412 || !entry)
@@ -27053,6 +27095,9 @@ var otplease = async (client, options, response) => {
27053
27095
  );
27054
27096
  if (wwwAuth.has("ipaddress")) {
27055
27097
  throw error("Authorization is not allowed from your ip address", {
27098
+ code: "ENEEDAUTH",
27099
+ status: response.statusCode,
27100
+ method: options.method,
27056
27101
  response
27057
27102
  });
27058
27103
  }
@@ -27085,17 +27130,30 @@ var otplease = async (client, options, response) => {
27085
27130
  }
27086
27131
  }
27087
27132
  throw error("Unrecognized OTP authentication challenge", {
27133
+ code: "ENEEDAUTH",
27134
+ status: response.statusCode,
27135
+ method: options.method,
27088
27136
  response
27089
27137
  });
27090
27138
  }
27091
27139
  if (wwwAuth.has("bearer")) {
27092
27140
  throw error(
27093
27141
  "Missing or invalid authentication token. Run `vlt login` or `vlt token add` to authenticate.",
27094
- { response }
27142
+ {
27143
+ code: "ENEEDAUTH",
27144
+ status: response.statusCode,
27145
+ method: options.method,
27146
+ response
27147
+ }
27095
27148
  );
27096
27149
  }
27097
27150
  if (wwwAuth.size) {
27098
- throw error("Unknown authentication challenge", { response });
27151
+ throw error("Unknown authentication challenge", {
27152
+ code: "ENEEDAUTH",
27153
+ status: response.statusCode,
27154
+ method: options.method,
27155
+ response
27156
+ });
27099
27157
  }
27100
27158
  const text = await responseBodyText(response).catch(() => "");
27101
27159
  if (text.toLowerCase().includes("one-time pass")) {
@@ -27446,7 +27504,40 @@ var RegistryClient = class {
27446
27504
  */
27447
27505
  async scroll(url, options = {}, seek) {
27448
27506
  const resp = await this.request(url, options);
27449
- const { objects, urls } = resp.json();
27507
+ const { statusCode } = resp;
27508
+ if (statusCode < 200 || statusCode >= 300) {
27509
+ let detail;
27510
+ try {
27511
+ const body2 = resp.json();
27512
+ if (body2 && typeof body2 === "object" && "error" in body2) {
27513
+ detail = body2.error;
27514
+ }
27515
+ } catch {
27516
+ }
27517
+ const status = STATUS_CODES[statusCode];
27518
+ throw error(
27519
+ `Failed to fetch paginated results: ${statusCode}${status ? ` ${status}` : ""}${typeof detail === "string" && detail ? `: ${detail}` : ""}`,
27520
+ { code: "EREQUEST", status: statusCode, url: String(url) }
27521
+ );
27522
+ }
27523
+ let body;
27524
+ try {
27525
+ body = resp.json();
27526
+ } catch (cause) {
27527
+ throw error("Invalid JSON in paginated registry response", {
27528
+ code: "EREQUEST",
27529
+ url: String(url),
27530
+ cause
27531
+ });
27532
+ }
27533
+ if (!body || typeof body !== "object" || !("objects" in body) || !Array.isArray(body.objects) || !("urls" in body) || !body.urls || typeof body.urls !== "object" || Array.isArray(body.urls) || "next" in body.urls && body.urls.next !== null && body.urls.next !== void 0 && typeof body.urls.next !== "string") {
27534
+ throw error("Invalid pagination in registry response", {
27535
+ code: "EREQUEST",
27536
+ url: String(url)
27537
+ });
27538
+ }
27539
+ const objects = body.objects;
27540
+ const urls = body.urls;
27450
27541
  return urls.next && !(seek && objects.some(seek)) ? objects.concat(await this.scroll(urls.next, options, seek)) : objects;
27451
27542
  }
27452
27543
  /**
@@ -27465,17 +27556,41 @@ var RegistryClient = class {
27465
27556
  const s = tok.replace(/^(Bearer|Basic) /i, "");
27466
27557
  const base = registryBase(registry);
27467
27558
  const tokensUrl = new URL("-/npm/v1/tokens", base);
27468
- const record = await this.seek(tokensUrl, ({ token }) => s.startsWith(token), {
27469
- useCache: false
27470
- }).catch(() => void 0);
27471
- if (record) {
27472
- const { key } = record;
27473
- await this.request(
27474
- new URL(`-/npm/v1/tokens/token/${key}`, base),
27475
- { useCache: false, method: "DELETE" }
27476
- );
27559
+ const stillLive = `Removing the local credential anyway; revoke the token in the registry UI if it is still live.`;
27560
+ try {
27561
+ let record;
27562
+ try {
27563
+ record = await this.seek(tokensUrl, ({ token }) => s.startsWith(token), {
27564
+ useCache: false
27565
+ });
27566
+ } catch (er) {
27567
+ log3(
27568
+ `Could not list tokens at ${tokensUrl}: ${asError(er).message}
27569
+ ` + stillLive
27570
+ );
27571
+ }
27572
+ if (record) {
27573
+ const deleteUrl = new URL(
27574
+ `-/npm/v1/tokens/token/${record.key}`,
27575
+ base
27576
+ );
27577
+ const failed = (detail) => log3(
27578
+ `Failed to revoke the token on the registry: ${detail}
27579
+ ` + stillLive
27580
+ );
27581
+ try {
27582
+ const response = await this.request(deleteUrl, {
27583
+ useCache: false,
27584
+ method: "DELETE"
27585
+ });
27586
+ if (!response.ok) failed(registryErrorMessage(response));
27587
+ } catch (er) {
27588
+ failed(asError(er).message);
27589
+ }
27590
+ }
27591
+ } finally {
27592
+ await deleteToken(registry, this.identity);
27477
27593
  }
27478
- await deleteToken(registry, this.identity);
27479
27594
  }
27480
27595
  /**
27481
27596
  * Log into the registry specified.
@@ -27579,11 +27694,19 @@ var RegistryClient = class {
27579
27694
  }
27580
27695
  return await this.#checkLogin(url, options);
27581
27696
  }
27697
+ assertOk(response, {
27698
+ message: "Web login failed",
27699
+ url,
27700
+ advice: (statusCode) => statusCode === 404 ? "This registry does not implement the web login endpoint." : void 0
27701
+ });
27582
27702
  if (response.statusCode === 200) {
27583
27703
  const token = getTokenResponse(response.json());
27584
27704
  if (token) return token;
27585
27705
  }
27586
27706
  throw error("Invalid response from web login endpoint", {
27707
+ code: "EREQUEST",
27708
+ url,
27709
+ status: response.statusCode,
27587
27710
  response
27588
27711
  });
27589
27712
  }
@@ -27641,7 +27764,8 @@ var RegistryClient = class {
27641
27764
  redirections = /* @__PURE__ */ new Set(),
27642
27765
  signal,
27643
27766
  otp = (process.env.VLT_OTP ?? "").trim(),
27644
- staleWhileRevalidate = true
27767
+ staleWhileRevalidate = true,
27768
+ forceRevalidate = false
27645
27769
  } = options;
27646
27770
  let { trustIntegrity } = options;
27647
27771
  const m = isCacheableMethod(method) ? method : void 0;
@@ -27650,12 +27774,18 @@ var RegistryClient = class {
27650
27774
  const key = cacheKey(method, u);
27651
27775
  const buffer = useCache ? await this.cache.fetch(key, { context: { integrity } }) : void 0;
27652
27776
  const entry = buffer ? this.#decodeCached(buffer) : void 0;
27653
- if (entry?.valid) {
27777
+ if (entry?.valid && !forceRevalidate) {
27654
27778
  logRequest(url, "cache", { method });
27655
27779
  return entry;
27656
27780
  }
27657
- if (staleWhileRevalidate && entry?.staleWhileRevalidate && m) {
27658
- register2(dirname3(this.cache.path()), m, url);
27781
+ const forcedFallback = forceRevalidate && entry?.staleWhileRevalidate ? entry : void 0;
27782
+ if (!forceRevalidate && staleWhileRevalidate && entry?.staleWhileRevalidate && m) {
27783
+ register2(
27784
+ dirname3(this.cache.path()),
27785
+ m,
27786
+ url,
27787
+ getHeader(options.headers, "accept")
27788
+ );
27659
27789
  logRequest(url, "stale", { method });
27660
27790
  return entry;
27661
27791
  }
@@ -27700,6 +27830,10 @@ var RegistryClient = class {
27700
27830
  options
27701
27831
  );
27702
27832
  } catch (er) {
27833
+ if (forcedFallback && !signal?.aborted) {
27834
+ logRequest(url, "stale", { method });
27835
+ return forcedFallback;
27836
+ }
27703
27837
  throw error("Request failed", {
27704
27838
  code: "EREQUEST",
27705
27839
  cause: er,
@@ -27728,7 +27862,8 @@ var RegistryClient = class {
27728
27862
  if (result.isGzip && !trustIntegrity) {
27729
27863
  result.checkIntegrity({ url });
27730
27864
  }
27731
- if (useCache) {
27865
+ const clobbersCachedEntry = forceRevalidate && !!entry && result.statusCode !== 200;
27866
+ if (useCache && !clobbersCachedEntry) {
27732
27867
  const buffer2 = result.encode();
27733
27868
  this.cache.set(
27734
27869
  key,
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-WGDTG44V.js";
15
15
  import {
16
16
  commandAliases
17
- } from "./chunk-XISRK3R5.js";
17
+ } from "./chunk-CEHPRPGQ.js";
18
18
  import {
19
19
  loadPackageJson
20
20
  } from "./chunk-E74WGW5C.js";
@@ -11,12 +11,12 @@ import {createRequire as _vlt_createRequire} from "node:module";
11
11
  var require = _vlt_createRequire(import.meta.filename);
12
12
  import {
13
13
  PackageInfoClient
14
- } from "./chunk-HRY5MJCA.js";
14
+ } from "./chunk-CTQSUNNE.js";
15
15
  import {
16
16
  Monorepo,
17
17
  PackageJson,
18
18
  PathScurry
19
- } from "./chunk-USTJECVS.js";
19
+ } from "./chunk-X2AWQGYG.js";
20
20
  import {
21
21
  resetCaches
22
22
  } from "./chunk-YOE3VZFX.js";
@@ -27,7 +27,7 @@ import {
27
27
  getCommand,
28
28
  isRecordField,
29
29
  recordFields
30
- } from "./chunk-XISRK3R5.js";
30
+ } from "./chunk-CEHPRPGQ.js";
31
31
  import {
32
32
  find,
33
33
  load,
@@ -38,6 +38,7 @@ import {
38
38
  assertRecordStringString,
39
39
  assertRecordStringT,
40
40
  getOptions,
41
+ isObject,
41
42
  isRecordStringString
42
43
  } from "./chunk-VFBCWAOC.js";
43
44
  import {
@@ -150,6 +151,7 @@ var assertRegistryKeys = (registries, file) => {
150
151
  for (const key of Object.keys(obj)) {
151
152
  if (key === "" || key.includes("~")) {
152
153
  throw error("Reserved character found in registries name", {
154
+ code: "ECONFIG",
153
155
  path: file,
154
156
  found: key
155
157
  });
@@ -190,6 +192,26 @@ var recordsToPairs = (obj) => {
190
192
  );
191
193
  };
192
194
  var kRecord = /* @__PURE__ */ Symbol("parsed key=value record");
195
+ var envKey = (k) => `VLT_${k.replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}`;
196
+ var kParentEnv = "__VLT_INTERNAL_EXPLICIT";
197
+ var parentEnv = () => {
198
+ try {
199
+ const p = JSON.parse(process.env[kParentEnv] ?? "");
200
+ return isObject(p) && isObject(p.explicit) && Object.entries(p.explicit).every(
201
+ ([k, v]) => isRecordField(k) ? Array.isArray(v) && v.every((x) => typeof x === "string") : !isObject(v)
202
+ ) && isRecordStringString(p.env) ? p : void 0;
203
+ } catch {
204
+ return void 0;
205
+ }
206
+ };
207
+ var dedupePairs = (pairs) => [
208
+ ...new Map(
209
+ pairs.map((p) => {
210
+ const eq = p.indexOf("=");
211
+ return [eq === -1 ? p : p.substring(0, eq), p];
212
+ })
213
+ ).values()
214
+ ];
193
215
  var Config = class _Config {
194
216
  /**
195
217
  * The {@link https://npmjs.com/jackspeak | JackSpeak} object
@@ -308,17 +330,56 @@ var Config = class _Config {
308
330
  parse(args = process.argv) {
309
331
  if (isParsed(this)) return this;
310
332
  this.#originalArgs = [...args];
333
+ const envKeys = Object.keys(defaultValues).filter(
334
+ (k) => process.env[envKey(k)] !== void 0
335
+ );
336
+ const parent = parentEnv();
337
+ const fileValues = this.#defaults();
311
338
  this.jack.loadEnvDefaults();
339
+ const envValues = this.#defaults();
312
340
  const p = this.jack.parseRaw(args);
341
+ const cliKeys = Object.keys(p.values);
313
342
  const fallback = getCommand(p.values["fallback-command"]);
314
343
  this.command = getCommand(p.positionals[0]);
315
344
  const cmdOrFallback = this.command ?? fallback;
316
345
  const cmdSpecific = cmdOrFallback && this.commandValues[cmdOrFallback];
317
- if (cmdSpecific) {
318
- this.jack.setConfigValues(recordsToPairs(cmdSpecific));
319
- }
346
+ const cmdPairs = cmdSpecific ? recordsToPairs(cmdSpecific) : {};
347
+ if (cmdSpecific) this.jack.setConfigValues(cmdPairs);
320
348
  this.jack.applyDefaults(p);
349
+ const values = p.values;
350
+ const explicit = {};
351
+ for (const k of /* @__PURE__ */ new Set([...envKeys, ...cliKeys])) {
352
+ const cli = cliKeys.includes(k) ? values[k] : void 0;
353
+ const env = this.#explicitEnv(k, envValues[k], parent);
354
+ if (isRecordField(k)) {
355
+ const pairs = [
356
+ ...env ?? [],
357
+ ...cli ?? []
358
+ ];
359
+ if (pairs.length) explicit[k] = dedupePairs(pairs);
360
+ } else if (cli !== void 0) explicit[k] = cli;
361
+ else if (env !== void 0 && !(k in cmdPairs))
362
+ explicit[k] = env;
363
+ }
364
+ this.explicit = explicit;
365
+ for (const k of recordFields) {
366
+ const env = envKeys.includes(k) ? envValues[k] : [];
367
+ const cli = cliKeys.includes(k) ? values[k] : [];
368
+ const pairs = [...env, ...cli];
369
+ if (!pairs.length) continue;
370
+ const base = (k in cmdPairs ? cmdPairs[k] : fileValues[k]) ?? [];
371
+ values[k] = dedupePairs([...base, ...pairs]);
372
+ }
321
373
  this.jack.writeEnv(p);
374
+ process.env[kParentEnv] = JSON.stringify({
375
+ explicit,
376
+ env: Object.fromEntries(
377
+ Object.keys(defaultValues).flatMap((k) => {
378
+ const v = process.env[envKey(k)];
379
+ return v === void 0 ? [] : [[envKey(k), v]];
380
+ })
381
+ )
382
+ });
322
383
  if (this.command) p.positionals.shift();
323
384
  else this.command = getCommand(p.values["fallback-command"]);
324
385
  Object.assign(this, p);
@@ -328,6 +389,35 @@ var Config = class _Config {
328
389
  if (!isParsed(this)) throw error("failed to parse config");
329
390
  return this;
330
391
  }
392
+ /**
393
+ * Values set on the command line or via `VLT_*` env for this run.
394
+ * Record fields hold only those `key=value` pairs, not the ones from
395
+ * config files.
396
+ *
397
+ * `VLT_*` env left as a parent vlt process wrote it only counts for
398
+ * what was explicit in that parent.
399
+ */
400
+ explicit = {};
401
+ // a field's explicit env value: all of it at the top level, the new
402
+ // pairs (or changed scalar) when inherited from a parent vlt. once a
403
+ // script changes a record var, the parent's explicit pairs are dropped.
404
+ #explicitEnv(k, value, parent) {
405
+ const cur = process.env[envKey(k)];
406
+ if (cur === void 0) return void 0;
407
+ const written = parent?.env[envKey(k)];
408
+ if (cur === written) return parent?.explicit[k];
409
+ if (!isRecordField(k) || written === void 0) return value;
410
+ const old = new Set(written.split("\n"));
411
+ return value.filter((p) => !old.has(p));
412
+ }
413
+ // the current jack defaults, ie config file (+ env, once loaded) values
414
+ #defaults() {
415
+ const d = { values: {}, positionals: [] };
416
+ this.jack.applyDefaults(
417
+ d
418
+ );
419
+ return d.values;
420
+ }
331
421
  /**
332
422
  * Get a `key=value` list option value as an object.
333
423
  *
@@ -605,8 +695,10 @@ var configWriteTarget = (conf, fallback) => {
605
695
  };
606
696
 
607
697
  export {
698
+ registrySelectors,
608
699
  registrySelectionFields,
609
700
  kCustomInspect,
701
+ assertRegistryKeys,
610
702
  pairsToRecords,
611
703
  recordsToPairs,
612
704
  Config,