@vltpkg/tar 0.0.0-3 → 0.0.0-31

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/README.md CHANGED
@@ -2,26 +2,27 @@
2
2
 
3
3
  # @vltpkg/tar
4
4
 
5
- A library for unpacking JavaScript package tarballs (gzip-compressed or raw) into a specified folder.
5
+ A library for unpacking JavaScript package tarballs (gzip-compressed
6
+ or raw) into a specified folder.
6
7
 
7
- **[Usage](#usage)**
8
- ·
9
- **[Caveats](#caveats)**
8
+ **[Usage](#usage)** · **[Caveats](#caveats)**
10
9
 
11
10
  ## Overview
12
11
 
13
- If you are unpacking anything other than npm packages, in precisely the way that [vlt](https://vlt.sh) does, then this is
14
- probably not what you're looking for.
12
+ If you are unpacking anything other than npm packages, in precisely
13
+ the way that [vlt](https://vlt.sh) does, then this is probably not
14
+ what you're looking for.
15
15
 
16
- For a very complete and battle-tested generic tar implementation in JavaScript, see [node-tar](http://npm.im/tar).
16
+ For a very complete and battle-tested generic tar implementation in
17
+ JavaScript, see [node-tar](http://npm.im/tar).
17
18
 
18
19
  ## Usage
19
20
 
20
21
  ### unpack(tarData, targetFolder)
21
22
 
22
23
  Pass your gzip-compressed or raw uncompressed JavaScript package
23
- tarball in a Buffer (or Uint8Array, or ArrayBuffer slice) into
24
- the function, along with the folder you want to drop it in.
24
+ tarball in a Buffer (or Uint8Array, or ArrayBuffer slice) into the
25
+ function, along with the folder you want to drop it in.
25
26
 
26
27
  It will unpack as fast as possible, using synchronous I/O.
27
28
 
@@ -38,14 +39,13 @@ unpack(unzipped, 'node_modules/target')
38
39
 
39
40
  ### `class Pool`
40
41
 
41
- Create a pool of worker threads which will service unpack
42
- requests in parallel.
42
+ Create a pool of worker threads which will service unpack requests in
43
+ parallel.
43
44
 
44
45
  New requests that get added will be assigned to workers as those
45
- workers become available. When a worker completes its task, and
46
- there are no more tasks to assign, it is terminated. If not
47
- enough workers are available to service requests, then new ones
48
- will be spawned.
46
+ workers become available. When a worker completes its task, and there
47
+ are no more tasks to assign, it is terminated. If not enough workers
48
+ are available to service requests, then new ones will be spawned.
49
49
 
50
50
  #### `pool.jobs`
51
51
 
@@ -66,29 +66,27 @@ completed.
66
66
 
67
67
  #### `pool.unpack(tarData: Buffer, target: string) => Promise<void>`
68
68
 
69
- Unpack the supplied Buffer of data into the target folder,
70
- using synchronous I/O in a worker thread.
69
+ Unpack the supplied Buffer of data into the target folder, using
70
+ synchronous I/O in a worker thread.
71
71
 
72
72
  Promise resolves when this unpack request has been completed.
73
73
 
74
74
  ## Caveats
75
75
 
76
- As stated above, **this is not a general purpose tar
77
- implementation**. It does not handle symbolic links at all (those
78
- aren't allowed in JavaScript packages). It does not respect
79
- uid/gid ownership flags. All files are with a mode of `0o644` (or
80
- `0o666` on Windows - technically it's `0o666` xor'ed with the
81
- system umask, so that'll often be `0o664` on linux systems). All
82
- directories are created with a mode of `0o755` by default (with
83
- the same windows/umask caveats as files, so maybe that's `0o775`
84
- or some such.) All ctime/mtime/atime/birthtime values will just
85
- be left as the current time.
86
-
87
- It does not do any of the binary linking or other stuff that a
88
- package manager will need to do. It _just_ does the unpack, as
89
- ruthlessly fast as possible, and that's all.
90
-
91
- Synchronous IO is used because that's faster and requires less
92
- CPU utilization. The `Pool` class manages multiple worker threads
93
- doing this work, so faster sync IO for the whole thing is much
94
- more optimal.
76
+ As stated above, **this is not a general purpose tar implementation**.
77
+ It does not handle symbolic links at all (those aren't allowed in
78
+ JavaScript packages). It does not respect uid/gid ownership flags. All
79
+ files are with a mode of `0o644` (or `0o666` on Windows - technically
80
+ it's `0o666` xor'ed with the system umask, so that'll often be `0o664`
81
+ on linux systems). All directories are created with a mode of `0o755`
82
+ by default (with the same windows/umask caveats as files, so maybe
83
+ that's `0o775` or some such.) All ctime/mtime/atime/birthtime values
84
+ will just be left as the current time.
85
+
86
+ It does not do any of the binary linking or other stuff that a package
87
+ manager will need to do. It _just_ does the unpack, as ruthlessly fast
88
+ as possible, and that's all.
89
+
90
+ Synchronous IO is used because that's faster and requires less CPU
91
+ utilization. The `Pool` class manages multiple worker threads doing
92
+ this work, so faster sync IO for the whole thing is much more optimal.
@@ -1 +1 @@
1
- {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/pool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAgB,MAAM,EAAE,MAAM,aAAa,CAAA;AAGlD,cAAc,aAAa,CAAA;AAE3B;;;;;;;GAOG;AACH,qBAAa,IAAI;;IACf;;;OAGG;IAEH,IAAI,EAAE,MAAM,CAAmD;IAC/D;;OAEG;IACH,OAAO,cAAoB;IAC3B;;OAEG;IACH,KAAK,EAAE,aAAa,EAAE,CAAK;IAC3B;;;OAGG;IACH,OAAO,6BAAmC;IAyC1C;;;;;;OAMG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAU7C"}
1
+ {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/pool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAgB,MAAM,EAAE,MAAM,aAAa,CAAA;AAGlD,cAAc,aAAa,CAAA;AAE3B;;;;;;;GAOG;AACH,qBAAa,IAAI;;IACf;;;OAGG;IAEH,IAAI,EAAE,MAAM,CAAmD;IAC/D;;OAEG;IACH,OAAO,cAAoB;IAC3B;;OAEG;IACH,KAAK,EAAE,aAAa,EAAE,CAAK;IAC3B;;;OAGG;IACH,OAAO,6BAAmC;IA0C1C;;;;;;OAMG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAU7C"}
package/dist/esm/pool.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { error } from '@vltpkg/error-cause';
2
- import os from 'os';
2
+ import { asError } from '@vltpkg/types';
3
+ import os from 'node:os';
3
4
  import { UnpackRequest } from "./unpack-request.js";
4
5
  import { isResponseOK, Worker } from "./worker.js";
5
6
  export * from "./worker.js";
@@ -45,8 +46,7 @@ export class Pool {
45
46
  /* c8 ignore start - nearly impossible in normal circumstances */
46
47
  }
47
48
  else {
48
- const message = m.error instanceof Error ? m.error.message : String(m.error);
49
- ur.reject(error(message || 'failed without error message', {
49
+ ur.reject(error(asError(m.error, 'failed without error message').message, {
50
50
  found: m,
51
51
  cause: m.error,
52
52
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGlD,cAAc,aAAa,CAAA;AAE3B;;;;;;;GAOG;AACH,MAAM,OAAO,IAAI;IACf;;;OAGG;IACH,oBAAoB;IACpB,IAAI,GAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAC/D;;OAEG;IACH,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;IAC3B;;OAEG;IACH,KAAK,GAAoB,EAAE,CAAA;IAC3B;;;OAGG;IACH,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAA;IAE1C,mCAAmC;IACnC,UAAU,CAAC,CAAS,EAAE,CAA6B;QACjD,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,CAAA;QAChB,sDAAsD;QACtD,0DAA0D;QAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC/B,oBAAoB;QACpB,IAAI,CAAC,EAAE;YAAE,OAAM;QACf,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YACpB,EAAE,CAAC,OAAO,EAAE,CAAA;YACZ,iEAAiE;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GACX,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YAC9D,EAAE,CAAC,MAAM,CACP,KAAK,CAAC,OAAO,IAAI,8BAA8B,EAAE;gBAC/C,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,CAAC,CAAC,KAAK;aACf,CAAC,CACH,CAAA;QACH,CAAC;QACD,oBAAoB;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,aAAa,CAAC,GAAkB;QAC9B,MAAM,CAAC,GAAW,IAAI,MAAM,CAAC,CAAC,CAA6B,EAAE,EAAE,CAC7D,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CACtB,CAAA;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACnB,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACrB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,MAAc;QAC1C,MAAM,EAAE,GAAG,IAAI,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;QAC3B,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACrB,CAAC;QACD,OAAO,EAAE,CAAC,OAAO,CAAA;IACnB,CAAC;CACF","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport os from 'os'\nimport { UnpackRequest } from './unpack-request.ts'\nimport { isResponseOK, Worker } from './worker.ts'\nimport type { ResponseError, ResponseOK } from './worker.ts'\n\nexport * from './worker.ts'\n\n/**\n * Automatically expanding/contracting set of workers to maximize parallelism\n * of unpack operations up to 1 less than the number of CPUs (or 1).\n *\n * `pool.unpack(tarData, target)` will perform the unpack operation\n * synchronously, in one of these workers, and returns a promise when the\n * worker has confirmed completion of the task.\n */\nexport class Pool {\n /**\n * Number of workers to emplly. Defaults to 1 less than the number of\n * CPUs, or 1.\n */\n /* c8 ignore next */\n jobs: number = 8 * (Math.max(os.availableParallelism(), 2) - 1)\n /**\n * Set of currently active worker threads\n */\n workers = new Set<Worker>()\n /**\n * Queue of requests awaiting an available worker\n */\n queue: UnpackRequest[] = []\n /**\n * Requests that have been assigned to a worker, but have not yet\n * been confirmed completed.\n */\n pending = new Map<number, UnpackRequest>()\n\n // handle a message from the worker\n #onMessage(w: Worker, m: ResponseError | ResponseOK) {\n const { id } = m\n // a request has been met or failed, report and either\n // pick up the next item in the queue, or terminate worker\n const ur = this.pending.get(id)\n /* c8 ignore next */\n if (!ur) return\n if (isResponseOK(m)) {\n ur.resolve()\n /* c8 ignore start - nearly impossible in normal circumstances */\n } else {\n const message =\n m.error instanceof Error ? m.error.message : String(m.error)\n ur.reject(\n error(message || 'failed without error message', {\n found: m,\n cause: m.error,\n }),\n )\n }\n /* c8 ignore stop */\n const next = this.queue.shift()\n if (!next) {\n this.workers.delete(w)\n } else {\n void w.process(next)\n }\n }\n\n // create a new worker\n #createWorker(req: UnpackRequest) {\n const w: Worker = new Worker((m: ResponseError | ResponseOK) =>\n this.#onMessage(w, m),\n )\n this.workers.add(w)\n void w.process(req)\n }\n\n /**\n * Provide the tardata to be unpacked, and the location where it's to be\n * placed. Will create a new worker up to the `jobs` value, and then start\n * pushing in the queue for workers to pick up as they become available.\n *\n * Returned promise resolves when the provided tarball has been extracted.\n */\n async unpack(tarData: Buffer, target: string) {\n const ur = new UnpackRequest(tarData, target)\n this.pending.set(ur.id, ur)\n if (this.workers.size < this.jobs) {\n this.#createWorker(ur)\n } else {\n this.queue.push(ur)\n }\n return ur.promise\n }\n}\n"]}
1
+ {"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGlD,cAAc,aAAa,CAAA;AAE3B;;;;;;;GAOG;AACH,MAAM,OAAO,IAAI;IACf;;;OAGG;IACH,oBAAoB;IACpB,IAAI,GAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAC/D;;OAEG;IACH,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;IAC3B;;OAEG;IACH,KAAK,GAAoB,EAAE,CAAA;IAC3B;;;OAGG;IACH,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAA;IAE1C,mCAAmC;IACnC,UAAU,CAAC,CAAS,EAAE,CAA6B;QACjD,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,CAAA;QAChB,sDAAsD;QACtD,0DAA0D;QAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC/B,oBAAoB;QACpB,IAAI,CAAC,EAAE;YAAE,OAAM;QACf,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YACpB,EAAE,CAAC,OAAO,EAAE,CAAA;YACZ,iEAAiE;QACnE,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,MAAM,CACP,KAAK,CACH,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,8BAA8B,CAAC,CAAC,OAAO,EACxD;gBACE,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,CAAC,CAAC,KAAK;aACf,CACF,CACF,CAAA;QACH,CAAC;QACD,oBAAoB;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,aAAa,CAAC,GAAkB;QAC9B,MAAM,CAAC,GAAW,IAAI,MAAM,CAAC,CAAC,CAA6B,EAAE,EAAE,CAC7D,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CACtB,CAAA;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACnB,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACrB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,MAAc;QAC1C,MAAM,EAAE,GAAG,IAAI,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;QAC3B,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACrB,CAAC;QACD,OAAO,EAAE,CAAC,OAAO,CAAA;IACnB,CAAC;CACF","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { asError } from '@vltpkg/types'\nimport os from 'node:os'\nimport { UnpackRequest } from './unpack-request.ts'\nimport { isResponseOK, Worker } from './worker.ts'\nimport type { ResponseError, ResponseOK } from './worker.ts'\n\nexport * from './worker.ts'\n\n/**\n * Automatically expanding/contracting set of workers to maximize parallelism\n * of unpack operations up to 1 less than the number of CPUs (or 1).\n *\n * `pool.unpack(tarData, target)` will perform the unpack operation\n * synchronously, in one of these workers, and returns a promise when the\n * worker has confirmed completion of the task.\n */\nexport class Pool {\n /**\n * Number of workers to emplly. Defaults to 1 less than the number of\n * CPUs, or 1.\n */\n /* c8 ignore next */\n jobs: number = 8 * (Math.max(os.availableParallelism(), 2) - 1)\n /**\n * Set of currently active worker threads\n */\n workers = new Set<Worker>()\n /**\n * Queue of requests awaiting an available worker\n */\n queue: UnpackRequest[] = []\n /**\n * Requests that have been assigned to a worker, but have not yet\n * been confirmed completed.\n */\n pending = new Map<number, UnpackRequest>()\n\n // handle a message from the worker\n #onMessage(w: Worker, m: ResponseError | ResponseOK) {\n const { id } = m\n // a request has been met or failed, report and either\n // pick up the next item in the queue, or terminate worker\n const ur = this.pending.get(id)\n /* c8 ignore next */\n if (!ur) return\n if (isResponseOK(m)) {\n ur.resolve()\n /* c8 ignore start - nearly impossible in normal circumstances */\n } else {\n ur.reject(\n error(\n asError(m.error, 'failed without error message').message,\n {\n found: m,\n cause: m.error,\n },\n ),\n )\n }\n /* c8 ignore stop */\n const next = this.queue.shift()\n if (!next) {\n this.workers.delete(w)\n } else {\n void w.process(next)\n }\n }\n\n // create a new worker\n #createWorker(req: UnpackRequest) {\n const w: Worker = new Worker((m: ResponseError | ResponseOK) =>\n this.#onMessage(w, m),\n )\n this.workers.add(w)\n void w.process(req)\n }\n\n /**\n * Provide the tardata to be unpacked, and the location where it's to be\n * placed. Will create a new worker up to the `jobs` value, and then start\n * pushing in the queue for workers to pick up as they become available.\n *\n * Returned promise resolves when the provided tarball has been extracted.\n */\n async unpack(tarData: Buffer, target: string) {\n const ur = new UnpackRequest(tarData, target)\n this.pending.set(ur.id, ur)\n if (this.workers.size < this.jobs) {\n this.#createWorker(ur)\n } else {\n this.queue.push(ur)\n }\n return ur.promise\n }\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import { error } from '@vltpkg/error-cause';
2
- import { randomBytes } from 'crypto';
3
- import { lstat, mkdir, rename, writeFile } from 'fs/promises';
4
- import { basename, dirname, parse, resolve } from 'path';
2
+ import { randomBytes } from 'node:crypto';
3
+ import { lstat, mkdir, rename, writeFile } from 'node:fs/promises';
4
+ import { basename, dirname, parse, resolve } from 'node:path';
5
5
  import { rimraf } from 'rimraf';
6
6
  import { Header } from 'tar/header';
7
7
  import { Pax } from 'tar/pax';
8
- import { unzip as unzipCB } from 'zlib';
8
+ import { unzip as unzipCB } from 'node:zlib';
9
9
  import { findTarDir } from "./find-tar-dir.js";
10
10
  const unzip = async (input) => new Promise((res, rej) =>
11
11
  /* c8 ignore start */
@@ -102,9 +102,7 @@ const unpackUnzipped = async (buffer, target) => {
102
102
  let ex = undefined;
103
103
  let gex = undefined;
104
104
  while (offset < buffer.length &&
105
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
106
- (h = new Header(buffer, offset, ex, gex)) &&
107
- !h.nullBlock) {
105
+ !(h = new Header(buffer, offset, ex, gex)).nullBlock) {
108
106
  offset += 512;
109
107
  ex = undefined;
110
108
  gex = undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"unpack.js","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { randomBytes } from 'crypto'\nimport { lstat, mkdir, rename, writeFile } from 'fs/promises'\nimport { basename, dirname, parse, resolve } from 'path'\nimport { rimraf } from 'rimraf'\nimport { Header } from 'tar/header'\nimport type { HeaderData } from 'tar/header'\nimport { Pax } from 'tar/pax'\nimport { unzip as unzipCB } from 'zlib'\nimport { findTarDir } from './find-tar-dir.ts'\n\nconst unzip = async (input: Buffer) =>\n new Promise<Buffer>(\n (res, rej) =>\n /* c8 ignore start */\n unzipCB(input, (er, result) => (er ? rej(er) : res(result))),\n /* c8 ignore stop */\n )\n\nconst exists = async (path: string): Promise<boolean> => {\n try {\n await lstat(path)\n return true\n } catch {\n return false\n }\n}\n\nlet id = 1\nconst tmp = randomBytes(6).toString('hex') + '.'\nconst tmpSuffix = () => tmp + String(id++)\n\nconst checkFs = (\n h: Header,\n tarDir: string | undefined,\n): h is Header & { path: string } => {\n /* c8 ignore start - impossible */\n if (!h.path) return false\n if (!tarDir) return false\n /* c8 ignore stop */\n h.path = h.path.replace(/[\\\\/]+/g, '/')\n const parsed = parse(h.path)\n if (parsed.root) return false\n const p = h.path.replace(/\\\\/, '/')\n // any .. at the beginning, end, or middle = no good\n if (/(\\/|)^\\.\\.(\\/|$)/.test(p)) return false\n // packages should always be in a 'package' tarDir in the archive\n if (!p.startsWith(tarDir)) return false\n return true\n}\n\nconst write = async (\n path: string,\n body: Buffer,\n executable = false,\n) => {\n await mkdirp(dirname(path))\n // if the mode is world-executable, then make it executable\n // this is needed for some packages that have a file that is\n // not a declared bin, but still used as a cli executable.\n await writeFile(path, body, {\n mode: executable ? 0o777 : 0o666,\n })\n}\n\nconst made = new Set<string>()\nconst making = new Map<string, Promise<boolean>>()\nconst mkdirp = async (d: string) => {\n if (!made.has(d)) {\n const m =\n making.get(d) ??\n mkdir(d, { recursive: true, mode: 0o777 }).then(() =>\n making.delete(d),\n )\n making.set(d, m)\n await m\n made.add(d)\n }\n}\n\nexport const unpack = async (\n tarData: Buffer,\n target: string,\n): Promise<void> => {\n const isGzip = tarData[0] === 0x1f && tarData[1] === 0x8b\n await unpackUnzipped(\n isGzip ? await unzip(tarData) : tarData,\n target,\n )\n}\n\nconst unpackUnzipped = async (\n buffer: Buffer,\n target: string,\n): Promise<void> => {\n /* c8 ignore start */\n const isGzip = buffer[0] === 0x1f && buffer[1] === 0x8b\n if (isGzip) {\n throw error('still gzipped after unzipping', {\n found: isGzip,\n wanted: false,\n })\n }\n /* c8 ignore stop */\n\n // another real quick gutcheck before we get started\n if (buffer.length % 512 !== 0) {\n throw error('Invalid tarball: length not divisible by 512', {\n found: buffer.length,\n })\n }\n if (buffer.length < 1024) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.length },\n )\n }\n // make sure the last kb is all zeros\n for (let i = buffer.length - 1024; i < buffer.length; i++) {\n if (buffer[i] !== 0) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.subarray(i, i + 10) },\n )\n }\n }\n\n const tmp =\n dirname(target) + '/.' + basename(target) + '.' + tmpSuffix()\n const og = tmp + '.ORIGINAL'\n await Promise.all([rimraf(tmp), rimraf(og)])\n\n let succeeded = false\n try {\n let tarDir: string | undefined = undefined\n let offset = 0\n let h: Header\n let ex: HeaderData | undefined = undefined\n let gex: HeaderData | undefined = undefined\n while (\n offset < buffer.length &&\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n (h = new Header(buffer, offset, ex, gex)) &&\n !h.nullBlock\n ) {\n offset += 512\n ex = undefined\n gex = undefined\n const size = h.size ?? 0\n const body = buffer.subarray(offset, offset + size)\n // skip invalid headers\n if (!h.cksumValid) continue\n offset += 512 * Math.ceil(size / 512)\n\n // TODO: tarDir might not be named \"package/\"\n // find the first tarDir in the first entry, and use that.\n switch (h.type) {\n case 'File':\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n /* c8 ignore next */\n if (!tarDir) continue\n if (!checkFs(h, tarDir)) continue\n await write(\n resolve(tmp, h.path.substring(tarDir.length)),\n body,\n // if it's world-executable, it's an executable\n // otherwise, make it read-only.\n 1 === ((h.mode ?? 0x666) & 1),\n )\n break\n\n case 'Directory':\n /* c8 ignore next 2 */\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n if (!tarDir) continue\n if (!checkFs(h, tarDir)) continue\n await mkdirp(resolve(tmp, h.path.substring(tarDir.length)))\n break\n\n case 'GlobalExtendedHeader':\n gex = Pax.parse(body.toString(), gex, true)\n break\n\n case 'ExtendedHeader':\n case 'OldExtendedHeader':\n ex = Pax.parse(body.toString(), ex, false)\n break\n\n case 'NextFileHasLongPath':\n case 'OldGnuLongPath':\n ex ??= Object.create(null) as HeaderData\n ex.path = body.toString().replace(/\\0.*/, '')\n break\n }\n }\n\n const targetExists = await exists(target)\n if (targetExists) await rename(target, og)\n await rename(tmp, target)\n if (targetExists) await rimraf(og)\n succeeded = true\n } finally {\n // do not handle error or obscure throw site, just do the cleanup\n // if it didn't complete successfully.\n if (!succeeded) {\n /* c8 ignore start */\n if (await exists(og)) {\n await rimraf(target)\n await rename(og, target)\n }\n /* c8 ignore stop */\n await rimraf(tmp)\n }\n }\n}\n"]}
1
+ {"version":3,"file":"unpack.js","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, rename, writeFile } from 'node:fs/promises'\nimport { basename, dirname, parse, resolve } from 'node:path'\nimport { rimraf } from 'rimraf'\nimport { Header } from 'tar/header'\nimport type { HeaderData } from 'tar/header'\nimport { Pax } from 'tar/pax'\nimport { unzip as unzipCB } from 'node:zlib'\nimport { findTarDir } from './find-tar-dir.ts'\n\nconst unzip = async (input: Buffer) =>\n new Promise<Buffer>(\n (res, rej) =>\n /* c8 ignore start */\n unzipCB(input, (er, result) => (er ? rej(er) : res(result))),\n /* c8 ignore stop */\n )\n\nconst exists = async (path: string): Promise<boolean> => {\n try {\n await lstat(path)\n return true\n } catch {\n return false\n }\n}\n\nlet id = 1\nconst tmp = randomBytes(6).toString('hex') + '.'\nconst tmpSuffix = () => tmp + String(id++)\n\nconst checkFs = (\n h: Header,\n tarDir: string | undefined,\n): h is Header & { path: string } => {\n /* c8 ignore start - impossible */\n if (!h.path) return false\n if (!tarDir) return false\n /* c8 ignore stop */\n h.path = h.path.replace(/[\\\\/]+/g, '/')\n const parsed = parse(h.path)\n if (parsed.root) return false\n const p = h.path.replace(/\\\\/, '/')\n // any .. at the beginning, end, or middle = no good\n if (/(\\/|)^\\.\\.(\\/|$)/.test(p)) return false\n // packages should always be in a 'package' tarDir in the archive\n if (!p.startsWith(tarDir)) return false\n return true\n}\n\nconst write = async (\n path: string,\n body: Buffer,\n executable = false,\n) => {\n await mkdirp(dirname(path))\n // if the mode is world-executable, then make it executable\n // this is needed for some packages that have a file that is\n // not a declared bin, but still used as a cli executable.\n await writeFile(path, body, {\n mode: executable ? 0o777 : 0o666,\n })\n}\n\nconst made = new Set<string>()\nconst making = new Map<string, Promise<boolean>>()\nconst mkdirp = async (d: string) => {\n if (!made.has(d)) {\n const m =\n making.get(d) ??\n mkdir(d, { recursive: true, mode: 0o777 }).then(() =>\n making.delete(d),\n )\n making.set(d, m)\n await m\n made.add(d)\n }\n}\n\nexport const unpack = async (\n tarData: Buffer,\n target: string,\n): Promise<void> => {\n const isGzip = tarData[0] === 0x1f && tarData[1] === 0x8b\n await unpackUnzipped(\n isGzip ? await unzip(tarData) : tarData,\n target,\n )\n}\n\nconst unpackUnzipped = async (\n buffer: Buffer,\n target: string,\n): Promise<void> => {\n /* c8 ignore start */\n const isGzip = buffer[0] === 0x1f && buffer[1] === 0x8b\n if (isGzip) {\n throw error('still gzipped after unzipping', {\n found: isGzip,\n wanted: false,\n })\n }\n /* c8 ignore stop */\n\n // another real quick gutcheck before we get started\n if (buffer.length % 512 !== 0) {\n throw error('Invalid tarball: length not divisible by 512', {\n found: buffer.length,\n })\n }\n if (buffer.length < 1024) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.length },\n )\n }\n // make sure the last kb is all zeros\n for (let i = buffer.length - 1024; i < buffer.length; i++) {\n if (buffer[i] !== 0) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.subarray(i, i + 10) },\n )\n }\n }\n\n const tmp =\n dirname(target) + '/.' + basename(target) + '.' + tmpSuffix()\n const og = tmp + '.ORIGINAL'\n await Promise.all([rimraf(tmp), rimraf(og)])\n\n let succeeded = false\n try {\n let tarDir: string | undefined = undefined\n let offset = 0\n let h: Header\n let ex: HeaderData | undefined = undefined\n let gex: HeaderData | undefined = undefined\n while (\n offset < buffer.length &&\n !(h = new Header(buffer, offset, ex, gex)).nullBlock\n ) {\n offset += 512\n ex = undefined\n gex = undefined\n const size = h.size ?? 0\n const body = buffer.subarray(offset, offset + size)\n // skip invalid headers\n if (!h.cksumValid) continue\n offset += 512 * Math.ceil(size / 512)\n\n // TODO: tarDir might not be named \"package/\"\n // find the first tarDir in the first entry, and use that.\n switch (h.type) {\n case 'File':\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n /* c8 ignore next */\n if (!tarDir) continue\n if (!checkFs(h, tarDir)) continue\n await write(\n resolve(tmp, h.path.substring(tarDir.length)),\n body,\n // if it's world-executable, it's an executable\n // otherwise, make it read-only.\n 1 === ((h.mode ?? 0x666) & 1),\n )\n break\n\n case 'Directory':\n /* c8 ignore next 2 */\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n if (!tarDir) continue\n if (!checkFs(h, tarDir)) continue\n await mkdirp(resolve(tmp, h.path.substring(tarDir.length)))\n break\n\n case 'GlobalExtendedHeader':\n gex = Pax.parse(body.toString(), gex, true)\n break\n\n case 'ExtendedHeader':\n case 'OldExtendedHeader':\n ex = Pax.parse(body.toString(), ex, false)\n break\n\n case 'NextFileHasLongPath':\n case 'OldGnuLongPath':\n ex ??= Object.create(null) as HeaderData\n ex.path = body.toString().replace(/\\0.*/, '')\n break\n }\n }\n\n const targetExists = await exists(target)\n if (targetExists) await rename(target, og)\n await rename(tmp, target)\n if (targetExists) await rimraf(og)\n succeeded = true\n } finally {\n // do not handle error or obscure throw site, just do the cleanup\n // if it didn't complete successfully.\n if (!succeeded) {\n /* c8 ignore start */\n if (await exists(og)) {\n await rimraf(target)\n await rename(og, target)\n }\n /* c8 ignore stop */\n await rimraf(tmp)\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@vltpkg/tar",
3
3
  "description": "An extremely limited and very fast tar extractor",
4
- "version": "0.0.0-3",
4
+ "version": "0.0.0-31",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
8
8
  "directory": "src/tar"
9
9
  },
10
+ "author": "vlt technology inc. <support@vlt.sh> (http://vlt.sh)",
10
11
  "tshy": {
11
12
  "selfLink": false,
12
13
  "liveDev": true,
@@ -24,22 +25,21 @@
24
25
  "dependencies": {
25
26
  "rimraf": "^6.0.1",
26
27
  "tar": "^7.4.3",
27
- "@vltpkg/error-cause": "0.0.0-3"
28
+ "@vltpkg/error-cause": "0.0.0-31",
29
+ "@vltpkg/types": "0.0.0-31"
28
30
  },
29
31
  "devDependencies": {
30
- "@eslint/js": "^9.20.0",
31
- "@types/eslint__js": "^8.42.3",
32
- "@types/node": "^22.13.1",
33
- "@types/tar": "^6.1.13",
34
- "eslint": "^9.20.0",
35
- "mutate-fs": "^2.1.1",
36
- "pacote": "^18.0.6",
37
- "prettier": "^3.4.2",
32
+ "@eslint/js": "^9.34.0",
33
+ "@types/node": "^22.17.2",
34
+ "@types/pacote": "^11.1.8",
35
+ "eslint": "^9.34.0",
36
+ "pacote": "^21.0.0",
37
+ "prettier": "^3.6.2",
38
38
  "tap": "^21.1.0",
39
39
  "tshy": "^3.0.2",
40
- "typedoc": "0.27.6",
40
+ "typedoc": "~0.27.9",
41
41
  "typescript": "5.7.3",
42
- "typescript-eslint": "^8.23.0",
42
+ "typescript-eslint": "^8.40.0",
43
43
  "@vltpkg/benchmark": "0.0.0"
44
44
  },
45
45
  "license": "BSD-2-Clause-Patent",
@@ -84,7 +84,7 @@
84
84
  ],
85
85
  "scripts": {
86
86
  "prebenchmark": "pnpm vlt-benchmark-download-fixtures",
87
- "benchmark": "node --no-warnings --experimental-strip-types scripts/benchmark.js",
87
+ "benchmark": "./scripts/benchmark.ts",
88
88
  "format": "prettier --write . --log-level warn --ignore-path ../../.prettierignore --cache",
89
89
  "format:check": "prettier --check . --ignore-path ../../.prettierignore --cache",
90
90
  "lint": "eslint . --fix",
@@ -92,6 +92,7 @@
92
92
  "snap": "tap",
93
93
  "test": "tap",
94
94
  "posttest": "tsc --noEmit",
95
+ "tshy": "tshy",
95
96
  "typecheck": "tsc --noEmit"
96
97
  }
97
98
  }