@datatruck/cli 0.18.0 → 0.20.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 (56) hide show
  1. package/Action/BackupAction.js +4 -2
  2. package/Action/BackupSessionsAction.js +2 -0
  3. package/Action/CleanCacheAction.js +1 -0
  4. package/Action/ConfigAction.js +1 -0
  5. package/Action/InitAction.js +2 -0
  6. package/Action/PruneAction.js +2 -0
  7. package/Action/RestoreAction.js +5 -3
  8. package/Action/RestoreSessionsAction.js +2 -0
  9. package/Action/SnapshotsAction.js +2 -0
  10. package/Command/CommandAbstract.js +2 -0
  11. package/Entity/BackupSessionEntity.js +5 -2
  12. package/Entity/BackupSessionRepositoryEntity.js +5 -2
  13. package/Entity/BackupSessionTaskEntity.js +4 -2
  14. package/Entity/CrudEntityAbstract.js +3 -0
  15. package/Entity/RestoreSessionEntity.js +4 -2
  16. package/Entity/RestoreSessionRepositoryEntity.js +5 -2
  17. package/Entity/RestoreSessionTaskEntity.js +4 -2
  18. package/Entity/StateEntityAbstract.js +5 -0
  19. package/Factory/CommandFactory.js +1 -1
  20. package/JsonSchema/DefinitionEnum.js +1 -1
  21. package/Repository/DatatruckRepository.d.ts +8 -13
  22. package/Repository/DatatruckRepository.js +122 -231
  23. package/Repository/GitRepository.js +1 -1
  24. package/Repository/RepositoryAbstract.js +4 -2
  25. package/Repository/ResticRepository.js +2 -1
  26. package/SessionDriver/ConsoleSessionDriver.js +9 -5
  27. package/SessionDriver/SessionDriverAbstract.js +3 -2
  28. package/SessionDriver/SqliteSessionDriver.js +2 -4
  29. package/SessionManager/BackupSessionManager.js +3 -6
  30. package/SessionManager/RestoreSessionManager.js +3 -6
  31. package/SessionManager/SessionManagerAbstract.js +4 -0
  32. package/Task/GitTask.js +3 -2
  33. package/Task/MariadbTask.js +6 -4
  34. package/Task/MssqlTask.js +2 -1
  35. package/Task/ScriptTask.js +1 -0
  36. package/Task/SqlDumpTaskAbstract.js +2 -1
  37. package/Task/TaskAbstract.js +2 -1
  38. package/config.schema.json +23 -37
  39. package/index.d.ts +1 -0
  40. package/index.js +1 -0
  41. package/package.json +8 -8
  42. package/utils/DataFormat.js +1 -0
  43. package/utils/Git.js +2 -1
  44. package/utils/ObjectVault.js +3 -5
  45. package/utils/Restic.js +1 -0
  46. package/utils/datatruck/paths.js +5 -1
  47. package/utils/fs.d.ts +23 -24
  48. package/utils/fs.js +108 -96
  49. package/utils/process.d.ts +1 -1
  50. package/utils/process.js +17 -8
  51. package/utils/string.d.ts +0 -2
  52. package/utils/string.js +1 -9
  53. package/utils/tar.d.ts +35 -0
  54. package/utils/tar.js +127 -0
  55. package/utils/zip.d.ts +0 -97
  56. package/utils/zip.js +0 -238
package/utils/process.js CHANGED
@@ -188,7 +188,7 @@ async function exec(command, argv = [], options = null, settings = {}) {
188
188
  toStderr: log.allToStderr,
189
189
  });
190
190
  }
191
- if (typeof options?.cwd === "string" && !(await (0, fs_1.checkDir)(options.cwd)))
191
+ if (typeof options?.cwd === "string" && !(await (0, fs_1.existsDir)(options.cwd)))
192
192
  throw new Error(`Current working directory does not exist: ${options.cwd}`);
193
193
  if (pipe?.stream instanceof fs_2.ReadStream && "onReadProgress" in pipe) {
194
194
  const fileInfo = await (0, promises_1.stat)(pipe.stream.path);
@@ -225,13 +225,13 @@ async function exec(command, argv = [], options = null, settings = {}) {
225
225
  if (spawnData.exitCode) {
226
226
  let exitCodeError;
227
227
  if (settings.stderr?.toExitCode) {
228
- exitCodeError = new Error(`Exit code ${spawnData.exitCode}: ${spawnData.stderr
228
+ exitCodeError = new Error(`Exit code ${spawnData.exitCode}: ${command} ${argv.join(" ")} | ${spawnData.stderr
229
229
  .split(/\r?\n/g)
230
230
  .filter((v) => !!v.length)
231
231
  .join(" | ")}`);
232
232
  }
233
233
  else {
234
- exitCodeError = new Error(`Exit code: ${spawnData.exitCode} (${command} ${argv.join(" ")})`);
234
+ exitCodeError = new Error(`Exit code ${spawnData.exitCode}: ${command} ${argv.join(" ")}`);
235
235
  }
236
236
  const exitCodeErrorResult = settings.onExitCodeError?.(spawnData, exitCodeError);
237
237
  if (exitCodeErrorResult instanceof Error) {
@@ -286,17 +286,24 @@ async function exec(command, argv = [], options = null, settings = {}) {
286
286
  if (!p.stdout)
287
287
  throw new Error(`stdout is not defined`);
288
288
  const parseLines = settings.stdout?.parseLines;
289
- const onData = (data) => {
289
+ const skipEmptyLines = parseLines === "skip-empty";
290
+ const onData = (inData) => {
291
+ let data = inData.toString();
292
+ if (parseLines) {
293
+ if (skipEmptyLines && !data.trim().length)
294
+ return;
295
+ data = `${inData}\n`;
296
+ }
290
297
  if (log.stdout)
291
298
  logExecStdout({
292
- data: parseLines ? `${data}\n` : data.toString(),
299
+ data,
293
300
  stderr: log.allToStderr,
294
301
  colorize: log.colorize,
295
302
  });
296
303
  if (settings.stdout?.save)
297
- spawnData.stdout += data.toString();
304
+ spawnData.stdout += data;
298
305
  if (settings.stdout?.onData)
299
- settings.stdout.onData(data.toString());
306
+ settings.stdout.onData(inData.toString());
300
307
  };
301
308
  if (parseLines) {
302
309
  const rl = (0, readline_1.createInterface)({
@@ -305,7 +312,9 @@ async function exec(command, argv = [], options = null, settings = {}) {
305
312
  rl.on("line", onData);
306
313
  rl.on("close", tryFinish);
307
314
  }
308
- else {
315
+ else if (log.stdout ||
316
+ settings.stdout?.save ||
317
+ settings.stdout?.onData) {
309
318
  p.stdout.on("data", onData);
310
319
  }
311
320
  }
package/utils/string.d.ts CHANGED
@@ -1,6 +1,4 @@
1
1
  export declare function serialize(message: string, data?: Object): string;
2
- export declare function ucfirst(value: string): string;
3
- export declare function lcfirst(value: string): string;
4
2
  export declare function snakeCase(value: string, char?: string): string;
5
3
  export declare function render(subject: string, vars: Record<string, string | undefined>): string;
6
4
  export declare function parseStringList(value: string, validValues?: string[]): string[];
package/utils/string.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.formatDateTime = exports.checkMatch = exports.checkPath = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.lcfirst = exports.ucfirst = exports.serialize = void 0;
3
+ exports.formatDateTime = exports.checkMatch = exports.checkPath = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.serialize = void 0;
4
4
  const AppError_1 = require("../Error/AppError");
5
5
  const micromatch_1 = require("micromatch");
6
6
  function serialize(message, data) {
@@ -9,14 +9,6 @@ function serialize(message, data) {
9
9
  return message;
10
10
  }
11
11
  exports.serialize = serialize;
12
- function ucfirst(value) {
13
- return value.charAt(0).toUpperCase() + value.slice(1);
14
- }
15
- exports.ucfirst = ucfirst;
16
- function lcfirst(value) {
17
- return value.charAt(0).toLowerCase() + value.slice(1);
18
- }
19
- exports.lcfirst = lcfirst;
20
12
  function snakeCase(value, char = "_") {
21
13
  return value.replace(/[A-Z]/g, (letter) => `${char}${letter.toLowerCase()}`);
22
14
  }
package/utils/tar.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ export type Progress = {
2
+ percent: number;
3
+ current: number;
4
+ total: number;
5
+ };
6
+ export type TarEntry = {
7
+ path: string;
8
+ progress: Progress;
9
+ };
10
+ export interface CreateTarOptions {
11
+ path: string;
12
+ verbose?: boolean;
13
+ output: string;
14
+ includeList: string;
15
+ compress?: boolean;
16
+ onEntry?: (entry: TarEntry) => void;
17
+ }
18
+ export interface ExtractOptions {
19
+ input: string;
20
+ output: string;
21
+ verbose?: boolean;
22
+ uncompress?: boolean;
23
+ total?: number;
24
+ onEntry?: (entry: TarEntry) => void;
25
+ }
26
+ export type TarVendor = "busybox" | "bsdtar" | "gnu";
27
+ export declare function getTarVendor(cache?: boolean, log?: boolean): Promise<TarVendor | null>;
28
+ export type ListTarOptions = {
29
+ input: string;
30
+ onEntry?: (entry: Pick<TarEntry, "path">) => void;
31
+ verbose?: boolean;
32
+ };
33
+ export declare function listTar(options: ListTarOptions): Promise<number>;
34
+ export declare function createTar(options: CreateTarOptions): Promise<void>;
35
+ export declare function extractTar(options: ExtractOptions): Promise<void>;
package/utils/tar.js ADDED
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractTar = exports.createTar = exports.listTar = exports.getTarVendor = void 0;
4
+ const cli_1 = require("./cli");
5
+ const fs_1 = require("./fs");
6
+ const math_1 = require("./math");
7
+ const process_1 = require("./process");
8
+ const promises_1 = require("fs/promises");
9
+ const os_1 = require("os");
10
+ let tarVendor;
11
+ async function getTarVendor(cache = true, log = false) {
12
+ if (cache && typeof tarVendor !== "undefined")
13
+ return tarVendor;
14
+ const p = await (0, process_1.exec)("tar", ["--help"], {}, {
15
+ log,
16
+ stdout: {
17
+ save: true,
18
+ },
19
+ });
20
+ const find = () => {
21
+ if (p.stdout.includes("BusyBox")) {
22
+ return "busybox";
23
+ }
24
+ else if (p.stdout.includes("bsdtar")) {
25
+ return "bsdtar";
26
+ }
27
+ else if (p.stdout.includes("GNU")) {
28
+ return "gnu";
29
+ }
30
+ else {
31
+ return null;
32
+ }
33
+ };
34
+ return (tarVendor = find());
35
+ }
36
+ exports.getTarVendor = getTarVendor;
37
+ async function listTar(options) {
38
+ let total = 0;
39
+ await (0, process_1.exec)("tar", ["-tf", toLocalPath(options.input), "--force-local"], {}, {
40
+ log: options.verbose,
41
+ stdout: {
42
+ parseLines: "skip-empty",
43
+ onData: (path) => {
44
+ options.onEntry?.({ path });
45
+ total++;
46
+ },
47
+ },
48
+ });
49
+ return total;
50
+ }
51
+ exports.listTar = listTar;
52
+ async function createTar(options) {
53
+ const vendor = await getTarVendor(true, options.verbose);
54
+ const total = await (0, fs_1.countFileLines)(options.includeList);
55
+ let current = 0;
56
+ await (0, process_1.exec)("tar", [
57
+ "-C",
58
+ toLocalPath(options.path),
59
+ options.compress ? "-czvf" : "-cvf",
60
+ toLocalPath(options.output),
61
+ "-T",
62
+ toLocalPath(options.includeList),
63
+ "--ignore-failed-read",
64
+ "--force-local",
65
+ ], {}, {
66
+ log: options.verbose,
67
+ stderr: { toExitCode: true },
68
+ stdout: {
69
+ parseLines: "skip-empty",
70
+ onData: (line) => {
71
+ current++;
72
+ const path = vendor === "bsdtar" ? line.slice(2) : line;
73
+ options.onEntry?.({
74
+ path,
75
+ progress: {
76
+ total,
77
+ current,
78
+ percent: (0, math_1.progressPercent)(total, current),
79
+ },
80
+ });
81
+ },
82
+ },
83
+ });
84
+ }
85
+ exports.createTar = createTar;
86
+ /**
87
+ * Fix `tar.exe: Option --force-local is not supported`
88
+ */
89
+ function toLocalPath(path) {
90
+ return (0, os_1.platform)() === "win32" ? path.replace(/\\/g, "/") : path;
91
+ }
92
+ async function extractTar(options) {
93
+ let total = options.total ??
94
+ (await listTar({ input: options.input, verbose: options.verbose }));
95
+ if (options.verbose)
96
+ (0, cli_1.logExec)("mkdir", ["-p", options.output]);
97
+ await (0, promises_1.mkdir)(options.output, { recursive: true });
98
+ await (0, fs_1.ensureEmptyDir)(options.output);
99
+ let current = 0;
100
+ await (0, process_1.exec)("tar", [
101
+ options.uncompress ? "-xzvpf" : "-xvpf",
102
+ toLocalPath(options.input),
103
+ "-C",
104
+ toLocalPath(options.output),
105
+ "--force-local",
106
+ ], {}, {
107
+ log: options.verbose,
108
+ stderr: {
109
+ toExitCode: true,
110
+ },
111
+ stdout: {
112
+ parseLines: "skip-empty",
113
+ onData: (path) => {
114
+ current++;
115
+ options.onEntry?.({
116
+ path,
117
+ progress: {
118
+ total,
119
+ current,
120
+ percent: (0, math_1.progressPercent)(total, current),
121
+ },
122
+ });
123
+ },
124
+ },
125
+ });
126
+ }
127
+ exports.extractTar = extractTar;
package/utils/zip.d.ts DELETED
@@ -1,97 +0,0 @@
1
- export interface ZipDataFilterType {
2
- recursive?: boolean;
3
- exclude?: boolean;
4
- patterns: string[];
5
- }
6
- export interface ZipDataType {
7
- command?: string;
8
- path: string;
9
- filter?: (ZipDataFilterType | string)[];
10
- output: string;
11
- deleteOnZip?: boolean;
12
- includeList?: string;
13
- excludeList?: string;
14
- verbose?: boolean;
15
- onProgress?: (data: {
16
- percent: number;
17
- total: number;
18
- current: number;
19
- path?: string;
20
- type?: "start" | "end";
21
- }) => void | Promise<void>;
22
- onStream?: (data: ZipStream) => void | Promise<void>;
23
- }
24
- export interface UnzipDataType {
25
- command?: string;
26
- input: string;
27
- files?: (ZipDataFilterType | string)[];
28
- output: string;
29
- verbose?: boolean;
30
- onProgress?: (data: {
31
- percent: number;
32
- current: number;
33
- path?: string;
34
- type?: "start" | "end";
35
- }) => void | Promise<void>;
36
- onStream?: (data: UnzipStream) => void | Promise<void>;
37
- }
38
- export declare function buildArguments(filters: (ZipDataFilterType | string)[]): string[];
39
- export declare function checkSSEOption(command?: string): Promise<boolean>;
40
- type ListZipStream = {
41
- Path?: string;
42
- Folder?: string;
43
- Size?: string;
44
- "Packed Size"?: string;
45
- Modified?: string;
46
- Created?: string;
47
- Accessed?: string;
48
- Attributes?: string;
49
- Encrypted?: string;
50
- Comment?: string;
51
- CRC?: string;
52
- Method?: string;
53
- Characteristics?: string;
54
- "Host OS"?: string;
55
- Version?: string;
56
- Volume?: string;
57
- Offset?: string;
58
- };
59
- export declare function listZip(data: {
60
- command?: string;
61
- path: string;
62
- onStream: (item: ListZipStream) => Promise<void>;
63
- verbose?: boolean;
64
- }): Promise<void>;
65
- export type ZipStream = {
66
- type: "progress";
67
- data: {
68
- progress: number;
69
- files: number;
70
- path: string;
71
- };
72
- } | {
73
- type: "summary";
74
- data: {
75
- folders: number;
76
- files: number;
77
- };
78
- };
79
- export declare function zip(data: ZipDataType): Promise<{
80
- folders: number;
81
- files: number;
82
- }>;
83
- export type UnzipStream = {
84
- type: "progress";
85
- data: {
86
- percent: number;
87
- files: number;
88
- path: string;
89
- };
90
- };
91
- export declare function unzip(data: UnzipDataType): Promise<{
92
- files: number;
93
- stdout: string;
94
- stderr: string;
95
- exitCode: number;
96
- }>;
97
- export {};
package/utils/zip.js DELETED
@@ -1,238 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.unzip = exports.zip = exports.listZip = exports.checkSSEOption = exports.buildArguments = void 0;
4
- const process_1 = require("./process");
5
- const path_1 = require("path");
6
- function buildArguments(filters) {
7
- const args = [];
8
- for (const item of filters) {
9
- let filter;
10
- if (typeof item === "string") {
11
- filter = {
12
- recursive: false,
13
- exclude: false,
14
- patterns: [item],
15
- };
16
- }
17
- else {
18
- filter = item;
19
- }
20
- args.push(...filter.patterns.map((value) => {
21
- let option = "-";
22
- option += filter.exclude ? "x" : "i";
23
- if (filter.recursive)
24
- option += "r";
25
- option += "!";
26
- option += (0, path_1.normalize)(value);
27
- return option;
28
- }));
29
- }
30
- return args;
31
- }
32
- exports.buildArguments = buildArguments;
33
- let checkSSEOptionResult;
34
- async function checkSSEOption(command = "7z") {
35
- const result = await (0, process_1.exec)(command, [], {}, {
36
- stdout: {
37
- save: true,
38
- },
39
- });
40
- if (typeof checkSSEOptionResult === "boolean")
41
- return checkSSEOptionResult;
42
- return (checkSSEOptionResult = result.stdout.includes(" -sse"));
43
- }
44
- exports.checkSSEOption = checkSSEOption;
45
- const listZipLineEqChar = " = ";
46
- function parseListZipLine(line, buffer) {
47
- if (buffer.started) {
48
- if (line === "") {
49
- if (buffer.opened) {
50
- const { stream } = buffer;
51
- buffer.stream = {};
52
- buffer.opened = false;
53
- return stream;
54
- }
55
- }
56
- else {
57
- const separator = line.indexOf(listZipLineEqChar);
58
- const key = line.slice(0, separator);
59
- const value = line.slice(separator + listZipLineEqChar.length);
60
- buffer.opened = true;
61
- buffer.stream[key] = value;
62
- }
63
- }
64
- else if (line.startsWith("----------")) {
65
- buffer.started = true;
66
- buffer.stream = {};
67
- }
68
- }
69
- async function listZip(data) {
70
- const buffer = {};
71
- await (0, process_1.exec)(data.command ?? "7z", ["l", data.path, "-slt"], {}, {
72
- log: {
73
- exec: data.verbose ?? false,
74
- stderr: data.verbose ?? false,
75
- stdout: false,
76
- },
77
- onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
78
- stdout: {
79
- parseLines: true,
80
- onData: async (line) => {
81
- const stream = parseListZipLine(line, buffer);
82
- if (stream) {
83
- await data.onStream?.(stream);
84
- }
85
- },
86
- },
87
- });
88
- }
89
- exports.listZip = listZip;
90
- function parseZipLine(line) {
91
- let matches = null;
92
- line = line.trim();
93
- if (!line.length)
94
- return;
95
- if ((matches = /^(\d+)% (\d+ )?\+/.exec(line))) {
96
- const path = line.slice(line.indexOf("+") + 1).trim();
97
- const progress = Number(matches[1]);
98
- const files = matches[2] ? Number(matches[2]) : 1;
99
- return {
100
- type: "progress",
101
- data: { progress, path, files },
102
- };
103
- }
104
- else if (line.startsWith("Add new data to archive:")) {
105
- const [, folders] = /(\d+) folders?/i.exec(line) || [, 0];
106
- const [, files] = /(\d+) files?/i.exec(line) || [, 0];
107
- return {
108
- type: "summary",
109
- data: {
110
- folders: Number(folders),
111
- files: Number(files),
112
- },
113
- };
114
- }
115
- }
116
- async function zip(data) {
117
- let summary = {
118
- folders: 0,
119
- files: 0,
120
- };
121
- await data.onProgress?.({
122
- current: 0,
123
- percent: 0,
124
- total: 0,
125
- type: "start",
126
- });
127
- await (0, process_1.exec)(data.command ?? "7z", [
128
- "a",
129
- // https://sourceforge.net/p/sevenzip/bugs/2099/,
130
- // https://github.com/mcmilk/7-Zip/commit/87ba6f01ba3c5b2ce3186bddfe3d7d880639193c#diff-779d6b1bfa6196b288478f78ca96c4d4c6d7ac6cf8be15a28a20dabc9137ca36L515
131
- ...((await checkSSEOption(data.command)) ? [] : ["-mmt1"]),
132
- "-bsp1",
133
- ...(data.deleteOnZip ? ["-sdel"] : []),
134
- (0, path_1.normalize)(data.output),
135
- ...buildArguments(data.filter ?? []),
136
- ...(data.includeList ? [`@${(0, path_1.normalize)(data.includeList)}`] : []),
137
- ...(data.excludeList ? [`-x@${(0, path_1.normalize)(data.excludeList)}`] : []),
138
- ], {
139
- cwd: data.path,
140
- }, {
141
- log: data.verbose ?? false,
142
- onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
143
- stdout: {
144
- onData: async (lines) => {
145
- for (const line of lines.replaceAll("\b", "").split(/\r?\n/)) {
146
- const stream = parseZipLine(line);
147
- if (stream) {
148
- if (stream.type === "summary")
149
- summary = stream.data;
150
- if (stream.type === "progress") {
151
- const current = Math.max(0, stream.data.files - 1);
152
- await data.onProgress?.({
153
- total: summary.files,
154
- current,
155
- path: stream.data.path,
156
- percent: stream.data.progress,
157
- });
158
- }
159
- await data.onStream?.(stream);
160
- }
161
- }
162
- },
163
- },
164
- });
165
- await data.onProgress?.({
166
- total: summary.files,
167
- current: summary.files,
168
- percent: 100,
169
- type: "end",
170
- });
171
- return summary;
172
- }
173
- exports.zip = zip;
174
- function parseUnzipLine(line) {
175
- let matches = null;
176
- if ((matches = /^\s*(?<percent>\d+)%(?: (?<files>\d+))? \-/.exec(line))) {
177
- const progress = Number(matches.groups["percent"]);
178
- const files = matches.groups["files"] ? Number(matches[2]) : 1;
179
- const path = line.slice(line.indexOf("-") + 1).trim();
180
- return {
181
- type: "progress",
182
- data: { percent: progress, path, files },
183
- };
184
- }
185
- }
186
- async function unzip(data) {
187
- let summary = {
188
- files: 0,
189
- };
190
- await data.onProgress?.({
191
- current: summary.files,
192
- percent: 0,
193
- type: "start",
194
- });
195
- const result = await (0, process_1.exec)(data.command ?? "7z", [
196
- "x",
197
- "-bsp1",
198
- (0, path_1.normalize)(data.input),
199
- ...buildArguments(data.files ?? []),
200
- `-o${(0, path_1.normalize)(data.output)}`,
201
- "-r",
202
- ], {}, {
203
- log: data.verbose ?? false,
204
- stderr: { toExitCode: true },
205
- stdout: {
206
- ...((data.onStream || data.onProgress) && {
207
- onData: async (chunk) => {
208
- const lines = chunk.replaceAll("\b", "").split(/\r?\n/);
209
- for (const line of lines) {
210
- const stream = parseUnzipLine(line);
211
- if (stream) {
212
- if (stream.type === "progress") {
213
- const current = Math.max(0, stream.data.files - 1);
214
- summary.files = stream.data.files;
215
- await data.onProgress?.({
216
- current,
217
- percent: stream.data.percent,
218
- path: stream.data.path,
219
- });
220
- }
221
- await data.onStream?.(stream);
222
- }
223
- }
224
- },
225
- }),
226
- },
227
- });
228
- await data.onProgress?.({
229
- current: summary.files,
230
- percent: 100,
231
- type: "end",
232
- });
233
- return {
234
- ...result,
235
- ...summary,
236
- };
237
- }
238
- exports.unzip = unzip;