@cj-tech-master/excelts 1.4.5-canary.20251212064440.3eb099f → 1.4.5-canary.20251212160853.7621827

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.
@@ -26,12 +26,18 @@ class Workbook {
26
26
  this.pivotTables = [];
27
27
  this._definedNames = new DefinedNames();
28
28
  }
29
+ /**
30
+ * xlsx file format operations
31
+ */
29
32
  get xlsx() {
30
33
  if (!this._xlsx) {
31
34
  this._xlsx = new XLSX(this);
32
35
  }
33
36
  return this._xlsx;
34
37
  }
38
+ /**
39
+ * csv file format operations
40
+ */
35
41
  get csv() {
36
42
  if (!this._csv) {
37
43
  this._csv = new CSV(this);
@@ -47,6 +53,9 @@ class Workbook {
47
53
  }
48
54
  return this._worksheets.length || 1;
49
55
  }
56
+ /**
57
+ * Add a new worksheet and return a reference to it
58
+ */
50
59
  addWorksheet(name, options) {
51
60
  const id = this.nextId;
52
61
  const lastOrderNo = this._worksheets.reduce((acc, ws) => ((ws && ws.orderNo) > acc ? ws.orderNo : acc), 0);
@@ -70,6 +79,9 @@ class Workbook {
70
79
  worksheet.destroy();
71
80
  }
72
81
  }
82
+ /**
83
+ * Fetch sheet by name or id
84
+ */
73
85
  getWorksheet(id) {
74
86
  if (id === undefined) {
75
87
  return this._worksheets.find(Boolean);
@@ -82,6 +94,9 @@ class Workbook {
82
94
  }
83
95
  return undefined;
84
96
  }
97
+ /**
98
+ * Return a clone of worksheets in order
99
+ */
85
100
  get worksheets() {
86
101
  // return a clone of _worksheets
87
102
  return this._worksheets
@@ -89,9 +104,14 @@ class Workbook {
89
104
  .sort((a, b) => a.orderNo - b.orderNo)
90
105
  .filter(Boolean);
91
106
  }
92
- eachSheet(iteratee) {
107
+ /**
108
+ * Iterate over all sheets.
109
+ *
110
+ * Note: `workbook.worksheets.forEach` will still work but this is better.
111
+ */
112
+ eachSheet(callback) {
93
113
  this.worksheets.forEach(sheet => {
94
- iteratee(sheet, sheet.id);
114
+ callback(sheet, sheet.id);
95
115
  });
96
116
  }
97
117
  get definedNames() {
@@ -101,6 +121,9 @@ class Workbook {
101
121
  // Note: themes are not an exposed feature, meddle at your peril!
102
122
  this._themes = undefined;
103
123
  }
124
+ /**
125
+ * Add Image to Workbook and return the id
126
+ */
104
127
  addImage(image) {
105
128
  // TODO: validation?
106
129
  const id = this.media.length;
@@ -130,14 +130,21 @@ class Worksheet {
130
130
  }
131
131
  this._name = name;
132
132
  }
133
+ /**
134
+ * The workbook that contains this worksheet
135
+ */
133
136
  get workbook() {
134
137
  return this._workbook;
135
138
  }
136
- // when you're done with this worksheet, call this to remove from workbook
139
+ /**
140
+ * When you're done with this worksheet, call this to remove from workbook
141
+ */
137
142
  destroy() {
138
143
  this._workbook.removeWorksheetEx(this);
139
144
  }
140
- // Get the bounding range of the cells in this worksheet
145
+ /**
146
+ * Get the bounding range of the cells in this worksheet
147
+ */
141
148
  get dimensions() {
142
149
  const dimensions = new Range();
143
150
  this._rows.forEach(row => {
@@ -152,12 +159,18 @@ class Worksheet {
152
159
  }
153
160
  // =========================================================================
154
161
  // Columns
155
- // get the current columns array.
162
+ /**
163
+ * Get the current columns array
164
+ */
156
165
  get columns() {
157
166
  return this._columns;
158
167
  }
159
- // set the columns from an array of column definitions.
160
- // Note: any headers defined will overwrite existing values.
168
+ /**
169
+ * Add column headers and define column keys and widths.
170
+ *
171
+ * Note: these column structures are a workbook-building convenience only,
172
+ * apart from the column width, they will not be fully persisted.
173
+ */
161
174
  set columns(value) {
162
175
  // calculate max header row count
163
176
  this._headerRowCount = value.reduce((pv, cv) => {
@@ -185,7 +198,9 @@ class Worksheet {
185
198
  eachColumnKey(f) {
186
199
  Object.keys(this._keys).forEach(key => f(this._keys[key], key));
187
200
  }
188
- // get a single column by col number. If it doesn't exist, create it and any gaps before it
201
+ /**
202
+ * Access an individual column by key, letter and 1-based column number
203
+ */
189
204
  getColumn(c) {
190
205
  let colNum;
191
206
  if (typeof c === "string") {
@@ -211,6 +226,17 @@ class Worksheet {
211
226
  }
212
227
  return this._columns[colNum - 1];
213
228
  }
229
+ /**
230
+ * Cut one or more columns (columns to the right are shifted left)
231
+ * and optionally insert more
232
+ *
233
+ * If column properties have been defined, they will be cut or moved accordingly
234
+ *
235
+ * Known Issue: If a splice causes any merged cells to move, the results may be unpredictable
236
+ *
237
+ * Also: If the worksheet has more rows than values in the column inserts,
238
+ * the rows will still be shifted as if the values existed
239
+ */
214
240
  spliceColumns(start, count, ...inserts) {
215
241
  const rows = this._rows;
216
242
  const nRows = rows.length;
@@ -250,9 +276,15 @@ class Worksheet {
250
276
  // account for defined names
251
277
  this.workbook.definedNames.spliceColumns(this.name, start, count, inserts.length);
252
278
  }
279
+ /**
280
+ * Get the last column in a worksheet
281
+ */
253
282
  get lastColumn() {
254
283
  return this.getColumn(this.columnCount);
255
284
  }
285
+ /**
286
+ * The total column size of the document. Equal to the maximum cell count from all of the rows
287
+ */
256
288
  get columnCount() {
257
289
  let maxCount = 0;
258
290
  this.eachRow(row => {
@@ -260,6 +292,9 @@ class Worksheet {
260
292
  });
261
293
  return maxCount;
262
294
  }
295
+ /**
296
+ * A count of the number of columns that have values
297
+ */
263
298
  get actualColumnCount() {
264
299
  // performance nightmare - for each row, counts all the columns used
265
300
  const counts = [];
@@ -291,23 +326,41 @@ class Worksheet {
291
326
  get _nextRow() {
292
327
  return this._lastRowNumber + 1;
293
328
  }
329
+ /**
330
+ * Get the last editable row in a worksheet (or undefined if there are none)
331
+ */
294
332
  get lastRow() {
295
333
  if (this._rows.length) {
296
334
  return this._rows[this._rows.length - 1];
297
335
  }
298
336
  return undefined;
299
337
  }
300
- // find a row (if exists) by row number
338
+ /**
339
+ * Tries to find and return row for row number, else undefined
340
+ *
341
+ * @param r - The 1-indexed row number
342
+ */
301
343
  findRow(r) {
302
344
  return this._rows[r - 1];
303
345
  }
304
- // find multiple rows (if exists) by row number
346
+ /**
347
+ * Tries to find and return rows for row number start and length, else undefined
348
+ *
349
+ * @param start - The 1-indexed starting row number
350
+ * @param length - The length of the expected array
351
+ */
305
352
  findRows(start, length) {
306
353
  return this._rows.slice(start - 1, start - 1 + length);
307
354
  }
355
+ /**
356
+ * The total row size of the document. Equal to the row number of the last row that has values.
357
+ */
308
358
  get rowCount() {
309
359
  return this._lastRowNumber;
310
360
  }
361
+ /**
362
+ * A count of the number of rows that have values. If a mid-document row is empty, it will not be included in the count.
363
+ */
311
364
  get actualRowCount() {
312
365
  // counts actual rows that have actual data
313
366
  let count = 0;
@@ -316,7 +369,9 @@ class Worksheet {
316
369
  });
317
370
  return count;
318
371
  }
319
- // get a row by row number.
372
+ /**
373
+ * Get or create row by 1-based index
374
+ */
320
375
  getRow(r) {
321
376
  let row = this._rows[r - 1];
322
377
  if (!row) {
@@ -324,7 +379,9 @@ class Worksheet {
324
379
  }
325
380
  return row;
326
381
  }
327
- // get multiple rows by row number.
382
+ /**
383
+ * Get or create rows by 1-based index
384
+ */
328
385
  getRows(start, length) {
329
386
  if (length < 1) {
330
387
  return undefined;
@@ -335,6 +392,10 @@ class Worksheet {
335
392
  }
336
393
  return rows;
337
394
  }
395
+ /**
396
+ * Add a couple of Rows by key-value, after the last current row, using the column keys,
397
+ * or add a row by contiguous Array (assign to columns A, B & C)
398
+ */
338
399
  addRow(value, style = "n") {
339
400
  const rowNo = this._nextRow;
340
401
  const row = this.getRow(rowNo);
@@ -342,6 +403,9 @@ class Worksheet {
342
403
  this._setStyleOption(rowNo, style[0] === "i" ? style : "n");
343
404
  return row;
344
405
  }
406
+ /**
407
+ * Add multiple rows by providing an array of arrays or key-value pairs
408
+ */
345
409
  addRows(value, style = "n") {
346
410
  const rows = [];
347
411
  value.forEach(row => {
@@ -349,11 +413,19 @@ class Worksheet {
349
413
  });
350
414
  return rows;
351
415
  }
416
+ /**
417
+ * Insert a Row by key-value, at the position (shifting down all rows from position),
418
+ * using the column keys, or add a row by contiguous Array (assign to columns A, B & C)
419
+ */
352
420
  insertRow(pos, value, style = "n") {
353
421
  this.spliceRows(pos, 0, value);
354
422
  this._setStyleOption(pos, style);
355
423
  return this.getRow(pos);
356
424
  }
425
+ /**
426
+ * Insert multiple rows at position (shifting down all rows from position)
427
+ * by providing an array of arrays or key-value pairs
428
+ */
357
429
  insertRows(pos, values, style = "n") {
358
430
  this.spliceRows(pos, 0, ...values);
359
431
  if (style !== "n") {
@@ -387,6 +459,9 @@ class Worksheet {
387
459
  });
388
460
  rDst.height = rSrc.height;
389
461
  }
462
+ /**
463
+ * Duplicate rows and insert new rows
464
+ */
390
465
  duplicateRow(rowNum, count, insert = false) {
391
466
  // create count duplicates of rowNum
392
467
  // either inserting new or overwriting existing rows
@@ -403,6 +478,12 @@ class Worksheet {
403
478
  });
404
479
  }
405
480
  }
481
+ /**
482
+ * Cut one or more rows (rows below are shifted up)
483
+ * and optionally insert more
484
+ *
485
+ * Known Issue: If a splice causes any merged cells to move, the results may be unpredictable
486
+ */
406
487
  spliceRows(start, count, ...inserts) {
407
488
  // same problem as row.splice, except worse.
408
489
  const nKeep = start + count;
@@ -467,26 +548,33 @@ class Worksheet {
467
548
  // account for defined names
468
549
  this.workbook.definedNames.spliceRows(this.name, start, count, nInserts);
469
550
  }
470
- eachRow(options, iteratee) {
471
- if (!iteratee) {
472
- iteratee = options;
473
- options = undefined;
551
+ eachRow(optOrCallback, maybeCallback) {
552
+ let options;
553
+ let callback;
554
+ if (typeof optOrCallback === "function") {
555
+ callback = optOrCallback;
556
+ }
557
+ else {
558
+ options = optOrCallback;
559
+ callback = maybeCallback;
474
560
  }
475
561
  if (options && options.includeEmpty) {
476
562
  const n = this._rows.length;
477
563
  for (let i = 1; i <= n; i++) {
478
- iteratee(this.getRow(i), i);
564
+ callback(this.getRow(i), i);
479
565
  }
480
566
  }
481
567
  else {
482
568
  this._rows.forEach(row => {
483
569
  if (row && row.hasValues) {
484
- iteratee(row, row.number);
570
+ callback(row, row.number);
485
571
  }
486
572
  });
487
573
  }
488
574
  }
489
- // return all rows as sparse array
575
+ /**
576
+ * Return all rows as sparse array
577
+ */
490
578
  getSheetValues() {
491
579
  const rows = [];
492
580
  this._rows.forEach(row => {
@@ -498,13 +586,17 @@ class Worksheet {
498
586
  }
499
587
  // =========================================================================
500
588
  // Cells
501
- // returns the cell at [r,c] or address given by r. If not found, return undefined
589
+ /**
590
+ * Returns the cell at [r,c] or address given by r. If not found, return undefined
591
+ */
502
592
  findCell(r, c) {
503
593
  const address = colCache.getAddress(r, c);
504
594
  const row = this._rows[address.row - 1];
505
595
  return row ? row.findCell(address.col) : undefined;
506
596
  }
507
- // return the cell at [r,c] or address given by r. If not found, create a new one.
597
+ /**
598
+ * Get or create cell at [r,c] or address given by r
599
+ */
508
600
  getCell(r, c) {
509
601
  const address = colCache.getAddress(r, c);
510
602
  const row = this.getRow(address.row);
@@ -512,7 +604,15 @@ class Worksheet {
512
604
  }
513
605
  // =========================================================================
514
606
  // Merge
515
- // convert the range defined by ['tl:br'], [tl,br] or [t,l,b,r] into a single 'merged' cell
607
+ /**
608
+ * Merge cells, either:
609
+ *
610
+ * tlbr string, e.g. `'A4:B5'`
611
+ *
612
+ * tl string, br string, e.g. `'G10', 'H11'`
613
+ *
614
+ * t, l, b, r numbers, e.g. `10,11,12,13`
615
+ */
516
616
  mergeCells(...cells) {
517
617
  const dimensions = new Range(cells);
518
618
  this._mergeCellsInternal(dimensions);
@@ -557,9 +657,11 @@ class Worksheet {
557
657
  // return true if this._merges has a merge object
558
658
  return Object.values(this._merges).some(Boolean);
559
659
  }
560
- // scan the range defined by ['tl:br'], [tl,br] or [t,l,b,r] and if any cell is part of a merge,
561
- // un-merge the group. Note this function can affect multiple merges and merge-blocks are
562
- // atomic - either they're all merged or all un-merged.
660
+ /**
661
+ * Scan the range and if any cell is part of a merge, un-merge the group.
662
+ * Note this function can affect multiple merges and merge-blocks are
663
+ * atomic - either they're all merged or all un-merged.
664
+ */
563
665
  unMergeCells(...cells) {
564
666
  const dimensions = new Range(cells);
565
667
  // find any cells in that range and unmerge them
@@ -631,6 +733,10 @@ class Worksheet {
631
733
  }
632
734
  // =========================================================================
633
735
  // Images
736
+ /**
737
+ * Using the image id from `Workbook.addImage`,
738
+ * embed an image within the worksheet to cover a range
739
+ */
634
740
  addImage(imageId, range) {
635
741
  const model = {
636
742
  type: "image",
@@ -642,6 +748,9 @@ class Worksheet {
642
748
  getImages() {
643
749
  return this._media.filter(m => m.type === "image");
644
750
  }
751
+ /**
752
+ * Using the image id from `Workbook.addImage`, set the background to the worksheet
753
+ */
645
754
  addBackgroundImage(imageId) {
646
755
  const model = {
647
756
  type: "background",
@@ -655,6 +764,9 @@ class Worksheet {
655
764
  }
656
765
  // =========================================================================
657
766
  // Worksheet Protection
767
+ /**
768
+ * Protect the worksheet with optional password and options
769
+ */
658
770
  protect(password, options) {
659
771
  // TODO: make this function truly async
660
772
  // perhaps marshal to worker thread or something
@@ -689,17 +801,29 @@ class Worksheet {
689
801
  }
690
802
  // =========================================================================
691
803
  // Tables
804
+ /**
805
+ * Add a new table and return a reference to it
806
+ */
692
807
  addTable(model) {
693
808
  const table = new Table(this, model);
694
809
  this.tables[model.name] = table;
695
810
  return table;
696
811
  }
812
+ /**
813
+ * Fetch table by name
814
+ */
697
815
  getTable(name) {
698
816
  return this.tables[name];
699
817
  }
818
+ /**
819
+ * Delete table by name
820
+ */
700
821
  removeTable(name) {
701
822
  delete this.tables[name];
702
823
  }
824
+ /**
825
+ * Fetch all tables in the worksheet
826
+ */
703
827
  getTables() {
704
828
  return Object.values(this.tables);
705
829
  }
@@ -715,9 +839,15 @@ Please leave feedback at https://github.com/excelts/excelts/discussions/2575`);
715
839
  }
716
840
  // ===========================================================================
717
841
  // Conditional Formatting
842
+ /**
843
+ * Add conditional formatting rules
844
+ */
718
845
  addConditionalFormatting(cf) {
719
846
  this.conditionalFormattings.push(cf);
720
847
  }
848
+ /**
849
+ * Delete conditional formatting rules
850
+ */
721
851
  removeConditionalFormatting(filter) {
722
852
  if (typeof filter === "number") {
723
853
  this.conditionalFormattings.splice(filter, 1);
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Simple ZIP extraction utilities
3
3
  * Provides easy-to-use Promise-based API for extracting ZIP files
4
+ * Works in both Node.js and browser environments
4
5
  */
5
- import { Readable } from "stream";
6
- import { createParse } from "./parse.js";
6
+ import { ZipParser } from "./zip-parser.js";
7
7
  /**
8
8
  * Extract all files from a ZIP buffer
9
9
  *
10
- * @param zipData - ZIP file data as Buffer or Uint8Array
10
+ * @param zipData - ZIP file data as Buffer, Uint8Array, or ArrayBuffer
11
11
  * @returns Map of file paths to their content
12
12
  *
13
13
  * @example
@@ -24,40 +24,24 @@ import { createParse } from "./parse.js";
24
24
  */
25
25
  export async function extractAll(zipData) {
26
26
  const files = new Map();
27
- const buffer = Buffer.isBuffer(zipData) ? zipData : Buffer.from(zipData);
28
- const parse = createParse({ forceStream: true });
29
- const stream = Readable.from([buffer]);
30
- stream.pipe(parse);
31
- for await (const entry of parse) {
32
- const zipEntry = entry;
33
- const isDirectory = zipEntry.type === "Directory";
34
- if (isDirectory) {
35
- files.set(zipEntry.path, {
36
- path: zipEntry.path,
37
- data: Buffer.alloc(0),
38
- isDirectory: true,
39
- size: 0
40
- });
41
- zipEntry.autodrain();
42
- }
43
- else {
44
- const data = await zipEntry.buffer();
45
- files.set(zipEntry.path, {
46
- path: zipEntry.path,
47
- data,
48
- isDirectory: false,
49
- size: data.length
50
- });
51
- }
27
+ const parser = new ZipParser(zipData);
28
+ for (const entry of parser.getEntries()) {
29
+ const data = await parser.extract(entry.path);
30
+ files.set(entry.path, {
31
+ path: entry.path,
32
+ data: data || new Uint8Array(0),
33
+ isDirectory: entry.isDirectory,
34
+ size: entry.uncompressedSize
35
+ });
52
36
  }
53
37
  return files;
54
38
  }
55
39
  /**
56
40
  * Extract a single file from a ZIP buffer
57
41
  *
58
- * @param zipData - ZIP file data as Buffer or Uint8Array
42
+ * @param zipData - ZIP file data as Buffer, Uint8Array, or ArrayBuffer
59
43
  * @param filePath - Path of the file to extract
60
- * @returns File content as Buffer, or null if not found
44
+ * @returns File content as Uint8Array, or null if not found
61
45
  *
62
46
  * @example
63
47
  * ```ts
@@ -66,31 +50,18 @@ export async function extractAll(zipData) {
66
50
  * const zipData = fs.readFileSync("archive.zip");
67
51
  * const content = await extractFile(zipData, "readme.txt");
68
52
  * if (content) {
69
- * console.log(content.toString("utf-8"));
53
+ * console.log(new TextDecoder().decode(content));
70
54
  * }
71
55
  * ```
72
56
  */
73
57
  export async function extractFile(zipData, filePath) {
74
- const buffer = Buffer.isBuffer(zipData) ? zipData : Buffer.from(zipData);
75
- const parse = createParse({ forceStream: true });
76
- const stream = Readable.from([buffer]);
77
- stream.pipe(parse);
78
- for await (const entry of parse) {
79
- const zipEntry = entry;
80
- if (zipEntry.path === filePath) {
81
- if (zipEntry.type === "Directory") {
82
- return Buffer.alloc(0);
83
- }
84
- return zipEntry.buffer();
85
- }
86
- zipEntry.autodrain();
87
- }
88
- return null;
58
+ const parser = new ZipParser(zipData);
59
+ return parser.extract(filePath);
89
60
  }
90
61
  /**
91
62
  * List all file paths in a ZIP buffer (without extracting content)
92
63
  *
93
- * @param zipData - ZIP file data as Buffer or Uint8Array
64
+ * @param zipData - ZIP file data as Buffer, Uint8Array, or ArrayBuffer
94
65
  * @returns Array of file paths
95
66
  *
96
67
  * @example
@@ -103,22 +74,13 @@ export async function extractFile(zipData, filePath) {
103
74
  * ```
104
75
  */
105
76
  export async function listFiles(zipData) {
106
- const paths = [];
107
- const buffer = Buffer.isBuffer(zipData) ? zipData : Buffer.from(zipData);
108
- const parse = createParse({ forceStream: true });
109
- const stream = Readable.from([buffer]);
110
- stream.pipe(parse);
111
- for await (const entry of parse) {
112
- const zipEntry = entry;
113
- paths.push(zipEntry.path);
114
- zipEntry.autodrain();
115
- }
116
- return paths;
77
+ const parser = new ZipParser(zipData);
78
+ return parser.listFiles();
117
79
  }
118
80
  /**
119
81
  * Iterate over ZIP entries with a callback (memory efficient for large ZIPs)
120
82
  *
121
- * @param zipData - ZIP file data as Buffer or Uint8Array
83
+ * @param zipData - ZIP file data as Buffer, Uint8Array, or ArrayBuffer
122
84
  * @param callback - Async callback for each entry, return false to stop iteration
123
85
  *
124
86
  * @example
@@ -128,33 +90,17 @@ export async function listFiles(zipData) {
128
90
  * await forEachEntry(zipData, async (path, getData) => {
129
91
  * if (path.endsWith(".xml")) {
130
92
  * const content = await getData();
131
- * console.log(content.toString("utf-8"));
93
+ * console.log(new TextDecoder().decode(content));
132
94
  * }
133
95
  * return true; // continue iteration
134
96
  * });
135
97
  * ```
136
98
  */
137
99
  export async function forEachEntry(zipData, callback) {
138
- const buffer = Buffer.isBuffer(zipData) ? zipData : Buffer.from(zipData);
139
- const parse = createParse({ forceStream: true });
140
- const stream = Readable.from([buffer]);
141
- stream.pipe(parse);
142
- for await (const entry of parse) {
143
- const zipEntry = entry;
144
- let dataPromise = null;
145
- const getData = () => {
146
- if (!dataPromise) {
147
- dataPromise = zipEntry.buffer();
148
- }
149
- return dataPromise;
150
- };
151
- const shouldContinue = await callback(zipEntry.path, getData, zipEntry);
152
- // If callback didn't read data, drain it
153
- if (!dataPromise) {
154
- zipEntry.autodrain();
155
- }
156
- if (shouldContinue === false) {
157
- break;
158
- }
159
- }
100
+ const parser = new ZipParser(zipData);
101
+ await parser.forEach(async (entry, getData) => {
102
+ return callback(entry.path, getData, entry);
103
+ });
160
104
  }
105
+ // Re-export ZipParser for advanced usage
106
+ export { ZipParser } from "./zip-parser.js";
@@ -1,8 +1,23 @@
1
1
  /**
2
2
  * Unzip utilities for parsing ZIP archives
3
+ *
4
+ * Two APIs are provided:
5
+ *
6
+ * 1. **Stream-based API** (Node.js only):
7
+ * - `Parse`, `createParse` - Parse ZIP files as a stream
8
+ * - Best for large files where you don't want to load entire file into memory
9
+ * - Requires Node.js `stream` module
10
+ *
11
+ * 2. **Buffer-based API** (Browser + Node.js):
12
+ * - `extractAll`, `extractFile`, `listFiles`, `forEachEntry`, `ZipParser`
13
+ * - Works in both Node.js and browser environments
14
+ * - Uses native `DecompressionStream` in browser, `zlib` in Node.js
15
+ * - Best for files already loaded into memory (ArrayBuffer, Uint8Array)
16
+ *
3
17
  * Original source: https://github.com/ZJONSSON/node-unzipper
4
18
  * License: MIT
5
19
  */
20
+ // Stream-based API (Node.js only - requires stream module)
6
21
  export { Parse, createParse } from "./parse.js";
7
22
  export { PullStream } from "./pull-stream.js";
8
23
  export { NoopStream } from "./noop-stream.js";
@@ -10,5 +25,5 @@ export { bufferStream } from "./buffer-stream.js";
10
25
  export { parse as parseBuffer } from "./parse-buffer.js";
11
26
  export { parseDateTime } from "./parse-datetime.js";
12
27
  export { parseExtraField } from "./parse-extra-field.js";
13
- // Simple extraction API
14
- export { extractAll, extractFile, listFiles, forEachEntry } from "./extract.js";
28
+ // Buffer-based API (Browser + Node.js - cross-platform)
29
+ export { extractAll, extractFile, listFiles, forEachEntry, ZipParser } from "./extract.js";