7zip-native 0.0.1 → 0.0.6
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 +255 -59
- package/dist/index.cjs +201 -40
- package/dist/index.d.cts +20 -7
- package/dist/index.d.mts +20 -7
- package/dist/index.d.ts +20 -7
- package/dist/index.mjs +202 -41
- package/package.json +3 -1
- package/prebuilds/darwin-arm64/7zip_native.node +0 -0
- package/prebuilds/darwin-arm64/lib7z.dylib +0 -0
- package/prebuilds/darwin-x64/7zip_native.node +0 -0
- package/prebuilds/darwin-x64/lib7z.dylib +0 -0
- package/prebuilds/linux-arm/7z.so +0 -0
- package/prebuilds/linux-arm/7zip_native.node +0 -0
- package/prebuilds/linux-arm64/7z.so +0 -0
- package/prebuilds/linux-arm64/7zip_native.node +0 -0
- package/prebuilds/linux-ia32/7z.so +0 -0
- package/prebuilds/linux-ia32/7zip_native.node +0 -0
- package/prebuilds/win32-arm64/7z.dll +0 -0
- package/prebuilds/win32-arm64/7zip_native.node +0 -0
- package/prebuilds/win32-x64/7z.dll +0 -0
- package/prebuilds/win32-x64/7zip_native.node +0 -0
- package/scripts/build-native.mjs +119 -0
- package/scripts/clean-upstream-build.mjs +9 -0
- package/scripts/verify-prebuild.mjs +29 -0
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var node_fs = require('node:fs');
|
|
4
4
|
var promises$1 = require('node:fs/promises');
|
|
5
|
+
var node_crypto = require('node:crypto');
|
|
5
6
|
var node_module = require('node:module');
|
|
6
7
|
var node_os = require('node:os');
|
|
7
8
|
var node_path = require('node:path');
|
|
@@ -124,6 +125,19 @@ async function ensureDirectory(directoryPath) {
|
|
|
124
125
|
throw new ArchiveError('ERR_ARCHIVE_PATH', `Destination path is not a real directory: ${directoryPath}`);
|
|
125
126
|
}
|
|
126
127
|
}
|
|
128
|
+
async function assertReplaceableOutput(filePath) {
|
|
129
|
+
try {
|
|
130
|
+
const details = await promises$1.lstat(filePath);
|
|
131
|
+
if (!details.isFile()) {
|
|
132
|
+
throw new ArchiveError('ERR_ARCHIVE_PATH', `Cannot replace a non-file extraction target: ${filePath}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof ArchiveError || error.code !== 'ENOENT') {
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
127
141
|
async function ensureExtractionRoot(root) {
|
|
128
142
|
try {
|
|
129
143
|
const details = await promises$1.lstat(root);
|
|
@@ -167,6 +181,7 @@ class NativeArchiveReadable extends node_stream.Readable {
|
|
|
167
181
|
maxBytes;
|
|
168
182
|
streamId;
|
|
169
183
|
outputBytes = 0n;
|
|
184
|
+
starting = false;
|
|
170
185
|
constructor(start, resumeNative, cancel, options, maxBytes) {
|
|
171
186
|
super({ highWaterMark: options.highWaterMark, signal: options.signal });
|
|
172
187
|
this.start = start;
|
|
@@ -175,38 +190,63 @@ class NativeArchiveReadable extends node_stream.Readable {
|
|
|
175
190
|
this.maxBytes = maxBytes;
|
|
176
191
|
}
|
|
177
192
|
_read() {
|
|
193
|
+
if (this.streamId !== undefined) {
|
|
194
|
+
try {
|
|
195
|
+
this.resumeNative(this.streamId);
|
|
196
|
+
}
|
|
197
|
+
catch (cause) {
|
|
198
|
+
this.destroy(extractionError(cause));
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (this.starting) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
this.starting = true;
|
|
178
206
|
try {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
207
|
+
Promise.resolve(this.start((chunk, error, done) => {
|
|
208
|
+
if (this.destroyed) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (error) {
|
|
212
|
+
this.destroy(extractionError(error));
|
|
213
|
+
}
|
|
214
|
+
else if (done) {
|
|
215
|
+
this.push(null);
|
|
216
|
+
}
|
|
217
|
+
else if (chunk) {
|
|
218
|
+
if (this.maxBytes !== null
|
|
219
|
+
&& this.outputBytes + BigInt(chunk.length) > this.maxBytes) {
|
|
220
|
+
this.destroy(new ArchiveError('ERR_RESOURCE_LIMIT', `Stream output exceeds the ${this.maxBytes}-byte limit`));
|
|
182
221
|
return;
|
|
183
222
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.outputBytes += BigInt(chunk.length);
|
|
197
|
-
this.push(chunk);
|
|
223
|
+
this.outputBytes += BigInt(chunk.length);
|
|
224
|
+
this.push(chunk);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
this.destroy(new ArchiveError('ERR_ARCHIVE_EXTRACT', 'Native stream returned an empty chunk notification'));
|
|
228
|
+
}
|
|
229
|
+
})).then((streamId) => {
|
|
230
|
+
this.streamId = streamId;
|
|
231
|
+
this.starting = false;
|
|
232
|
+
try {
|
|
233
|
+
if (this.destroyed) {
|
|
234
|
+
this.cancel(streamId);
|
|
198
235
|
}
|
|
199
236
|
else {
|
|
200
|
-
this.
|
|
237
|
+
this.resumeNative(streamId);
|
|
201
238
|
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
239
|
+
}
|
|
240
|
+
catch (cause) {
|
|
241
|
+
this.destroy(extractionError(cause));
|
|
242
|
+
}
|
|
243
|
+
}, (cause) => {
|
|
244
|
+
this.starting = false;
|
|
245
|
+
this.destroy(extractionError(cause));
|
|
246
|
+
});
|
|
208
247
|
}
|
|
209
248
|
catch (cause) {
|
|
249
|
+
this.starting = false;
|
|
210
250
|
this.destroy(extractionError(cause));
|
|
211
251
|
}
|
|
212
252
|
}
|
|
@@ -272,21 +312,41 @@ class Archive {
|
|
|
272
312
|
}
|
|
273
313
|
return (await this.entries()).find(entry => typeof idOrPath === 'number' ? entry.id === idOrPath : entry.path === idOrPath);
|
|
274
314
|
}
|
|
275
|
-
async extract(
|
|
315
|
+
async extract(idOrPathOrPaths) {
|
|
276
316
|
this.assertOpen();
|
|
277
|
-
const
|
|
278
|
-
|
|
317
|
+
const isBatch = Array.isArray(idOrPathOrPaths);
|
|
318
|
+
let selectors;
|
|
319
|
+
if (isBatch) {
|
|
320
|
+
selectors = idOrPathOrPaths;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
selectors = [idOrPathOrPaths];
|
|
324
|
+
}
|
|
325
|
+
const numericIds = selectors.filter((selector) => typeof selector === 'number');
|
|
326
|
+
let ids;
|
|
327
|
+
if (numericIds.length === selectors.length) {
|
|
328
|
+
this.validateIds(numericIds);
|
|
329
|
+
ids = numericIds;
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
ids = await this.resolveEntryIds(selectors);
|
|
333
|
+
}
|
|
279
334
|
try {
|
|
280
335
|
const buffers = await native.extract(this.handle, ids);
|
|
281
|
-
return
|
|
336
|
+
return isBatch ? buffers : buffers[0];
|
|
282
337
|
}
|
|
283
338
|
catch (cause) {
|
|
284
339
|
throw extractionError(cause);
|
|
285
340
|
}
|
|
286
341
|
}
|
|
287
|
-
createReadStream(
|
|
342
|
+
createReadStream(idOrPath, options = {}) {
|
|
288
343
|
this.assertOpen();
|
|
289
|
-
|
|
344
|
+
if (typeof idOrPath === 'number') {
|
|
345
|
+
this.validateIds([idOrPath]);
|
|
346
|
+
}
|
|
347
|
+
else if (typeof idOrPath !== 'string') {
|
|
348
|
+
throw new TypeError('Entry selector must be an ID or archive path');
|
|
349
|
+
}
|
|
290
350
|
if (!options || typeof options !== 'object') {
|
|
291
351
|
throw new TypeError('Stream options must be an object');
|
|
292
352
|
}
|
|
@@ -298,13 +358,18 @@ class Archive {
|
|
|
298
358
|
}
|
|
299
359
|
options.signal?.throwIfAborted();
|
|
300
360
|
const maxBytes = normalizeMaxBytes(options.maxBytes, 'maxBytes');
|
|
301
|
-
return new NativeArchiveReadable(
|
|
361
|
+
return new NativeArchiveReadable((callback) => {
|
|
362
|
+
if (typeof idOrPath === 'number') {
|
|
363
|
+
return native.startStream(this.handle, idOrPath, callback);
|
|
364
|
+
}
|
|
365
|
+
return this.resolveEntryId(idOrPath).then(id => native.startStream(this.handle, id, callback));
|
|
366
|
+
}, streamId => native.resumeStream(streamId), streamId => native.cancelStream(streamId), options, maxBytes);
|
|
302
367
|
}
|
|
303
|
-
async extractToStream(
|
|
368
|
+
async extractToStream(idOrPath, destination, options = {}) {
|
|
304
369
|
if (!destination || typeof destination.write !== 'function') {
|
|
305
370
|
throw new TypeError('Destination must be a writable stream');
|
|
306
371
|
}
|
|
307
|
-
await promises.pipeline(this.createReadStream(
|
|
372
|
+
await promises.pipeline(this.createReadStream(idOrPath, options), destination, { signal: options.signal });
|
|
308
373
|
}
|
|
309
374
|
async extractToFolder(destination, options = {}) {
|
|
310
375
|
this.assertOpen();
|
|
@@ -314,10 +379,19 @@ class Archive {
|
|
|
314
379
|
if (!options || typeof options !== 'object') {
|
|
315
380
|
throw new TypeError('Folder extraction options must be an object');
|
|
316
381
|
}
|
|
382
|
+
if (options.overwrite !== undefined && typeof options.overwrite !== 'boolean') {
|
|
383
|
+
throw new TypeError('Folder extraction overwrite option must be a boolean');
|
|
384
|
+
}
|
|
385
|
+
if (options.onProgress !== undefined && typeof options.onProgress !== 'function') {
|
|
386
|
+
throw new TypeError('Folder extraction onProgress option must be a function');
|
|
387
|
+
}
|
|
317
388
|
options.signal?.throwIfAborted();
|
|
318
389
|
const maxBytes = normalizeMaxBytes(options.maxBytes, 'maxBytes');
|
|
319
390
|
const entries = await this.entries();
|
|
320
391
|
let selectedEntries = entries;
|
|
392
|
+
if (options.ids !== undefined && options.paths !== undefined) {
|
|
393
|
+
throw new TypeError('Specify either folder extraction IDs or paths, not both');
|
|
394
|
+
}
|
|
321
395
|
if (options.ids !== undefined) {
|
|
322
396
|
if (!Array.isArray(options.ids)) {
|
|
323
397
|
throw new TypeError('Folder extraction IDs must be an array');
|
|
@@ -332,6 +406,21 @@ class Archive {
|
|
|
332
406
|
return entry;
|
|
333
407
|
});
|
|
334
408
|
}
|
|
409
|
+
else if (options.paths !== undefined) {
|
|
410
|
+
if (!Array.isArray(options.paths)
|
|
411
|
+
|| options.paths.some(entryPath => typeof entryPath !== 'string')) {
|
|
412
|
+
throw new TypeError('Folder extraction paths must be an array of strings');
|
|
413
|
+
}
|
|
414
|
+
const ids = await this.resolveEntryIds(options.paths);
|
|
415
|
+
const entriesById = new Map(entries.map(entry => [entry.id, entry]));
|
|
416
|
+
selectedEntries = ids.map((id) => {
|
|
417
|
+
const entry = entriesById.get(id);
|
|
418
|
+
if (!entry) {
|
|
419
|
+
throw new ArchiveError('ERR_INVALID_ENTRY', `Entry ID ${id} is out of range`);
|
|
420
|
+
}
|
|
421
|
+
return entry;
|
|
422
|
+
});
|
|
423
|
+
}
|
|
335
424
|
const root = node_path.resolve(destination);
|
|
336
425
|
const plans = makeOutputPlans(root, selectedEntries);
|
|
337
426
|
const expectedBytes = selectedEntries.reduce((total, entry) => total + (entry.isDirectory ? 0n : entry.size), 0n);
|
|
@@ -341,6 +430,26 @@ class Archive {
|
|
|
341
430
|
options.signal?.throwIfAborted();
|
|
342
431
|
await ensureExtractionRoot(root);
|
|
343
432
|
let extractedBytes = 0n;
|
|
433
|
+
let filesExtracted = 0;
|
|
434
|
+
const totalFiles = plans.filter(plan => !plan.isDirectory).length;
|
|
435
|
+
const reportProgress = () => {
|
|
436
|
+
let percent = 0;
|
|
437
|
+
if (expectedBytes > 0n) {
|
|
438
|
+
const scaledPercent = extractedBytes * 10000n / expectedBytes;
|
|
439
|
+
percent = Number(scaledPercent > 9900n ? 9900n : scaledPercent) / 100;
|
|
440
|
+
}
|
|
441
|
+
if (filesExtracted === totalFiles) {
|
|
442
|
+
percent = 100;
|
|
443
|
+
}
|
|
444
|
+
options.onProgress?.({
|
|
445
|
+
filesExtracted,
|
|
446
|
+
totalFiles,
|
|
447
|
+
bytesProcessed: extractedBytes,
|
|
448
|
+
totalBytes: expectedBytes,
|
|
449
|
+
percent,
|
|
450
|
+
});
|
|
451
|
+
};
|
|
452
|
+
reportProgress();
|
|
344
453
|
for (const plan of plans) {
|
|
345
454
|
options.signal?.throwIfAborted();
|
|
346
455
|
if (plan.isDirectory) {
|
|
@@ -348,7 +457,6 @@ class Archive {
|
|
|
348
457
|
continue;
|
|
349
458
|
}
|
|
350
459
|
await ensureOutputParents(root, plan.targetPath);
|
|
351
|
-
const output = node_fs.createWriteStream(plan.targetPath, { flags: 'wx', mode: 0o600 });
|
|
352
460
|
const limit = new node_stream.Transform({
|
|
353
461
|
transform(chunk, _encoding, callback) {
|
|
354
462
|
const size = BigInt(chunk.length);
|
|
@@ -357,18 +465,52 @@ class Archive {
|
|
|
357
465
|
return;
|
|
358
466
|
}
|
|
359
467
|
extractedBytes += size;
|
|
468
|
+
try {
|
|
469
|
+
reportProgress();
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
callback(error instanceof Error ? error : new Error(String(error)));
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
360
475
|
callback(null, chunk);
|
|
361
476
|
},
|
|
362
477
|
});
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
478
|
+
if (options.overwrite) {
|
|
479
|
+
await assertReplaceableOutput(plan.targetPath);
|
|
480
|
+
const temporaryPath = node_path.join(node_path.dirname(plan.targetPath), `.7zip-native-${node_crypto.randomUUID()}.tmp`);
|
|
481
|
+
try {
|
|
482
|
+
await promises.pipeline(this.createReadStream(plan.entry.id, {
|
|
483
|
+
signal: options.signal,
|
|
484
|
+
maxBytes: null,
|
|
485
|
+
}), limit, node_fs.createWriteStream(temporaryPath, { flags: 'wx', mode: 0o600 }), { signal: options.signal });
|
|
486
|
+
await assertReplaceableOutput(plan.targetPath);
|
|
487
|
+
await promises$1.rename(temporaryPath, plan.targetPath);
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
await promises$1.rm(temporaryPath, { force: true });
|
|
491
|
+
throw error;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
await promises.pipeline(this.createReadStream(plan.entry.id, {
|
|
496
|
+
signal: options.signal,
|
|
497
|
+
maxBytes: null,
|
|
498
|
+
}), limit, node_fs.createWriteStream(plan.targetPath, { flags: 'wx', mode: 0o600 }), { signal: options.signal });
|
|
499
|
+
}
|
|
500
|
+
filesExtracted++;
|
|
501
|
+
reportProgress();
|
|
367
502
|
}
|
|
368
503
|
}
|
|
369
|
-
async read(
|
|
504
|
+
async read(idOrPath, options) {
|
|
370
505
|
this.assertOpen();
|
|
371
|
-
|
|
506
|
+
let id;
|
|
507
|
+
if (typeof idOrPath === 'number') {
|
|
508
|
+
this.validateIds([idOrPath]);
|
|
509
|
+
id = idOrPath;
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
id = await this.resolveEntryId(idOrPath);
|
|
513
|
+
}
|
|
372
514
|
const offset = this.toUnsignedBigInt(options.offset ?? 0, 'offset');
|
|
373
515
|
const length = this.toUnsignedBigInt(options.length, 'length');
|
|
374
516
|
const maxUInt64 = (1n << 64n) - 1n;
|
|
@@ -399,6 +541,25 @@ class Archive {
|
|
|
399
541
|
throw new ArchiveError('ERR_INVALID_ENTRY', 'Entry IDs must be unique non-negative safe integers');
|
|
400
542
|
}
|
|
401
543
|
}
|
|
544
|
+
async resolveEntryId(selector) {
|
|
545
|
+
if (typeof selector === 'number') {
|
|
546
|
+
this.validateIds([selector]);
|
|
547
|
+
return selector;
|
|
548
|
+
}
|
|
549
|
+
if (typeof selector !== 'string') {
|
|
550
|
+
throw new TypeError('Entry selector must be an ID or archive path');
|
|
551
|
+
}
|
|
552
|
+
const entry = await this.getEntry(selector);
|
|
553
|
+
if (!entry) {
|
|
554
|
+
throw new ArchiveError('ERR_INVALID_ENTRY', `Archive entry "${selector}" was not found`);
|
|
555
|
+
}
|
|
556
|
+
return entry.id;
|
|
557
|
+
}
|
|
558
|
+
async resolveEntryIds(selectors) {
|
|
559
|
+
const ids = await Promise.all(selectors.map(selector => this.resolveEntryId(selector)));
|
|
560
|
+
this.validateIds(ids);
|
|
561
|
+
return ids;
|
|
562
|
+
}
|
|
402
563
|
toUnsignedBigInt(value, label) {
|
|
403
564
|
if (typeof value === 'bigint') {
|
|
404
565
|
if (value < 0n) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Readable, Writable } from 'node:stream';
|
|
2
2
|
|
|
3
3
|
type EntryId = number;
|
|
4
|
+
type EntrySelector = EntryId | string;
|
|
4
5
|
interface ArchiveEntry {
|
|
5
6
|
readonly id: EntryId;
|
|
6
7
|
readonly path: string;
|
|
@@ -18,6 +19,13 @@ interface ReadOptions {
|
|
|
18
19
|
interface OpenOptions {
|
|
19
20
|
readonly password?: string;
|
|
20
21
|
}
|
|
22
|
+
interface ExtractToFolderProgress {
|
|
23
|
+
readonly filesExtracted: number;
|
|
24
|
+
readonly totalFiles: number;
|
|
25
|
+
readonly bytesProcessed: bigint;
|
|
26
|
+
readonly totalBytes: bigint;
|
|
27
|
+
readonly percent: number;
|
|
28
|
+
}
|
|
21
29
|
interface ReadStreamOptions {
|
|
22
30
|
readonly highWaterMark?: number;
|
|
23
31
|
readonly maxBytes?: number | bigint | null;
|
|
@@ -25,6 +33,9 @@ interface ReadStreamOptions {
|
|
|
25
33
|
}
|
|
26
34
|
interface ExtractToFolderOptions {
|
|
27
35
|
readonly ids?: readonly EntryId[];
|
|
36
|
+
readonly paths?: readonly string[];
|
|
37
|
+
readonly overwrite?: boolean;
|
|
38
|
+
readonly onProgress?: (progress: ExtractToFolderProgress) => void;
|
|
28
39
|
readonly maxBytes?: number | bigint | null;
|
|
29
40
|
readonly signal?: AbortSignal;
|
|
30
41
|
}
|
|
@@ -42,18 +53,20 @@ declare class Archive {
|
|
|
42
53
|
static concurrency(value?: number): number;
|
|
43
54
|
static open(path: string, options?: OpenOptions): Promise<Archive>;
|
|
44
55
|
entries(): Promise<readonly ArchiveEntry[]>;
|
|
45
|
-
getEntry(idOrPath:
|
|
46
|
-
extract(
|
|
47
|
-
extract(
|
|
48
|
-
createReadStream(
|
|
49
|
-
extractToStream(
|
|
56
|
+
getEntry(idOrPath: EntrySelector): Promise<ArchiveEntry | undefined>;
|
|
57
|
+
extract(idOrPath: EntrySelector): Promise<Buffer>;
|
|
58
|
+
extract(idsOrPaths: readonly EntrySelector[]): Promise<Buffer[]>;
|
|
59
|
+
createReadStream(idOrPath: EntrySelector, options?: ReadStreamOptions): Readable;
|
|
60
|
+
extractToStream(idOrPath: EntrySelector, destination: Writable, options?: ReadStreamOptions): Promise<void>;
|
|
50
61
|
extractToFolder(destination: string, options?: ExtractToFolderOptions): Promise<void>;
|
|
51
|
-
read(
|
|
62
|
+
read(idOrPath: EntrySelector, options: ReadOptions): Promise<Buffer>;
|
|
52
63
|
close(): Promise<void>;
|
|
53
64
|
private assertOpen;
|
|
54
65
|
private validateIds;
|
|
66
|
+
private resolveEntryId;
|
|
67
|
+
private resolveEntryIds;
|
|
55
68
|
private toUnsignedBigInt;
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
export { Archive, ArchiveError };
|
|
59
|
-
export type { ArchiveEntry, ArchiveErrorCode, EntryId, ExtractToFolderOptions, OpenOptions, ReadOptions, ReadStreamOptions };
|
|
72
|
+
export type { ArchiveEntry, ArchiveErrorCode, EntryId, EntrySelector, ExtractToFolderOptions, ExtractToFolderProgress, OpenOptions, ReadOptions, ReadStreamOptions };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Readable, Writable } from 'node:stream';
|
|
2
2
|
|
|
3
3
|
type EntryId = number;
|
|
4
|
+
type EntrySelector = EntryId | string;
|
|
4
5
|
interface ArchiveEntry {
|
|
5
6
|
readonly id: EntryId;
|
|
6
7
|
readonly path: string;
|
|
@@ -18,6 +19,13 @@ interface ReadOptions {
|
|
|
18
19
|
interface OpenOptions {
|
|
19
20
|
readonly password?: string;
|
|
20
21
|
}
|
|
22
|
+
interface ExtractToFolderProgress {
|
|
23
|
+
readonly filesExtracted: number;
|
|
24
|
+
readonly totalFiles: number;
|
|
25
|
+
readonly bytesProcessed: bigint;
|
|
26
|
+
readonly totalBytes: bigint;
|
|
27
|
+
readonly percent: number;
|
|
28
|
+
}
|
|
21
29
|
interface ReadStreamOptions {
|
|
22
30
|
readonly highWaterMark?: number;
|
|
23
31
|
readonly maxBytes?: number | bigint | null;
|
|
@@ -25,6 +33,9 @@ interface ReadStreamOptions {
|
|
|
25
33
|
}
|
|
26
34
|
interface ExtractToFolderOptions {
|
|
27
35
|
readonly ids?: readonly EntryId[];
|
|
36
|
+
readonly paths?: readonly string[];
|
|
37
|
+
readonly overwrite?: boolean;
|
|
38
|
+
readonly onProgress?: (progress: ExtractToFolderProgress) => void;
|
|
28
39
|
readonly maxBytes?: number | bigint | null;
|
|
29
40
|
readonly signal?: AbortSignal;
|
|
30
41
|
}
|
|
@@ -42,18 +53,20 @@ declare class Archive {
|
|
|
42
53
|
static concurrency(value?: number): number;
|
|
43
54
|
static open(path: string, options?: OpenOptions): Promise<Archive>;
|
|
44
55
|
entries(): Promise<readonly ArchiveEntry[]>;
|
|
45
|
-
getEntry(idOrPath:
|
|
46
|
-
extract(
|
|
47
|
-
extract(
|
|
48
|
-
createReadStream(
|
|
49
|
-
extractToStream(
|
|
56
|
+
getEntry(idOrPath: EntrySelector): Promise<ArchiveEntry | undefined>;
|
|
57
|
+
extract(idOrPath: EntrySelector): Promise<Buffer>;
|
|
58
|
+
extract(idsOrPaths: readonly EntrySelector[]): Promise<Buffer[]>;
|
|
59
|
+
createReadStream(idOrPath: EntrySelector, options?: ReadStreamOptions): Readable;
|
|
60
|
+
extractToStream(idOrPath: EntrySelector, destination: Writable, options?: ReadStreamOptions): Promise<void>;
|
|
50
61
|
extractToFolder(destination: string, options?: ExtractToFolderOptions): Promise<void>;
|
|
51
|
-
read(
|
|
62
|
+
read(idOrPath: EntrySelector, options: ReadOptions): Promise<Buffer>;
|
|
52
63
|
close(): Promise<void>;
|
|
53
64
|
private assertOpen;
|
|
54
65
|
private validateIds;
|
|
66
|
+
private resolveEntryId;
|
|
67
|
+
private resolveEntryIds;
|
|
55
68
|
private toUnsignedBigInt;
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
export { Archive, ArchiveError };
|
|
59
|
-
export type { ArchiveEntry, ArchiveErrorCode, EntryId, ExtractToFolderOptions, OpenOptions, ReadOptions, ReadStreamOptions };
|
|
72
|
+
export type { ArchiveEntry, ArchiveErrorCode, EntryId, EntrySelector, ExtractToFolderOptions, ExtractToFolderProgress, OpenOptions, ReadOptions, ReadStreamOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Readable, Writable } from 'node:stream';
|
|
2
2
|
|
|
3
3
|
type EntryId = number;
|
|
4
|
+
type EntrySelector = EntryId | string;
|
|
4
5
|
interface ArchiveEntry {
|
|
5
6
|
readonly id: EntryId;
|
|
6
7
|
readonly path: string;
|
|
@@ -18,6 +19,13 @@ interface ReadOptions {
|
|
|
18
19
|
interface OpenOptions {
|
|
19
20
|
readonly password?: string;
|
|
20
21
|
}
|
|
22
|
+
interface ExtractToFolderProgress {
|
|
23
|
+
readonly filesExtracted: number;
|
|
24
|
+
readonly totalFiles: number;
|
|
25
|
+
readonly bytesProcessed: bigint;
|
|
26
|
+
readonly totalBytes: bigint;
|
|
27
|
+
readonly percent: number;
|
|
28
|
+
}
|
|
21
29
|
interface ReadStreamOptions {
|
|
22
30
|
readonly highWaterMark?: number;
|
|
23
31
|
readonly maxBytes?: number | bigint | null;
|
|
@@ -25,6 +33,9 @@ interface ReadStreamOptions {
|
|
|
25
33
|
}
|
|
26
34
|
interface ExtractToFolderOptions {
|
|
27
35
|
readonly ids?: readonly EntryId[];
|
|
36
|
+
readonly paths?: readonly string[];
|
|
37
|
+
readonly overwrite?: boolean;
|
|
38
|
+
readonly onProgress?: (progress: ExtractToFolderProgress) => void;
|
|
28
39
|
readonly maxBytes?: number | bigint | null;
|
|
29
40
|
readonly signal?: AbortSignal;
|
|
30
41
|
}
|
|
@@ -42,18 +53,20 @@ declare class Archive {
|
|
|
42
53
|
static concurrency(value?: number): number;
|
|
43
54
|
static open(path: string, options?: OpenOptions): Promise<Archive>;
|
|
44
55
|
entries(): Promise<readonly ArchiveEntry[]>;
|
|
45
|
-
getEntry(idOrPath:
|
|
46
|
-
extract(
|
|
47
|
-
extract(
|
|
48
|
-
createReadStream(
|
|
49
|
-
extractToStream(
|
|
56
|
+
getEntry(idOrPath: EntrySelector): Promise<ArchiveEntry | undefined>;
|
|
57
|
+
extract(idOrPath: EntrySelector): Promise<Buffer>;
|
|
58
|
+
extract(idsOrPaths: readonly EntrySelector[]): Promise<Buffer[]>;
|
|
59
|
+
createReadStream(idOrPath: EntrySelector, options?: ReadStreamOptions): Readable;
|
|
60
|
+
extractToStream(idOrPath: EntrySelector, destination: Writable, options?: ReadStreamOptions): Promise<void>;
|
|
50
61
|
extractToFolder(destination: string, options?: ExtractToFolderOptions): Promise<void>;
|
|
51
|
-
read(
|
|
62
|
+
read(idOrPath: EntrySelector, options: ReadOptions): Promise<Buffer>;
|
|
52
63
|
close(): Promise<void>;
|
|
53
64
|
private assertOpen;
|
|
54
65
|
private validateIds;
|
|
66
|
+
private resolveEntryId;
|
|
67
|
+
private resolveEntryIds;
|
|
55
68
|
private toUnsignedBigInt;
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
export { Archive, ArchiveError };
|
|
59
|
-
export type { ArchiveEntry, ArchiveErrorCode, EntryId, ExtractToFolderOptions, OpenOptions, ReadOptions, ReadStreamOptions };
|
|
72
|
+
export type { ArchiveEntry, ArchiveErrorCode, EntryId, EntrySelector, ExtractToFolderOptions, ExtractToFolderProgress, OpenOptions, ReadOptions, ReadStreamOptions };
|