@cj-tech-master/excelts 4.2.1-canary.20260111102127.f808a37 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/THIRD_PARTY_NOTICES.md +31 -0
  2. package/dist/browser/index.browser.d.ts +0 -1
  3. package/dist/browser/index.browser.js +0 -12
  4. package/dist/browser/modules/archive/byte-queue.d.ts +18 -0
  5. package/dist/browser/modules/archive/byte-queue.js +125 -0
  6. package/dist/browser/modules/archive/{compression/compress.base.js → compress.base.js} +1 -1
  7. package/dist/browser/modules/archive/{compression/compress.browser.d.ts → compress.browser.d.ts} +8 -2
  8. package/dist/{esm/modules/archive/compression → browser/modules/archive}/compress.browser.js +11 -3
  9. package/dist/browser/modules/archive/{compression/compress.d.ts → compress.d.ts} +2 -2
  10. package/dist/{esm/modules/archive/compression → browser/modules/archive}/compress.js +1 -1
  11. package/dist/browser/modules/archive/{compression/crc32.browser.d.ts → crc32.browser.d.ts} +1 -1
  12. package/dist/browser/modules/archive/{compression/crc32.d.ts → crc32.d.ts} +1 -1
  13. package/dist/browser/modules/archive/{compression/crc32.js → crc32.js} +1 -1
  14. package/dist/browser/modules/archive/defaults.d.ts +0 -1
  15. package/dist/browser/modules/archive/defaults.js +3 -6
  16. package/dist/browser/modules/archive/{compression/deflate-fallback.js → deflate-fallback.js} +1 -1
  17. package/dist/browser/modules/archive/{unzip/extract.d.ts → extract.d.ts} +2 -2
  18. package/dist/browser/modules/archive/index.base.d.ts +4 -4
  19. package/dist/browser/modules/archive/index.base.js +6 -3
  20. package/dist/browser/modules/archive/index.browser.d.ts +4 -3
  21. package/dist/browser/modules/archive/index.browser.js +7 -3
  22. package/dist/browser/modules/archive/index.d.ts +4 -3
  23. package/dist/browser/modules/archive/index.js +5 -3
  24. package/dist/browser/modules/archive/{unzip/stream.base.d.ts → parse.base.d.ts} +2 -36
  25. package/dist/browser/modules/archive/parse.base.js +644 -0
  26. package/dist/browser/modules/archive/{unzip/stream.browser.d.ts → parse.browser.d.ts} +1 -1
  27. package/dist/{esm/modules/archive/unzip/stream.browser.js → browser/modules/archive/parse.browser.js} +110 -371
  28. package/dist/browser/modules/archive/{unzip/stream.d.ts → parse.d.ts} +2 -2
  29. package/dist/{esm/modules/archive/unzip/stream.js → browser/modules/archive/parse.js} +5 -6
  30. package/dist/browser/modules/archive/{compression/streaming-compress.browser.d.ts → streaming-compress.browser.d.ts} +2 -2
  31. package/dist/browser/modules/archive/{compression/streaming-compress.browser.js → streaming-compress.browser.js} +3 -3
  32. package/dist/browser/modules/archive/{compression/streaming-compress.d.ts → streaming-compress.d.ts} +2 -2
  33. package/dist/browser/modules/archive/{compression/streaming-compress.js → streaming-compress.js} +2 -2
  34. package/dist/browser/modules/archive/{zip/stream.d.ts → streaming-zip.d.ts} +5 -28
  35. package/dist/{esm/modules/archive/zip/stream.js → browser/modules/archive/streaming-zip.js} +48 -192
  36. package/dist/browser/modules/archive/utils/bytes.js +16 -16
  37. package/dist/browser/modules/archive/utils/parse-buffer.js +23 -21
  38. package/dist/browser/modules/archive/utils/timestamps.js +1 -62
  39. package/dist/browser/modules/archive/utils/zip-extra-fields.d.ts +1 -1
  40. package/dist/browser/modules/archive/utils/zip-extra-fields.js +14 -26
  41. package/dist/browser/modules/archive/utils/zip-extra.d.ts +18 -0
  42. package/dist/browser/modules/archive/utils/zip-extra.js +68 -0
  43. package/dist/browser/modules/archive/zip-builder.d.ts +117 -0
  44. package/dist/browser/modules/archive/zip-builder.js +292 -0
  45. package/dist/browser/modules/archive/zip-constants.d.ts +18 -0
  46. package/dist/browser/modules/archive/zip-constants.js +23 -0
  47. package/dist/{esm/modules/archive/zip → browser/modules/archive}/zip-entry-metadata.js +3 -3
  48. package/dist/{types/modules/archive/unzip → browser/modules/archive}/zip-parser.d.ts +1 -1
  49. package/dist/{esm/modules/archive/unzip → browser/modules/archive}/zip-parser.js +24 -38
  50. package/dist/browser/modules/archive/{zip-spec/zip-records.d.ts → zip-records.d.ts} +0 -20
  51. package/dist/browser/modules/archive/zip-records.js +84 -0
  52. package/dist/browser/modules/excel/stream/workbook-reader.browser.js +1 -1
  53. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +1 -1
  54. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +1 -1
  55. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +6 -3
  56. package/dist/browser/modules/excel/xlsx/xlsx.js +1 -1
  57. package/dist/browser/modules/stream/streams.browser.d.ts +30 -28
  58. package/dist/browser/modules/stream/streams.browser.js +710 -830
  59. package/dist/browser/modules/stream/streams.js +58 -140
  60. package/dist/cjs/modules/archive/byte-queue.js +129 -0
  61. package/dist/cjs/modules/archive/{compression/compress.base.js → compress.base.js} +1 -1
  62. package/dist/cjs/modules/archive/{compression/compress.browser.js → compress.browser.js} +11 -3
  63. package/dist/cjs/modules/archive/{compression/compress.js → compress.js} +1 -1
  64. package/dist/cjs/modules/archive/{compression/crc32.js → crc32.js} +1 -1
  65. package/dist/cjs/modules/archive/defaults.js +4 -7
  66. package/dist/cjs/modules/archive/{compression/deflate-fallback.js → deflate-fallback.js} +1 -1
  67. package/dist/cjs/modules/archive/index.base.js +19 -9
  68. package/dist/cjs/modules/archive/index.browser.js +10 -4
  69. package/dist/cjs/modules/archive/index.js +8 -4
  70. package/dist/cjs/modules/archive/parse.base.js +666 -0
  71. package/dist/cjs/modules/archive/{unzip/stream.browser.js → parse.browser.js} +111 -372
  72. package/dist/cjs/modules/archive/{unzip/stream.js → parse.js} +8 -9
  73. package/dist/cjs/modules/archive/{compression/streaming-compress.browser.js → streaming-compress.browser.js} +3 -3
  74. package/dist/cjs/modules/archive/{compression/streaming-compress.js → streaming-compress.js} +2 -2
  75. package/dist/cjs/modules/archive/{zip/stream.js → streaming-zip.js} +50 -194
  76. package/dist/cjs/modules/archive/utils/bytes.js +16 -16
  77. package/dist/cjs/modules/archive/utils/parse-buffer.js +23 -21
  78. package/dist/cjs/modules/archive/utils/timestamps.js +3 -64
  79. package/dist/cjs/modules/archive/utils/zip-extra-fields.js +14 -26
  80. package/dist/cjs/modules/archive/utils/zip-extra.js +74 -0
  81. package/dist/cjs/modules/archive/zip-builder.js +297 -0
  82. package/dist/cjs/modules/archive/zip-constants.js +26 -0
  83. package/dist/cjs/modules/archive/{zip/zip-entry-metadata.js → zip-entry-metadata.js} +5 -5
  84. package/dist/cjs/modules/archive/{unzip/zip-parser.js → zip-parser.js} +33 -47
  85. package/dist/cjs/modules/archive/zip-records.js +90 -0
  86. package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +2 -2
  87. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +4 -4
  88. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +9 -6
  89. package/dist/cjs/modules/excel/xlsx/xlsx.js +2 -2
  90. package/dist/cjs/modules/stream/streams.browser.js +710 -830
  91. package/dist/cjs/modules/stream/streams.js +58 -140
  92. package/dist/esm/index.browser.js +0 -12
  93. package/dist/esm/modules/archive/byte-queue.js +125 -0
  94. package/dist/esm/modules/archive/{compression/compress.base.js → compress.base.js} +1 -1
  95. package/dist/{browser/modules/archive/compression → esm/modules/archive}/compress.browser.js +11 -3
  96. package/dist/{browser/modules/archive/compression → esm/modules/archive}/compress.js +1 -1
  97. package/dist/esm/modules/archive/{compression/crc32.js → crc32.js} +1 -1
  98. package/dist/esm/modules/archive/defaults.js +3 -6
  99. package/dist/esm/modules/archive/{compression/deflate-fallback.js → deflate-fallback.js} +1 -1
  100. package/dist/esm/modules/archive/index.base.js +6 -3
  101. package/dist/esm/modules/archive/index.browser.js +7 -3
  102. package/dist/esm/modules/archive/index.js +5 -3
  103. package/dist/esm/modules/archive/parse.base.js +644 -0
  104. package/dist/{browser/modules/archive/unzip/stream.browser.js → esm/modules/archive/parse.browser.js} +110 -371
  105. package/dist/{browser/modules/archive/unzip/stream.js → esm/modules/archive/parse.js} +5 -6
  106. package/dist/esm/modules/archive/{compression/streaming-compress.browser.js → streaming-compress.browser.js} +3 -3
  107. package/dist/esm/modules/archive/{compression/streaming-compress.js → streaming-compress.js} +2 -2
  108. package/dist/{browser/modules/archive/zip/stream.js → esm/modules/archive/streaming-zip.js} +48 -192
  109. package/dist/esm/modules/archive/utils/bytes.js +16 -16
  110. package/dist/esm/modules/archive/utils/parse-buffer.js +23 -21
  111. package/dist/esm/modules/archive/utils/timestamps.js +1 -62
  112. package/dist/esm/modules/archive/utils/zip-extra-fields.js +14 -26
  113. package/dist/esm/modules/archive/utils/zip-extra.js +68 -0
  114. package/dist/esm/modules/archive/zip-builder.js +292 -0
  115. package/dist/esm/modules/archive/zip-constants.js +23 -0
  116. package/dist/{browser/modules/archive/zip → esm/modules/archive}/zip-entry-metadata.js +3 -3
  117. package/dist/{browser/modules/archive/unzip → esm/modules/archive}/zip-parser.js +24 -38
  118. package/dist/esm/modules/archive/zip-records.js +84 -0
  119. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +1 -1
  120. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +1 -1
  121. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +6 -3
  122. package/dist/esm/modules/excel/xlsx/xlsx.js +1 -1
  123. package/dist/esm/modules/stream/streams.browser.js +710 -830
  124. package/dist/esm/modules/stream/streams.js +58 -140
  125. package/dist/iife/THIRD_PARTY_NOTICES.md +31 -0
  126. package/dist/iife/excelts.iife.js +4425 -6215
  127. package/dist/iife/excelts.iife.js.map +1 -1
  128. package/dist/iife/excelts.iife.min.js +31 -103
  129. package/dist/types/index.browser.d.ts +0 -1
  130. package/dist/types/modules/archive/byte-queue.d.ts +18 -0
  131. package/dist/types/modules/archive/{compression/compress.browser.d.ts → compress.browser.d.ts} +8 -2
  132. package/dist/types/modules/archive/defaults.d.ts +0 -1
  133. package/dist/types/modules/archive/index.base.d.ts +4 -4
  134. package/dist/types/modules/archive/index.browser.d.ts +4 -3
  135. package/dist/types/modules/archive/index.d.ts +4 -3
  136. package/dist/types/modules/archive/{unzip/stream.base.d.ts → parse.base.d.ts} +4 -38
  137. package/dist/types/modules/archive/{unzip/stream.browser.d.ts → parse.browser.d.ts} +2 -2
  138. package/dist/types/modules/archive/{unzip/stream.d.ts → parse.d.ts} +3 -3
  139. package/dist/types/modules/archive/{compression/streaming-compress.browser.d.ts → streaming-compress.browser.d.ts} +1 -1
  140. package/dist/types/modules/archive/{zip/stream.d.ts → streaming-zip.d.ts} +6 -29
  141. package/dist/types/modules/archive/utils/zip-extra-fields.d.ts +1 -1
  142. package/dist/types/modules/archive/utils/zip-extra.d.ts +18 -0
  143. package/dist/types/modules/archive/zip-builder.d.ts +117 -0
  144. package/dist/types/modules/archive/zip-constants.d.ts +18 -0
  145. package/dist/types/modules/archive/{zip/zip-entry-metadata.d.ts → zip-entry-metadata.d.ts} +1 -1
  146. package/dist/{browser/modules/archive/unzip → types/modules/archive}/zip-parser.d.ts +1 -1
  147. package/dist/types/modules/archive/{zip-spec/zip-records.d.ts → zip-records.d.ts} +0 -20
  148. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +1 -1
  149. package/dist/types/modules/stream/streams.browser.d.ts +30 -28
  150. package/package.json +1 -5
  151. package/dist/browser/modules/archive/internal/byte-queue.d.ts +0 -33
  152. package/dist/browser/modules/archive/internal/byte-queue.js +0 -407
  153. package/dist/browser/modules/archive/io/archive-sink.d.ts +0 -9
  154. package/dist/browser/modules/archive/io/archive-sink.js +0 -77
  155. package/dist/browser/modules/archive/io/archive-source.d.ts +0 -8
  156. package/dist/browser/modules/archive/io/archive-source.js +0 -107
  157. package/dist/browser/modules/archive/unzip/index.d.ts +0 -40
  158. package/dist/browser/modules/archive/unzip/index.js +0 -164
  159. package/dist/browser/modules/archive/unzip/stream.base.js +0 -1022
  160. package/dist/browser/modules/archive/utils/async-queue.d.ts +0 -7
  161. package/dist/browser/modules/archive/utils/async-queue.js +0 -103
  162. package/dist/browser/modules/archive/utils/compressibility.d.ts +0 -10
  163. package/dist/browser/modules/archive/utils/compressibility.js +0 -57
  164. package/dist/browser/modules/archive/utils/pattern-scanner.d.ts +0 -21
  165. package/dist/browser/modules/archive/utils/pattern-scanner.js +0 -27
  166. package/dist/browser/modules/archive/zip/index.d.ts +0 -42
  167. package/dist/browser/modules/archive/zip/index.js +0 -157
  168. package/dist/browser/modules/archive/zip/zip-bytes.d.ts +0 -73
  169. package/dist/browser/modules/archive/zip/zip-bytes.js +0 -239
  170. package/dist/browser/modules/archive/zip-spec/zip-records.js +0 -126
  171. package/dist/cjs/modules/archive/internal/byte-queue.js +0 -411
  172. package/dist/cjs/modules/archive/io/archive-sink.js +0 -82
  173. package/dist/cjs/modules/archive/io/archive-source.js +0 -114
  174. package/dist/cjs/modules/archive/unzip/index.js +0 -170
  175. package/dist/cjs/modules/archive/unzip/stream.base.js +0 -1044
  176. package/dist/cjs/modules/archive/utils/async-queue.js +0 -106
  177. package/dist/cjs/modules/archive/utils/compressibility.js +0 -60
  178. package/dist/cjs/modules/archive/utils/pattern-scanner.js +0 -31
  179. package/dist/cjs/modules/archive/zip/index.js +0 -162
  180. package/dist/cjs/modules/archive/zip/zip-bytes.js +0 -242
  181. package/dist/cjs/modules/archive/zip-spec/zip-records.js +0 -136
  182. package/dist/esm/modules/archive/internal/byte-queue.js +0 -407
  183. package/dist/esm/modules/archive/io/archive-sink.js +0 -77
  184. package/dist/esm/modules/archive/io/archive-source.js +0 -107
  185. package/dist/esm/modules/archive/unzip/index.js +0 -164
  186. package/dist/esm/modules/archive/unzip/stream.base.js +0 -1022
  187. package/dist/esm/modules/archive/utils/async-queue.js +0 -103
  188. package/dist/esm/modules/archive/utils/compressibility.js +0 -57
  189. package/dist/esm/modules/archive/utils/pattern-scanner.js +0 -27
  190. package/dist/esm/modules/archive/zip/index.js +0 -157
  191. package/dist/esm/modules/archive/zip/zip-bytes.js +0 -239
  192. package/dist/esm/modules/archive/zip-spec/zip-records.js +0 -126
  193. package/dist/types/modules/archive/internal/byte-queue.d.ts +0 -33
  194. package/dist/types/modules/archive/io/archive-sink.d.ts +0 -9
  195. package/dist/types/modules/archive/io/archive-source.d.ts +0 -8
  196. package/dist/types/modules/archive/unzip/index.d.ts +0 -40
  197. package/dist/types/modules/archive/utils/async-queue.d.ts +0 -7
  198. package/dist/types/modules/archive/utils/compressibility.d.ts +0 -10
  199. package/dist/types/modules/archive/utils/pattern-scanner.d.ts +0 -21
  200. package/dist/types/modules/archive/zip/index.d.ts +0 -42
  201. package/dist/types/modules/archive/zip/zip-bytes.d.ts +0 -73
  202. /package/dist/browser/modules/archive/{compression/compress.base.d.ts → compress.base.d.ts} +0 -0
  203. /package/dist/browser/modules/archive/{compression/crc32.base.d.ts → crc32.base.d.ts} +0 -0
  204. /package/dist/browser/modules/archive/{compression/crc32.base.js → crc32.base.js} +0 -0
  205. /package/dist/browser/modules/archive/{compression/crc32.browser.js → crc32.browser.js} +0 -0
  206. /package/dist/browser/modules/archive/{compression/deflate-fallback.d.ts → deflate-fallback.d.ts} +0 -0
  207. /package/dist/browser/modules/archive/{unzip/extract.js → extract.js} +0 -0
  208. /package/dist/browser/modules/archive/{compression/streaming-compress.base.d.ts → streaming-compress.base.d.ts} +0 -0
  209. /package/dist/browser/modules/archive/{compression/streaming-compress.base.js → streaming-compress.base.js} +0 -0
  210. /package/dist/browser/modules/archive/{zip-spec/zip-entry-info.d.ts → zip-entry-info.d.ts} +0 -0
  211. /package/dist/browser/modules/archive/{zip-spec/zip-entry-info.js → zip-entry-info.js} +0 -0
  212. /package/dist/browser/modules/archive/{zip/zip-entry-metadata.d.ts → zip-entry-metadata.d.ts} +0 -0
  213. /package/dist/cjs/modules/archive/{compression/crc32.base.js → crc32.base.js} +0 -0
  214. /package/dist/cjs/modules/archive/{compression/crc32.browser.js → crc32.browser.js} +0 -0
  215. /package/dist/cjs/modules/archive/{unzip/extract.js → extract.js} +0 -0
  216. /package/dist/cjs/modules/archive/{compression/streaming-compress.base.js → streaming-compress.base.js} +0 -0
  217. /package/dist/cjs/modules/archive/{zip-spec/zip-entry-info.js → zip-entry-info.js} +0 -0
  218. /package/dist/esm/modules/archive/{compression/crc32.base.js → crc32.base.js} +0 -0
  219. /package/dist/esm/modules/archive/{compression/crc32.browser.js → crc32.browser.js} +0 -0
  220. /package/dist/esm/modules/archive/{unzip/extract.js → extract.js} +0 -0
  221. /package/dist/esm/modules/archive/{compression/streaming-compress.base.js → streaming-compress.base.js} +0 -0
  222. /package/dist/esm/modules/archive/{zip-spec/zip-entry-info.js → zip-entry-info.js} +0 -0
  223. /package/dist/types/modules/archive/{compression/compress.base.d.ts → compress.base.d.ts} +0 -0
  224. /package/dist/types/modules/archive/{compression/compress.d.ts → compress.d.ts} +0 -0
  225. /package/dist/types/modules/archive/{compression/crc32.base.d.ts → crc32.base.d.ts} +0 -0
  226. /package/dist/types/modules/archive/{compression/crc32.browser.d.ts → crc32.browser.d.ts} +0 -0
  227. /package/dist/types/modules/archive/{compression/crc32.d.ts → crc32.d.ts} +0 -0
  228. /package/dist/types/modules/archive/{compression/deflate-fallback.d.ts → deflate-fallback.d.ts} +0 -0
  229. /package/dist/types/modules/archive/{unzip/extract.d.ts → extract.d.ts} +0 -0
  230. /package/dist/types/modules/archive/{compression/streaming-compress.base.d.ts → streaming-compress.base.d.ts} +0 -0
  231. /package/dist/types/modules/archive/{compression/streaming-compress.d.ts → streaming-compress.d.ts} +0 -0
  232. /package/dist/types/modules/archive/{zip-spec/zip-entry-info.d.ts → zip-entry-info.d.ts} +0 -0
@@ -0,0 +1,68 @@
1
+ const EXTENDED_TIMESTAMP_ID = 0x5455;
2
+ function clampUint32(value) {
3
+ if (!Number.isFinite(value)) {
4
+ return 0;
5
+ }
6
+ if (value <= 0) {
7
+ return 0;
8
+ }
9
+ // 0xFFFFFFFF fits JS safe integer.
10
+ if (value >= 0xffffffff) {
11
+ return 0xffffffff;
12
+ }
13
+ return value >>> 0;
14
+ }
15
+ export function unixSecondsFromDate(date) {
16
+ return clampUint32(Math.floor(date.getTime() / 1000));
17
+ }
18
+ /**
19
+ * Build Info-ZIP "Extended Timestamp" extra field (0x5455).
20
+ * We write only mtime (UTC, Unix seconds) to minimize size.
21
+ *
22
+ * Layout:
23
+ * - Header ID: 2 bytes (0x5455)
24
+ * - Data size: 2 bytes
25
+ * - Flags: 1 byte (bit0 = mtime)
26
+ * - mtime: 4 bytes (Unix seconds)
27
+ */
28
+ export function buildExtendedTimestampExtraFieldFromUnixSeconds(unixSeconds) {
29
+ const ts = clampUint32(unixSeconds);
30
+ // flags(1) + mtime(4)
31
+ const payloadSize = 5;
32
+ const out = new Uint8Array(4 + payloadSize);
33
+ const view = new DataView(out.buffer);
34
+ view.setUint16(0, EXTENDED_TIMESTAMP_ID, true);
35
+ view.setUint16(2, payloadSize, true);
36
+ out[4] = 0x01; // mtime present
37
+ view.setUint32(5, ts, true);
38
+ return out;
39
+ }
40
+ export function buildExtendedTimestampExtraFieldFromDate(date) {
41
+ return buildExtendedTimestampExtraFieldFromUnixSeconds(unixSecondsFromDate(date));
42
+ }
43
+ /**
44
+ * Parse Info-ZIP "Extended Timestamp" extra field (0x5455) and return mtime.
45
+ * Returns Unix seconds (UTC) if present.
46
+ */
47
+ export function parseExtendedTimestampMtimeUnixSeconds(extraField) {
48
+ const view = new DataView(extraField.buffer, extraField.byteOffset, extraField.byteLength);
49
+ let offset = 0;
50
+ while (offset + 4 <= extraField.length) {
51
+ const headerId = view.getUint16(offset, true);
52
+ const dataSize = view.getUint16(offset + 2, true);
53
+ const dataStart = offset + 4;
54
+ const dataEnd = dataStart + dataSize;
55
+ if (dataEnd > extraField.length) {
56
+ break;
57
+ }
58
+ if (headerId === EXTENDED_TIMESTAMP_ID && dataSize >= 1) {
59
+ const flags = extraField[dataStart];
60
+ if ((flags & 0x01) !== 0 && dataSize >= 5) {
61
+ // mtime is 4 bytes right after flags.
62
+ return view.getUint32(dataStart + 1, true) >>> 0;
63
+ }
64
+ }
65
+ offset = dataEnd;
66
+ }
67
+ return undefined;
68
+ }
@@ -0,0 +1,292 @@
1
+ /**
2
+ * ZIP file format builder
3
+ *
4
+ * Implements ZIP file structure according to PKWARE's APPNOTE.TXT specification
5
+ * https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
6
+ *
7
+ * ZIP file structure:
8
+ * ┌──────────────────────────┐
9
+ * │ Local File Header 1 │
10
+ * │ File Data 1 │
11
+ * ├──────────────────────────┤
12
+ * │ Local File Header 2 │
13
+ * │ File Data 2 │
14
+ * ├──────────────────────────┤
15
+ * │ ... │
16
+ * ├──────────────────────────┤
17
+ * │ Central Directory 1 │
18
+ * │ Central Directory 2 │
19
+ * │ ... │
20
+ * ├──────────────────────────┤
21
+ * │ End of Central Directory │
22
+ * └──────────────────────────┘
23
+ */
24
+ import { compress, compressSync } from "./compress.js";
25
+ import { crc32 } from "./crc32.js";
26
+ import { concatUint8Arrays, sumUint8ArrayLengths } from "./utils/bytes.js";
27
+ import {} from "./utils/timestamps.js";
28
+ import { buildZipEntryMetadata, resolveZipCompressionMethod } from "./zip-entry-metadata.js";
29
+ import { DEFAULT_ZIP_LEVEL, DEFAULT_ZIP_TIMESTAMPS } from "./defaults.js";
30
+ import { buildCentralDirectoryHeader, buildEndOfCentralDirectory, buildLocalFileHeader } from "./zip-records.js";
31
+ import { FLAG_UTF8, VERSION_MADE_BY, VERSION_NEEDED } from "./zip-constants.js";
32
+ const LOCAL_FILE_HEADER_FIXED_SIZE = 30;
33
+ function encodeZipComment(comment) {
34
+ // Keep empty comment as empty bytes (no encoding surprises).
35
+ return comment ? new TextEncoder().encode(comment) : new Uint8Array(0);
36
+ }
37
+ function shouldDeflate(level, data) {
38
+ return level > 0 && data.length > 0;
39
+ }
40
+ function computeLocalRecordSize(entry) {
41
+ return (LOCAL_FILE_HEADER_FIXED_SIZE +
42
+ entry.name.length +
43
+ entry.extraField.length +
44
+ entry.compressedData.length);
45
+ }
46
+ function buildProcessedEntry(entry, offset, settings, compressedData) {
47
+ const modDate = entry.modTime ?? settings.defaultModTime;
48
+ const isCompressed = shouldDeflate(settings.level, entry.data);
49
+ const metadata = buildZipEntryMetadata({
50
+ name: entry.name,
51
+ comment: entry.comment,
52
+ modTime: modDate,
53
+ timestamps: settings.timestamps,
54
+ useDataDescriptor: false,
55
+ deflate: isCompressed
56
+ });
57
+ return {
58
+ name: metadata.nameBytes,
59
+ data: entry.data,
60
+ compressedData,
61
+ crc: crc32(entry.data),
62
+ compressionMethod: resolveZipCompressionMethod(isCompressed),
63
+ modTime: metadata.dosTime,
64
+ modDate: metadata.dosDate,
65
+ extraField: metadata.extraField,
66
+ comment: metadata.commentBytes,
67
+ offset
68
+ };
69
+ }
70
+ function appendProcessedEntry(processedEntries, entry, compressedData, currentOffset, settings) {
71
+ const processedEntry = buildProcessedEntry(entry, currentOffset, settings, compressedData);
72
+ processedEntries.push(processedEntry);
73
+ return {
74
+ processedEntry,
75
+ nextOffset: currentOffset + computeLocalRecordSize(processedEntry)
76
+ };
77
+ }
78
+ function finalizeZip(processedEntries, zipComment, centralDirOffset) {
79
+ // Build ZIP structure
80
+ const chunks = [];
81
+ // Local file headers and data
82
+ for (const entry of processedEntries) {
83
+ chunks.push(buildLocalFileHeaderChunk(entry));
84
+ chunks.push(entry.compressedData);
85
+ }
86
+ chunks.push(...buildCentralDirectorySection(processedEntries, centralDirOffset, zipComment));
87
+ return concatUint8Arrays(chunks);
88
+ }
89
+ function buildLocalFileHeaderChunk(entry) {
90
+ return buildLocalFileHeader({
91
+ fileName: entry.name,
92
+ extraField: entry.extraField,
93
+ flags: FLAG_UTF8,
94
+ compressionMethod: entry.compressionMethod,
95
+ dosTime: entry.modTime,
96
+ dosDate: entry.modDate,
97
+ crc32: entry.crc,
98
+ compressedSize: entry.compressedData.length,
99
+ uncompressedSize: entry.data.length,
100
+ versionNeeded: VERSION_NEEDED
101
+ });
102
+ }
103
+ function buildCentralDirHeaderChunk(entry) {
104
+ return buildCentralDirectoryHeader({
105
+ fileName: entry.name,
106
+ extraField: entry.extraField,
107
+ comment: entry.comment,
108
+ flags: FLAG_UTF8,
109
+ compressionMethod: entry.compressionMethod,
110
+ dosTime: entry.modTime,
111
+ dosDate: entry.modDate,
112
+ crc32: entry.crc,
113
+ compressedSize: entry.compressedData.length,
114
+ uncompressedSize: entry.data.length,
115
+ localHeaderOffset: entry.offset,
116
+ versionMadeBy: VERSION_MADE_BY,
117
+ versionNeeded: VERSION_NEEDED
118
+ });
119
+ }
120
+ function buildCentralDirectorySection(processedEntries, centralDirOffset, zipComment) {
121
+ const chunks = [];
122
+ for (const entry of processedEntries) {
123
+ chunks.push(buildCentralDirHeaderChunk(entry));
124
+ }
125
+ const centralDirSize = sumUint8ArrayLengths(chunks);
126
+ chunks.push(buildEndOfCentralDirectory({
127
+ entryCount: processedEntries.length,
128
+ centralDirSize,
129
+ centralDirOffset,
130
+ comment: zipComment
131
+ }));
132
+ return chunks;
133
+ }
134
+ /**
135
+ * Create a ZIP file from entries (async)
136
+ *
137
+ * @param entries - Files to include in ZIP
138
+ * @param options - ZIP options
139
+ * @returns ZIP file as Uint8Array
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * const zip = await createZip([
144
+ * { name: "hello.txt", data: new TextEncoder().encode("Hello!") },
145
+ * { name: "folder/file.txt", data: new TextEncoder().encode("Nested!") }
146
+ * ], { level: 6 });
147
+ * ```
148
+ */
149
+ export async function createZip(entries, options = {}) {
150
+ const level = options.level ?? DEFAULT_ZIP_LEVEL;
151
+ const timestamps = options.timestamps ?? DEFAULT_ZIP_TIMESTAMPS;
152
+ const zipComment = encodeZipComment(options.comment);
153
+ const defaultModTime = new Date();
154
+ const settings = {
155
+ level,
156
+ timestamps,
157
+ defaultModTime
158
+ };
159
+ const compressOptions = {
160
+ level,
161
+ thresholdBytes: options.thresholdBytes
162
+ };
163
+ const compressedDatas = await Promise.all(entries.map(async (entry) => {
164
+ return shouldDeflate(level, entry.data) ? compress(entry.data, compressOptions) : entry.data;
165
+ }));
166
+ // Process entries
167
+ const processedEntries = [];
168
+ let currentOffset = 0;
169
+ for (let i = 0; i < entries.length; i++) {
170
+ const entry = entries[i];
171
+ const compressedData = compressedDatas[i];
172
+ const result = appendProcessedEntry(processedEntries, entry, compressedData, currentOffset, settings);
173
+ currentOffset = result.nextOffset;
174
+ }
175
+ return finalizeZip(processedEntries, zipComment, currentOffset);
176
+ }
177
+ /**
178
+ * Create a ZIP file from entries (sync)
179
+ *
180
+ * This is supported in both Node.js and browser builds.
181
+ */
182
+ export function createZipSync(entries, options = {}) {
183
+ const level = options.level ?? DEFAULT_ZIP_LEVEL;
184
+ const timestamps = options.timestamps ?? DEFAULT_ZIP_TIMESTAMPS;
185
+ const zipComment = encodeZipComment(options.comment);
186
+ const defaultModTime = new Date();
187
+ const settings = {
188
+ level,
189
+ timestamps,
190
+ defaultModTime
191
+ };
192
+ const compressOptions = {
193
+ level,
194
+ thresholdBytes: options.thresholdBytes
195
+ };
196
+ // Process entries
197
+ const processedEntries = [];
198
+ let currentOffset = 0;
199
+ for (const entry of entries) {
200
+ // Compress data
201
+ const compressedData = shouldDeflate(level, entry.data)
202
+ ? compressSync(entry.data, compressOptions)
203
+ : entry.data;
204
+ const result = appendProcessedEntry(processedEntries, entry, compressedData, currentOffset, settings);
205
+ currentOffset = result.nextOffset;
206
+ }
207
+ return finalizeZip(processedEntries, zipComment, currentOffset);
208
+ }
209
+ /**
210
+ * Streaming ZIP builder for large files
211
+ * Writes chunks to a callback as they are generated
212
+ */
213
+ export class ZipBuilder {
214
+ /**
215
+ * Create a new ZIP builder
216
+ * @param options - ZIP options
217
+ */
218
+ constructor(options = {}) {
219
+ this.entries = [];
220
+ this.currentOffset = 0;
221
+ this.finalized = false;
222
+ this.level = options.level ?? DEFAULT_ZIP_LEVEL;
223
+ this.zipComment = encodeZipComment(options.comment);
224
+ this.timestamps = options.timestamps ?? DEFAULT_ZIP_TIMESTAMPS;
225
+ this.compressOptions = {
226
+ level: this.level,
227
+ thresholdBytes: options.thresholdBytes
228
+ };
229
+ this.settings = {
230
+ level: this.level,
231
+ timestamps: this.timestamps,
232
+ defaultModTime: new Date()
233
+ };
234
+ }
235
+ /**
236
+ * Add a file to the ZIP (async)
237
+ * @param entry - File entry
238
+ * @returns Local file header and compressed data chunks
239
+ */
240
+ async addFile(entry) {
241
+ if (this.finalized) {
242
+ throw new Error("Cannot add files after finalizing");
243
+ }
244
+ // Compress data
245
+ const compressedData = shouldDeflate(this.level, entry.data)
246
+ ? await compress(entry.data, this.compressOptions)
247
+ : entry.data;
248
+ const result = appendProcessedEntry(this.entries, entry, compressedData, this.currentOffset, this.settings);
249
+ this.currentOffset = result.nextOffset;
250
+ return [buildLocalFileHeaderChunk(result.processedEntry), compressedData];
251
+ }
252
+ /**
253
+ * Add a file to the ZIP (sync)
254
+ * @param entry - File entry
255
+ * @returns Local file header and compressed data chunks
256
+ */
257
+ addFileSync(entry) {
258
+ if (this.finalized) {
259
+ throw new Error("Cannot add files after finalizing");
260
+ }
261
+ // Compress data
262
+ const compressedData = shouldDeflate(this.level, entry.data)
263
+ ? compressSync(entry.data, this.compressOptions)
264
+ : entry.data;
265
+ const result = appendProcessedEntry(this.entries, entry, compressedData, this.currentOffset, this.settings);
266
+ this.currentOffset = result.nextOffset;
267
+ return [buildLocalFileHeaderChunk(result.processedEntry), compressedData];
268
+ }
269
+ /**
270
+ * Finalize the ZIP and return central directory + end record
271
+ * @returns Central directory and end of central directory chunks
272
+ */
273
+ finalize() {
274
+ if (this.finalized) {
275
+ throw new Error("ZIP already finalized");
276
+ }
277
+ this.finalized = true;
278
+ return buildCentralDirectorySection(this.entries, this.currentOffset, this.zipComment);
279
+ }
280
+ /**
281
+ * Get current number of entries
282
+ */
283
+ get entryCount() {
284
+ return this.entries.length;
285
+ }
286
+ /**
287
+ * Get current ZIP data size (without central directory)
288
+ */
289
+ get dataSize() {
290
+ return this.currentOffset;
291
+ }
292
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * ZIP format constants (PKWARE APPNOTE)
3
+ * Shared by ZIP writer and parser implementations.
4
+ */
5
+ // Signatures
6
+ export const LOCAL_FILE_HEADER_SIG = 0x04034b50;
7
+ export const CENTRAL_DIR_HEADER_SIG = 0x02014b50;
8
+ export const END_OF_CENTRAL_DIR_SIG = 0x06054b50;
9
+ export const DATA_DESCRIPTOR_SIG = 0x08074b50;
10
+ export const ZIP64_END_OF_CENTRAL_DIR_SIG = 0x06064b50;
11
+ export const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50;
12
+ // Versions
13
+ export const VERSION_NEEDED = 20; // 2.0 - supports DEFLATE
14
+ export const VERSION_MADE_BY = 20; // 2.0
15
+ // Compression methods
16
+ export const COMPRESSION_STORE = 0;
17
+ export const COMPRESSION_DEFLATE = 8;
18
+ // General purpose bit flags
19
+ export const FLAG_UTF8 = 0x0800;
20
+ export const FLAG_DATA_DESCRIPTOR = 0x0008;
21
+ // ZIP64 / sentinel sizes
22
+ export const UINT16_MAX = 0xffff;
23
+ export const UINT32_MAX = 0xffffffff;
@@ -1,6 +1,6 @@
1
- import { encodeUtf8 } from "../utils/text.js";
2
- import { buildZipTimestampExtraField, dateToZipDos } from "../utils/timestamps.js";
3
- import { COMPRESSION_DEFLATE, COMPRESSION_STORE, FLAG_DATA_DESCRIPTOR, FLAG_UTF8 } from "../zip-spec/zip-records.js";
1
+ import { encodeUtf8 } from "./utils/text.js";
2
+ import { buildZipTimestampExtraField, dateToZipDos } from "./utils/timestamps.js";
3
+ import { COMPRESSION_DEFLATE, COMPRESSION_STORE, FLAG_DATA_DESCRIPTOR, FLAG_UTF8 } from "./zip-constants.js";
4
4
  export function resolveZipCompressionMethod(deflate) {
5
5
  return deflate ? COMPRESSION_DEFLATE : COMPRESSION_STORE;
6
6
  }
@@ -3,11 +3,11 @@
3
3
  * Works in both Node.js and browser environments
4
4
  * No dependency on Node.js stream module
5
5
  */
6
- import { decompress, decompressSync } from "../compression/compress.browser.js";
7
- import { BinaryReader } from "../utils/binary.js";
8
- import { resolveZipLastModifiedDateFromUnixSeconds } from "../utils/timestamps.js";
9
- import { parseZipExtraFields } from "../utils/zip-extra-fields.js";
10
- import { CENTRAL_DIR_HEADER_SIG, COMPRESSION_DEFLATE, COMPRESSION_STORE, LOCAL_FILE_HEADER_SIG, UINT16_MAX, UINT32_MAX, ZIP64_END_OF_CENTRAL_DIR_SIG } from "../zip-spec/zip-records.js";
6
+ import { decompress, decompressSync } from "./compress.js";
7
+ import { BinaryReader } from "./utils/binary.js";
8
+ import { resolveZipLastModifiedDateFromUnixSeconds } from "./utils/timestamps.js";
9
+ import { parseZipExtraFields } from "./utils/zip-extra-fields.js";
10
+ import { CENTRAL_DIR_HEADER_SIG, COMPRESSION_DEFLATE, COMPRESSION_STORE, END_OF_CENTRAL_DIR_SIG, LOCAL_FILE_HEADER_SIG, UINT16_MAX, UINT32_MAX, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG, ZIP64_END_OF_CENTRAL_DIR_SIG } from "./zip-constants.js";
11
11
  /**
12
12
  * Find the End of Central Directory record
13
13
  * Searches backwards from the end of the file
@@ -16,13 +16,9 @@ function findEndOfCentralDir(data) {
16
16
  // EOCD is at least 22 bytes, search backwards
17
17
  // Comment can be up to 65535 bytes
18
18
  const minOffset = Math.max(0, data.length - 65557);
19
- // Signature bytes (little-endian): 0x06054b50 -> 50 4b 05 06
20
- const b0 = 0x50;
21
- const b1 = 0x4b;
22
- const b2 = 0x05;
23
- const b3 = 0x06;
19
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
24
20
  for (let i = data.length - 22; i >= minOffset; i--) {
25
- if (data[i] === b0 && data[i + 1] === b1 && data[i + 2] === b2 && data[i + 3] === b3) {
21
+ if (view.getUint32(i, true) === END_OF_CENTRAL_DIR_SIG) {
26
22
  return i;
27
23
  }
28
24
  }
@@ -37,11 +33,8 @@ function findZip64EOCDLocator(data, eocdOffset) {
37
33
  if (locatorOffset < 0) {
38
34
  return -1;
39
35
  }
40
- // Signature bytes (little-endian): 0x07064b50 -> 50 4b 06 07
41
- if (data[locatorOffset] === 0x50 &&
42
- data[locatorOffset + 1] === 0x4b &&
43
- data[locatorOffset + 2] === 0x06 &&
44
- data[locatorOffset + 3] === 0x07) {
36
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
37
+ if (view.getUint32(locatorOffset, true) === ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
45
38
  return locatorOffset;
46
39
  }
47
40
  return -1;
@@ -51,7 +44,7 @@ function findZip64EOCDLocator(data, eocdOffset) {
51
44
  */
52
45
  function parseZipEntries(data, options = {}) {
53
46
  const { decodeStrings = true } = options;
54
- let entries = [];
47
+ const entries = [];
55
48
  // Find End of Central Directory
56
49
  const eocdOffset = findEndOfCentralDir(data);
57
50
  if (eocdOffset === -1) {
@@ -103,10 +96,6 @@ function parseZipEntries(data, options = {}) {
103
96
  }
104
97
  }
105
98
  }
106
- // Preallocate to avoid repeated array growth on large archives.
107
- if (totalEntries > 0) {
108
- entries = new Array(totalEntries);
109
- }
110
99
  // Read Central Directory entries
111
100
  const centralReader = new BinaryReader(data, centralDirOffset);
112
101
  for (let i = 0; i < totalEntries; i++) {
@@ -155,26 +144,23 @@ function parseZipEntries(data, options = {}) {
155
144
  // Check for UTF-8 flag (bit 11)
156
145
  const isUtf8 = (flags & 0x800) !== 0;
157
146
  const useUtf8 = decodeStrings && isUtf8;
158
- const fileName = fileNameLength > 0 ? centralReader.readString(fileNameLength, useUtf8) : "";
159
- let extraFields = {};
160
- if (extraFieldLength > 0) {
161
- const extraField = centralReader.readBytes(extraFieldLength);
162
- const vars = {
163
- compressedSize,
164
- uncompressedSize,
165
- offsetToLocalFileHeader: localHeaderOffset
166
- };
167
- extraFields = parseZipExtraFields(extraField, vars);
168
- compressedSize = vars.compressedSize;
169
- uncompressedSize = vars.uncompressedSize;
170
- localHeaderOffset = vars.offsetToLocalFileHeader ?? localHeaderOffset;
171
- }
172
- const comment = commentLength > 0 ? centralReader.readString(commentLength, useUtf8) : "";
147
+ const fileName = centralReader.readString(fileNameLength, useUtf8);
148
+ const extraField = centralReader.readBytes(extraFieldLength);
149
+ const comment = centralReader.readString(commentLength, useUtf8);
150
+ const vars = {
151
+ compressedSize,
152
+ uncompressedSize,
153
+ offsetToLocalFileHeader: localHeaderOffset
154
+ };
155
+ const extraFields = extraFieldLength > 0 ? parseZipExtraFields(extraField, vars) : {};
156
+ compressedSize = vars.compressedSize;
157
+ uncompressedSize = vars.uncompressedSize;
158
+ localHeaderOffset = vars.offsetToLocalFileHeader ?? localHeaderOffset;
173
159
  const isDirectory = fileName.endsWith("/") || (externalAttributes & 0x10) !== 0;
174
160
  const isEncrypted = (flags & 0x01) !== 0;
175
161
  const unixSecondsMtime = extraFields.mtimeUnixSeconds;
176
162
  const lastModified = resolveZipLastModifiedDateFromUnixSeconds(lastModDate, lastModTime, unixSecondsMtime);
177
- entries[i] = {
163
+ entries.push({
178
164
  path: fileName,
179
165
  isDirectory,
180
166
  compressedSize,
@@ -186,7 +172,7 @@ function parseZipEntries(data, options = {}) {
186
172
  comment,
187
173
  externalAttributes,
188
174
  isEncrypted
189
- };
175
+ });
190
176
  }
191
177
  return entries;
192
178
  }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * ZIP record builders (PKWARE APPNOTE)
3
+ *
4
+ * Shared by streaming zip writer and buffer zip builder.
5
+ */
6
+ import { CENTRAL_DIR_HEADER_SIG, DATA_DESCRIPTOR_SIG, END_OF_CENTRAL_DIR_SIG, LOCAL_FILE_HEADER_SIG, VERSION_MADE_BY, VERSION_NEEDED } from "./zip-constants.js";
7
+ export function buildLocalFileHeader(input) {
8
+ const versionNeeded = input.versionNeeded ?? VERSION_NEEDED;
9
+ const header = new Uint8Array(30 + input.fileName.length + input.extraField.length);
10
+ const view = new DataView(header.buffer);
11
+ view.setUint32(0, LOCAL_FILE_HEADER_SIG, true);
12
+ view.setUint16(4, versionNeeded, true);
13
+ view.setUint16(6, input.flags, true);
14
+ view.setUint16(8, input.compressionMethod, true);
15
+ view.setUint16(10, input.dosTime, true);
16
+ view.setUint16(12, input.dosDate, true);
17
+ view.setUint32(14, input.crc32, true);
18
+ view.setUint32(18, input.compressedSize, true);
19
+ view.setUint32(22, input.uncompressedSize, true);
20
+ view.setUint16(26, input.fileName.length, true);
21
+ view.setUint16(28, input.extraField.length, true);
22
+ header.set(input.fileName, 30);
23
+ if (input.extraField.length > 0) {
24
+ header.set(input.extraField, 30 + input.fileName.length);
25
+ }
26
+ return header;
27
+ }
28
+ export function buildCentralDirectoryHeader(input) {
29
+ const versionMadeBy = input.versionMadeBy ?? VERSION_MADE_BY;
30
+ const versionNeeded = input.versionNeeded ?? VERSION_NEEDED;
31
+ const externalAttributes = input.externalAttributes ?? 0;
32
+ const header = new Uint8Array(46 + input.fileName.length + input.extraField.length + input.comment.length);
33
+ const view = new DataView(header.buffer);
34
+ view.setUint32(0, CENTRAL_DIR_HEADER_SIG, true);
35
+ view.setUint16(4, versionMadeBy, true);
36
+ view.setUint16(6, versionNeeded, true);
37
+ view.setUint16(8, input.flags, true);
38
+ view.setUint16(10, input.compressionMethod, true);
39
+ view.setUint16(12, input.dosTime, true);
40
+ view.setUint16(14, input.dosDate, true);
41
+ view.setUint32(16, input.crc32, true);
42
+ view.setUint32(20, input.compressedSize, true);
43
+ view.setUint32(24, input.uncompressedSize, true);
44
+ view.setUint16(28, input.fileName.length, true);
45
+ view.setUint16(30, input.extraField.length, true);
46
+ view.setUint16(32, input.comment.length, true);
47
+ view.setUint16(34, 0, true); // disk number start
48
+ view.setUint16(36, 0, true); // internal file attributes
49
+ view.setUint32(38, externalAttributes, true);
50
+ view.setUint32(42, input.localHeaderOffset, true);
51
+ header.set(input.fileName, 46);
52
+ if (input.extraField.length > 0) {
53
+ header.set(input.extraField, 46 + input.fileName.length);
54
+ }
55
+ if (input.comment.length > 0) {
56
+ header.set(input.comment, 46 + input.fileName.length + input.extraField.length);
57
+ }
58
+ return header;
59
+ }
60
+ export function buildEndOfCentralDirectory(input) {
61
+ const record = new Uint8Array(22 + input.comment.length);
62
+ const view = new DataView(record.buffer);
63
+ view.setUint32(0, END_OF_CENTRAL_DIR_SIG, true);
64
+ view.setUint16(4, 0, true);
65
+ view.setUint16(6, 0, true);
66
+ view.setUint16(8, input.entryCount, true);
67
+ view.setUint16(10, input.entryCount, true);
68
+ view.setUint32(12, input.centralDirSize, true);
69
+ view.setUint32(16, input.centralDirOffset, true);
70
+ view.setUint16(20, input.comment.length, true);
71
+ if (input.comment.length > 0) {
72
+ record.set(input.comment, 22);
73
+ }
74
+ return record;
75
+ }
76
+ export function buildDataDescriptor(crc32, compressedSize, uncompressedSize) {
77
+ const descriptor = new Uint8Array(16);
78
+ const view = new DataView(descriptor.buffer);
79
+ view.setUint32(0, DATA_DESCRIPTOR_SIG, true);
80
+ view.setUint32(4, crc32, true);
81
+ view.setUint32(8, compressedSize, true);
82
+ view.setUint32(12, uncompressedSize, true);
83
+ return descriptor;
84
+ }
@@ -9,7 +9,7 @@
9
9
  * with filesystem-specific features (filename input + temp-file buffering).
10
10
  */
11
11
  import { EventEmitter, Readable } from "../../stream/index.js";
12
- import { createParse } from "../../archive/unzip/stream.js";
12
+ import { createParse } from "../../archive/parse.js";
13
13
  import { iterateStream } from "../utils/iterate-stream.js";
14
14
  import { getWorksheetNoFromWorksheetPath, getWorksheetNoFromWorksheetRelsPath, normalizeZipPath, OOXML_PATHS, worksheetRelTarget } from "../utils/ooxml-paths.js";
15
15
  import { parseSax } from "../utils/parse-sax.js";
@@ -7,7 +7,7 @@
7
7
  * Node.js uses `workbook-writer.ts`, which extends the same base implementation
8
8
  * with filesystem-specific features (filename output + image loading).
9
9
  */
10
- import { Zip, ZipDeflate } from "../../archive/zip/stream.js";
10
+ import { Zip, ZipDeflate } from "../../archive/streaming-zip.js";
11
11
  import { StreamBuf } from "../utils/stream-buf.js";
12
12
  import { base64ToUint8Array } from "../../../utils/utils.js";
13
13
  import { RelType } from "../xlsx/rel-type.js";
@@ -30,8 +30,8 @@ import { theme1Xml } from "./xml/theme1.js";
30
30
  import { RelType } from "./rel-type.js";
31
31
  import { StreamBuf } from "../utils/stream-buf.js";
32
32
  import { bufferToString, base64ToUint8Array } from "../../../utils/utils.js";
33
- import { StreamingZip, ZipDeflateFile } from "../../archive/zip/stream.js";
34
- import { ZipParser } from "../../archive/unzip/zip-parser.js";
33
+ import { StreamingZip, ZipDeflateFile } from "../../archive/streaming-zip.js";
34
+ import { ZipParser } from "../../archive/index.js";
35
35
  import { PassThrough, concatUint8Arrays } from "../../stream/index.js";
36
36
  import { commentsPath, commentsRelTargetFromWorksheetName, ctrlPropPath, drawingPath, drawingRelsPath, OOXML_REL_TARGETS, pivotTableRelTargetFromWorksheetName, pivotCacheDefinitionRelTargetFromWorkbook, getCommentsIndexFromPath, getDrawingNameFromPath, getDrawingNameFromRelsPath, getMediaFilenameFromPath, mediaPath, getPivotCacheDefinitionNameFromPath, getPivotCacheDefinitionNameFromRelsPath, getPivotCacheRecordsNameFromPath, getPivotTableNameFromPath, getPivotTableNameFromRelsPath, pivotCacheDefinitionPath, pivotCacheDefinitionRelsPath, pivotCacheDefinitionRelTargetFromPivotTable, pivotCacheRecordsPath, pivotCacheRecordsRelTarget, pivotTablePath, pivotTableRelsPath, getTableNameFromPath, tablePath, tableRelTargetFromWorksheetName, themePath, getThemeNameFromPath, getVmlDrawingNameFromPath, getWorksheetNoFromWorksheetPath, getWorksheetNoFromWorksheetRelsPath, isBinaryEntryPath, normalizeZipPath, OOXML_PATHS, vmlDrawingRelTargetFromWorksheetName, vmlDrawingPath, worksheetPath, worksheetRelsPath } from "../utils/ooxml-paths.js";
37
37
  class StreamingZipWriterAdapter {
@@ -126,7 +126,10 @@ class StreamingZipWriterAdapter {
126
126
  timestamps: this.timestamps
127
127
  });
128
128
  this.zip.add(file);
129
- file.push(buffer, true);
129
+ const pushResult = file.push(buffer, true);
130
+ if (pushResult && typeof pushResult.catch === "function") {
131
+ pushResult.catch((err) => this._emit("error", err));
132
+ }
130
133
  }
131
134
  finalize() {
132
135
  if (this.finalized) {
@@ -16,7 +16,7 @@
16
16
  import fs from "fs";
17
17
  import { fileExists } from "../../../utils/utils.js";
18
18
  import { XLSX as XLSXBase } from "./xlsx.browser.js";
19
- import { Parse } from "../../archive/unzip/stream.js";
19
+ import { Parse } from "../../archive/index.js";
20
20
  import { Writable, pipeline } from "../../stream/index.js";
21
21
  class XLSX extends XLSXBase {
22
22
  constructor(workbook) {