@cj-tech-master/excelts 4.2.0-canary.20260110080706.375ff37 → 4.2.0-canary.20260110111632.c88c61c

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 (38) hide show
  1. package/dist/browser/modules/archive/compress.base.d.ts +1 -0
  2. package/dist/browser/modules/archive/compress.base.js +1 -0
  3. package/dist/browser/modules/archive/compress.browser.d.ts +8 -0
  4. package/dist/browser/modules/archive/compress.browser.js +16 -9
  5. package/dist/browser/modules/archive/parse.base.d.ts +22 -1
  6. package/dist/browser/modules/archive/parse.base.js +38 -4
  7. package/dist/browser/modules/archive/parse.browser.js +6 -1
  8. package/dist/browser/modules/archive/parse.js +1 -1
  9. package/dist/browser/modules/excel/form-control.d.ts +2 -0
  10. package/dist/browser/modules/excel/form-control.js +54 -16
  11. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +17 -3
  12. package/dist/browser/modules/stream/streams.browser.d.ts +2 -0
  13. package/dist/browser/modules/stream/streams.browser.js +58 -25
  14. package/dist/cjs/modules/archive/compress.base.js +1 -0
  15. package/dist/cjs/modules/archive/compress.browser.js +15 -8
  16. package/dist/cjs/modules/archive/parse.base.js +38 -4
  17. package/dist/cjs/modules/archive/parse.browser.js +6 -1
  18. package/dist/cjs/modules/archive/parse.js +1 -1
  19. package/dist/cjs/modules/excel/form-control.js +54 -16
  20. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +17 -3
  21. package/dist/cjs/modules/stream/streams.browser.js +58 -25
  22. package/dist/esm/modules/archive/compress.base.js +1 -0
  23. package/dist/esm/modules/archive/compress.browser.js +16 -9
  24. package/dist/esm/modules/archive/parse.base.js +38 -4
  25. package/dist/esm/modules/archive/parse.browser.js +6 -1
  26. package/dist/esm/modules/archive/parse.js +1 -1
  27. package/dist/esm/modules/excel/form-control.js +54 -16
  28. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +17 -3
  29. package/dist/esm/modules/stream/streams.browser.js +58 -25
  30. package/dist/iife/excelts.iife.js +162 -38
  31. package/dist/iife/excelts.iife.js.map +1 -1
  32. package/dist/iife/excelts.iife.min.js +19 -19
  33. package/dist/types/modules/archive/compress.base.d.ts +1 -0
  34. package/dist/types/modules/archive/compress.browser.d.ts +8 -0
  35. package/dist/types/modules/archive/parse.base.d.ts +22 -1
  36. package/dist/types/modules/excel/form-control.d.ts +2 -0
  37. package/dist/types/modules/stream/streams.browser.d.ts +2 -0
  38. package/package.json +1 -1
@@ -290,8 +290,10 @@ class WorkSheetXform extends BaseXform {
290
290
  for (const control of model.formControls) {
291
291
  const globalCtrlPropId = options.formControlRefs.length + 1;
292
292
  control.ctrlPropId = globalCtrlPropId;
293
+ const relId = nextRid(rels);
294
+ control.ctrlPropRelId = relId;
293
295
  rels.push({
294
- Id: nextRid(rels),
296
+ Id: relId,
295
297
  Type: RelType.CtrlProp,
296
298
  Target: ctrlPropRelTargetFromWorksheet(globalCtrlPropId)
297
299
  });
@@ -354,15 +356,27 @@ class WorkSheetXform extends BaseXform {
354
356
  this.map.drawing.render(xmlStream, model.drawing); // Note: must be after rowBreaks/colBreaks
355
357
  this.map.picture.render(xmlStream, model.background); // Note: must be after drawing
356
358
  this.map.tableParts.render(xmlStream, model.tables);
357
- this.map.extLst.render(xmlStream, model);
359
+ // Controls section for legacy form controls (checkboxes, etc.)
360
+ // Excel expects <controls> entries that reference ctrlProp relationships.
361
+ if (model.formControls && model.formControls.length > 0) {
362
+ xmlStream.openNode("controls");
363
+ for (const control of model.formControls) {
364
+ if (control.ctrlPropRelId) {
365
+ xmlStream.leafNode("control", { shapeId: control.shapeId, "r:id": control.ctrlPropRelId });
366
+ }
367
+ }
368
+ xmlStream.closeNode();
369
+ }
358
370
  if (model.rels) {
359
- // add a <legacyDrawing /> node for each comment
371
+ // Add a <legacyDrawing /> node for each VML drawing relationship (comments and/or form controls).
360
372
  model.rels.forEach(rel => {
361
373
  if (rel.Type === RelType.VmlDrawing) {
362
374
  xmlStream.leafNode("legacyDrawing", { "r:id": rel.Id });
363
375
  }
364
376
  });
365
377
  }
378
+ // extLst should be the last element in the worksheet.
379
+ this.map.extLst.render(xmlStream, model);
366
380
  xmlStream.closeNode();
367
381
  }
368
382
  parseOpen(node) {
@@ -384,55 +384,58 @@ export class Readable extends EventEmitter {
384
384
  // causing `instanceof Transform/Writable/Duplex` to fail even when the object
385
385
  // is a valid destination.
386
386
  const dest = destination;
387
- // Get the actual writable target.
388
- // Prefer internal `_writable` (Transform/Duplex wrappers), else treat the destination as writable-like.
389
- const candidate = dest?._writable ?? dest;
390
- const hasWrite = typeof candidate?.write === "function";
391
- const hasEnd = typeof candidate?.end === "function";
392
- const hasOn = typeof candidate?.on === "function";
393
- const hasOnce = typeof candidate?.once === "function";
394
- const hasOff = typeof candidate?.off === "function";
395
- if (!hasWrite || !hasEnd || (!hasOnce && !hasOn) || (!hasOff && !candidate?.removeListener)) {
387
+ // For event handling (drain, once, off), we need the object that emits events.
388
+ // For write/end, we must call the destination's own write()/end() methods,
389
+ // NOT the internal _writable, because Transform.write() has important logic
390
+ // (like auto-consume) that _writable.write() bypasses.
391
+ const eventTarget = dest;
392
+ const hasWrite = typeof dest?.write === "function";
393
+ const hasEnd = typeof dest?.end === "function";
394
+ const hasOn = typeof eventTarget?.on === "function";
395
+ const hasOnce = typeof eventTarget?.once === "function";
396
+ const hasOff = typeof eventTarget?.off === "function";
397
+ if (!hasWrite || !hasEnd || (!hasOnce && !hasOn) || (!hasOff && !eventTarget?.removeListener)) {
396
398
  throw new Error("Readable.pipe: invalid destination");
397
399
  }
398
- const target = candidate;
399
- this._pipeTo.push(target);
400
+ this._pipeTo.push(dest);
400
401
  // Create listeners that we can later remove
401
402
  const dataListener = (chunk) => {
402
- const canWrite = target.write(chunk);
403
+ // Call destination's write() method (not internal _writable.write())
404
+ // This ensures Transform.write() logic runs properly
405
+ const canWrite = dest.write(chunk);
403
406
  if (!canWrite) {
404
407
  this.pause();
405
- if (typeof target.once === "function") {
406
- target.once("drain", () => this.resume());
408
+ if (typeof eventTarget.once === "function") {
409
+ eventTarget.once("drain", () => this.resume());
407
410
  }
408
411
  else {
409
412
  const resumeOnce = () => {
410
- if (typeof target.off === "function") {
411
- target.off("drain", resumeOnce);
413
+ if (typeof eventTarget.off === "function") {
414
+ eventTarget.off("drain", resumeOnce);
412
415
  }
413
- else if (typeof target.removeListener === "function") {
414
- target.removeListener("drain", resumeOnce);
416
+ else if (typeof eventTarget.removeListener === "function") {
417
+ eventTarget.removeListener("drain", resumeOnce);
415
418
  }
416
419
  this.resume();
417
420
  };
418
- target.on("drain", resumeOnce);
421
+ eventTarget.on("drain", resumeOnce);
419
422
  }
420
423
  }
421
424
  };
422
425
  const endListener = () => {
423
- target.end();
426
+ dest.end();
424
427
  };
425
428
  const errorListener = (err) => {
426
- if (typeof target.destroy === "function") {
427
- target.destroy(err);
429
+ if (typeof dest.destroy === "function") {
430
+ dest.destroy(err);
428
431
  }
429
432
  else {
430
433
  // Best-effort: forward error to the destination if it supports events.
431
- target.emit?.("error", err);
434
+ eventTarget.emit?.("error", err);
432
435
  }
433
436
  };
434
437
  // Store listeners for later removal in unpipe
435
- this._pipeListeners.set(target, {
438
+ this._pipeListeners.set(dest, {
436
439
  data: dataListener,
437
440
  end: endListener,
438
441
  error: errorListener
@@ -1358,6 +1361,8 @@ export class Transform extends EventEmitter {
1358
1361
  this._autoConsumeEnded = false;
1359
1362
  /** @internal - promise that resolves when auto-consume finishes */
1360
1363
  this._autoConsumePromise = null;
1364
+ /** @internal - list of piped destinations for forwarding auto-consumed data */
1365
+ this._pipeDestinations = [];
1361
1366
  this.objectMode = options?.objectMode ?? false;
1362
1367
  const userTransform = options?.transform;
1363
1368
  const userFlush = options?.flush;
@@ -1624,10 +1629,18 @@ export class Transform extends EventEmitter {
1624
1629
  for await (const chunk of this._readable) {
1625
1630
  // Buffer the data for later retrieval
1626
1631
  this._autoConsumedBuffer.push(chunk);
1632
+ // Forward to any piped destinations
1633
+ for (const dest of this._pipeDestinations) {
1634
+ dest.write(chunk);
1635
+ }
1627
1636
  // Also emit data event for listeners
1628
1637
  this.emit("data", chunk);
1629
1638
  }
1630
1639
  this._autoConsumeEnded = true;
1640
+ // End all piped destinations
1641
+ for (const dest of this._pipeDestinations) {
1642
+ dest.end();
1643
+ }
1631
1644
  this.emit("end");
1632
1645
  }
1633
1646
  catch (err) {
@@ -1677,8 +1690,28 @@ export class Transform extends EventEmitter {
1677
1690
  * Pipe to another stream (writable, transform, or duplex)
1678
1691
  */
1679
1692
  pipe(destination) {
1680
- // Mark as having consumer to prevent auto-consume conflict
1693
+ // Mark as having consumer to prevent new auto-consume from starting
1681
1694
  this._hasDataConsumer = true;
1695
+ // Get the writable target - handle both Transform (with internal _writable) and plain Writable
1696
+ const dest = destination;
1697
+ const target = dest?._writable ?? dest;
1698
+ // Register destination for forwarding
1699
+ this._pipeDestinations.push(target);
1700
+ // If auto-consume is running or has run, we need to handle buffered data ourselves
1701
+ if (this._readableConsuming) {
1702
+ // Forward any buffered data from auto-consume to the destination
1703
+ for (let i = 0; i < this._autoConsumedBuffer.length; i++) {
1704
+ target.write(this._autoConsumedBuffer[i]);
1705
+ }
1706
+ // If auto-consume has ended, end the destination too
1707
+ if (this._autoConsumeEnded) {
1708
+ target.end();
1709
+ }
1710
+ // Don't call _readable.pipe() - auto-consume already consumed _readable
1711
+ // Future data will be forwarded via the 'data' event listener below
1712
+ return destination;
1713
+ }
1714
+ // No auto-consume running - use normal pipe through _readable
1682
1715
  return this._readable.pipe(destination);
1683
1716
  }
1684
1717
  /**
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @cj-tech-master/excelts v4.2.0-canary.20260110080706.375ff37
2
+ * @cj-tech-master/excelts v4.2.0-canary.20260110111632.c88c61c
3
3
  * TypeScript Excel Workbook Manager - Read and Write xlsx and csv Files.
4
4
  * (c) 2026 cjnoname
5
5
  * Released under the MIT License
@@ -2767,9 +2767,24 @@ var ExcelTS = (function(exports) {
2767
2767
  _parseRange(range$1) {
2768
2768
  let tl;
2769
2769
  let br;
2770
- if (typeof range$1 === "string") {
2770
+ if (typeof range$1 === "string") if (range$1.includes(":")) {
2771
2771
  const decoded = colCache.decode(range$1);
2772
- if ("top" in decoded) {
2772
+ if ("top" in decoded) if (decoded.left === decoded.right && decoded.top === decoded.bottom) {
2773
+ const col = decoded.left - 1;
2774
+ const row = decoded.top - 1;
2775
+ tl = {
2776
+ col,
2777
+ colOff: DEFAULT_COL_OFF,
2778
+ row,
2779
+ rowOff: DEFAULT_ROW_OFF
2780
+ };
2781
+ br = {
2782
+ col: col + 2,
2783
+ colOff: DEFAULT_END_COL_OFF,
2784
+ row: row + 1,
2785
+ rowOff: DEFAULT_END_ROW_OFF
2786
+ };
2787
+ } else {
2773
2788
  tl = {
2774
2789
  col: decoded.left - 1,
2775
2790
  colOff: DEFAULT_COL_OFF,
@@ -2782,7 +2797,8 @@ var ExcelTS = (function(exports) {
2782
2797
  row: decoded.bottom - 1,
2783
2798
  rowOff: DEFAULT_END_ROW_OFF
2784
2799
  };
2785
- } else {
2800
+ }
2801
+ else {
2786
2802
  tl = {
2787
2803
  col: decoded.col - 1,
2788
2804
  colOff: DEFAULT_COL_OFF,
@@ -2796,7 +2812,22 @@ var ExcelTS = (function(exports) {
2796
2812
  rowOff: DEFAULT_END_ROW_OFF
2797
2813
  };
2798
2814
  }
2799
- } else if ("startCol" in range$1) {
2815
+ } else {
2816
+ const decoded = colCache.decodeAddress(range$1);
2817
+ tl = {
2818
+ col: decoded.col - 1,
2819
+ colOff: DEFAULT_COL_OFF,
2820
+ row: decoded.row - 1,
2821
+ rowOff: DEFAULT_ROW_OFF
2822
+ };
2823
+ br = {
2824
+ col: decoded.col + 1,
2825
+ colOff: DEFAULT_END_COL_OFF,
2826
+ row: decoded.row,
2827
+ rowOff: DEFAULT_END_ROW_OFF
2828
+ };
2829
+ }
2830
+ else if ("startCol" in range$1) {
2800
2831
  tl = {
2801
2832
  col: range$1.startCol,
2802
2833
  colOff: range$1.startColOff ?? DEFAULT_COL_OFF,
@@ -3550,37 +3581,36 @@ var ExcelTS = (function(exports) {
3550
3581
  */
3551
3582
  pipe(destination) {
3552
3583
  const dest = destination;
3553
- const candidate = dest?._writable ?? dest;
3554
- const hasWrite = typeof candidate?.write === "function";
3555
- const hasEnd = typeof candidate?.end === "function";
3556
- const hasOn = typeof candidate?.on === "function";
3557
- const hasOnce = typeof candidate?.once === "function";
3558
- const hasOff = typeof candidate?.off === "function";
3559
- if (!hasWrite || !hasEnd || !hasOnce && !hasOn || !hasOff && !candidate?.removeListener) throw new Error("Readable.pipe: invalid destination");
3560
- const target = candidate;
3561
- this._pipeTo.push(target);
3584
+ const eventTarget = dest;
3585
+ const hasWrite = typeof dest?.write === "function";
3586
+ const hasEnd = typeof dest?.end === "function";
3587
+ const hasOn = typeof eventTarget?.on === "function";
3588
+ const hasOnce = typeof eventTarget?.once === "function";
3589
+ const hasOff = typeof eventTarget?.off === "function";
3590
+ if (!hasWrite || !hasEnd || !hasOnce && !hasOn || !hasOff && !eventTarget?.removeListener) throw new Error("Readable.pipe: invalid destination");
3591
+ this._pipeTo.push(dest);
3562
3592
  const dataListener = (chunk) => {
3563
- if (!target.write(chunk)) {
3593
+ if (!dest.write(chunk)) {
3564
3594
  this.pause();
3565
- if (typeof target.once === "function") target.once("drain", () => this.resume());
3595
+ if (typeof eventTarget.once === "function") eventTarget.once("drain", () => this.resume());
3566
3596
  else {
3567
3597
  const resumeOnce = () => {
3568
- if (typeof target.off === "function") target.off("drain", resumeOnce);
3569
- else if (typeof target.removeListener === "function") target.removeListener("drain", resumeOnce);
3598
+ if (typeof eventTarget.off === "function") eventTarget.off("drain", resumeOnce);
3599
+ else if (typeof eventTarget.removeListener === "function") eventTarget.removeListener("drain", resumeOnce);
3570
3600
  this.resume();
3571
3601
  };
3572
- target.on("drain", resumeOnce);
3602
+ eventTarget.on("drain", resumeOnce);
3573
3603
  }
3574
3604
  }
3575
3605
  };
3576
3606
  const endListener = () => {
3577
- target.end();
3607
+ dest.end();
3578
3608
  };
3579
3609
  const errorListener = (err) => {
3580
- if (typeof target.destroy === "function") target.destroy(err);
3581
- else target.emit?.("error", err);
3610
+ if (typeof dest.destroy === "function") dest.destroy(err);
3611
+ else eventTarget.emit?.("error", err);
3582
3612
  };
3583
- this._pipeListeners.set(target, {
3613
+ this._pipeListeners.set(dest, {
3584
3614
  data: dataListener,
3585
3615
  end: endListener,
3586
3616
  error: errorListener
@@ -4299,6 +4329,7 @@ var ExcelTS = (function(exports) {
4299
4329
  this._autoConsumedBufferIndex = 0;
4300
4330
  this._autoConsumeEnded = false;
4301
4331
  this._autoConsumePromise = null;
4332
+ this._pipeDestinations = [];
4302
4333
  this.objectMode = options?.objectMode ?? false;
4303
4334
  const userTransform = options?.transform;
4304
4335
  const userFlush = options?.flush;
@@ -4473,9 +4504,11 @@ var ExcelTS = (function(exports) {
4473
4504
  try {
4474
4505
  for await (const chunk of this._readable) {
4475
4506
  this._autoConsumedBuffer.push(chunk);
4507
+ for (const dest of this._pipeDestinations) dest.write(chunk);
4476
4508
  this.emit("data", chunk);
4477
4509
  }
4478
4510
  this._autoConsumeEnded = true;
4511
+ for (const dest of this._pipeDestinations) dest.end();
4479
4512
  this.emit("end");
4480
4513
  } catch (err) {
4481
4514
  this.emit("error", err);
@@ -4509,6 +4542,14 @@ var ExcelTS = (function(exports) {
4509
4542
  */
4510
4543
  pipe(destination) {
4511
4544
  this._hasDataConsumer = true;
4545
+ const dest = destination;
4546
+ const target = dest?._writable ?? dest;
4547
+ this._pipeDestinations.push(target);
4548
+ if (this._readableConsuming) {
4549
+ for (let i = 0; i < this._autoConsumedBuffer.length; i++) target.write(this._autoConsumedBuffer[i]);
4550
+ if (this._autoConsumeEnded) target.end();
4551
+ return destination;
4552
+ }
4512
4553
  return this._readable.pipe(destination);
4513
4554
  }
4514
4555
  /**
@@ -5008,6 +5049,68 @@ var ExcelTS = (function(exports) {
5008
5049
  if (callback) promise.then(() => callback(null)).catch((err) => callback(err));
5009
5050
  return promise;
5010
5051
  }
5052
+ /**
5053
+ * Wait for a stream to finish, close, or error.
5054
+ * Node.js compatible with support for options and callbacks.
5055
+ *
5056
+ * @example
5057
+ * // Promise usage
5058
+ * await finished(stream);
5059
+ *
5060
+ * @example
5061
+ * // With options
5062
+ * await finished(stream, { readable: false }); // Only wait for writable side
5063
+ *
5064
+ * @example
5065
+ * // Callback usage
5066
+ * finished(stream, (err) => {
5067
+ * if (err) console.error('Stream error', err);
5068
+ * });
5069
+ */
5070
+ function finished(stream, optionsOrCallback, callback) {
5071
+ let options = {};
5072
+ let cb;
5073
+ if (typeof optionsOrCallback === "function") cb = optionsOrCallback;
5074
+ else if (optionsOrCallback) {
5075
+ options = optionsOrCallback;
5076
+ cb = callback;
5077
+ }
5078
+ const promise = new Promise((resolve, reject) => {
5079
+ const normalizedStream = toBrowserPipelineStream(stream);
5080
+ let resolved = false;
5081
+ const done = (err) => {
5082
+ if (resolved) return;
5083
+ resolved = true;
5084
+ if (err && !options.error) reject(err);
5085
+ else resolve();
5086
+ };
5087
+ if (options.signal) {
5088
+ if (options.signal.aborted) {
5089
+ done(/* @__PURE__ */ new Error("Aborted"));
5090
+ return;
5091
+ }
5092
+ options.signal.addEventListener("abort", () => {
5093
+ done(/* @__PURE__ */ new Error("Aborted"));
5094
+ });
5095
+ }
5096
+ const checkReadable = options.readable !== false;
5097
+ const checkWritable = options.writable !== false;
5098
+ if (checkReadable && normalizedStream.readableEnded) {
5099
+ done();
5100
+ return;
5101
+ }
5102
+ if (checkWritable && normalizedStream.writableFinished) {
5103
+ done();
5104
+ return;
5105
+ }
5106
+ if (checkWritable) normalizedStream.on("finish", () => done());
5107
+ if (checkReadable) normalizedStream.on("end", () => done());
5108
+ normalizedStream.on("error", (err) => done(err));
5109
+ normalizedStream.on("close", () => done());
5110
+ });
5111
+ if (cb) promise.then(() => cb(null)).catch((err) => cb(err));
5112
+ return promise;
5113
+ }
5011
5114
 
5012
5115
  //#endregion
5013
5116
  //#region src/modules/excel/utils/encryptor.browser.ts
@@ -13625,8 +13728,10 @@ var ExcelTS = (function(exports) {
13625
13728
  for (const control of model.formControls) {
13626
13729
  const globalCtrlPropId = options.formControlRefs.length + 1;
13627
13730
  control.ctrlPropId = globalCtrlPropId;
13731
+ const relId = nextRid(rels);
13732
+ control.ctrlPropRelId = relId;
13628
13733
  rels.push({
13629
- Id: nextRid(rels),
13734
+ Id: relId,
13630
13735
  Type: RelType.CtrlProp,
13631
13736
  Target: ctrlPropRelTargetFromWorksheet(globalCtrlPropId)
13632
13737
  });
@@ -13679,10 +13784,18 @@ var ExcelTS = (function(exports) {
13679
13784
  this.map.drawing.render(xmlStream, model.drawing);
13680
13785
  this.map.picture.render(xmlStream, model.background);
13681
13786
  this.map.tableParts.render(xmlStream, model.tables);
13682
- this.map.extLst.render(xmlStream, model);
13787
+ if (model.formControls && model.formControls.length > 0) {
13788
+ xmlStream.openNode("controls");
13789
+ for (const control of model.formControls) if (control.ctrlPropRelId) xmlStream.leafNode("control", {
13790
+ shapeId: control.shapeId,
13791
+ "r:id": control.ctrlPropRelId
13792
+ });
13793
+ xmlStream.closeNode();
13794
+ }
13683
13795
  if (model.rels) model.rels.forEach((rel) => {
13684
13796
  if (rel.Type === RelType.VmlDrawing) xmlStream.leafNode("legacyDrawing", { "r:id": rel.Id });
13685
13797
  });
13798
+ this.map.extLst.render(xmlStream, model);
13686
13799
  xmlStream.closeNode();
13687
13800
  }
13688
13801
  parseOpen(node) {
@@ -17886,17 +17999,10 @@ var ExcelTS = (function(exports) {
17886
17999
  * Default threshold (in bytes) to choose the lower-overhead path.
17887
18000
  *
17888
18001
  * This is a performance knob, not a correctness requirement.
18002
+ * Default: 8MB.
17889
18003
  */
17890
18004
  const DEFAULT_COMPRESS_THRESHOLD_BYTES = 8 * 1024 * 1024;
17891
18005
  /**
17892
- * Resolve the effective threshold bytes.
17893
- */
17894
- function resolveCompressThresholdBytes(options) {
17895
- const value = options.thresholdBytes;
17896
- if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return DEFAULT_COMPRESS_THRESHOLD_BYTES;
17897
- return value;
17898
- }
17899
- /**
17900
18006
  * Non-cached probe for CompressionStream("deflate-raw") support.
17901
18007
  *
17902
18008
  * Prefer this in code paths that want up-to-date environment checks
@@ -18775,12 +18881,16 @@ var ExcelTS = (function(exports) {
18775
18881
  /**
18776
18882
  * Decompress data using browser's native DecompressionStream or JS fallback
18777
18883
  *
18884
+ * Note: We always prefer native DecompressionStream when available because
18885
+ * it's significantly faster than pure JS implementation, regardless of data size.
18886
+ * The threshold is only useful for compression where the overhead matters more.
18887
+ *
18778
18888
  * @param data - Compressed data (deflate-raw format)
18889
+ * @param options - Decompression options (kept for API parity; currently unused in browser)
18779
18890
  * @returns Decompressed data
18780
18891
  */
18781
18892
  async function decompress(data, options = {}) {
18782
- const thresholdBytes = resolveCompressThresholdBytes(options);
18783
- if (hasDeflateRawDecompressionStream() && data.byteLength > thresholdBytes) return decompressWithStream(data);
18893
+ if (hasDeflateRawDecompressionStream()) return decompressWithStream(data);
18784
18894
  return inflateRaw(data);
18785
18895
  }
18786
18896
  /**
@@ -19483,8 +19593,13 @@ var ExcelTS = (function(exports) {
19483
19593
  queueMicrotask(pull);
19484
19594
  return output;
19485
19595
  }
19596
+ /**
19597
+ * Default threshold for small file optimization (5MB).
19598
+ */
19599
+ const DEFAULT_PARSE_THRESHOLD_BYTES = 5 * 1024 * 1024;
19486
19600
  const endDirectorySignature = writeUint32LE(END_OF_CENTRAL_DIR_SIG);
19487
- async function runParseLoop(opts, io, emitter, inflateFactory, state) {
19601
+ async function runParseLoop(opts, io, emitter, inflateFactory, state, inflateRawSync) {
19602
+ const thresholdBytes = opts.thresholdBytes ?? DEFAULT_PARSE_THRESHOLD_BYTES;
19488
19603
  while (true) {
19489
19604
  const sigBytes = await io.pull(4);
19490
19605
  if (sigBytes.length === 0) {
@@ -19498,7 +19613,7 @@ var ExcelTS = (function(exports) {
19498
19613
  continue;
19499
19614
  }
19500
19615
  if (signature === LOCAL_FILE_HEADER_SIG) {
19501
- await readFileRecord(opts, io, emitter, inflateFactory, state);
19616
+ await readFileRecord(opts, io, emitter, inflateFactory, state, thresholdBytes, inflateRawSync);
19502
19617
  continue;
19503
19618
  }
19504
19619
  if (signature === CENTRAL_DIR_HEADER_SIG) {
@@ -19524,7 +19639,7 @@ var ExcelTS = (function(exports) {
19524
19639
  return;
19525
19640
  }
19526
19641
  }
19527
- async function readFileRecord(opts, io, emitter, inflateFactory, state) {
19642
+ async function readFileRecord(opts, io, emitter, inflateFactory, state, thresholdBytes, inflateRawSync) {
19528
19643
  const { vars: headerVars, fileNameBuffer, extraFieldData } = await readLocalFileHeader(async (l) => io.pull(l));
19529
19644
  const vars = headerVars;
19530
19645
  if (state.crxHeader) vars.crxHeader = state.crxHeader;
@@ -19564,6 +19679,15 @@ var ExcelTS = (function(exports) {
19564
19679
  vars,
19565
19680
  extraFields: entry.extraFields
19566
19681
  });
19682
+ const sizesTrusted = !hasDataDescriptorFlag(vars.flags);
19683
+ const compressedSize = vars.compressedSize || 0;
19684
+ const uncompressedSize = vars.uncompressedSize || 0;
19685
+ if (sizesTrusted && fileSizeKnown && inflateRawSync && vars.compressionMethod !== 0 && !autodraining && compressedSize <= thresholdBytes && uncompressedSize <= thresholdBytes) {
19686
+ const decompressedData = inflateRawSync(await io.pull(compressedSize));
19687
+ entry.end(decompressedData);
19688
+ await finished(entry, { readable: false });
19689
+ return;
19690
+ }
19567
19691
  const inflater = vars.compressionMethod && !autodraining ? inflateFactory() : new PassThrough();
19568
19692
  if (fileSizeKnown) {
19569
19693
  await pipeline(io.stream(vars.compressedSize || 0), inflater, entry);