@datatruck/cli 0.29.1 → 0.30.1

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.
@@ -4,6 +4,7 @@ exports.createDatatruckServer = exports.headerKey = void 0;
4
4
  const http_1 = require("../http");
5
5
  const virtual_fs_1 = require("../virtual-fs");
6
6
  const fs_1 = require("fs");
7
+ const promises_1 = require("fs/promises");
7
8
  const http_2 = require("http");
8
9
  function parseUrl(inUrl) {
9
10
  const url = new URL(`http://127.0.0.1${inUrl}`);
@@ -23,14 +24,26 @@ exports.headerKey = {
23
24
  user: "x-dtt-user",
24
25
  password: "x-dtt-password",
25
26
  };
26
- function validateRequest(req, users) {
27
- const name = req.headers[exports.headerKey.user];
28
- const password = req.headers[exports.headerKey.password];
29
- return users.some((user) => user.name.length &&
30
- user.password.length &&
31
- user.name === name &&
32
- user.password === password);
27
+ function validateRequest(req, options) {
28
+ const list = options.allowlist;
29
+ if (list && (list.enabled ?? true) && list.remoteAddresses) {
30
+ const remoteAddress = getRemoteAddress(req, options);
31
+ if (!remoteAddress || !list.remoteAddresses.includes(remoteAddress))
32
+ return false;
33
+ }
34
+ const name = req.headers[exports.headerKey.user]?.toString().trim();
35
+ const password = req.headers[exports.headerKey.password]?.toString().trim();
36
+ if (!name?.length || !password?.length)
37
+ return;
38
+ return (options.users?.some((user) => user.name === name && user.password === password) || false);
33
39
  }
40
+ const getRemoteAddress = (req, options) => {
41
+ return ((options.trustProxy
42
+ ? options.trustProxy === true
43
+ ? req.headers["x-real-ip"]?.toString()
44
+ : req.headers[options.trustProxy.remoteAddressHeader]?.toString()
45
+ : undefined) ?? req.socket.remoteAddress);
46
+ };
34
47
  function createDatatruckServer(options) {
35
48
  const log = options.log ?? true;
36
49
  return (0, http_2.createServer)(async (req, res) => {
@@ -38,7 +51,7 @@ function createDatatruckServer(options) {
38
51
  if (req.url === "/" || req.url === "/favicon.ico") {
39
52
  return res.end();
40
53
  }
41
- else if (!validateRequest(req, options.users || [])) {
54
+ else if (!validateRequest(req, options)) {
42
55
  res.statusCode = 401;
43
56
  return res.end();
44
57
  }
@@ -50,7 +63,8 @@ function createDatatruckServer(options) {
50
63
  const { action, params } = parseUrl(req.url);
51
64
  if (action === "upload") {
52
65
  const [target] = params;
53
- const file = (0, fs_1.createWriteStream)(fs.resolvePath(target));
66
+ const path = fs.resolvePath(target);
67
+ const file = (0, fs_1.createWriteStream)(path);
54
68
  req.pipe(file);
55
69
  await new Promise((resolve, reject) => {
56
70
  req.on("error", reject);
@@ -60,7 +74,10 @@ function createDatatruckServer(options) {
60
74
  }
61
75
  else if (action === "download") {
62
76
  const [target] = params;
63
- const file = (0, fs_1.createReadStream)(fs.resolvePath(target));
77
+ const path = fs.resolvePath(target);
78
+ const file = (0, fs_1.createReadStream)(path);
79
+ const fileStat = await (0, promises_1.stat)(path);
80
+ res.setHeader("Content-Length", fileStat.size);
64
81
  file.pipe(res);
65
82
  await new Promise((resolve, reject) => {
66
83
  req.on("error", reject);
@@ -82,14 +99,16 @@ function createDatatruckServer(options) {
82
99
  if (json !== undefined)
83
100
  res.write(JSON.stringify(json));
84
101
  }
85
- res.end();
86
102
  if (log)
87
103
  console.info(`<${action}`);
104
+ res.end();
88
105
  }
89
106
  catch (error) {
90
107
  if (log)
91
108
  console.error(`<${req.url}`, error);
92
109
  res.statusCode = 500;
110
+ res.statusMessage = error.message;
111
+ res.end();
93
112
  }
94
113
  });
95
114
  }
@@ -0,0 +1,6 @@
1
+ type EventNameType = "exit" | "SIGINT" | "SIGUSR1" | "SIGUSR2" | "SIGTERM" | "uncaughtException";
2
+ export declare function triggerExitEvent(eventName: EventNameType, ...args: any[]): void;
3
+ export declare function enableExitEvents(): void;
4
+ export declare function disableExitEvents(): void;
5
+ export declare function onExit(cb: (eventName: EventNameType, ...args: any[]) => void, priority?: number): () => boolean;
6
+ export {};
package/utils/exit.js ADDED
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.onExit = exports.disableExitEvents = exports.enableExitEvents = exports.triggerExitEvent = void 0;
4
+ const eventNames = [
5
+ `exit`,
6
+ `SIGINT`,
7
+ `SIGUSR1`,
8
+ `SIGUSR2`,
9
+ `uncaughtException`,
10
+ `SIGTERM`,
11
+ ];
12
+ const listeners = new Set();
13
+ const disableExitDisposes = new Set();
14
+ function triggerExitEvent(eventName, ...args) {
15
+ if (!disableExitDisposes.size) {
16
+ process.emit(eventName, ...args);
17
+ return;
18
+ }
19
+ try {
20
+ disableExitEvents();
21
+ const items = [...listeners].sort((a, b) => b.priority - a.priority);
22
+ for (const { cb } of items) {
23
+ try {
24
+ cb(eventName, ...args);
25
+ }
26
+ catch (_) { }
27
+ }
28
+ }
29
+ catch (_) {
30
+ process.exit(5);
31
+ }
32
+ }
33
+ exports.triggerExitEvent = triggerExitEvent;
34
+ function enableExitEvents() {
35
+ disableExitEvents();
36
+ for (const eventName of eventNames) {
37
+ const listener = (...args) => triggerExitEvent(eventName, ...args);
38
+ process.on(eventName, listener);
39
+ disableExitDisposes.add(() => process.off(eventName, listener));
40
+ }
41
+ }
42
+ exports.enableExitEvents = enableExitEvents;
43
+ function disableExitEvents() {
44
+ for (const dispose of disableExitDisposes)
45
+ dispose();
46
+ disableExitDisposes.clear();
47
+ }
48
+ exports.disableExitEvents = disableExitEvents;
49
+ function onExit(cb, priority) {
50
+ if (!disableExitDisposes.size)
51
+ enableExitEvents();
52
+ const listener = { cb, priority: priority ?? 0 };
53
+ listeners.add(listener);
54
+ return () => listeners.delete(listener);
55
+ }
56
+ exports.onExit = onExit;
package/utils/fs.d.ts CHANGED
@@ -133,4 +133,7 @@ export declare function fetchDiskStats(path: string): Promise<DiskStats>;
133
133
  export declare function checkFreeDiskSpace(stat: DiskStats, inSize: string | number): Promise<void>;
134
134
  export declare function ensureFreeDiskSpace(input: string[] | DiskStats, inSize: number | string): Promise<void>;
135
135
  export declare function groupFiles(inFiles: string[], suffixes?: string[], gzSuffix?: string): [string[], Record<string, string>];
136
+ export declare function asFile(input: string | {
137
+ path: string;
138
+ }): Promise<[string, (() => Promise<void>) | undefined]>;
136
139
  export {};
package/utils/fs.js CHANGED
@@ -3,12 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.groupFiles = exports.ensureFreeDiskSpace = exports.checkFreeDiskSpace = exports.fetchDiskStats = exports.initEmptyDir = exports.tryRm = exports.safeRename = exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.createProgress = exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.fastFolderSizeAsync = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureExistsDir = exports.ensureSingleFile = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
6
+ exports.asFile = exports.groupFiles = exports.ensureFreeDiskSpace = exports.checkFreeDiskSpace = exports.fetchDiskStats = exports.initEmptyDir = exports.tryRm = exports.safeRename = exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.createProgress = exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.fastFolderSizeAsync = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureExistsDir = exports.ensureSingleFile = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
7
+ const bytes_1 = require("./bytes");
7
8
  const math_1 = require("./math");
8
9
  const path_1 = require("./path");
9
10
  const string_1 = require("./string");
11
+ const temp_1 = require("./temp");
10
12
  const async_1 = require("async");
11
- const bytes_1 = __importDefault(require("bytes"));
12
13
  const fast_folder_size_1 = __importDefault(require("fast-folder-size"));
13
14
  const fast_glob_1 = __importDefault(require("fast-glob"));
14
15
  const fs_1 = require("fs");
@@ -238,7 +239,7 @@ async function writeGitIgnoreList(options) {
238
239
  }
239
240
  exports.writeGitIgnoreList = writeGitIgnoreList;
240
241
  async function waitForClose(stream) {
241
- return new Promise(async (resolve, reject) => {
242
+ return new Promise((resolve, reject) => {
242
243
  stream.on("close", resolve);
243
244
  stream.on("error", reject);
244
245
  return stream;
@@ -566,10 +567,10 @@ async function fetchDiskStats(path) {
566
567
  }
567
568
  exports.fetchDiskStats = fetchDiskStats;
568
569
  async function checkFreeDiskSpace(stat, inSize) {
569
- const humanSize = typeof inSize === "number" ? (0, bytes_1.default)(inSize) : inSize;
570
- const size = bytes_1.default.parse(inSize);
570
+ const humanSize = typeof inSize === "number" ? (0, bytes_1.formatBytes)(inSize) : inSize;
571
+ const size = typeof inSize === "number" ? inSize : (0, bytes_1.parseSize)(inSize);
571
572
  if (stat.free < size)
572
- throw new Error(`Free disk space is less than ${humanSize}: ${(0, bytes_1.default)(stat.free)}/${(0, bytes_1.default)(stat.total)}`);
573
+ throw new Error(`Free disk space is less than ${humanSize}: ${(0, bytes_1.formatBytes)(stat.free)}/${(0, bytes_1.formatBytes)(stat.total)}`);
573
574
  }
574
575
  exports.checkFreeDiskSpace = checkFreeDiskSpace;
575
576
  async function ensureFreeDiskSpace(input, inSize) {
@@ -608,3 +609,20 @@ function groupFiles(inFiles, suffixes, gzSuffix = ".tar.gz") {
608
609
  return [Object.keys(grouped), compressed];
609
610
  }
610
611
  exports.groupFiles = groupFiles;
612
+ async function asFile(input) {
613
+ if (typeof input === "string") {
614
+ const dir = await (0, temp_1.mkTmpDir)("text-as-file");
615
+ const path = (0, path_2.join)(dir, "contents.txt");
616
+ await (0, promises_1.writeFile)(path, input);
617
+ return [
618
+ path,
619
+ async () => {
620
+ await (0, promises_1.rm)(dir, { recursive: true });
621
+ },
622
+ ];
623
+ }
624
+ else {
625
+ return [input.path, undefined];
626
+ }
627
+ }
628
+ exports.asFile = asFile;
package/utils/http.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ import { BasicProgress } from "./progress";
2
3
  import { IncomingMessage, Server } from "http";
3
4
  export declare function closeServer(server: Server): Promise<void>;
4
5
  export declare function readRequestData(req: IncomingMessage): Promise<string | undefined>;
@@ -14,6 +15,7 @@ export declare function downloadFile(url: string, output: string, options?: {
14
15
  headers?: Record<string, string>;
15
16
  query?: Record<string, string>;
16
17
  timeout?: number;
18
+ onProgress?: (progress: BasicProgress) => void;
17
19
  }): Promise<void>;
18
20
  export declare function uploadFile(url: string, path: string, options?: {
19
21
  headers?: Record<string, string>;
package/utils/http.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.uploadFile = exports.downloadFile = exports.post = exports.fetchJson = exports.readRequestData = exports.closeServer = void 0;
4
+ const math_1 = require("./math");
4
5
  const fs_1 = require("fs");
5
6
  const promises_1 = require("fs/promises");
6
7
  const http_1 = require("http");
@@ -89,16 +90,34 @@ async function post(url, data, options = {}) {
89
90
  }
90
91
  exports.post = post;
91
92
  async function downloadFile(url, output, options = {}) {
92
- const timeout = options.timeout ?? 3600 * 100;
93
+ const timeout = options.timeout ?? 3600 * 1000; // 60m
93
94
  const file = (0, fs_1.createWriteStream)(output);
94
95
  await new Promise((resolve, reject) => {
95
96
  const req = request(href(url, options.query), {
96
97
  headers: options.headers,
97
98
  }, (res) => {
99
+ const contentLength = res.headers["content-length"] ?? "";
100
+ if (!/^\d+$/.test(contentLength))
101
+ return reject(new Error(`Invalid 'content-length': ${contentLength}`));
102
+ const total = Number(contentLength);
103
+ let current = 0;
98
104
  if (res.statusCode === 200) {
105
+ if (options.onProgress) {
106
+ res.on("data", (chunk) => {
107
+ current += chunk.byteLength;
108
+ options.onProgress({
109
+ percent: (0, math_1.progressPercent)(total, current),
110
+ current,
111
+ total,
112
+ });
113
+ });
114
+ }
99
115
  res
100
116
  .on("error", async (error) => {
101
- file.destroy();
117
+ try {
118
+ file.destroy();
119
+ }
120
+ catch (_) { }
102
121
  try {
103
122
  await (0, promises_1.unlink)(output);
104
123
  }
package/utils/list.d.ts CHANGED
@@ -46,6 +46,7 @@ export declare class Listr3<T extends Listr3Context> extends Listr<void, "defaul
46
46
  };
47
47
  readonly resultMap: Record<string, Listr3TaskResult<T>>;
48
48
  readonly resultList: Listr3TaskResult<T>[];
49
+ readonly logger: List3Logger;
49
50
  protected execTimer: Timer;
50
51
  constructor($options: {
51
52
  streams?: Streams;
@@ -59,6 +60,7 @@ export declare class Listr3<T extends Listr3Context> extends Listr<void, "defaul
59
60
  add(tasks: ListrTask<void, ListrGetRendererClassFromValue<"default">> | ListrTask<void, ListrGetRendererClassFromValue<"default">>[]): this;
60
61
  getSummaryResult(): SummaryResult;
61
62
  getResult(): (SummaryResult | Listr3TaskResult<T>)[];
63
+ protected release(): void;
62
64
  exec(): Promise<(Listr3TaskResult<T> | SummaryResult)[]>;
63
65
  }
64
66
  export {};
package/utils/list.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Listr3 = exports.List3Logger = void 0;
4
4
  const date_1 = require("./date");
5
+ const exit_1 = require("./exit");
5
6
  const stream_1 = require("./stream");
6
7
  const listr2_1 = require("listr2");
7
8
  class List3Logger extends listr2_1.ListrLogger {
@@ -17,8 +18,10 @@ class Listr3 extends listr2_1.Listr {
17
18
  $options;
18
19
  resultMap = {};
19
20
  resultList = [];
21
+ logger;
20
22
  execTimer;
21
23
  constructor($options) {
24
+ const logger = new List3Logger();
22
25
  super([], {
23
26
  renderer: "default",
24
27
  collectErrors: "minimal",
@@ -27,12 +30,12 @@ class Listr3 extends listr2_1.Listr {
27
30
  }),
28
31
  fallbackRenderer: "simple",
29
32
  fallbackRendererOptions: {
30
- logger: new List3Logger(),
33
+ logger: logger,
31
34
  timestamp: listr2_1.PRESET_TIMESTAMP,
32
35
  timer: listr2_1.PRESET_TIMER,
33
36
  },
34
37
  rendererOptions: {
35
- logger: new List3Logger(),
38
+ logger: logger,
36
39
  collapseSubtasks: false,
37
40
  collapseErrors: false,
38
41
  timer: listr2_1.PRESET_TIMER,
@@ -40,6 +43,7 @@ class Listr3 extends listr2_1.Listr {
40
43
  });
41
44
  this.$options = $options;
42
45
  this.execTimer = (0, date_1.createTimer)();
46
+ this.logger = logger;
43
47
  }
44
48
  serializeKeyIndex(keyIndex) {
45
49
  return typeof keyIndex !== "undefined"
@@ -127,7 +131,18 @@ class Listr3 extends listr2_1.Listr {
127
131
  getResult() {
128
132
  return [...this.resultList, this.getSummaryResult()];
129
133
  }
134
+ release() {
135
+ for (const task of this.tasks)
136
+ if (task.isPending())
137
+ task.state$ = listr2_1.ListrTaskState.FAILED;
138
+ this["renderer"].end(new Error("Interrupted."));
139
+ }
130
140
  async exec() {
141
+ const dispose = (0, exit_1.onExit)(() => {
142
+ this.$options.progressManager?.dispose();
143
+ this.execTimer.reset();
144
+ this.release();
145
+ }, 1);
131
146
  try {
132
147
  this.$options.progressManager?.start();
133
148
  this.execTimer.reset();
@@ -138,7 +153,7 @@ class Listr3 extends listr2_1.Listr {
138
153
  throw error;
139
154
  }
140
155
  finally {
141
- this.$options.progressManager?.dispose();
156
+ dispose();
142
157
  }
143
158
  }
144
159
  }
@@ -30,7 +30,7 @@ export interface ExecSettingsInterface {
30
30
  stream: Readable;
31
31
  };
32
32
  log?: ExecLogSettingsType | boolean;
33
- onSpawn?: (p: ChildProcess) => any;
33
+ onSpawn?: (p: ChildProcess) => void | undefined;
34
34
  stdout?: {
35
35
  save?: boolean;
36
36
  parseLines?: boolean | "skip-empty";
@@ -103,6 +103,4 @@ export declare function createProcess<O1 extends boolean, O2 extends boolean>(co
103
103
  stderr: string;
104
104
  } : {})>;
105
105
  export declare function exec(command: string, argv?: string[], options?: SpawnOptions | null, settings?: ExecSettingsInterface): Promise<ExecResultType>;
106
- type EventNameType = "exit" | "SIGINT" | "SIGUSR1" | "SIGUSR2" | "SIGTERM" | "uncaughtException";
107
- export declare function onExit(cb: (eventName: EventNameType, ...args: any[]) => void): void;
108
106
  export {};
package/utils/process.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.onExit = exports.exec = exports.createProcess = exports.logProcessExec = exports.waitForClose = exports.parseStreamData = exports.logExecStderr = exports.logExecStdout = void 0;
6
+ exports.exec = exports.createProcess = exports.logProcessExec = exports.waitForClose = exports.parseStreamData = exports.logExecStderr = exports.logExecStdout = void 0;
7
7
  const cli_1 = require("./cli");
8
8
  const fs_1 = require("./fs");
9
9
  const math_1 = require("./math");
@@ -179,46 +179,45 @@ async function exec(command, argv = [], options = null, settings = {}) {
179
179
  else if (settings.log) {
180
180
  log = settings.log;
181
181
  }
182
- return new Promise(async (resolve, reject) => {
183
- if (log.exec) {
184
- logProcessExec(command, argv, {
185
- env: options?.env,
186
- envNames: log.envNames,
187
- pipe: pipe?.stream,
188
- toStderr: log.allToStderr,
189
- });
190
- }
191
- if (typeof options?.cwd === "string" && !(await (0, fs_1.existsDir)(options.cwd)))
192
- return reject(new Error(`Current working directory does not exist: ${options.cwd}`));
193
- if (pipe?.stream instanceof fs_2.ReadStream && "onReadProgress" in pipe) {
194
- const fileInfo = await (0, promises_1.stat)(pipe.stream.path);
195
- const totalBytes = fileInfo.size;
196
- let currentBytes = 0;
197
- pipe.stream.on("data", (data) => {
198
- currentBytes += data.length;
199
- pipe.onReadProgress?.({
200
- totalBytes: totalBytes,
201
- currentBytes: currentBytes,
202
- progress: (0, math_1.progressPercent)(totalBytes, currentBytes),
203
- });
182
+ if (log.exec)
183
+ logProcessExec(command, argv, {
184
+ env: options?.env,
185
+ envNames: log.envNames,
186
+ pipe: pipe?.stream,
187
+ toStderr: log.allToStderr,
188
+ });
189
+ if (typeof options?.cwd === "string" && !(await (0, fs_1.existsDir)(options.cwd)))
190
+ throw new Error(`Current working directory does not exist: ${options.cwd}`);
191
+ if (pipe?.stream instanceof fs_2.ReadStream && "onReadProgress" in pipe) {
192
+ const fileInfo = await (0, promises_1.stat)(pipe.stream.path);
193
+ const totalBytes = fileInfo.size;
194
+ let currentBytes = 0;
195
+ pipe.stream.on("data", (data) => {
196
+ currentBytes += data.length;
197
+ pipe.onReadProgress?.({
198
+ totalBytes: totalBytes,
199
+ currentBytes: currentBytes,
200
+ progress: (0, math_1.progressPercent)(totalBytes, currentBytes),
204
201
  });
205
- }
206
- const p = (0, child_process_1.spawn)(command, argv, options ?? {});
207
- await settings.onSpawn?.(p);
208
- let spawnError;
209
- const spawnData = {
210
- stdout: "",
211
- stderr: "",
212
- exitCode: 0,
213
- };
214
- let finishListeners = 1;
215
- if (pipe?.stream instanceof fs_2.WriteStream)
216
- finishListeners++;
217
- if (settings.stdout?.parseLines)
218
- finishListeners++;
219
- if (settings.stderr?.parseLines)
220
- finishListeners++;
221
- let streamError;
202
+ });
203
+ }
204
+ const p = (0, child_process_1.spawn)(command, argv, options ?? {});
205
+ settings.onSpawn?.(p);
206
+ let spawnError;
207
+ const spawnData = {
208
+ stdout: "",
209
+ stderr: "",
210
+ exitCode: 0,
211
+ };
212
+ let finishListeners = 1;
213
+ if (pipe?.stream instanceof fs_2.WriteStream)
214
+ finishListeners++;
215
+ if (settings.stdout?.parseLines)
216
+ finishListeners++;
217
+ if (settings.stderr?.parseLines)
218
+ finishListeners++;
219
+ let streamError;
220
+ return new Promise((resolve, reject) => {
222
221
  const tryFinish = () => {
223
222
  if (!--finishListeners)
224
223
  finish();
@@ -336,17 +335,3 @@ async function exec(command, argv = [], options = null, settings = {}) {
336
335
  });
337
336
  }
338
337
  exports.exec = exec;
339
- const eventNames = [
340
- `exit`,
341
- `SIGINT`,
342
- `SIGUSR1`,
343
- `SIGUSR2`,
344
- `uncaughtException`,
345
- `SIGTERM`,
346
- ];
347
- function onExit(cb) {
348
- for (const eventName of eventNames) {
349
- process.on(eventName, (...args) => cb(eventName, ...args));
350
- }
351
- }
352
- exports.onExit = onExit;
@@ -1,5 +1,10 @@
1
1
  /// <reference types="node" />
2
2
  import { Timer } from "./date";
3
+ export type BasicProgress = {
4
+ percent: number;
5
+ current: number;
6
+ total: number;
7
+ };
3
8
  export type ProgressStats = {
4
9
  percent?: number;
5
10
  total?: number;
@@ -12,29 +17,36 @@ export type Progress = {
12
17
  absolute?: ProgressStats;
13
18
  relative?: ProgressStats;
14
19
  };
20
+ export type ProgressTty = "auto" | boolean;
21
+ export type ProgressMode = "auto" | "interval" | `interval:${number}` | boolean;
15
22
  export declare class ProgressManager {
16
23
  readonly options: {
17
24
  verbose?: boolean;
18
25
  /**
19
- * @default true
26
+ * @default false
27
+ */
28
+ tty?: ProgressTty;
29
+ /**
30
+ * @default "interval"
20
31
  */
21
- tty?: boolean | "auto";
22
- enabled?: boolean | "auto" | "interval";
23
- interval?: number;
32
+ mode?: ProgressMode;
24
33
  };
25
34
  protected timer: Timer;
26
35
  protected interval: Timer | undefined;
27
- protected keydownListener: ((data: Buffer) => void) | undefined;
28
- readonly tty: boolean;
29
- readonly enabled: boolean | "interval";
36
+ protected intervalMs: number;
37
+ protected keydownListener: ((data: Buffer | undefined) => void) | undefined;
38
+ readonly tty: Exclude<ProgressTty, "auto">;
39
+ readonly mode: Exclude<ProgressMode, "auto" | `interval:${number}`>;
30
40
  constructor(options: {
31
41
  verbose?: boolean;
32
42
  /**
33
- * @default true
43
+ * @default false
44
+ */
45
+ tty?: ProgressTty;
46
+ /**
47
+ * @default "interval"
34
48
  */
35
- tty?: boolean | "auto";
36
- enabled?: boolean | "auto" | "interval";
37
- interval?: number;
49
+ mode?: ProgressMode;
38
50
  });
39
51
  elapsed(): number;
40
52
  start(): void;
package/utils/progress.js CHANGED
@@ -1,21 +1,20 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.renderProgressStats = exports.renderProgress = exports.ProgressManager = void 0;
4
+ const bytes_1 = require("./bytes");
7
5
  const cli_1 = require("./cli");
8
6
  const date_1 = require("./date");
9
- const bytes_1 = __importDefault(require("bytes"));
7
+ const exit_1 = require("./exit");
10
8
  const chalk_1 = require("chalk");
11
9
  const readline_1 = require("readline");
12
10
  class ProgressManager {
13
11
  options;
14
12
  timer = (0, date_1.createTimer)();
15
13
  interval = (0, date_1.createTimer)();
14
+ intervalMs;
16
15
  keydownListener;
17
16
  tty;
18
- enabled;
17
+ mode;
19
18
  constructor(options) {
20
19
  this.options = options;
21
20
  this.tty =
@@ -24,12 +23,21 @@ class ProgressManager {
24
23
  ? false
25
24
  : process.stdout.isTTY
26
25
  : !!options.tty;
27
- this.enabled =
28
- options.enabled === "auto"
29
- ? this.tty
30
- ? true
31
- : "interval"
32
- : !!options.enabled;
26
+ const mode = options.mode === "auto"
27
+ ? this.tty
28
+ ? `interval:${300}`
29
+ : "interval"
30
+ : options.mode ?? "interval";
31
+ this.intervalMs = 1000;
32
+ if (typeof mode === "string" && mode.startsWith("interval:")) {
33
+ const [, ms] = mode.split(":");
34
+ this.mode = "interval";
35
+ if (/^\d+$/.test(ms))
36
+ this.intervalMs = Number(ms);
37
+ }
38
+ else {
39
+ this.mode = mode;
40
+ }
33
41
  }
34
42
  elapsed() {
35
43
  return this.timer.elapsed();
@@ -41,10 +49,10 @@ class ProgressManager {
41
49
  process.stdin?.resume();
42
50
  process.stdin?.setEncoding("utf8");
43
51
  process.stdin?.on("keypress", (this.keydownListener = (inKey) => {
44
- const key = inKey.toString();
52
+ const key = inKey?.toString() || "";
45
53
  if (key === "\u0003") {
46
54
  process.stdin.setRawMode?.(false);
47
- process.emit("SIGINT");
55
+ (0, exit_1.triggerExitEvent)("SIGINT");
48
56
  }
49
57
  else if (/^(\r\n)|\r|\n$/.test(key)) {
50
58
  this.interval = undefined;
@@ -59,11 +67,11 @@ class ProgressManager {
59
67
  }
60
68
  }
61
69
  update(progress, cb) {
62
- if (!this.enabled)
70
+ if (!this.mode)
63
71
  return;
64
- if (this.enabled === "interval") {
72
+ if (this.mode === "interval") {
65
73
  if (this.interval) {
66
- if (!this.interval.reset(this.options.interval ?? 5000))
74
+ if (!this.interval.reset(this.intervalMs))
67
75
  return;
68
76
  }
69
77
  else {
@@ -89,7 +97,7 @@ function renderProgressStats(stats, progressBar) {
89
97
  text.push(`${stats.percent.toFixed(2).padStart(5, " ")}%`);
90
98
  }
91
99
  if (typeof stats.current === "number" || typeof stats.total === "number") {
92
- const format = (value) => stats.format === "size" ? (0, bytes_1.default)(value) : value.toString();
100
+ const format = (value) => stats.format === "size" ? (0, bytes_1.formatBytes)(value) : value.toString();
93
101
  const pad = 8;
94
102
  let values = [];
95
103
  if (typeof stats.current === "number" && typeof stats.total === "number") {
package/utils/tar.d.ts CHANGED
@@ -1,12 +1,8 @@
1
+ import { BasicProgress } from "./progress";
1
2
  import type { JSONSchema7 } from "json-schema";
2
- export type Progress = {
3
- percent: number;
4
- current: number;
5
- total: number;
6
- };
7
3
  export type TarEntry = {
8
4
  path: string;
9
- progress: Progress;
5
+ progress: BasicProgress;
10
6
  };
11
7
  export type CoresOptions = number | {
12
8
  percent: number;