@vltpkg/cli-js 1.1.1 → 1.2.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 (82) hide show
  1. package/{access-YYMAAPHV.js → access-FTHPFPUJ.js} +8 -8
  2. package/{bugs-RK5JBPSC.js → bugs-QS6HQUO2.js} +17 -17
  3. package/{build-DVJSYCNF.js → build-H27SXMAS.js} +11 -11
  4. package/{cache-JKQNGZ7L.js → cache-IB4HMFDT.js} +143 -14
  5. package/cache-unzip-src-unzip.js +2934 -164
  6. package/{chunk-BWEH7DHQ.js → chunk-3CUFJPBK.js} +1 -1
  7. package/{chunk-CBASIDQH.js → chunk-55DYW2MP.js} +1 -1
  8. package/{chunk-6FT6K5YN.js → chunk-5BD4QGW2.js} +25 -7
  9. package/{chunk-WE2TQN32.js → chunk-5PP77V44.js} +2 -2
  10. package/{chunk-LN2A74PF.js → chunk-5YB6UIC3.js} +247 -37
  11. package/{chunk-CEHPRPGQ.js → chunk-6A3XS52F.js} +33 -0
  12. package/{chunk-X2AWQGYG.js → chunk-6G7MTZGS.js} +6 -6
  13. package/{chunk-V4YCZZHY.js → chunk-7KFMQ3BR.js} +16 -8
  14. package/{chunk-JZJWASXL.js → chunk-B2FK2HHL.js} +79 -58
  15. package/{chunk-DF5K4CYR.js → chunk-FOJCK57G.js} +5 -5
  16. package/{chunk-GDT6KI4I.js → chunk-FSZF2RSQ.js} +4 -4
  17. package/{chunk-VFBCWAOC.js → chunk-G5BSQ6DP.js} +7 -0
  18. package/{chunk-XKVU23NC.js → chunk-G5NJ7CYI.js} +1 -1
  19. package/{chunk-34TE4HZS.js → chunk-GUATFMMU.js} +2 -2
  20. package/{chunk-YBVTY6ZW.js → chunk-JTUZP2OD.js} +1 -1
  21. package/{chunk-MZA6N2TA.js → chunk-LD4BQJBG.js} +4 -4
  22. package/{chunk-KDF7PEBY.js → chunk-LEGPLJWK.js} +5 -5
  23. package/{chunk-XIF734VO.js → chunk-LKQ5R4VX.js} +4 -4
  24. package/{chunk-DR4Z63B6.js → chunk-NJZSCUD4.js} +3 -3
  25. package/{chunk-2PWSMJD7.js → chunk-O44Z6MAV.js} +1 -1
  26. package/{chunk-DS7YMIHP.js → chunk-OE6VHHN4.js} +135 -36
  27. package/{src-MOKZQTH2.js → chunk-QA6RE2GS.js} +249 -28
  28. package/chunk-SPRVRSEL.js +75 -0
  29. package/{chunk-YOE3VZFX.js → chunk-SYGF27W7.js} +2 -2
  30. package/{chunk-LR42WTKN.js → chunk-UNWQVOLY.js} +14 -12
  31. package/{chunk-SNOBGFNM.js → chunk-UQUIO7LW.js} +47 -6
  32. package/{chunk-QQYTPGIL.js → chunk-VHHLO5L6.js} +1 -1
  33. package/{chunk-3LUM7NX5.js → chunk-YFNQ6HZ3.js} +3 -3
  34. package/{chunk-GDJ7JT2R.js → chunk-YTT3UHUB.js} +1 -1
  35. package/{ci-WVYVR4XK.js → ci-XJBYXFFJ.js} +10 -10
  36. package/cli-package.json +2 -1
  37. package/{config-VYOTYBGS.js → config-4Y46SH5K.js} +8 -8
  38. package/{config-2MFZVP2N.js → config-H2Q4ABSS.js} +12 -12
  39. package/{create-OJPLHBRR.js → create-LUYL2QI4.js} +18 -18
  40. package/{deprecate-V4PKGFF7.js → deprecate-5ANCI2L6.js} +13 -13
  41. package/{dist-tag-DNLV4VDE.js → dist-tag-SD2CRWIL.js} +8 -8
  42. package/{docs-LXHDCGL5.js → docs-B6LVNWTP.js} +17 -17
  43. package/{exec-P32YSP44.js → exec-CJ5KQA72.js} +18 -18
  44. package/{exec-cache-JZ5PDTOY.js → exec-cache-EE7DAOW2.js} +16 -16
  45. package/{exec-local-HHA464H4.js → exec-local-HT3VBN6S.js} +15 -15
  46. package/{help-GVTTOYUL.js → help-GZ44WYDS.js} +4 -4
  47. package/{init-RENGG74N.js → init-HVXRXFVY.js} +10 -10
  48. package/{install-V6VXOBH2.js → install-E2C7EE6P.js} +16 -16
  49. package/{list-7N7Y5OXB.js → list-V4V6SHJP.js} +18 -18
  50. package/{login-D2QSAUJC.js → login-VRFV7MCE.js} +12 -12
  51. package/{logout-QPOYBQNF.js → logout-SU75R7BN.js} +8 -8
  52. package/{pack-4YYGXP3A.js → pack-IVGKUXTL.js} +11 -11
  53. package/package.json +1 -1
  54. package/{ping-QYRIZONU.js → ping-WB222SDT.js} +8 -8
  55. package/{pkg-WQTNABKT.js → pkg-LAAFNONA.js} +11 -11
  56. package/{profile-PRI7WXK7.js → profile-P3AVHRDI.js} +8 -8
  57. package/{publish-PSBYJQS7.js → publish-IUNB3KH5.js} +17 -17
  58. package/{query-UFYLQW4N.js → query-XCN55INS.js} +18 -18
  59. package/{registry-YTJZ3AQD.js → registry-QQLWJHJI.js} +5 -5
  60. package/registry-client-src-revalidate.js +5940 -5804
  61. package/{repo-4S6ETFXX.js → repo-BQDWUCX5.js} +17 -17
  62. package/{reporter-GLWYHI2Y.js → reporter-5BVUNWQ6.js} +13 -13
  63. package/{run-OU7NUB7A.js → run-QT7DX243.js} +15 -15
  64. package/{run-exec-QPBY7ULE.js → run-exec-XYUI7GLN.js} +15 -15
  65. package/security-archive-src-update-expired.js +1 -1
  66. package/{setup-23QXG473.js → setup-CXDJXRAG.js} +18 -18
  67. package/{src-3GN7TDNH.js → src-2BUT4WYP.js} +7 -5
  68. package/src-OKMGXMAD.js +212 -0
  69. package/{src-575IYJOL.js → src-UBAERP25.js} +14 -14
  70. package/{token-FCIA3RGD.js → token-CBOK6DMT.js} +8 -8
  71. package/{uninstall-BQVZVKB5.js → uninstall-27VP46KJ.js} +12 -12
  72. package/{unpublish-YGJ5HEYF.js → unpublish-F4637OQX.js} +8 -8
  73. package/{update-WCGV66JK.js → update-NGWLJJ22.js} +15 -15
  74. package/{version-7EA3UQG7.js → version-WPD2KNVC.js} +13 -13
  75. package/{view-5FWIENVE.js → view-YKFTRRPD.js} +11 -11
  76. package/vlr.js +1 -1
  77. package/vlrx.js +1 -1
  78. package/vlt.js +1 -1
  79. package/vlx.js +1 -1
  80. package/vlxl.js +1 -1
  81. package/{whoami-O4ZTBIC4.js → whoami-I5Q6RTAP.js} +8 -8
  82. package/chunk-WD74RJXW.js +0 -75
@@ -14,24 +14,28 @@ import {
14
14
  } from "./chunk-APMYKJI2.js";
15
15
  import {
16
16
  assertOk,
17
- registryErrorMessage
18
- } from "./chunk-SNOBGFNM.js";
17
+ registryErrorMessage,
18
+ storeRoot,
19
+ tokenRefusal
20
+ } from "./chunk-UQUIO7LW.js";
19
21
  import {
20
22
  userAgent
21
- } from "./chunk-YBVTY6ZW.js";
23
+ } from "./chunk-JTUZP2OD.js";
22
24
  import {
23
25
  I,
24
26
  logRequest
25
27
  } from "./chunk-U7TEQCBN.js";
26
- import {
27
- asError
28
- } from "./chunk-VFBCWAOC.js";
29
28
  import {
30
29
  XDG
31
30
  } from "./chunk-XNLSTHDK.js";
32
31
  import {
33
32
  rimraf
34
33
  } from "./chunk-BHJT53TP.js";
34
+ import {
35
+ asError,
36
+ integrityHex,
37
+ integrityRE
38
+ } from "./chunk-G5BSQ6DP.js";
35
39
  import {
36
40
  error
37
41
  } from "./chunk-WZWDS3W4.js";
@@ -25805,6 +25809,7 @@ var Cache = class _Cache extends I {
25805
25809
  #pending = /* @__PURE__ */ new Set();
25806
25810
  onDiskWrite;
25807
25811
  onDiskDelete;
25812
+ store;
25808
25813
  /**
25809
25814
  * A list of the actions currently happening in the background
25810
25815
  */
@@ -25823,6 +25828,7 @@ var Cache = class _Cache extends I {
25823
25828
  onDiskWrite,
25824
25829
  onDiskDelete,
25825
25830
  path,
25831
+ store,
25826
25832
  fetchMethod: _,
25827
25833
  sizeCalculation = options.maxSize || options.maxEntrySize ? (v, k) => v.length + k.length : void 0,
25828
25834
  ...lruOpts
@@ -25846,6 +25852,7 @@ var Cache = class _Cache extends I {
25846
25852
  });
25847
25853
  this.onDiskWrite = onDiskWrite;
25848
25854
  this.onDiskDelete = onDiskDelete;
25855
+ this.store = store;
25849
25856
  this.#path = path;
25850
25857
  }
25851
25858
  /**
@@ -25971,16 +25978,14 @@ var Cache = class _Cache extends I {
25971
25978
  */
25972
25979
  integrityPath(integrity) {
25973
25980
  if (!integrity) return void 0;
25974
- const m = /^sha512-([a-zA-Z0-9/+]{86}==)$/.exec(integrity);
25975
- const hash2 = m?.[1];
25976
- if (!hash2) {
25981
+ const hex = integrityHex(integrity);
25982
+ if (!hex) {
25977
25983
  throw error("invalid integrity value", {
25978
25984
  found: integrity,
25979
- wanted: /^sha512-([a-zA-Z0-9/+]{86}==)$/
25985
+ wanted: integrityRE
25980
25986
  });
25981
25987
  }
25982
- const base = Buffer.from(hash2, "base64").toString("hex");
25983
- return resolve(this.#path, base);
25988
+ return resolve(this.#path, hex);
25984
25989
  }
25985
25990
  /**
25986
25991
  * Read synchronously from the fs cache storage if not already
@@ -26007,13 +26012,20 @@ var Cache = class _Cache extends I {
26007
26012
  }
26008
26013
  /* c8 ignore stop */
26009
26014
  /**
26010
- * Delete path and path + '.key'
26015
+ * Delete path and path + '.key', and with an integrity, its
26016
+ * integrity link and global store entry
26011
26017
  */
26012
26018
  async #diskDelete(path, integrity) {
26013
- const intPath = this.#maybeIntegrityPath(integrity);
26014
26019
  const paths = [path, path + ".key"];
26015
- if (intPath) paths.push(intPath);
26016
- return await rimraf(paths);
26020
+ const hex = integrityHex(integrity);
26021
+ if (hex) paths.push(resolve(this.#path, hex));
26022
+ const deleted = await rimraf(paths);
26023
+ if (hex && this.store) {
26024
+ const entry = resolve(this.store, hex);
26025
+ await rimraf(entry);
26026
+ await rimraf([entry + ".json", entry + ".copied"]);
26027
+ }
26028
+ return deleted;
26017
26029
  }
26018
26030
  #maybeIntegrityPath(i) {
26019
26031
  try {
@@ -26090,9 +26102,10 @@ var __CODE_SPLIT_SCRIPT_NAME = resolve2(import.meta.dirname, "cache-unzip-src-un
26090
26102
  var isDeno = globalThis.Deno != void 0;
26091
26103
  var didProcessBeforeExitHook = false;
26092
26104
  var registered = /* @__PURE__ */ new Map();
26093
- var register = (path, key) => {
26094
- const r = registered.get(path) ?? /* @__PURE__ */ new Set();
26095
- r.add(key);
26105
+ var register = (path, key, store, integrity) => {
26106
+ const r = registered.get(path) ?? { keys: /* @__PURE__ */ new Map() };
26107
+ r.keys.set(key, integrity ?? r.keys.get(key));
26108
+ r.store ??= store;
26096
26109
  registered.set(path, r);
26097
26110
  if (!didProcessBeforeExitHook) {
26098
26111
  didProcessBeforeExitHook = true;
@@ -26101,8 +26114,8 @@ var register = (path, key) => {
26101
26114
  };
26102
26115
  var handleBeforeExit = () => {
26103
26116
  const compileCacheDir = module.getCompileCacheDir();
26104
- for (const [path, r] of registered) {
26105
- if (!r.size) return;
26117
+ for (const [path, { keys, store }] of registered) {
26118
+ if (!keys.size) return;
26106
26119
  const env = { ...process.env };
26107
26120
  if (compileCacheDir) env.NODE_COMPILE_CACHE ??= compileCacheDir;
26108
26121
  const args = [];
@@ -26114,14 +26127,17 @@ var handleBeforeExit = () => {
26114
26127
  );
26115
26128
  }
26116
26129
  args.push(__CODE_SPLIT_SCRIPT_NAME, path);
26130
+ if (store) args.push(store);
26117
26131
  registered.delete(path);
26118
26132
  const proc2 = spawn(process.execPath, args, {
26119
26133
  detached,
26120
26134
  stdio: ["pipe", "ignore", "ignore"],
26121
26135
  env
26122
26136
  });
26123
- for (const key of r) {
26124
- proc2.stdin.write(`${key}\0`);
26137
+ for (const [key, integrity] of keys) {
26138
+ proc2.stdin.write(
26139
+ integrity ? `${key} ${integrity}\0` : `${key}\0`
26140
+ );
26125
26141
  }
26126
26142
  proc2.stdin.end();
26127
26143
  if (detached) {
@@ -26630,8 +26646,9 @@ var CacheEntry = class _CacheEntry {
26630
26646
  * This method **will throw** if the integrity values do not match.
26631
26647
  *
26632
26648
  * Note that this will *usually* not be true if the value is coming out of
26633
- * the cache, because the cache entries are un-gzipped in place. It should
26634
- * _only_ be called for artifacts that come from an actual http response.
26649
+ * the cache, because cache entries not exploded into the global store are
26650
+ * un-gzipped in place. It should _only_ be called for artifacts that come
26651
+ * from an actual http response.
26635
26652
  *
26636
26653
  * Returns true if anything was actually verified.
26637
26654
  */
@@ -26648,6 +26665,29 @@ var CacheEntry = class _CacheEntry {
26648
26665
  }
26649
26666
  return true;
26650
26667
  }
26668
+ /**
26669
+ * Check the body against the RFC 9530 digest the server sent with it,
26670
+ * for a response that had no expected integrity. A registry that omits
26671
+ * `dist.integrity` labels every tarball, so a missing digest fails when
26672
+ * `required`. Like {@link checkIntegrity}, only for an actual http
26673
+ * response: cached bodies are un-gzipped in place.
26674
+ *
26675
+ * **Will throw** on a mismatch. Returns the hash of the body.
26676
+ */
26677
+ checkDigest(required, context = {}) {
26678
+ const computed = this.integrityActual;
26679
+ const { digest } = this;
26680
+ if (digest ? digest !== computed : required) {
26681
+ throw error("Integrity check failure", {
26682
+ code: "EINTEGRITY",
26683
+ response: this,
26684
+ wanted: digest,
26685
+ found: computed,
26686
+ ...context
26687
+ });
26688
+ }
26689
+ return computed;
26690
+ }
26651
26691
  get integrityActual() {
26652
26692
  if (this.#integrityActual) return this.#integrityActual;
26653
26693
  const hash2 = createHash2("sha512");
@@ -26669,6 +26709,16 @@ var CacheEntry = class _CacheEntry {
26669
26709
  get integrity() {
26670
26710
  return this.#integrity;
26671
26711
  }
26712
+ /**
26713
+ * The sha-512 member of an RFC 9530 `Repr-Digest` (or `Content-Digest`)
26714
+ * response header, as an SRI string. A registry that serves packuments
26715
+ * without `dist.integrity` labels each tarball this way instead.
26716
+ */
26717
+ get digest() {
26718
+ const value = this.getHeaderString("repr-digest") ?? this.getHeaderString("content-digest");
26719
+ const m = value && /(?:^|,)\s*sha-512=:([A-Za-z0-9+/]{86}==):/.exec(value);
26720
+ return m ? `sha512-${m[1]}` : void 0;
26721
+ }
26672
26722
  /**
26673
26723
  * Give it a key, and it'll return the buffer of that header value
26674
26724
  */
@@ -26690,6 +26740,19 @@ var CacheEntry = class _CacheEntry {
26690
26740
  setHeader(h, value) {
26691
26741
  this.#headers = setRawHeader(this.#headers, h, value);
26692
26742
  }
26743
+ /**
26744
+ * Remove a header, if present
26745
+ */
26746
+ deleteHeader(h) {
26747
+ const key = h.toLowerCase();
26748
+ for (let i = 0; i < this.#headers.length; i += 2) {
26749
+ const k = this.#headers[i];
26750
+ if (k && getDecodedValue(k).toLowerCase() === key) {
26751
+ this.#headers.splice(i, 2);
26752
+ return;
26753
+ }
26754
+ }
26755
+ }
26693
26756
  /**
26694
26757
  * Return the body of the entry as a Buffer
26695
26758
  */
@@ -26869,6 +26932,16 @@ var CacheEntry = class _CacheEntry {
26869
26932
  const gzipBytes = buffer.subarray(headSize, headSize + 2);
26870
26933
  return gzipBytes[0] === 31 && gzipBytes[1] === 139;
26871
26934
  }
26935
+ /**
26936
+ * Head-only check for a 200 non-JSON body with an integrity header,
26937
+ * i.e. a tarball the global store can be built from.
26938
+ */
26939
+ static isTarballEntry(buffer) {
26940
+ const parsed = _CacheEntry.#parseHead(buffer);
26941
+ if (parsed?.statusCode !== 200 || !parsed.integrity) return false;
26942
+ const ct = getRawHeader(parsed.headers, "content-type");
26943
+ return !ct || !/\bjson\b/.test(getDecodedValue(ct));
26944
+ }
26872
26945
  /**
26873
26946
  * Encode status + headers (no body) as they appear at the start of
26874
26947
  * an on-disk cache file.
@@ -27115,6 +27188,10 @@ var otplease = async (client, options, response) => {
27115
27188
  });
27116
27189
  }
27117
27190
  if (wwwAuth.has("bearer")) {
27191
+ const text2 = await responseBodyText(response).catch(() => "");
27192
+ if (tokenRefusal({ statusCode: 401, text: () => text2 })) {
27193
+ return { bodyConsumed: text2 };
27194
+ }
27118
27195
  throw error(
27119
27196
  "Missing or invalid authentication token. Run `vlt login` or `vlt token add` to authenticate.",
27120
27197
  {
@@ -27449,12 +27526,14 @@ var RegistryClient = class {
27449
27526
  this.identity = identity;
27450
27527
  this.staleWhileRevalidateFactor = staleWhileRevalidateFactor;
27451
27528
  const path = resolve4(cache, "registry-client");
27529
+ const store = options.storeRoot ?? storeRoot(cache);
27452
27530
  this.cache = new Cache({
27453
27531
  path,
27532
+ store,
27454
27533
  maxSize: parseCacheMaxSize(process.env.VLT_CACHE_MAX_SIZE),
27455
27534
  onDiskWrite(_path, key, data) {
27456
- if (CacheEntry.isGzipEntry(data)) {
27457
- register(path, key);
27535
+ if (CacheEntry.isGzipEntry(data) || CacheEntry.isTarballEntry(data)) {
27536
+ register(path, key, store);
27458
27537
  }
27459
27538
  }
27460
27539
  });
@@ -27728,12 +27807,32 @@ var RegistryClient = class {
27728
27807
  if (entry.statusCode !== 200 || !entry.valid || entry.isJSON) {
27729
27808
  continue;
27730
27809
  }
27731
- return { path, body: entry.buffer() };
27810
+ return {
27811
+ path,
27812
+ key,
27813
+ body: entry.buffer(),
27814
+ integrity: entry.integrity,
27815
+ gzip: CacheEntry.isGzipEntry(buf)
27816
+ };
27732
27817
  }
27733
27818
  } catch {
27734
27819
  }
27735
27820
  return void 0;
27736
27821
  }
27822
+ /**
27823
+ * Queue the cached tarball at `key` (a {@link CachedBody} key) for the
27824
+ * background child: exploded into the global store when that is on,
27825
+ * else un-gzipped. `integrity` finds it when only the integrity path
27826
+ * holds it.
27827
+ */
27828
+ queueForStore(key, integrity) {
27829
+ register(
27830
+ this.cache.path(),
27831
+ key,
27832
+ this.cache.store,
27833
+ integrity
27834
+ );
27835
+ }
27737
27836
  async request(url, options = {}) {
27738
27837
  const u = typeof url === "string" ? new URL(url) : url;
27739
27838
  const {
@@ -27745,7 +27844,7 @@ var RegistryClient = class {
27745
27844
  staleWhileRevalidate = true,
27746
27845
  forceRevalidate = false
27747
27846
  } = options;
27748
- let { trustIntegrity } = options;
27847
+ const { trustIntegrity, verifyDigest } = options;
27749
27848
  const m = isCacheableMethod(method) ? method : void 0;
27750
27849
  const { useCache = !!m } = options;
27751
27850
  signal?.throwIfAborted();
@@ -27837,14 +27936,16 @@ var RegistryClient = class {
27837
27936
  durationMs: Date.now() - requestStart
27838
27937
  }
27839
27938
  );
27840
- if (result.getHeader("integrity")) {
27841
- trustIntegrity = true;
27939
+ if (!trustIntegrity && !result.fromCache) {
27940
+ result.deleteHeader("integrity");
27941
+ if (result.isGzip) result.checkIntegrity({ url });
27842
27942
  }
27843
- if (result.isGzip && !trustIntegrity) {
27844
- result.checkIntegrity({ url });
27943
+ if (verifyDigest && !integrity && !result.fromCache && result.statusCode === 200) {
27944
+ result.checkDigest(verifyDigest === "required", { url });
27845
27945
  }
27846
27946
  const clobbersCachedEntry = forceRevalidate && !!entry && result.statusCode !== 200;
27847
27947
  if (useCache && !clobbersCachedEntry) {
27948
+ const integrity2 = result.integrity ?? (result.statusCode === 200 && !result.isJSON ? result.integrityActual : void 0);
27848
27949
  const buffer2 = result.encode();
27849
27950
  this.cache.set(
27850
27951
  key,
@@ -27853,9 +27954,7 @@ var RegistryClient = class {
27853
27954
  buffer2.byteOffset,
27854
27955
  buffer2.byteLength
27855
27956
  ),
27856
- {
27857
- integrity: result.integrity
27858
- }
27957
+ { integrity: integrity2 }
27859
27958
  );
27860
27959
  }
27861
27960
  return result;
@@ -13,19 +13,78 @@ import {
13
13
  rimraf,
14
14
  rimrafSync
15
15
  } from "./chunk-BHJT53TP.js";
16
- import "./chunk-VE6CCH33.js";
16
+ import {
17
+ isManifest,
18
+ normalizeBinPaths
19
+ } from "./chunk-G5BSQ6DP.js";
17
20
  import {
18
21
  error
19
22
  } from "./chunk-WZWDS3W4.js";
20
- import "./chunk-PZLD7RTK.js";
23
+
24
+ // ../../src/tar/src/store-index.ts
25
+ import { readFileSync } from "node:fs";
26
+ import { debuglog } from "node:util";
27
+ var debug = debuglog("vlt");
28
+ var storeIndexPath = (storeEntry) => storeEntry + ".json";
29
+ var isRecord = (x) => !!x && typeof x === "object" && !Array.isArray(x);
30
+ var isOptString = (x) => x === void 0 || typeof x === "string";
31
+ var unsafePath = /(?:^|\/)\.{0,2}(?:\/|$)|\\/;
32
+ var isRelPath = (p) => typeof p === "string" && !unsafePath.test(p);
33
+ var isIndexFile = (f) => Array.isArray(f) && f.length === 3 && isRelPath(f[0]) && typeof f[1] === "number" && (f[2] === 0 || f[2] === 1);
34
+ var isStoreIndex = (x) => isRecord(x) && x.v === 1 && typeof x.scripts === "boolean" && isOptString(x.name) && isOptString(x.version) && (x.bins === void 0 || isRecord(x.bins) && Object.values(x.bins).every((b) => typeof b === "string")) && Array.isArray(x.dirs) && x.dirs.every(isRelPath) && Array.isArray(x.files) && x.files.every(isIndexFile) && isOptString(x.manifest);
35
+ var readStoreIndex = (storeEntry) => {
36
+ let index;
37
+ try {
38
+ index = JSON.parse(
39
+ readFileSync(storeIndexPath(storeEntry), "utf8")
40
+ );
41
+ } catch (er) {
42
+ if (er.code !== "ENOENT") {
43
+ debug("global store: invalid index", storeEntry);
44
+ }
45
+ return void 0;
46
+ }
47
+ if (isStoreIndex(index)) return index;
48
+ debug("global store: invalid index", storeEntry);
49
+ return void 0;
50
+ };
51
+ var storeIndexManifest = (packageJson, bindingGyp) => {
52
+ let pkg;
53
+ try {
54
+ pkg = JSON.parse(
55
+ packageJson.toString("utf8").replace(/^\uFEFF/, "")
56
+ );
57
+ } catch (cause) {
58
+ throw error("invalid package.json in tarball", { cause });
59
+ }
60
+ if (!isRecord(pkg)) {
61
+ throw error("invalid package.json in tarball", { found: pkg });
62
+ }
63
+ const { name: name2, version, scripts, bin } = pkg;
64
+ const s = isRecord(scripts) ? scripts : {};
65
+ const result = {
66
+ scripts: !!(s.install || s.preinstall || s.postinstall) || bindingGyp
67
+ };
68
+ const bins = normalizeBinPaths({
69
+ name: typeof name2 === "string" ? name2 : void 0,
70
+ bin
71
+ });
72
+ if (bins && Object.keys(bins).length) result.bins = bins;
73
+ if (typeof name2 === "string") result.name = name2;
74
+ if (typeof version === "string") result.version = version;
75
+ if (isManifest(pkg)) result.manifest = JSON.stringify(pkg);
76
+ return result;
77
+ };
21
78
 
22
79
  // ../../src/tar/src/unpack.ts
23
80
  import { randomBytes } from "node:crypto";
24
81
  import {
82
+ chmodSync,
25
83
  lstatSync,
26
84
  mkdirSync,
27
- readFileSync,
85
+ readFileSync as readFileSync2,
28
86
  renameSync,
87
+ statSync,
29
88
  writeFileSync
30
89
  } from "node:fs";
31
90
  import { lstat, mkdir, rename, writeFile } from "node:fs/promises";
@@ -33,6 +92,7 @@ import {
33
92
  basename as basename2,
34
93
  dirname,
35
94
  isAbsolute,
95
+ join,
36
96
  relative,
37
97
  resolve,
38
98
  sep
@@ -688,7 +748,7 @@ var unpackSync = (tarData, target) => {
688
748
  const isGzip = tarData[0] === 31 && tarData[1] === 139;
689
749
  unpackUnzippedSync(isGzip ? unzipSync(tarData) : tarData, target);
690
750
  };
691
- var unpackFileSync = (file, target, offset = 0) => unpackSync(readFileSync(file).subarray(offset), target);
751
+ var unpackFileSync = (file, target, offset = 0) => unpackSync(readFileSync2(file).subarray(offset), target);
692
752
  var tmpName = (target) => dirname(target) + sep + "." + basename2(target) + "." + tmpSuffix();
693
753
  var parseTarball = (buffer, tmp2) => {
694
754
  const isGzip = buffer[0] === 31 && buffer[1] === 139;
@@ -863,32 +923,193 @@ var unpackUnzippedSync = (buffer, target) => {
863
923
  }
864
924
  }
865
925
  };
926
+ var storeLayout = (tarData, dir) => {
927
+ const isGzip = tarData[0] === 31 && tarData[1] === 139;
928
+ const { dirs, files } = parseTarball(
929
+ isGzip ? unzipSync(tarData) : tarData,
930
+ dir
931
+ );
932
+ const rel = (p) => relative(dir, p).replace(/\\/g, "/");
933
+ const list = files.map((f) => [rel(f.path), f]);
934
+ const pj = list.find(([p]) => p === "package.json")?.[1];
935
+ if (!pj) throw error("no package.json in tarball", { path: dir });
936
+ const manifest = storeIndexManifest(
937
+ pj.body,
938
+ list.some(([p]) => p === "binding.gyp")
939
+ );
940
+ const bins = new Set(
941
+ Object.values(manifest.bins ?? {}).map(entryKey)
942
+ );
943
+ const indexFiles = [];
944
+ const binFiles = [];
945
+ for (const [p, f] of list) {
946
+ if (bins.has(entryKey(p))) {
947
+ f.executable = true;
948
+ binFiles.push(f.path);
949
+ }
950
+ indexFiles.push([p, f.body.length, f.executable ? 1 : 0]);
951
+ }
952
+ const allDirs = /* @__PURE__ */ new Set();
953
+ for (const d of dirs) {
954
+ for (let p = rel(d); p && !allDirs.has(p); ) {
955
+ allDirs.add(p);
956
+ p = p.slice(0, Math.max(0, p.lastIndexOf("/")));
957
+ }
958
+ }
959
+ const indexDirs = [...allDirs].sort().sort((a, b) => a.length - b.length);
960
+ return {
961
+ index: {
962
+ v: 1,
963
+ files: indexFiles.sort((a, b) => a[0] < b[0] ? -1 : 1),
964
+ dirs: indexDirs,
965
+ ...manifest
966
+ },
967
+ files,
968
+ binFiles
969
+ };
970
+ };
971
+ var unpackToStoreSync = (tarData, dir) => {
972
+ const { index, files, binFiles } = storeLayout(tarData, dir);
973
+ mkdirSync(dirname(dir), { recursive: true });
974
+ mkdirSync(dir, { mode: 511 });
975
+ let succeeded = false;
976
+ try {
977
+ for (const d of index.dirs) {
978
+ mkdirSync(join(dir, d), { recursive: true, mode: 511 });
979
+ }
980
+ for (const f of files) {
981
+ writeFileSync(f.path, f.body, {
982
+ mode: f.executable ? 511 : 438
983
+ });
984
+ }
985
+ let binMode = 0;
986
+ for (const p of binFiles) {
987
+ binMode ||= statSync(p).mode & 511 | 73;
988
+ chmodSync(p, binMode);
989
+ }
990
+ succeeded = true;
991
+ } finally {
992
+ if (!succeeded) rimrafSync(dir);
993
+ }
994
+ return { index };
995
+ };
866
996
 
867
- // ../../src/tar/src/pool.ts
868
- import { readFile } from "node:fs/promises";
869
- var syncUnpack = process.env.VLT_TAR_SYNC !== "0";
870
- var Pool = class {
871
- /**
872
- * Provide the tardata to be unpacked, and the location where it's to be
873
- * placed. Resolves when the tarball has been extracted.
874
- */
875
- async unpack(tarData, target) {
876
- if (!syncUnpack) return unpack(tarData, target);
877
- unpackSync(tarData, target);
878
- }
879
- /**
880
- * Same, reading the tarball from a file and skipping `offset` leading
881
- * bytes, so a cache entry is unpacked without loading it into the
882
- * registry client's in-memory cache.
883
- */
884
- async unpackFile(file, target, offset = 0) {
885
- if (!syncUnpack) {
886
- return unpack((await readFile(file)).subarray(offset), target);
887
- }
888
- unpackFileSync(file, target, offset);
997
+ // ../../src/tar/src/store-entry.ts
998
+ import {
999
+ closeSync,
1000
+ lstatSync as lstatSync2,
1001
+ openSync,
1002
+ readdirSync,
1003
+ readFileSync as readFileSync3,
1004
+ statSync as statSync2
1005
+ } from "node:fs";
1006
+ import { join as join2, relative as relative2 } from "node:path";
1007
+ import { isDeepStrictEqual } from "node:util";
1008
+ var noThrow = { throwIfNoEntry: false };
1009
+ var entryName = /^([0-9a-f]{128})(?:\.json|\.copied)?$/;
1010
+ var relPath = (from, to) => relative2(from, to).replace(/\\/g, "/");
1011
+ var storeEntryNames = (root) => {
1012
+ let names;
1013
+ try {
1014
+ names = readdirSync(root);
1015
+ } catch {
1016
+ return [];
1017
+ }
1018
+ const hexes = /* @__PURE__ */ new Set();
1019
+ for (const name2 of names) {
1020
+ const hex = entryName.exec(name2)?.[1];
1021
+ if (hex) hexes.add(hex);
1022
+ }
1023
+ return [...hexes].sort();
1024
+ };
1025
+ var storeCopiedPath = (storeEntry) => storeEntry + ".copied";
1026
+ var markStoreEntryCopied = (storeEntry) => {
1027
+ try {
1028
+ closeSync(openSync(storeCopiedPath(storeEntry), "wx"));
1029
+ } catch {
889
1030
  }
890
1031
  };
1032
+ var removeStoreEntry = (storeEntry) => {
1033
+ rimrafSync(storeEntry);
1034
+ rimrafSync(storeIndexPath(storeEntry));
1035
+ rimrafSync(storeCopiedPath(storeEntry));
1036
+ };
1037
+ var storeEntryTime = (storeEntry) => (statSync2(storeIndexPath(storeEntry), noThrow) ?? statSync2(storeEntry, noThrow))?.mtimeMs ?? 0;
1038
+ var storeEntryCopied = (storeEntry, index = readStoreIndex(storeEntry)) => !!index && (index.scripts || !!lstatSync2(storeCopiedPath(storeEntry), noThrow)) && !!lstatSync2(storeEntry, noThrow)?.isDirectory();
1039
+ var storeEntryLinked = (storeEntry, index = readStoreIndex(storeEntry)) => !!index?.files.some(
1040
+ ([p]) => (lstatSync2(join2(storeEntry, p), noThrow)?.nlink ?? 1) > 1
1041
+ );
1042
+ var indexKeys = [
1043
+ "v",
1044
+ "files",
1045
+ "dirs",
1046
+ "scripts",
1047
+ "bins",
1048
+ "name",
1049
+ "version"
1050
+ ];
1051
+ var verifyStoreEntry = (storeEntry, tarData) => {
1052
+ let layout;
1053
+ try {
1054
+ layout = storeLayout(tarData, storeEntry);
1055
+ } catch {
1056
+ return "bad tarball";
1057
+ }
1058
+ const index = readStoreIndex(storeEntry);
1059
+ if (!index) return "no index";
1060
+ if (indexKeys.some(
1061
+ (k) => !isDeepStrictEqual(index[k], layout.index[k])
1062
+ ) || index.manifest !== void 0 && index.manifest !== layout.index.manifest) {
1063
+ return "index differs";
1064
+ }
1065
+ const found = /* @__PURE__ */ new Set();
1066
+ try {
1067
+ for (const d of readdirSync(storeEntry, {
1068
+ recursive: true,
1069
+ withFileTypes: true
1070
+ })) {
1071
+ if (!d.isDirectory()) {
1072
+ found.add(relPath(storeEntry, join2(d.parentPath, d.name)));
1073
+ }
1074
+ }
1075
+ } catch {
1076
+ return "missing";
1077
+ }
1078
+ const modes = process.platform !== "win32";
1079
+ for (const f of layout.files) {
1080
+ const p = relPath(storeEntry, f.path);
1081
+ if (!found.delete(p)) return `missing ${p}`;
1082
+ let body;
1083
+ let mode;
1084
+ try {
1085
+ mode = statSync2(f.path).mode;
1086
+ body = readFileSync3(f.path);
1087
+ } catch {
1088
+ return `unreadable ${p}`;
1089
+ }
1090
+ if (!body.equals(f.body)) return `modified ${p}`;
1091
+ if (modes && (mode & 73) !== 0 !== f.executable) {
1092
+ return `mode ${p}`;
1093
+ }
1094
+ }
1095
+ const [extra] = found;
1096
+ return extra === void 0 ? void 0 : `extra ${extra}`;
1097
+ };
1098
+
891
1099
  export {
892
- Pool,
893
- unpack
1100
+ storeIndexPath,
1101
+ readStoreIndex,
1102
+ unpack,
1103
+ unpackSync,
1104
+ unpackFileSync,
1105
+ tmpName,
1106
+ unpackToStoreSync,
1107
+ storeEntryNames,
1108
+ storeCopiedPath,
1109
+ markStoreEntryCopied,
1110
+ removeStoreEntry,
1111
+ storeEntryTime,
1112
+ storeEntryCopied,
1113
+ storeEntryLinked,
1114
+ verifyStoreEntry
894
1115
  };