@cj-tech-master/excelts 4.2.0 → 4.2.1-canary.20260112134913.a3cecdd

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 (317) hide show
  1. package/THIRD_PARTY_NOTICES.md +0 -31
  2. package/dist/browser/index.browser.d.ts +1 -0
  3. package/dist/browser/index.browser.js +12 -0
  4. package/dist/{types/modules/archive → browser/modules/archive/compression}/compress.base.d.ts +1 -0
  5. package/dist/browser/modules/archive/{compress.base.js → compression/compress.base.js} +2 -1
  6. package/dist/{types/modules/archive → browser/modules/archive/compression}/compress.browser.d.ts +10 -8
  7. package/dist/{esm/modules/archive → browser/modules/archive/compression}/compress.browser.js +18 -19
  8. package/dist/browser/modules/archive/{compress.d.ts → compression/compress.d.ts} +2 -2
  9. package/dist/browser/modules/archive/{compress.js → compression/compress.js} +1 -1
  10. package/dist/browser/modules/archive/{crc32.browser.d.ts → compression/crc32.browser.d.ts} +1 -1
  11. package/dist/browser/modules/archive/{crc32.d.ts → compression/crc32.d.ts} +1 -1
  12. package/dist/browser/modules/archive/{crc32.js → compression/crc32.js} +1 -1
  13. package/dist/browser/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
  14. package/dist/browser/modules/archive/{streaming-compress.browser.d.ts → compression/streaming-compress.browser.d.ts} +2 -2
  15. package/dist/browser/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
  16. package/dist/browser/modules/archive/{streaming-compress.d.ts → compression/streaming-compress.d.ts} +2 -2
  17. package/dist/browser/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
  18. package/dist/browser/modules/archive/defaults.d.ts +1 -0
  19. package/dist/browser/modules/archive/defaults.js +6 -3
  20. package/dist/browser/modules/archive/index.base.d.ts +4 -4
  21. package/dist/browser/modules/archive/index.base.js +3 -6
  22. package/dist/browser/modules/archive/index.browser.d.ts +3 -4
  23. package/dist/browser/modules/archive/index.browser.js +3 -7
  24. package/dist/browser/modules/archive/index.d.ts +3 -4
  25. package/dist/browser/modules/archive/index.js +3 -5
  26. package/dist/browser/modules/archive/internal/byte-queue.d.ts +33 -0
  27. package/dist/browser/modules/archive/internal/byte-queue.js +407 -0
  28. package/dist/browser/modules/archive/io/archive-sink.d.ts +8 -0
  29. package/dist/browser/modules/archive/io/archive-sink.js +45 -0
  30. package/dist/browser/modules/archive/io/archive-source.d.ts +6 -0
  31. package/dist/browser/modules/archive/io/archive-source.js +100 -0
  32. package/dist/browser/modules/archive/{extract.d.ts → unzip/extract.d.ts} +2 -2
  33. package/dist/browser/modules/archive/unzip/index.d.ts +40 -0
  34. package/dist/browser/modules/archive/unzip/index.js +164 -0
  35. package/dist/browser/modules/archive/{parse.base.d.ts → unzip/stream.base.d.ts} +58 -3
  36. package/dist/browser/modules/archive/unzip/stream.base.js +1022 -0
  37. package/dist/browser/modules/archive/{parse.browser.d.ts → unzip/stream.browser.d.ts} +1 -1
  38. package/dist/browser/modules/archive/{parse.browser.js → unzip/stream.browser.js} +376 -110
  39. package/dist/browser/modules/archive/{parse.d.ts → unzip/stream.d.ts} +2 -2
  40. package/dist/{esm/modules/archive/parse.js → browser/modules/archive/unzip/stream.js} +7 -6
  41. package/dist/{types/modules/archive → browser/modules/archive/unzip}/zip-parser.d.ts +1 -1
  42. package/dist/{esm/modules/archive → browser/modules/archive/unzip}/zip-parser.js +38 -24
  43. package/dist/browser/modules/archive/utils/async-queue.d.ts +7 -0
  44. package/dist/browser/modules/archive/utils/async-queue.js +103 -0
  45. package/dist/browser/modules/archive/utils/bytes.js +16 -16
  46. package/dist/browser/modules/archive/utils/compressibility.d.ts +10 -0
  47. package/dist/browser/modules/archive/utils/compressibility.js +57 -0
  48. package/dist/browser/modules/archive/utils/parse-buffer.js +21 -23
  49. package/dist/browser/modules/archive/utils/pattern-scanner.d.ts +21 -0
  50. package/dist/browser/modules/archive/utils/pattern-scanner.js +27 -0
  51. package/dist/browser/modules/archive/utils/timestamps.js +62 -1
  52. package/dist/browser/modules/archive/utils/zip-extra-fields.d.ts +1 -1
  53. package/dist/browser/modules/archive/utils/zip-extra-fields.js +26 -14
  54. package/dist/browser/modules/archive/zip/index.d.ts +42 -0
  55. package/dist/browser/modules/archive/zip/index.js +157 -0
  56. package/dist/browser/modules/archive/{streaming-zip.d.ts → zip/stream.d.ts} +28 -5
  57. package/dist/browser/modules/archive/{streaming-zip.js → zip/stream.js} +192 -48
  58. package/dist/browser/modules/archive/zip/zip-bytes.d.ts +73 -0
  59. package/dist/browser/modules/archive/zip/zip-bytes.js +239 -0
  60. package/dist/{esm/modules/archive → browser/modules/archive/zip}/zip-entry-metadata.js +3 -3
  61. package/dist/browser/modules/archive/{zip-records.d.ts → zip-spec/zip-records.d.ts} +20 -0
  62. package/dist/browser/modules/archive/zip-spec/zip-records.js +126 -0
  63. package/dist/browser/modules/excel/form-control.d.ts +2 -0
  64. package/dist/browser/modules/excel/form-control.js +54 -16
  65. package/dist/browser/modules/excel/stream/workbook-reader.browser.js +1 -1
  66. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +1 -1
  67. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +1 -1
  68. package/dist/browser/modules/excel/utils/ooxml-validator.d.ts +48 -0
  69. package/dist/browser/modules/excel/utils/ooxml-validator.js +469 -0
  70. package/dist/browser/modules/excel/worksheet.js +5 -2
  71. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
  72. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  73. package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
  74. package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
  75. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
  76. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  77. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  78. package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
  79. package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  80. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +117 -5
  81. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +3 -6
  82. package/dist/browser/modules/excel/xlsx/xlsx.js +1 -1
  83. package/dist/browser/modules/stream/base-transform.d.ts +3 -0
  84. package/dist/browser/modules/stream/base-transform.js +34 -20
  85. package/dist/browser/modules/stream/buffered-stream.d.ts +2 -12
  86. package/dist/browser/modules/stream/chunked-builder.js +4 -4
  87. package/dist/browser/modules/stream/index.browser.d.ts +13 -19
  88. package/dist/browser/modules/stream/index.browser.js +10 -22
  89. package/dist/browser/modules/stream/index.d.ts +18 -41
  90. package/dist/browser/modules/stream/index.js +15 -44
  91. package/dist/browser/modules/stream/internal/event-utils.d.ts +17 -0
  92. package/dist/browser/modules/stream/internal/event-utils.js +40 -0
  93. package/dist/browser/modules/stream/internal/type-guards.d.ts +9 -0
  94. package/dist/browser/modules/stream/internal/type-guards.js +24 -0
  95. package/dist/browser/modules/stream/pull-stream.d.ts +5 -6
  96. package/dist/browser/modules/stream/pull-stream.js +107 -43
  97. package/dist/browser/modules/stream/shared.d.ts +1 -1
  98. package/dist/browser/modules/stream/shared.js +7 -4
  99. package/dist/browser/modules/stream/streams.browser.d.ts +32 -42
  100. package/dist/browser/modules/stream/streams.browser.js +941 -823
  101. package/dist/browser/modules/stream/streams.d.ts +4 -20
  102. package/dist/browser/modules/stream/streams.js +146 -95
  103. package/dist/browser/modules/stream/utils.js +5 -38
  104. package/dist/cjs/modules/archive/{compress.base.js → compression/compress.base.js} +2 -1
  105. package/dist/cjs/modules/archive/{compress.browser.js → compression/compress.browser.js} +18 -19
  106. package/dist/cjs/modules/archive/{compress.js → compression/compress.js} +1 -1
  107. package/dist/cjs/modules/archive/{crc32.js → compression/crc32.js} +1 -1
  108. package/dist/cjs/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
  109. package/dist/cjs/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
  110. package/dist/cjs/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
  111. package/dist/cjs/modules/archive/defaults.js +7 -4
  112. package/dist/cjs/modules/archive/index.base.js +9 -19
  113. package/dist/cjs/modules/archive/index.browser.js +4 -10
  114. package/dist/cjs/modules/archive/index.js +4 -8
  115. package/dist/cjs/modules/archive/internal/byte-queue.js +411 -0
  116. package/dist/cjs/modules/archive/io/archive-sink.js +49 -0
  117. package/dist/cjs/modules/archive/io/archive-source.js +105 -0
  118. package/dist/cjs/modules/archive/unzip/index.js +170 -0
  119. package/dist/cjs/modules/archive/unzip/stream.base.js +1044 -0
  120. package/dist/cjs/modules/archive/{parse.browser.js → unzip/stream.browser.js} +377 -111
  121. package/dist/cjs/modules/archive/{parse.js → unzip/stream.js} +9 -8
  122. package/dist/cjs/modules/archive/{zip-parser.js → unzip/zip-parser.js} +47 -33
  123. package/dist/cjs/modules/archive/utils/async-queue.js +106 -0
  124. package/dist/cjs/modules/archive/utils/bytes.js +16 -16
  125. package/dist/cjs/modules/archive/utils/compressibility.js +60 -0
  126. package/dist/cjs/modules/archive/utils/parse-buffer.js +21 -23
  127. package/dist/cjs/modules/archive/utils/pattern-scanner.js +31 -0
  128. package/dist/cjs/modules/archive/utils/timestamps.js +64 -3
  129. package/dist/cjs/modules/archive/utils/zip-extra-fields.js +26 -14
  130. package/dist/cjs/modules/archive/zip/index.js +162 -0
  131. package/dist/cjs/modules/archive/{streaming-zip.js → zip/stream.js} +194 -50
  132. package/dist/cjs/modules/archive/zip/zip-bytes.js +242 -0
  133. package/dist/cjs/modules/archive/{zip-entry-metadata.js → zip/zip-entry-metadata.js} +5 -5
  134. package/dist/cjs/modules/archive/zip-spec/zip-records.js +136 -0
  135. package/dist/cjs/modules/excel/form-control.js +54 -16
  136. package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +2 -2
  137. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +4 -4
  138. package/dist/cjs/modules/excel/utils/ooxml-validator.js +475 -0
  139. package/dist/cjs/modules/excel/worksheet.js +5 -2
  140. package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  141. package/dist/cjs/modules/excel/xlsx/xform/drawing/sp-xform.js +115 -0
  142. package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  143. package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  144. package/dist/cjs/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  145. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +117 -5
  146. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +6 -9
  147. package/dist/cjs/modules/excel/xlsx/xlsx.js +2 -2
  148. package/dist/cjs/modules/stream/base-transform.js +34 -20
  149. package/dist/cjs/modules/stream/chunked-builder.js +4 -4
  150. package/dist/cjs/modules/stream/index.browser.js +10 -17
  151. package/dist/cjs/modules/stream/index.js +15 -39
  152. package/dist/cjs/modules/stream/internal/event-utils.js +43 -0
  153. package/dist/cjs/modules/stream/internal/type-guards.js +30 -0
  154. package/dist/cjs/modules/stream/pull-stream.js +107 -43
  155. package/dist/cjs/modules/stream/shared.js +7 -4
  156. package/dist/cjs/modules/stream/streams.browser.js +947 -834
  157. package/dist/cjs/modules/stream/streams.js +156 -107
  158. package/dist/cjs/modules/stream/utils.js +3 -36
  159. package/dist/esm/index.browser.js +12 -0
  160. package/dist/esm/modules/archive/{compress.base.js → compression/compress.base.js} +2 -1
  161. package/dist/{browser/modules/archive → esm/modules/archive/compression}/compress.browser.js +18 -19
  162. package/dist/esm/modules/archive/{compress.js → compression/compress.js} +1 -1
  163. package/dist/esm/modules/archive/{crc32.js → compression/crc32.js} +1 -1
  164. package/dist/esm/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
  165. package/dist/esm/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
  166. package/dist/esm/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
  167. package/dist/esm/modules/archive/defaults.js +6 -3
  168. package/dist/esm/modules/archive/index.base.js +3 -6
  169. package/dist/esm/modules/archive/index.browser.js +3 -7
  170. package/dist/esm/modules/archive/index.js +3 -5
  171. package/dist/esm/modules/archive/internal/byte-queue.js +407 -0
  172. package/dist/esm/modules/archive/io/archive-sink.js +45 -0
  173. package/dist/esm/modules/archive/io/archive-source.js +100 -0
  174. package/dist/esm/modules/archive/unzip/index.js +164 -0
  175. package/dist/esm/modules/archive/unzip/stream.base.js +1022 -0
  176. package/dist/esm/modules/archive/{parse.browser.js → unzip/stream.browser.js} +376 -110
  177. package/dist/{browser/modules/archive/parse.js → esm/modules/archive/unzip/stream.js} +7 -6
  178. package/dist/{browser/modules/archive → esm/modules/archive/unzip}/zip-parser.js +38 -24
  179. package/dist/esm/modules/archive/utils/async-queue.js +103 -0
  180. package/dist/esm/modules/archive/utils/bytes.js +16 -16
  181. package/dist/esm/modules/archive/utils/compressibility.js +57 -0
  182. package/dist/esm/modules/archive/utils/parse-buffer.js +21 -23
  183. package/dist/esm/modules/archive/utils/pattern-scanner.js +27 -0
  184. package/dist/esm/modules/archive/utils/timestamps.js +62 -1
  185. package/dist/esm/modules/archive/utils/zip-extra-fields.js +26 -14
  186. package/dist/esm/modules/archive/zip/index.js +157 -0
  187. package/dist/esm/modules/archive/{streaming-zip.js → zip/stream.js} +192 -48
  188. package/dist/esm/modules/archive/zip/zip-bytes.js +239 -0
  189. package/dist/{browser/modules/archive → esm/modules/archive/zip}/zip-entry-metadata.js +3 -3
  190. package/dist/esm/modules/archive/zip-spec/zip-records.js +126 -0
  191. package/dist/esm/modules/excel/form-control.js +54 -16
  192. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +1 -1
  193. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +1 -1
  194. package/dist/esm/modules/excel/utils/ooxml-validator.js +469 -0
  195. package/dist/esm/modules/excel/worksheet.js +5 -2
  196. package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  197. package/dist/esm/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
  198. package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  199. package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  200. package/dist/esm/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  201. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +117 -5
  202. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +3 -6
  203. package/dist/esm/modules/excel/xlsx/xlsx.js +1 -1
  204. package/dist/esm/modules/stream/base-transform.js +34 -20
  205. package/dist/esm/modules/stream/chunked-builder.js +4 -4
  206. package/dist/esm/modules/stream/index.browser.js +10 -22
  207. package/dist/esm/modules/stream/index.js +15 -44
  208. package/dist/esm/modules/stream/internal/event-utils.js +40 -0
  209. package/dist/esm/modules/stream/internal/type-guards.js +24 -0
  210. package/dist/esm/modules/stream/pull-stream.js +107 -43
  211. package/dist/esm/modules/stream/shared.js +7 -4
  212. package/dist/esm/modules/stream/streams.browser.js +941 -823
  213. package/dist/esm/modules/stream/streams.js +146 -95
  214. package/dist/esm/modules/stream/utils.js +5 -38
  215. package/dist/iife/THIRD_PARTY_NOTICES.md +81 -0
  216. package/dist/iife/excelts.iife.js +4979 -2800
  217. package/dist/iife/excelts.iife.js.map +1 -1
  218. package/dist/iife/excelts.iife.min.js +103 -31
  219. package/dist/types/index.browser.d.ts +1 -0
  220. package/dist/{browser/modules/archive → types/modules/archive/compression}/compress.base.d.ts +1 -0
  221. package/dist/{browser/modules/archive → types/modules/archive/compression}/compress.browser.d.ts +10 -8
  222. package/dist/types/modules/archive/{streaming-compress.browser.d.ts → compression/streaming-compress.browser.d.ts} +1 -1
  223. package/dist/types/modules/archive/defaults.d.ts +1 -0
  224. package/dist/types/modules/archive/index.base.d.ts +4 -4
  225. package/dist/types/modules/archive/index.browser.d.ts +3 -4
  226. package/dist/types/modules/archive/index.d.ts +3 -4
  227. package/dist/types/modules/archive/internal/byte-queue.d.ts +33 -0
  228. package/dist/types/modules/archive/io/archive-sink.d.ts +8 -0
  229. package/dist/types/modules/archive/io/archive-source.d.ts +6 -0
  230. package/dist/types/modules/archive/unzip/index.d.ts +40 -0
  231. package/dist/types/modules/archive/{parse.base.d.ts → unzip/stream.base.d.ts} +60 -5
  232. package/dist/types/modules/archive/{parse.browser.d.ts → unzip/stream.browser.d.ts} +2 -2
  233. package/dist/types/modules/archive/{parse.d.ts → unzip/stream.d.ts} +3 -3
  234. package/dist/{browser/modules/archive → types/modules/archive/unzip}/zip-parser.d.ts +1 -1
  235. package/dist/types/modules/archive/utils/async-queue.d.ts +7 -0
  236. package/dist/types/modules/archive/utils/compressibility.d.ts +10 -0
  237. package/dist/types/modules/archive/utils/pattern-scanner.d.ts +21 -0
  238. package/dist/types/modules/archive/utils/zip-extra-fields.d.ts +1 -1
  239. package/dist/types/modules/archive/zip/index.d.ts +42 -0
  240. package/dist/types/modules/archive/{streaming-zip.d.ts → zip/stream.d.ts} +29 -6
  241. package/dist/types/modules/archive/zip/zip-bytes.d.ts +73 -0
  242. package/dist/types/modules/archive/{zip-entry-metadata.d.ts → zip/zip-entry-metadata.d.ts} +1 -1
  243. package/dist/types/modules/archive/{zip-records.d.ts → zip-spec/zip-records.d.ts} +20 -0
  244. package/dist/types/modules/excel/form-control.d.ts +2 -0
  245. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +1 -1
  246. package/dist/types/modules/excel/utils/ooxml-validator.d.ts +48 -0
  247. package/dist/types/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
  248. package/dist/types/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
  249. package/dist/types/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
  250. package/dist/types/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
  251. package/dist/types/modules/stream/base-transform.d.ts +3 -0
  252. package/dist/types/modules/stream/buffered-stream.d.ts +2 -12
  253. package/dist/types/modules/stream/index.browser.d.ts +13 -19
  254. package/dist/types/modules/stream/index.d.ts +18 -41
  255. package/dist/types/modules/stream/internal/event-utils.d.ts +17 -0
  256. package/dist/types/modules/stream/internal/type-guards.d.ts +9 -0
  257. package/dist/types/modules/stream/pull-stream.d.ts +5 -6
  258. package/dist/types/modules/stream/shared.d.ts +1 -1
  259. package/dist/types/modules/stream/streams.browser.d.ts +32 -42
  260. package/dist/types/modules/stream/streams.d.ts +4 -20
  261. package/package.json +19 -15
  262. package/dist/browser/modules/archive/byte-queue.d.ts +0 -18
  263. package/dist/browser/modules/archive/byte-queue.js +0 -125
  264. package/dist/browser/modules/archive/parse.base.js +0 -610
  265. package/dist/browser/modules/archive/utils/zip-extra.d.ts +0 -18
  266. package/dist/browser/modules/archive/utils/zip-extra.js +0 -68
  267. package/dist/browser/modules/archive/zip-builder.d.ts +0 -117
  268. package/dist/browser/modules/archive/zip-builder.js +0 -292
  269. package/dist/browser/modules/archive/zip-constants.d.ts +0 -18
  270. package/dist/browser/modules/archive/zip-constants.js +0 -23
  271. package/dist/browser/modules/archive/zip-records.js +0 -84
  272. package/dist/cjs/modules/archive/byte-queue.js +0 -129
  273. package/dist/cjs/modules/archive/parse.base.js +0 -632
  274. package/dist/cjs/modules/archive/utils/zip-extra.js +0 -74
  275. package/dist/cjs/modules/archive/zip-builder.js +0 -297
  276. package/dist/cjs/modules/archive/zip-constants.js +0 -26
  277. package/dist/cjs/modules/archive/zip-records.js +0 -90
  278. package/dist/esm/modules/archive/byte-queue.js +0 -125
  279. package/dist/esm/modules/archive/parse.base.js +0 -610
  280. package/dist/esm/modules/archive/utils/zip-extra.js +0 -68
  281. package/dist/esm/modules/archive/zip-builder.js +0 -292
  282. package/dist/esm/modules/archive/zip-constants.js +0 -23
  283. package/dist/esm/modules/archive/zip-records.js +0 -84
  284. package/dist/types/modules/archive/byte-queue.d.ts +0 -18
  285. package/dist/types/modules/archive/utils/zip-extra.d.ts +0 -18
  286. package/dist/types/modules/archive/zip-builder.d.ts +0 -117
  287. package/dist/types/modules/archive/zip-constants.d.ts +0 -18
  288. /package/dist/browser/modules/archive/{crc32.base.d.ts → compression/crc32.base.d.ts} +0 -0
  289. /package/dist/browser/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
  290. /package/dist/browser/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
  291. /package/dist/browser/modules/archive/{deflate-fallback.d.ts → compression/deflate-fallback.d.ts} +0 -0
  292. /package/dist/browser/modules/archive/{streaming-compress.base.d.ts → compression/streaming-compress.base.d.ts} +0 -0
  293. /package/dist/browser/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
  294. /package/dist/browser/modules/archive/{extract.js → unzip/extract.js} +0 -0
  295. /package/dist/browser/modules/archive/{zip-entry-metadata.d.ts → zip/zip-entry-metadata.d.ts} +0 -0
  296. /package/dist/browser/modules/archive/{zip-entry-info.d.ts → zip-spec/zip-entry-info.d.ts} +0 -0
  297. /package/dist/browser/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
  298. /package/dist/cjs/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
  299. /package/dist/cjs/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
  300. /package/dist/cjs/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
  301. /package/dist/cjs/modules/archive/{extract.js → unzip/extract.js} +0 -0
  302. /package/dist/cjs/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
  303. /package/dist/esm/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
  304. /package/dist/esm/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
  305. /package/dist/esm/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
  306. /package/dist/esm/modules/archive/{extract.js → unzip/extract.js} +0 -0
  307. /package/dist/esm/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
  308. /package/dist/{LICENSE → iife/LICENSE} +0 -0
  309. /package/dist/types/modules/archive/{compress.d.ts → compression/compress.d.ts} +0 -0
  310. /package/dist/types/modules/archive/{crc32.base.d.ts → compression/crc32.base.d.ts} +0 -0
  311. /package/dist/types/modules/archive/{crc32.browser.d.ts → compression/crc32.browser.d.ts} +0 -0
  312. /package/dist/types/modules/archive/{crc32.d.ts → compression/crc32.d.ts} +0 -0
  313. /package/dist/types/modules/archive/{deflate-fallback.d.ts → compression/deflate-fallback.d.ts} +0 -0
  314. /package/dist/types/modules/archive/{streaming-compress.base.d.ts → compression/streaming-compress.base.d.ts} +0 -0
  315. /package/dist/types/modules/archive/{streaming-compress.d.ts → compression/streaming-compress.d.ts} +0 -0
  316. /package/dist/types/modules/archive/{extract.d.ts → unzip/extract.d.ts} +0 -0
  317. /package/dist/types/modules/archive/{zip-entry-info.d.ts → zip-spec/zip-entry-info.d.ts} +0 -0
@@ -12,7 +12,7 @@
12
12
  * - Edge >= 89
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.promises = exports.consumers = exports.streamToBuffer = exports.BufferedStream = exports.BufferChunk = exports.StringChunk = exports.PullStream = exports.Collector = exports.PassThrough = exports.Duplex = exports.Transform = exports.Writable = exports.Readable = void 0;
15
+ exports.promises = exports.consumers = exports.streamToBuffer = exports.BufferChunk = exports.StringChunk = exports.BufferedStream = exports.PullStream = exports.Collector = exports.PassThrough = exports.Duplex = exports.Transform = exports.Writable = exports.Readable = void 0;
16
16
  exports.normalizeWritable = normalizeWritable;
17
17
  exports.createReadable = createReadable;
18
18
  exports.createReadableFromAsyncIterable = createReadableFromAsyncIterable;
@@ -53,8 +53,47 @@ exports.isWritable = isWritable;
53
53
  exports.duplexPair = duplexPair;
54
54
  const event_emitter_1 = require("./event-emitter.js");
55
55
  const pull_stream_1 = require("./pull-stream.js");
56
+ Object.defineProperty(exports, "PullStream", { enumerable: true, get: function () { return pull_stream_1.PullStream; } });
56
57
  const buffered_stream_1 = require("./buffered-stream.js");
58
+ Object.defineProperty(exports, "BufferedStream", { enumerable: true, get: function () { return buffered_stream_1.BufferedStream; } });
59
+ Object.defineProperty(exports, "BufferChunk", { enumerable: true, get: function () { return buffered_stream_1.BufferChunk; } });
60
+ Object.defineProperty(exports, "StringChunk", { enumerable: true, get: function () { return buffered_stream_1.StringChunk; } });
57
61
  const shared_1 = require("./shared.js");
62
+ const type_guards_1 = require("./internal/type-guards.js");
63
+ const removeEmitterListener = (emitter, event, listener) => {
64
+ if (typeof emitter.off === "function") {
65
+ emitter.off(event, listener);
66
+ }
67
+ else if (typeof emitter.removeListener === "function") {
68
+ emitter.removeListener(event, listener);
69
+ }
70
+ };
71
+ const addEmitterListener = (emitter, event, listener, options) => {
72
+ if (options?.once && typeof emitter.once === "function") {
73
+ emitter.once(event, listener);
74
+ }
75
+ else {
76
+ emitter.on(event, listener);
77
+ }
78
+ return () => removeEmitterListener(emitter, event, listener);
79
+ };
80
+ const createListenerRegistry = () => {
81
+ const listeners = [];
82
+ return {
83
+ add: (emitter, event, listener) => {
84
+ listeners.push(addEmitterListener(emitter, event, listener));
85
+ },
86
+ once: (emitter, event, listener) => {
87
+ listeners.push(addEmitterListener(emitter, event, listener, { once: true }));
88
+ },
89
+ cleanup: () => {
90
+ for (let i = listeners.length - 1; i >= 0; i--) {
91
+ listeners[i]();
92
+ }
93
+ listeners.length = 0;
94
+ }
95
+ };
96
+ };
58
97
  // =============================================================================
59
98
  // Readable Stream Wrapper
60
99
  // =============================================================================
@@ -71,6 +110,7 @@ class Readable extends event_emitter_1.EventEmitter {
71
110
  this._bufferSize = 0;
72
111
  this._reading = false;
73
112
  this._ended = false;
113
+ this._endEmitted = false;
74
114
  this._destroyed = false;
75
115
  this._errored = null;
76
116
  this._closed = false;
@@ -127,20 +167,7 @@ class Readable extends event_emitter_1.EventEmitter {
127
167
  */
128
168
  static from(iterable, options) {
129
169
  const readable = new Readable({ ...options, objectMode: options?.objectMode ?? true });
130
- (async () => {
131
- try {
132
- for await (const chunk of iterable) {
133
- if (!readable.push(chunk)) {
134
- // Backpressure
135
- await new Promise(resolve => setTimeout(resolve, 0));
136
- }
137
- }
138
- readable.push(null);
139
- }
140
- catch (err) {
141
- readable.destroy(err);
142
- }
143
- })();
170
+ pumpAsyncIterableToReadable(readable, toAsyncIterable(iterable));
144
171
  return readable;
145
172
  }
146
173
  /**
@@ -185,16 +212,30 @@ class Readable extends event_emitter_1.EventEmitter {
185
212
  // Controller may already be closed
186
213
  }
187
214
  }
188
- this.emit("end");
215
+ // Emit 'end' only after buffered data is fully drained.
216
+ // This avoids premature 'end' when producers push null while paused.
217
+ if (this._bufferedLength() === 0) {
218
+ this._emitEndOnce();
219
+ }
189
220
  // Note: Don't call destroy() here, let the stream be consumed naturally
190
221
  // The reader will return done:true when it finishes reading
191
222
  return false;
192
223
  }
224
+ // Keep the internal Web ReadableStream in sync for controllable streams.
225
+ // For external Web streams (_webStreamMode=true), push() is not the data source.
226
+ if (controller && !this._webStreamMode) {
227
+ try {
228
+ controller.enqueue(chunk);
229
+ }
230
+ catch {
231
+ // Controller may be closed/errored; Node-side buffering/events still work.
232
+ }
233
+ }
193
234
  if (this._flowing) {
194
235
  // In flowing mode, emit data directly without buffering or enqueueing
195
236
  // const chunkStr = chunk instanceof Uint8Array ? new TextDecoder().decode(chunk.slice(0, 50)) : String(chunk).slice(0, 50);
196
237
  // console.log(`[Readable#${this._id}.push FLOWING] emit data size:${(chunk as any).length || (chunk as any).byteLength} start:"${chunkStr}"`);
197
- this.emit("data", chunk);
238
+ this.emit("data", this._applyEncoding(chunk));
198
239
  // Check if stream was paused during emit (backpressure from consumer)
199
240
  if (!this._flowing) {
200
241
  return false;
@@ -219,10 +260,8 @@ class Readable extends event_emitter_1.EventEmitter {
219
260
  if (!this.objectMode) {
220
261
  this._bufferSize += this._getChunkSize(chunk);
221
262
  }
222
- // NOTE: Do NOT enqueue to Web Stream controller here!
223
- // In push mode, _buffer is the only source of data for data events.
224
- // Web Stream is only used for async iteration when not in push mode.
225
- // Enqueueing here would cause data duplication when _startReading is also running.
263
+ // NOTE: We still buffer for Node-style read()/data semantics.
264
+ // The internal Web ReadableStream is also fed via controller.enqueue() above.
226
265
  // Emit readable event when buffer goes from empty to having data
227
266
  if (wasEmpty) {
228
267
  queueMicrotask(() => this.emit("readable"));
@@ -236,6 +275,13 @@ class Readable extends event_emitter_1.EventEmitter {
236
275
  return this._bufferSize < this.readableHighWaterMark;
237
276
  }
238
277
  }
278
+ _emitEndOnce() {
279
+ if (this._endEmitted) {
280
+ return;
281
+ }
282
+ this._endEmitted = true;
283
+ this.emit("end");
284
+ }
239
285
  /**
240
286
  * Put a chunk back at the front of the buffer
241
287
  * Note: unshift is allowed even after end, as it's used to put back already read data
@@ -260,14 +306,22 @@ class Readable extends event_emitter_1.EventEmitter {
260
306
  if (!this.objectMode) {
261
307
  this._bufferSize -= this._getChunkSize(chunk);
262
308
  }
263
- return this._applyEncoding(chunk);
309
+ const decoded = this._applyEncoding(chunk);
310
+ if (this._ended && this._bufferedLength() === 0) {
311
+ queueMicrotask(() => this._emitEndOnce());
312
+ }
313
+ return decoded;
264
314
  }
265
315
  // For binary mode, handle size
266
316
  const chunk = this._bufferShift();
267
317
  if (!this.objectMode) {
268
318
  this._bufferSize -= this._getChunkSize(chunk);
269
319
  }
270
- return this._applyEncoding(chunk);
320
+ const decoded = this._applyEncoding(chunk);
321
+ if (this._ended && this._bufferedLength() === 0) {
322
+ queueMicrotask(() => this._emitEndOnce());
323
+ }
324
+ return decoded;
271
325
  }
272
326
  return null;
273
327
  }
@@ -373,11 +427,11 @@ class Readable extends event_emitter_1.EventEmitter {
373
427
  if (!this.objectMode) {
374
428
  this._bufferSize -= this._getChunkSize(chunk);
375
429
  }
376
- this.emit("data", chunk);
430
+ this.emit("data", this._applyEncoding(chunk));
377
431
  }
378
432
  // If already ended, emit end event
379
433
  if (this._ended && this._bufferedLength() === 0) {
380
- this.emit("end");
434
+ this._emitEndOnce();
381
435
  }
382
436
  else if (this._read) {
383
437
  // Call user-provided read function asynchronously
@@ -425,58 +479,72 @@ class Readable extends event_emitter_1.EventEmitter {
425
479
  // causing `instanceof Transform/Writable/Duplex` to fail even when the object
426
480
  // is a valid destination.
427
481
  const dest = destination;
428
- // Get the actual writable target.
429
- // Prefer internal `_writable` (Transform/Duplex wrappers), else treat the destination as writable-like.
430
- const candidate = dest?._writable ?? dest;
431
- const hasWrite = typeof candidate?.write === "function";
432
- const hasEnd = typeof candidate?.end === "function";
433
- const hasOn = typeof candidate?.on === "function";
434
- const hasOnce = typeof candidate?.once === "function";
435
- const hasOff = typeof candidate?.off === "function";
436
- if (!hasWrite || !hasEnd || (!hasOnce && !hasOn) || (!hasOff && !candidate?.removeListener)) {
482
+ // For event handling (drain, once, off), we need the object that emits events.
483
+ // For write/end, we must call the destination's own write()/end() methods,
484
+ // NOT the internal _writable, because Transform.write() has important logic
485
+ // (like auto-consume) that _writable.write() bypasses.
486
+ const eventTarget = dest;
487
+ const hasWrite = typeof dest?.write === "function";
488
+ const hasEnd = typeof dest?.end === "function";
489
+ const hasOn = typeof eventTarget?.on === "function";
490
+ const hasOnce = typeof eventTarget?.once === "function";
491
+ const hasOff = typeof eventTarget?.off === "function";
492
+ if (!hasWrite || !hasEnd || (!hasOnce && !hasOn) || (!hasOff && !eventTarget?.removeListener)) {
437
493
  throw new Error("Readable.pipe: invalid destination");
438
494
  }
439
- const target = candidate;
440
- this._pipeTo.push(target);
495
+ this._pipeTo.push(dest);
441
496
  // Create listeners that we can later remove
497
+ let drainListener;
498
+ const removeDrainListener = () => {
499
+ if (!drainListener) {
500
+ return;
501
+ }
502
+ if (typeof eventTarget.off === "function") {
503
+ eventTarget.off("drain", drainListener);
504
+ }
505
+ else if (typeof eventTarget.removeListener === "function") {
506
+ eventTarget.removeListener("drain", drainListener);
507
+ }
508
+ drainListener = undefined;
509
+ };
442
510
  const dataListener = (chunk) => {
443
- const canWrite = target.write(chunk);
511
+ // Call destination's write() method (not internal _writable.write())
512
+ // This ensures Transform.write() logic runs properly
513
+ const canWrite = dest.write(chunk);
444
514
  if (!canWrite) {
445
515
  this.pause();
446
- if (typeof target.once === "function") {
447
- target.once("drain", () => this.resume());
448
- }
449
- else {
450
- const resumeOnce = () => {
451
- if (typeof target.off === "function") {
452
- target.off("drain", resumeOnce);
453
- }
454
- else if (typeof target.removeListener === "function") {
455
- target.removeListener("drain", resumeOnce);
456
- }
516
+ // Install a removable, once-style drain listener.
517
+ if (!drainListener) {
518
+ drainListener = () => {
519
+ removeDrainListener();
457
520
  this.resume();
458
521
  };
459
- target.on("drain", resumeOnce);
522
+ eventTarget.on("drain", drainListener);
523
+ const entry = this._pipeListeners.get(dest);
524
+ if (entry) {
525
+ entry.drain = drainListener;
526
+ }
460
527
  }
461
528
  }
462
529
  };
463
530
  const endListener = () => {
464
- target.end();
531
+ dest.end();
465
532
  };
466
533
  const errorListener = (err) => {
467
- if (typeof target.destroy === "function") {
468
- target.destroy(err);
534
+ if (typeof dest.destroy === "function") {
535
+ dest.destroy(err);
469
536
  }
470
537
  else {
471
538
  // Best-effort: forward error to the destination if it supports events.
472
- target.emit?.("error", err);
539
+ eventTarget.emit?.("error", err);
473
540
  }
474
541
  };
475
542
  // Store listeners for later removal in unpipe
476
- this._pipeListeners.set(target, {
543
+ this._pipeListeners.set(dest, {
477
544
  data: dataListener,
478
545
  end: endListener,
479
- error: errorListener
546
+ error: errorListener,
547
+ eventTarget
480
548
  });
481
549
  this.on("data", dataListener);
482
550
  this.once("end", endListener);
@@ -499,6 +567,14 @@ class Readable extends event_emitter_1.EventEmitter {
499
567
  this.off("data", listeners.data);
500
568
  this.off("end", listeners.end);
501
569
  this.off("error", listeners.error);
570
+ if (listeners.drain) {
571
+ if (typeof listeners.eventTarget?.off === "function") {
572
+ listeners.eventTarget.off("drain", listeners.drain);
573
+ }
574
+ else if (typeof listeners.eventTarget?.removeListener === "function") {
575
+ listeners.eventTarget.removeListener("drain", listeners.drain);
576
+ }
577
+ }
502
578
  this._pipeListeners.delete(destination);
503
579
  }
504
580
  }
@@ -510,6 +586,14 @@ class Readable extends event_emitter_1.EventEmitter {
510
586
  this.off("data", listeners.data);
511
587
  this.off("end", listeners.end);
512
588
  this.off("error", listeners.error);
589
+ if (listeners.drain) {
590
+ if (typeof listeners.eventTarget?.off === "function") {
591
+ listeners.eventTarget.off("drain", listeners.drain);
592
+ }
593
+ else if (typeof listeners.eventTarget?.removeListener === "function") {
594
+ listeners.eventTarget.removeListener("drain", listeners.drain);
595
+ }
596
+ }
513
597
  this._pipeListeners.delete(target);
514
598
  }
515
599
  }
@@ -528,12 +612,26 @@ class Readable extends event_emitter_1.EventEmitter {
528
612
  }
529
613
  this._destroyed = true;
530
614
  this._ended = true;
615
+ // Ensure we detach from destinations to avoid leaking listeners.
616
+ this.unpipe();
531
617
  if (error) {
532
618
  this._errored = error;
533
619
  this.emit("error", error);
534
620
  }
535
621
  if (this._reader) {
536
- this._reader.cancel().catch(() => { });
622
+ const reader = this._reader;
623
+ this._reader = null;
624
+ reader
625
+ .cancel()
626
+ .catch(() => { })
627
+ .finally(() => {
628
+ try {
629
+ reader.releaseLock();
630
+ }
631
+ catch {
632
+ // Ignore if a read is still pending
633
+ }
634
+ });
537
635
  }
538
636
  this._closed = true;
539
637
  this.emit("close");
@@ -612,18 +710,38 @@ class Readable extends event_emitter_1.EventEmitter {
612
710
  const { done, value } = await this._reader.read();
613
711
  // Check _pushMode again after async read - if push() was called, stop reading
614
712
  if (this._pushMode) {
713
+ if (this._reader) {
714
+ const reader = this._reader;
715
+ this._reader = null;
716
+ try {
717
+ reader.releaseLock();
718
+ }
719
+ catch {
720
+ // Ignore if a read is still pending
721
+ }
722
+ }
615
723
  break;
616
724
  }
617
725
  if (done) {
618
726
  this._ended = true;
619
- this.emit("end");
727
+ this._emitEndOnce();
728
+ if (this._reader) {
729
+ const reader = this._reader;
730
+ this._reader = null;
731
+ try {
732
+ reader.releaseLock();
733
+ }
734
+ catch {
735
+ // Ignore if a read is still pending
736
+ }
737
+ }
620
738
  break;
621
739
  }
622
740
  if (value !== undefined) {
623
741
  // In flowing mode, emit data directly without buffering
624
742
  // Only buffer if not flowing (paused mode)
625
743
  if (this._flowing) {
626
- this.emit("data", value);
744
+ this.emit("data", this._applyEncoding(value));
627
745
  }
628
746
  else {
629
747
  this._buffer.push(value);
@@ -636,6 +754,16 @@ class Readable extends event_emitter_1.EventEmitter {
636
754
  }
637
755
  catch (err) {
638
756
  this.emit("error", err);
757
+ if (this._reader) {
758
+ const reader = this._reader;
759
+ this._reader = null;
760
+ try {
761
+ reader.releaseLock();
762
+ }
763
+ catch {
764
+ // Ignore if a read is still pending
765
+ }
766
+ }
639
767
  }
640
768
  finally {
641
769
  this._reading = false;
@@ -643,7 +771,8 @@ class Readable extends event_emitter_1.EventEmitter {
643
771
  }
644
772
  /**
645
773
  * Async iterator support
646
- * Uses Web Stream reader for non-push mode, event-based for push mode
774
+ * Uses a unified event-queue iterator with simple backpressure.
775
+ * This matches Node's behavior more closely (iterator drives flowing mode).
647
776
  */
648
777
  async *[Symbol.asyncIterator]() {
649
778
  // First yield any buffered data
@@ -652,117 +781,124 @@ class Readable extends event_emitter_1.EventEmitter {
652
781
  if (!this.objectMode) {
653
782
  this._bufferSize -= this._getChunkSize(chunk);
654
783
  }
655
- yield chunk;
784
+ yield this._applyEncoding(chunk);
656
785
  }
657
- // If already ended, we're done
658
786
  if (this._ended) {
659
787
  return;
660
788
  }
661
- // For controllable streams (not created from external Web Stream),
662
- // use event-based iteration since data comes from push() calls
663
- if (!this._webStreamMode) {
664
- // Create a promise-based queue for incoming data
665
- const dataQueue = [];
666
- let resolveNext = null;
667
- let rejectNext = null;
668
- let done = false;
669
- let streamError = null;
670
- let dataQueueIndex = 0;
671
- const dataHandler = (chunk) => {
672
- if (resolveNext) {
673
- resolveNext(chunk);
674
- resolveNext = null;
675
- rejectNext = null;
676
- }
677
- else {
678
- dataQueue.push(chunk);
679
- }
680
- };
681
- const endHandler = () => {
682
- done = true;
683
- if (resolveNext) {
684
- resolveNext(null);
685
- resolveNext = null;
686
- rejectNext = null;
687
- }
688
- };
689
- const errorHandler = (err) => {
690
- done = true;
691
- streamError = err;
692
- if (rejectNext) {
693
- rejectNext(err);
694
- resolveNext = null;
695
- rejectNext = null;
696
- }
697
- };
698
- const closeHandler = () => {
699
- // If stream closed without end event (e.g., after destroy()),
700
- // treat it as done
701
- done = true;
702
- if (resolveNext) {
703
- resolveNext(null);
704
- resolveNext = null;
705
- rejectNext = null;
706
- }
707
- };
708
- this.on("data", dataHandler);
709
- this.on("end", endHandler);
710
- this.on("error", errorHandler);
711
- this.on("close", closeHandler);
712
- try {
713
- // Enter flowing mode
714
- this.resume();
715
- while (!done || dataQueueIndex < dataQueue.length) {
716
- // Check for error before processing
717
- if (streamError) {
718
- throw streamError;
719
- }
720
- if (dataQueueIndex < dataQueue.length) {
721
- const chunk = dataQueue[dataQueueIndex++];
722
- if (dataQueueIndex >= 1024 && dataQueueIndex * 2 >= dataQueue.length) {
723
- dataQueue.splice(0, dataQueueIndex);
724
- dataQueueIndex = 0;
725
- }
726
- yield chunk;
727
- }
728
- else if (!done) {
729
- const chunk = await new Promise((resolve, reject) => {
730
- resolveNext = resolve;
731
- rejectNext = reject;
732
- });
733
- if (chunk !== null) {
734
- yield chunk;
735
- }
736
- }
737
- }
738
- // Check for error after loop
739
- if (streamError) {
740
- throw streamError;
741
- }
789
+ const highWaterMark = this.readableHighWaterMark;
790
+ const lowWaterMark = Math.max(0, Math.floor(highWaterMark / 2));
791
+ const chunkSizeForBackpressure = (chunk) => {
792
+ if (this.objectMode) {
793
+ return 1;
742
794
  }
743
- finally {
744
- this.off("data", dataHandler);
745
- this.off("end", endHandler);
746
- this.off("error", errorHandler);
747
- this.off("close", closeHandler);
795
+ if (chunk instanceof Uint8Array) {
796
+ return chunk.byteLength;
748
797
  }
749
- return;
750
- }
751
- // For Web Stream mode, use the underlying reader
752
- if (!this._reader) {
753
- this._reader = this._stream.getReader();
754
- }
798
+ if (typeof chunk === "string") {
799
+ return chunk.length;
800
+ }
801
+ return 1;
802
+ };
803
+ const dataQueue = [];
804
+ let dataQueueIndex = 0;
805
+ let queuedSize = 0;
806
+ let resolveNext = null;
807
+ let rejectNext = null;
808
+ let done = false;
809
+ let pausedByIterator = false;
810
+ let streamError = null;
811
+ const dataHandler = (chunk) => {
812
+ // data events are already encoding-aware; do not decode again here.
813
+ if (resolveNext) {
814
+ resolveNext(chunk);
815
+ resolveNext = null;
816
+ rejectNext = null;
817
+ }
818
+ else {
819
+ dataQueue.push(chunk);
820
+ }
821
+ queuedSize += chunkSizeForBackpressure(chunk);
822
+ if (!pausedByIterator && queuedSize >= highWaterMark) {
823
+ pausedByIterator = true;
824
+ this.pause();
825
+ }
826
+ };
827
+ const endHandler = () => {
828
+ done = true;
829
+ if (resolveNext) {
830
+ resolveNext(null);
831
+ resolveNext = null;
832
+ rejectNext = null;
833
+ }
834
+ };
835
+ const closeHandler = () => {
836
+ done = true;
837
+ if (resolveNext) {
838
+ resolveNext(null);
839
+ resolveNext = null;
840
+ rejectNext = null;
841
+ }
842
+ };
843
+ const errorHandler = (err) => {
844
+ done = true;
845
+ streamError = err;
846
+ if (rejectNext) {
847
+ rejectNext(err);
848
+ resolveNext = null;
849
+ rejectNext = null;
850
+ }
851
+ };
852
+ this.on("data", dataHandler);
853
+ this.on("end", endHandler);
854
+ this.on("error", errorHandler);
855
+ this.on("close", closeHandler);
755
856
  try {
857
+ // Iterator consumption should drive the stream.
858
+ this.resume();
756
859
  while (true) {
757
- const { done, value } = await this._reader.read();
860
+ if (streamError) {
861
+ throw streamError;
862
+ }
863
+ if (dataQueueIndex < dataQueue.length) {
864
+ const chunk = dataQueue[dataQueueIndex++];
865
+ queuedSize -= chunkSizeForBackpressure(chunk);
866
+ if (dataQueueIndex >= 1024 && dataQueueIndex * 2 >= dataQueue.length) {
867
+ dataQueue.splice(0, dataQueueIndex);
868
+ dataQueueIndex = 0;
869
+ }
870
+ if (pausedByIterator && queuedSize <= lowWaterMark && !done && !this._destroyed) {
871
+ pausedByIterator = false;
872
+ this.resume();
873
+ }
874
+ yield chunk;
875
+ continue;
876
+ }
758
877
  if (done) {
759
878
  break;
760
879
  }
761
- yield value;
880
+ const chunk = await new Promise((resolve, reject) => {
881
+ resolveNext = resolve;
882
+ rejectNext = reject;
883
+ });
884
+ if (chunk !== null) {
885
+ queuedSize -= chunkSizeForBackpressure(chunk);
886
+ if (pausedByIterator && queuedSize <= lowWaterMark && !done && !this._destroyed) {
887
+ pausedByIterator = false;
888
+ this.resume();
889
+ }
890
+ yield chunk;
891
+ }
892
+ }
893
+ if (streamError) {
894
+ throw streamError;
762
895
  }
763
896
  }
764
897
  finally {
765
- this._reader.releaseLock();
898
+ this.off("data", dataHandler);
899
+ this.off("end", endHandler);
900
+ this.off("error", errorHandler);
901
+ this.off("close", closeHandler);
766
902
  }
767
903
  }
768
904
  /**
@@ -982,6 +1118,32 @@ class Readable extends event_emitter_1.EventEmitter {
982
1118
  }
983
1119
  }
984
1120
  exports.Readable = Readable;
1121
+ function toAsyncIterable(iterable) {
1122
+ if (iterable && typeof iterable[Symbol.asyncIterator] === "function") {
1123
+ return iterable;
1124
+ }
1125
+ return (async function* () {
1126
+ for (const item of iterable) {
1127
+ yield item;
1128
+ }
1129
+ })();
1130
+ }
1131
+ function pumpAsyncIterableToReadable(readable, iterable) {
1132
+ (async () => {
1133
+ try {
1134
+ for await (const chunk of iterable) {
1135
+ if (!readable.push(chunk)) {
1136
+ // Simple backpressure: yield to consumer.
1137
+ await new Promise(resolve => setTimeout(resolve, 0));
1138
+ }
1139
+ }
1140
+ readable.push(null);
1141
+ }
1142
+ catch (err) {
1143
+ readable.destroy(err);
1144
+ }
1145
+ })();
1146
+ }
985
1147
  // =============================================================================
986
1148
  // Writable Stream Wrapper
987
1149
  // =============================================================================
@@ -999,10 +1161,12 @@ class Writable extends event_emitter_1.EventEmitter {
999
1161
  this._closed = false;
1000
1162
  this._pendingWrites = 0;
1001
1163
  this._writableLength = 0;
1164
+ this._needDrain = false;
1002
1165
  this._corked = 0;
1003
1166
  this._corkedChunks = [];
1004
1167
  this._defaultEncoding = "utf8";
1005
1168
  this._aborted = false;
1169
+ this._ownsStream = false;
1006
1170
  this.objectMode = options?.objectMode ?? false;
1007
1171
  this.writableHighWaterMark = options?.highWaterMark ?? 16384;
1008
1172
  this.autoDestroy = options?.autoDestroy ?? true;
@@ -1018,8 +1182,10 @@ class Writable extends event_emitter_1.EventEmitter {
1018
1182
  }
1019
1183
  if (options?.stream) {
1020
1184
  this._stream = options.stream;
1185
+ this._ownsStream = false;
1021
1186
  }
1022
1187
  else {
1188
+ this._ownsStream = true;
1023
1189
  // Create bound references to instance properties/methods for use in WritableStream callbacks
1024
1190
  const getWriteFunc = () => this._writeFunc;
1025
1191
  const getFinalFunc = () => this._finalFunc;
@@ -1126,25 +1292,37 @@ class Writable extends event_emitter_1.EventEmitter {
1126
1292
  this._writableLength += chunkSize;
1127
1293
  return this._writableLength < this.writableHighWaterMark;
1128
1294
  }
1129
- return this._doWrite(chunk, cb);
1295
+ const ok = this._doWrite(chunk, cb);
1296
+ if (!ok) {
1297
+ this._needDrain = true;
1298
+ }
1299
+ return ok;
1130
1300
  }
1131
1301
  _doWrite(chunk, callback) {
1132
1302
  // Track pending writes for writableLength
1133
1303
  const chunkSize = this._getChunkSize(chunk);
1134
1304
  this._pendingWrites++;
1135
1305
  this._writableLength += chunkSize;
1136
- this._getWriter()
1306
+ const writer = this._getWriter();
1307
+ writer
1137
1308
  .write(chunk)
1138
1309
  .then(() => {
1139
1310
  this._pendingWrites--;
1140
1311
  this._writableLength -= chunkSize;
1141
- this.emit("drain");
1312
+ if (this._needDrain && this._writableLength < this.writableHighWaterMark) {
1313
+ this._needDrain = false;
1314
+ this.emit("drain");
1315
+ }
1142
1316
  callback?.(null);
1143
1317
  })
1144
1318
  .catch(err => {
1145
1319
  this._pendingWrites--;
1146
1320
  this._writableLength -= chunkSize;
1147
- this.emit("error", err);
1321
+ // Avoid double-emitting if we're already in an errored/destroyed state.
1322
+ if (!this._destroyed) {
1323
+ this._errored = err;
1324
+ this.emit("error", err);
1325
+ }
1148
1326
  callback?.(err);
1149
1327
  });
1150
1328
  // Return false if we've exceeded high water mark (for backpressure)
@@ -1175,12 +1353,29 @@ class Writable extends event_emitter_1.EventEmitter {
1175
1353
  : callback;
1176
1354
  const finish = async () => {
1177
1355
  try {
1356
+ const writer = this._getWriter();
1178
1357
  if (chunk !== undefined) {
1179
- await this._getWriter().write(chunk);
1358
+ await writer.write(chunk);
1359
+ }
1360
+ await writer.close();
1361
+ if (this._writer === writer) {
1362
+ this._writer = null;
1363
+ try {
1364
+ writer.releaseLock();
1365
+ }
1366
+ catch {
1367
+ // Ignore
1368
+ }
1369
+ }
1370
+ // If we own the underlying Web WritableStream, its `close()` handler already
1371
+ // emits finish/close. For external streams, we must emit finish ourselves.
1372
+ if (!this._ownsStream) {
1373
+ this._finished = true;
1374
+ this.emit("finish");
1375
+ if (this.emitClose) {
1376
+ this.emit("close");
1377
+ }
1180
1378
  }
1181
- await this._getWriter().close();
1182
- this._finished = true;
1183
- this.emit("finish");
1184
1379
  if (cb) {
1185
1380
  cb();
1186
1381
  }
@@ -1201,12 +1396,24 @@ class Writable extends event_emitter_1.EventEmitter {
1201
1396
  }
1202
1397
  this._destroyed = true;
1203
1398
  this._ended = true;
1204
- if (error) {
1399
+ if (error && !this._errored) {
1205
1400
  this._errored = error;
1206
1401
  this.emit("error", error);
1207
1402
  }
1208
1403
  if (this._writer) {
1209
- this._writer.abort(error).catch(() => { });
1404
+ const writer = this._writer;
1405
+ this._writer = null;
1406
+ writer
1407
+ .abort(error)
1408
+ .catch(() => { })
1409
+ .finally(() => {
1410
+ try {
1411
+ writer.releaseLock();
1412
+ }
1413
+ catch {
1414
+ // Ignore
1415
+ }
1416
+ });
1210
1417
  }
1211
1418
  this._closed = true;
1212
1419
  this.emit("close");
@@ -1358,332 +1565,259 @@ function normalizeWritable(stream) {
1358
1565
  */
1359
1566
  class Transform extends event_emitter_1.EventEmitter {
1360
1567
  /**
1361
- * Push data to the readable side (Node.js compatibility)
1362
- * Can be called from within transform callback
1568
+ * Push data to the readable side (Node.js compatibility).
1569
+ * Intended to be called from within transform/flush.
1363
1570
  */
1364
1571
  push(chunk) {
1365
- if (chunk === null) {
1366
- return false;
1367
- }
1368
- if (this._transformController) {
1369
- // If we're in a transform callback, enqueue directly
1370
- this._transformController.enqueue(chunk);
1371
- }
1372
- else {
1373
- // Otherwise buffer for later
1374
- this._pushBuffer.push(chunk);
1375
- }
1376
- return true;
1572
+ return this._readable.push(chunk);
1377
1573
  }
1378
1574
  constructor(options) {
1379
1575
  super();
1380
- this._ended = false;
1381
1576
  this._destroyed = false;
1577
+ this._ended = false;
1382
1578
  this._errored = false;
1383
- // Buffer for Node.js style push() calls during transform
1384
- this._pushBuffer = [];
1385
- // Controller for enqueueing pushed data (set during transform execution)
1386
- this._transformController = null;
1387
- // Buffer for writes that occur after end() but before writable is closed
1388
- this._pendingEndWrites = [];
1389
- // Whether end() has been called but writable not yet closed
1390
- this._endPending = false;
1391
- // Track if we've already set up data forwarding
1392
1579
  this._dataForwardingSetup = false;
1393
- /** @internal - whether we have a data event consumer */
1394
- this._hasDataConsumer = false;
1395
- /** @internal - whether we're auto-consuming the readable */
1396
- this._readableConsuming = false;
1397
- /** @internal - buffer for auto-consumed data */
1398
- this._autoConsumedBuffer = [];
1399
- this._autoConsumedBufferIndex = 0;
1400
- /** @internal - whether auto-consume has ended */
1401
- this._autoConsumeEnded = false;
1402
- /** @internal - promise that resolves when auto-consume finishes */
1403
- this._autoConsumePromise = null;
1580
+ this._endTimer = null;
1581
+ this._webStream = null;
1582
+ this._sideForwardingCleanup = null;
1404
1583
  this.objectMode = options?.objectMode ?? false;
1405
- const userTransform = options?.transform;
1406
- const userFlush = options?.flush;
1407
- // Create bound references for use in TransformStream callbacks
1408
- const setController = (ctrl) => {
1409
- this._transformController = ctrl;
1410
- };
1411
- const emitEvent = (event, ...args) => {
1412
- if (event === "error") {
1413
- // Only emit error once to prevent duplicate events
1414
- if (this._errored) {
1415
- return false;
1416
- }
1417
- this._errored = true;
1418
- // Also destroy the writable to prevent further writes
1419
- this._writable.destroy(args[0]);
1584
+ this._transformImpl = options?.transform;
1585
+ this._flushImpl = options?.flush;
1586
+ this._readable = new Readable({
1587
+ objectMode: this.objectMode
1588
+ });
1589
+ this._writable = new Writable({
1590
+ objectMode: this.objectMode,
1591
+ write: (chunk, _encoding, callback) => {
1592
+ this._runTransform(chunk)
1593
+ .then(() => callback(null))
1594
+ .catch(err => callback(err));
1595
+ },
1596
+ final: callback => {
1597
+ this._runFlush()
1598
+ .then(() => {
1599
+ this._readable.push(null);
1600
+ callback(null);
1601
+ })
1602
+ .catch(err => callback(err));
1420
1603
  }
1421
- return this.emit(event, ...args);
1422
- };
1423
- const getInstance = () => this;
1424
- // Check if subclass overrides _transform (for Node.js compatibility)
1425
- // We need to check this at runtime since the subclass constructor runs after super()
1426
- const hasSubclassTransform = () => {
1427
- // If userTransform was provided in options, use that
1428
- if (userTransform) {
1429
- return false;
1604
+ });
1605
+ this._setupSideForwarding();
1606
+ }
1607
+ _setupSideForwarding() {
1608
+ if (this._sideForwardingCleanup) {
1609
+ this._sideForwardingCleanup();
1610
+ this._sideForwardingCleanup = null;
1611
+ }
1612
+ const registry = createListenerRegistry();
1613
+ registry.once(this._readable, "end", () => this.emit("end"));
1614
+ registry.add(this._readable, "error", err => this._emitErrorOnce(err));
1615
+ registry.once(this._writable, "finish", () => this.emit("finish"));
1616
+ registry.add(this._writable, "drain", () => this.emit("drain"));
1617
+ registry.add(this._writable, "error", err => this._emitErrorOnce(err));
1618
+ this._sideForwardingCleanup = () => registry.cleanup();
1619
+ }
1620
+ _scheduleEnd() {
1621
+ if (this._destroyed || this._errored) {
1622
+ return;
1623
+ }
1624
+ if (this._writable.writableEnded) {
1625
+ return;
1626
+ }
1627
+ if (this._endTimer) {
1628
+ clearTimeout(this._endTimer);
1629
+ }
1630
+ // Defer closing to allow writes triggered during 'data' callbacks.
1631
+ this._endTimer = setTimeout(() => {
1632
+ this._endTimer = null;
1633
+ if (this._destroyed || this._errored || this._writable.writableEnded) {
1634
+ return;
1430
1635
  }
1431
- // Check if _transform is overridden (not the base class no-op)
1432
- const proto = Object.getPrototypeOf(this);
1433
- return proto._transform !== Transform.prototype._transform;
1434
- };
1435
- const hasSubclassFlush = () => {
1436
- if (userFlush) {
1437
- return false;
1636
+ this._writable.end();
1637
+ }, 0);
1638
+ }
1639
+ _emitErrorOnce(err) {
1640
+ if (this._errored) {
1641
+ return;
1642
+ }
1643
+ this._errored = true;
1644
+ const error = err instanceof Error ? err : new Error(String(err));
1645
+ this.emit("error", error);
1646
+ if (!this._destroyed) {
1647
+ this._destroyed = true;
1648
+ this._readable.destroy(error);
1649
+ this._writable.destroy(error);
1650
+ queueMicrotask(() => this.emit("close"));
1651
+ }
1652
+ }
1653
+ _hasSubclassTransform() {
1654
+ if (this._transformImpl) {
1655
+ return false;
1656
+ }
1657
+ const proto = Object.getPrototypeOf(this);
1658
+ return proto._transform !== Transform.prototype._transform;
1659
+ }
1660
+ _hasSubclassFlush() {
1661
+ if (this._flushImpl) {
1662
+ return false;
1663
+ }
1664
+ const proto = Object.getPrototypeOf(this);
1665
+ return proto._flush !== Transform.prototype._flush;
1666
+ }
1667
+ async _runTransform(chunk) {
1668
+ if (this._destroyed || this._errored) {
1669
+ throw new Error(this._errored ? "Cannot write after stream errored" : "Cannot write after stream destroyed");
1670
+ }
1671
+ try {
1672
+ if (this._hasSubclassTransform()) {
1673
+ await new Promise((resolve, reject) => {
1674
+ this._transform(chunk, "utf8", (err, data) => {
1675
+ if (err) {
1676
+ reject(err);
1677
+ return;
1678
+ }
1679
+ if (data !== undefined) {
1680
+ this.push(data);
1681
+ }
1682
+ resolve();
1683
+ });
1684
+ });
1685
+ return;
1438
1686
  }
1439
- const proto = Object.getPrototypeOf(this);
1440
- return proto._flush !== Transform.prototype._flush;
1441
- };
1442
- this._stream = new TransformStream({
1443
- transform: async (chunk, controller) => {
1444
- // Skip processing if already errored
1445
- if (this._errored) {
1446
- return;
1447
- }
1448
- try {
1449
- // Set controller for push() to use
1450
- setController(controller);
1451
- // Check for subclass _transform override first
1452
- if (hasSubclassTransform()) {
1453
- // Call subclass _transform method (Node.js style)
1454
- // _transform signature is (chunk, encoding, callback)
1455
- await new Promise((resolve, reject) => {
1456
- this._transform(chunk, "utf8", (err, data) => {
1457
- if (err) {
1458
- reject(err);
1459
- }
1460
- else {
1461
- if (data !== undefined) {
1462
- controller.enqueue(data);
1463
- }
1464
- resolve();
1465
- }
1466
- });
1467
- });
1468
- }
1469
- else if (userTransform) {
1470
- const transformParamCount = userTransform.length;
1471
- if (transformParamCount >= 3) {
1472
- // Node.js style: transform(chunk, encoding, callback)
1473
- await new Promise((resolve, reject) => {
1474
- userTransform.call(getInstance(), chunk, "utf8", (err, data) => {
1475
- if (err) {
1476
- reject(err);
1477
- }
1478
- else {
1479
- if (data !== undefined) {
1480
- controller.enqueue(data);
1481
- }
1482
- resolve();
1483
- }
1484
- });
1485
- });
1687
+ const userTransform = this._transformImpl;
1688
+ if (!userTransform) {
1689
+ this.push(chunk);
1690
+ return;
1691
+ }
1692
+ const paramCount = userTransform.length;
1693
+ if (paramCount >= 3) {
1694
+ await new Promise((resolve, reject) => {
1695
+ userTransform.call(this, chunk, "utf8", (err, data) => {
1696
+ if (err) {
1697
+ reject(err);
1698
+ return;
1486
1699
  }
1487
- else if (transformParamCount === 2) {
1488
- await new Promise((resolve, reject) => {
1489
- userTransform.call(getInstance(), chunk, (err, data) => {
1490
- if (err) {
1491
- reject(err);
1492
- }
1493
- else {
1494
- if (data !== undefined) {
1495
- controller.enqueue(data);
1496
- }
1497
- resolve();
1498
- }
1499
- });
1500
- });
1700
+ if (data !== undefined) {
1701
+ this.push(data);
1501
1702
  }
1502
- else {
1503
- // Simple style: transform(chunk) => result
1504
- const result = userTransform.call(getInstance(), chunk);
1505
- if (result && typeof result.then === "function") {
1506
- const awaitedResult = await result;
1507
- if (awaitedResult !== undefined) {
1508
- controller.enqueue(awaitedResult);
1509
- }
1510
- }
1511
- else {
1512
- if (result !== undefined) {
1513
- controller.enqueue(result);
1514
- }
1515
- }
1703
+ resolve();
1704
+ });
1705
+ });
1706
+ return;
1707
+ }
1708
+ if (paramCount === 2) {
1709
+ await new Promise((resolve, reject) => {
1710
+ userTransform.call(this, chunk, (err, data) => {
1711
+ if (err) {
1712
+ reject(err);
1713
+ return;
1516
1714
  }
1517
- }
1518
- else {
1519
- // Default: pass through
1520
- controller.enqueue(chunk);
1521
- }
1522
- }
1523
- catch (err) {
1524
- controller.error(err);
1525
- emitEvent("error", err);
1526
- }
1527
- finally {
1528
- setController(null);
1715
+ if (data !== undefined) {
1716
+ this.push(data);
1717
+ }
1718
+ resolve();
1719
+ });
1720
+ });
1721
+ return;
1722
+ }
1723
+ const result = userTransform.call(this, chunk);
1724
+ if (result && typeof result.then === "function") {
1725
+ const awaited = await result;
1726
+ if (awaited !== undefined) {
1727
+ this.push(awaited);
1529
1728
  }
1530
- },
1531
- flush: async (controller) => {
1532
- try {
1533
- setController(controller);
1534
- // Check for subclass _flush override first
1535
- if (hasSubclassFlush()) {
1536
- await new Promise((resolve, reject) => {
1537
- this._flush((err, data) => {
1538
- if (err) {
1539
- reject(err);
1540
- }
1541
- else {
1542
- if (data !== undefined) {
1543
- controller.enqueue(data);
1544
- }
1545
- resolve();
1546
- }
1547
- });
1548
- });
1549
- }
1550
- else if (userFlush) {
1551
- const flushParamCount = userFlush.length;
1552
- if (flushParamCount >= 1) {
1553
- // Node.js style: flush(callback)
1554
- await new Promise((resolve, reject) => {
1555
- userFlush.call(getInstance(), (err, data) => {
1556
- if (err) {
1557
- reject(err);
1558
- }
1559
- else {
1560
- if (data !== undefined) {
1561
- controller.enqueue(data);
1562
- }
1563
- resolve();
1564
- }
1565
- });
1566
- });
1729
+ return;
1730
+ }
1731
+ if (result !== undefined) {
1732
+ this.push(result);
1733
+ }
1734
+ }
1735
+ catch (err) {
1736
+ this._emitErrorOnce(err);
1737
+ throw err;
1738
+ }
1739
+ }
1740
+ async _runFlush() {
1741
+ if (this._destroyed || this._errored) {
1742
+ return;
1743
+ }
1744
+ try {
1745
+ if (this._hasSubclassFlush()) {
1746
+ await new Promise((resolve, reject) => {
1747
+ this._flush((err, data) => {
1748
+ if (err) {
1749
+ reject(err);
1750
+ return;
1567
1751
  }
1568
- else {
1569
- // Simple style: flush() => result
1570
- const result = userFlush.call(getInstance());
1571
- if (result && typeof result.then === "function") {
1572
- const awaitedResult = await result;
1573
- if (awaitedResult !== undefined && awaitedResult !== null) {
1574
- controller.enqueue(awaitedResult);
1575
- }
1576
- }
1577
- else {
1578
- if (result !== undefined && result !== null) {
1579
- controller.enqueue(result);
1580
- }
1581
- }
1752
+ if (data !== undefined) {
1753
+ this.push(data);
1582
1754
  }
1583
- }
1584
- // No flush defined - nothing to do
1585
- }
1586
- catch (err) {
1587
- controller.error(err);
1588
- emitEvent("error", err);
1589
- }
1590
- finally {
1591
- setController(null);
1592
- }
1755
+ resolve();
1756
+ });
1757
+ });
1758
+ return;
1593
1759
  }
1594
- });
1595
- this._readable = new Readable({
1596
- stream: this._stream.readable,
1597
- objectMode: this.objectMode
1598
- });
1599
- this._writable = new Writable({
1600
- stream: this._stream.writable,
1601
- objectMode: this.objectMode
1602
- });
1603
- // Forward non-data events (data forwarding is lazy to avoid premature flowing)
1604
- this._readable.on("end", () => this.emit("end"));
1605
- // Only forward errors if not already errored (to prevent duplicate events)
1606
- this._readable.on("error", err => {
1607
- if (!this._errored) {
1608
- this._errored = true;
1609
- this.emit("error", err);
1760
+ const userFlush = this._flushImpl;
1761
+ if (!userFlush) {
1762
+ return;
1763
+ }
1764
+ const paramCount = userFlush.length;
1765
+ if (paramCount >= 1) {
1766
+ await new Promise((resolve, reject) => {
1767
+ userFlush.call(this, (err, data) => {
1768
+ if (err) {
1769
+ reject(err);
1770
+ return;
1771
+ }
1772
+ if (data !== undefined) {
1773
+ this.push(data);
1774
+ }
1775
+ resolve();
1776
+ });
1777
+ });
1778
+ return;
1610
1779
  }
1611
- });
1612
- this._writable.on("finish", () => this.emit("finish"));
1613
- this._writable.on("drain", () => this.emit("drain"));
1614
- // Only forward errors if not already errored (to prevent duplicate events)
1615
- this._writable.on("error", err => {
1616
- if (!this._errored) {
1617
- this._errored = true;
1618
- this.emit("error", err);
1780
+ const result = userFlush.call(this);
1781
+ if (result && typeof result.then === "function") {
1782
+ const awaited = await result;
1783
+ if (awaited !== undefined && awaited !== null) {
1784
+ this.push(awaited);
1785
+ }
1786
+ return;
1619
1787
  }
1620
- });
1788
+ if (result !== undefined && result !== null) {
1789
+ this.push(result);
1790
+ }
1791
+ }
1792
+ catch (err) {
1793
+ this._emitErrorOnce(err);
1794
+ throw err;
1795
+ }
1621
1796
  }
1622
1797
  /**
1623
- * Override on to start flowing when data listener is added
1798
+ * Override on() to lazily forward readable 'data' events.
1799
+ * Avoids starting flowing mode unless requested.
1624
1800
  */
1625
1801
  on(event, listener) {
1626
- // Set up data forwarding when first external data listener is added
1627
1802
  if (event === "data" && !this._dataForwardingSetup) {
1628
1803
  this._dataForwardingSetup = true;
1629
- this._readable.on("data", data => this.emit("data", data));
1630
- }
1631
- super.on(event, listener);
1632
- // When data listener is added, mark as having consumer
1633
- // and start the readable in flowing mode
1634
- if (event === "data") {
1635
- this._hasDataConsumer = true;
1636
- this._readable.resume();
1804
+ this._readable.on("data", chunk => this.emit("data", chunk));
1637
1805
  }
1638
- return this;
1806
+ return super.on(event, listener);
1639
1807
  }
1640
1808
  write(chunk, encodingOrCallback, callback) {
1641
1809
  const cb = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
1642
- if (this._destroyed || this._errored) {
1643
- const err = new Error(this._errored ? "Cannot write after stream errored" : "Cannot write after stream destroyed");
1644
- queueMicrotask(() => this.emit("error", err));
1645
- cb?.(err);
1646
- return false;
1647
- }
1648
- // Ensure readable is being consumed to allow transform to execute
1649
- // This matches Node.js behavior where transform executes immediately on write
1650
- // Only auto-consume if no explicit consumer (data listener or pipe)
1651
- if (!this._readableConsuming && !this._hasDataConsumer) {
1652
- this._readableConsuming = true;
1653
- this._startAutoConsume();
1654
- }
1655
- // If end() was called but writable not yet closed, buffer the write
1656
- // This allows writes during data event handlers to be processed
1657
- if (this._endPending) {
1658
- this._pendingEndWrites.push({ chunk, callback: cb });
1659
- return true;
1810
+ // If end() has been requested, keep the close deferred as long as writes continue.
1811
+ if (this._ended && !this._writable.writableEnded) {
1812
+ this._scheduleEnd();
1660
1813
  }
1661
1814
  return this._writable.write(chunk, cb);
1662
1815
  }
1663
- /** @internal - auto-consume readable to allow transform to execute */
1664
- _startAutoConsume() {
1665
- this._autoConsumePromise = (async () => {
1666
- try {
1667
- for await (const chunk of this._readable) {
1668
- // Buffer the data for later retrieval
1669
- this._autoConsumedBuffer.push(chunk);
1670
- // Also emit data event for listeners
1671
- this.emit("data", chunk);
1672
- }
1673
- this._autoConsumeEnded = true;
1674
- this.emit("end");
1675
- }
1676
- catch (err) {
1677
- this.emit("error", err);
1678
- }
1679
- })();
1680
- }
1681
1816
  end(chunkOrCallback, encodingOrCallback, callback) {
1682
1817
  if (this._ended) {
1683
1818
  return this;
1684
1819
  }
1685
1820
  this._ended = true;
1686
- this._endPending = true;
1687
1821
  const chunk = typeof chunkOrCallback === "function" ? undefined : chunkOrCallback;
1688
1822
  const cb = typeof chunkOrCallback === "function"
1689
1823
  ? chunkOrCallback
@@ -1696,18 +1830,7 @@ class Transform extends event_emitter_1.EventEmitter {
1696
1830
  if (chunk !== undefined) {
1697
1831
  this._writable.write(chunk);
1698
1832
  }
1699
- // Use setTimeout(0) instead of queueMicrotask to ensure all transform
1700
- // processing and data events complete before we close the writable.
1701
- // Microtasks run before the TransformStream processes data.
1702
- setTimeout(() => {
1703
- // Process any writes that occurred during data events
1704
- for (const { chunk: pendingChunk, callback } of this._pendingEndWrites) {
1705
- this._writable.write(pendingChunk, callback);
1706
- }
1707
- this._pendingEndWrites = [];
1708
- this._endPending = false;
1709
- this._writable.end();
1710
- }, 0);
1833
+ this._scheduleEnd();
1711
1834
  return this;
1712
1835
  }
1713
1836
  /**
@@ -1717,11 +1840,9 @@ class Transform extends event_emitter_1.EventEmitter {
1717
1840
  return this._readable.read(size);
1718
1841
  }
1719
1842
  /**
1720
- * Pipe to another stream (writable, transform, or duplex)
1843
+ * Pipe readable side to destination
1721
1844
  */
1722
1845
  pipe(destination) {
1723
- // Mark as having consumer to prevent auto-consume conflict
1724
- this._hasDataConsumer = true;
1725
1846
  return this._readable.pipe(destination);
1726
1847
  }
1727
1848
  /**
@@ -1759,6 +1880,10 @@ class Transform extends event_emitter_1.EventEmitter {
1759
1880
  return;
1760
1881
  }
1761
1882
  this._destroyed = true;
1883
+ if (this._sideForwardingCleanup) {
1884
+ this._sideForwardingCleanup();
1885
+ this._sideForwardingCleanup = null;
1886
+ }
1762
1887
  this._readable.destroy(error);
1763
1888
  this._writable.destroy(error);
1764
1889
  queueMicrotask(() => this.emit("close"));
@@ -1767,7 +1892,44 @@ class Transform extends event_emitter_1.EventEmitter {
1767
1892
  * Get the underlying Web TransformStream
1768
1893
  */
1769
1894
  get webStream() {
1770
- return this._stream;
1895
+ if (this._webStream) {
1896
+ return this._webStream;
1897
+ }
1898
+ // Web Streams interop layer.
1899
+ const iterator = this[Symbol.asyncIterator]();
1900
+ const readable = new ReadableStream({
1901
+ pull: async (controller) => {
1902
+ const { done, value } = await iterator.next();
1903
+ if (done) {
1904
+ controller.close();
1905
+ return;
1906
+ }
1907
+ controller.enqueue(value);
1908
+ },
1909
+ cancel: reason => {
1910
+ this.destroy(reason instanceof Error ? reason : new Error(String(reason)));
1911
+ }
1912
+ });
1913
+ const writable = new WritableStream({
1914
+ write: chunk => new Promise((resolve, reject) => {
1915
+ this.write(chunk, err => {
1916
+ if (err) {
1917
+ reject(err);
1918
+ }
1919
+ else {
1920
+ resolve();
1921
+ }
1922
+ });
1923
+ }),
1924
+ close: () => new Promise(resolve => {
1925
+ this.end(() => resolve());
1926
+ }),
1927
+ abort: reason => {
1928
+ this.destroy(reason instanceof Error ? reason : new Error(String(reason)));
1929
+ }
1930
+ });
1931
+ this._webStream = { readable, writable };
1932
+ return this._webStream;
1771
1933
  }
1772
1934
  get readable() {
1773
1935
  return this._readable.readable;
@@ -1809,19 +1971,6 @@ class Transform extends event_emitter_1.EventEmitter {
1809
1971
  * Async iterator support
1810
1972
  */
1811
1973
  async *[Symbol.asyncIterator]() {
1812
- // If auto-consume is running, wait for it to finish and use its buffer
1813
- if (this._autoConsumePromise) {
1814
- await this._autoConsumePromise;
1815
- // Yield all buffered data
1816
- while (this._autoConsumedBufferIndex < this._autoConsumedBuffer.length) {
1817
- yield this._autoConsumedBuffer[this._autoConsumedBufferIndex++];
1818
- }
1819
- // Reset when drained to avoid prefix growth
1820
- this._autoConsumedBuffer.length = 0;
1821
- this._autoConsumedBufferIndex = 0;
1822
- return;
1823
- }
1824
- // Otherwise delegate to readable's iterator
1825
1974
  yield* this._readable[Symbol.asyncIterator]();
1826
1975
  }
1827
1976
  // =========================================================================
@@ -1832,23 +1981,18 @@ class Transform extends event_emitter_1.EventEmitter {
1832
1981
  */
1833
1982
  static fromWeb(webStream, options) {
1834
1983
  const transform = new Transform(options);
1835
- // Connect the web stream - set the internal _stream property
1836
- transform._stream = webStream;
1984
+ transform._webStream = webStream;
1837
1985
  // Replace internal streams with the ones from the web stream
1838
1986
  const newReadable = Readable.fromWeb(webStream.readable, { objectMode: options?.objectMode });
1839
1987
  const newWritable = Writable.fromWeb(webStream.writable, { objectMode: options?.objectMode });
1840
- // Remove old event listeners before replacing
1841
- transform._readable.removeAllListeners();
1842
- transform._writable.removeAllListeners();
1988
+ if (transform._sideForwardingCleanup) {
1989
+ transform._sideForwardingCleanup();
1990
+ transform._sideForwardingCleanup = null;
1991
+ }
1843
1992
  transform._readable = newReadable;
1844
1993
  transform._writable = newWritable;
1845
- // Re-connect event forwarding
1846
- newReadable.on("data", (data) => transform.emit("data", data));
1847
- newReadable.on("end", () => transform.emit("end"));
1848
- newReadable.on("error", (err) => transform.emit("error", err));
1849
- newWritable.on("finish", () => transform.emit("finish"));
1850
- newWritable.on("drain", () => transform.emit("drain"));
1851
- newWritable.on("error", (err) => transform.emit("error", err));
1994
+ // Re-connect event forwarding (data forwarding remains lazy via Transform.on)
1995
+ transform._setupSideForwarding();
1852
1996
  return transform;
1853
1997
  }
1854
1998
  /**
@@ -1905,7 +2049,13 @@ class Duplex extends event_emitter_1.EventEmitter {
1905
2049
  callback();
1906
2050
  }
1907
2051
  });
1908
- readable.on("error", err => duplex.emit("error", err));
2052
+ const onError = (err) => {
2053
+ duplex.emit("error", err);
2054
+ };
2055
+ const cleanupError = addEmitterListener(readable, "error", onError);
2056
+ addEmitterListener(readable, "end", cleanupError, { once: true });
2057
+ addEmitterListener(readable, "close", cleanupError, { once: true });
2058
+ addEmitterListener(sink, "finish", cleanupError, { once: true });
1909
2059
  readable.pipe(sink);
1910
2060
  };
1911
2061
  // If it has readable and/or writable properties
@@ -1913,21 +2063,25 @@ class Duplex extends event_emitter_1.EventEmitter {
1913
2063
  source !== null &&
1914
2064
  "readable" in source &&
1915
2065
  "writable" in source) {
1916
- const duplex = new Duplex();
1917
2066
  const pair = source;
1918
- if (pair.readable) {
1919
- forwardReadableToDuplex(pair.readable, duplex);
1920
- }
1921
- if (pair.writable) {
1922
- return new Duplex({
1923
- objectMode: duplex.writableObjectMode,
1924
- write(chunk, encoding, callback) {
2067
+ // Create one duplex that can bridge both sides.
2068
+ // (Previous behavior returned a new writable-only Duplex and dropped the readable side.)
2069
+ const duplex = new Duplex({
2070
+ readableObjectMode: pair.readable?.readableObjectMode,
2071
+ writableObjectMode: pair.writable?.writableObjectMode,
2072
+ write: pair.writable
2073
+ ? (chunk, encoding, callback) => {
1925
2074
  pair.writable.write(chunk, encoding, callback);
1926
- },
1927
- final(callback) {
2075
+ }
2076
+ : undefined,
2077
+ final: pair.writable
2078
+ ? callback => {
1928
2079
  pair.writable.end(callback);
1929
2080
  }
1930
- });
2081
+ : undefined
2082
+ });
2083
+ if (pair.readable) {
2084
+ forwardReadableToDuplex(pair.readable, duplex);
1931
2085
  }
1932
2086
  return duplex;
1933
2087
  }
@@ -1965,9 +2119,22 @@ class Duplex extends event_emitter_1.EventEmitter {
1965
2119
  */
1966
2120
  static fromWeb(pair, options) {
1967
2121
  const duplex = new Duplex(options);
1968
- // Replace internal streams
1969
- duplex._readable = new Readable({ stream: pair.readable });
1970
- duplex._writable = new Writable({ stream: pair.writable });
2122
+ const newReadable = new Readable({
2123
+ stream: pair.readable,
2124
+ objectMode: duplex.readableObjectMode
2125
+ });
2126
+ const newWritable = new Writable({
2127
+ stream: pair.writable,
2128
+ objectMode: duplex.writableObjectMode
2129
+ });
2130
+ if (duplex._sideForwardingCleanup) {
2131
+ duplex._sideForwardingCleanup();
2132
+ duplex._sideForwardingCleanup = null;
2133
+ }
2134
+ duplex._readable = newReadable;
2135
+ duplex._writable = newWritable;
2136
+ // Re-wire event forwarding (data forwarding remains lazy via Duplex.on)
2137
+ duplex._setupSideForwarding();
1971
2138
  return duplex;
1972
2139
  }
1973
2140
  /**
@@ -1983,6 +2150,7 @@ class Duplex extends event_emitter_1.EventEmitter {
1983
2150
  super();
1984
2151
  // Track if we've already set up data forwarding
1985
2152
  this._dataForwardingSetup = false;
2153
+ this._sideForwardingCleanup = null;
1986
2154
  this.allowHalfOpen = options?.allowHalfOpen ?? true;
1987
2155
  // Support shorthand objectMode option
1988
2156
  const objectMode = options?.objectMode ?? false;
@@ -1999,23 +2167,31 @@ class Duplex extends event_emitter_1.EventEmitter {
1999
2167
  write: options?.write?.bind(this),
2000
2168
  final: options?.final?.bind(this)
2001
2169
  });
2170
+ this._setupSideForwarding();
2171
+ }
2172
+ _setupSideForwarding() {
2173
+ if (this._sideForwardingCleanup) {
2174
+ this._sideForwardingCleanup();
2175
+ this._sideForwardingCleanup = null;
2176
+ }
2177
+ const registry = createListenerRegistry();
2002
2178
  // Forward non-data events (data forwarding is lazy to avoid premature flowing)
2003
- this._readable.on("end", () => {
2179
+ registry.once(this._readable, "end", () => {
2004
2180
  this.emit("end");
2005
- // If not allowHalfOpen, end the writable side too
2006
2181
  if (!this.allowHalfOpen) {
2007
2182
  this._writable.end();
2008
2183
  }
2009
2184
  });
2010
- this._readable.on("error", err => this.emit("error", err));
2011
- this._writable.on("finish", () => this.emit("finish"));
2012
- this._writable.on("drain", () => this.emit("drain"));
2013
- this._writable.on("close", () => {
2014
- // If not allowHalfOpen, destroy the readable side too
2185
+ registry.add(this._readable, "error", err => this.emit("error", err));
2186
+ registry.add(this._writable, "error", err => this.emit("error", err));
2187
+ registry.once(this._writable, "finish", () => this.emit("finish"));
2188
+ registry.add(this._writable, "drain", () => this.emit("drain"));
2189
+ registry.once(this._writable, "close", () => {
2015
2190
  if (!this.allowHalfOpen && !this._readable.destroyed) {
2016
2191
  this._readable.destroy();
2017
2192
  }
2018
2193
  });
2194
+ this._sideForwardingCleanup = () => registry.cleanup();
2019
2195
  }
2020
2196
  /**
2021
2197
  * Override on() to set up data forwarding lazily
@@ -2134,6 +2310,10 @@ class Duplex extends event_emitter_1.EventEmitter {
2134
2310
  * Destroy both sides
2135
2311
  */
2136
2312
  destroy(error) {
2313
+ if (this._sideForwardingCleanup) {
2314
+ this._sideForwardingCleanup();
2315
+ this._sideForwardingCleanup = null;
2316
+ }
2137
2317
  this._readable.destroy(error);
2138
2318
  this._writable.destroy(error);
2139
2319
  return this;
@@ -2275,64 +2455,22 @@ class Collector extends Writable {
2275
2455
  }
2276
2456
  exports.Collector = Collector;
2277
2457
  // =============================================================================
2278
- // PullStream / BufferedStream / DataChunk helpers
2279
- // =============================================================================
2280
- class PullStream extends pull_stream_1.PullStream {
2281
- // Keep constructor signature aligned with streams.browser.ts public API
2282
- constructor(options) {
2283
- super(options);
2284
- }
2285
- }
2286
- exports.PullStream = PullStream;
2287
- class StringChunk extends buffered_stream_1.StringChunk {
2288
- }
2289
- exports.StringChunk = StringChunk;
2290
- class BufferChunk extends buffered_stream_1.BufferChunk {
2291
- }
2292
- exports.BufferChunk = BufferChunk;
2293
- class BufferedStream extends buffered_stream_1.BufferedStream {
2294
- constructor(options) {
2295
- super(options);
2296
- }
2297
- }
2298
- exports.BufferedStream = BufferedStream;
2299
- // =============================================================================
2300
2458
  // Stream Creation Functions
2301
2459
  // =============================================================================
2302
2460
  /**
2303
2461
  * Create a readable stream with custom read implementation
2304
2462
  */
2305
2463
  function createReadable(options) {
2306
- const readable = new Readable(options);
2307
- // Override read behavior if provided
2308
- if (options?.read) {
2309
- const originalRead = readable.read.bind(readable);
2310
- readable.read = function (size) {
2311
- options.read(size ?? 16384);
2312
- return originalRead(size);
2313
- };
2314
- }
2315
- return readable;
2464
+ // Readable already supports Node-style `read()` via the constructor option.
2465
+ // Keep this helper minimal to avoid accidental double-read behavior.
2466
+ return new Readable(options);
2316
2467
  }
2317
2468
  /**
2318
2469
  * Create a readable stream from an async iterable
2319
2470
  */
2320
2471
  function createReadableFromAsyncIterable(iterable, options) {
2321
2472
  const readable = new Readable({ ...options, objectMode: options?.objectMode ?? true });
2322
- (async () => {
2323
- try {
2324
- for await (const chunk of iterable) {
2325
- if (!readable.push(chunk)) {
2326
- // Backpressure - wait a bit
2327
- await new Promise(resolve => setTimeout(resolve, 0));
2328
- }
2329
- }
2330
- readable.push(null);
2331
- }
2332
- catch (err) {
2333
- readable.destroy(err);
2334
- }
2335
- })();
2473
+ pumpAsyncIterableToReadable(readable, iterable);
2336
2474
  return readable;
2337
2475
  }
2338
2476
  /**
@@ -2361,38 +2499,8 @@ function createReadableFromArray(data, options) {
2361
2499
  * Create a writable stream with custom write implementation
2362
2500
  */
2363
2501
  function createWritable(options) {
2364
- // Create a custom WritableStream with user's handlers
2365
- const stream = new WritableStream({
2366
- write: async (chunk) => {
2367
- if (options?.write) {
2368
- return new Promise((resolve, reject) => {
2369
- options.write(chunk, "utf8", err => {
2370
- if (err) {
2371
- reject(err);
2372
- }
2373
- else {
2374
- resolve();
2375
- }
2376
- });
2377
- });
2378
- }
2379
- },
2380
- close: async () => {
2381
- if (options?.final) {
2382
- return new Promise((resolve, reject) => {
2383
- options.final(err => {
2384
- if (err) {
2385
- reject(err);
2386
- }
2387
- else {
2388
- resolve();
2389
- }
2390
- });
2391
- });
2392
- }
2393
- }
2394
- });
2395
- return new Writable({ ...options, stream });
2502
+ // Writable already supports Node-style `write()` / `final()` via the constructor.
2503
+ return new Writable(options);
2396
2504
  }
2397
2505
  /**
2398
2506
  * Create a transform stream from a transform function
@@ -2420,28 +2528,14 @@ function createPassThrough(options) {
2420
2528
  * Create a pull stream
2421
2529
  */
2422
2530
  function createPullStream(options) {
2423
- return new PullStream(options);
2531
+ return new pull_stream_1.PullStream(options);
2424
2532
  }
2425
2533
  /**
2426
2534
  * Create a buffered stream
2427
2535
  */
2428
2536
  function createBufferedStream(options) {
2429
- return new BufferedStream(options);
2537
+ return new buffered_stream_1.BufferedStream(options);
2430
2538
  }
2431
- const isReadableStream = (value) => !!value && typeof value === "object" && typeof value.getReader === "function";
2432
- const isAsyncIterable = (value) => {
2433
- if (!value || (typeof value !== "object" && typeof value !== "function")) {
2434
- return false;
2435
- }
2436
- return typeof value[Symbol.asyncIterator] === "function";
2437
- };
2438
- const isWritableStream = (value) => !!value && typeof value === "object" && typeof value.getWriter === "function";
2439
- const isTransformStream = (value) => !!value &&
2440
- typeof value === "object" &&
2441
- !!value.readable &&
2442
- !!value.writable &&
2443
- isReadableStream(value.readable) &&
2444
- isWritableStream(value.writable);
2445
2539
  const isPipelineOptions = (value) => {
2446
2540
  if (!value || typeof value !== "object") {
2447
2541
  return false;
@@ -2466,13 +2560,13 @@ const toBrowserPipelineStream = (stream) => {
2466
2560
  stream instanceof Duplex) {
2467
2561
  return stream;
2468
2562
  }
2469
- if (isTransformStream(stream)) {
2563
+ if ((0, type_guards_1.isTransformStream)(stream)) {
2470
2564
  return Transform.fromWeb(stream);
2471
2565
  }
2472
- if (isReadableStream(stream)) {
2566
+ if ((0, type_guards_1.isReadableStream)(stream)) {
2473
2567
  return Readable.fromWeb(stream);
2474
2568
  }
2475
- if (isWritableStream(stream)) {
2569
+ if ((0, type_guards_1.isWritableStream)(stream)) {
2476
2570
  return Writable.fromWeb(stream);
2477
2571
  }
2478
2572
  return stream;
@@ -2527,11 +2621,17 @@ function pipeline(...args) {
2527
2621
  const transforms = normalized.slice(1, -1);
2528
2622
  let completed = false;
2529
2623
  const allStreams = [source, ...transforms, destination];
2530
- const cleanup = (error) => {
2624
+ const registry = createListenerRegistry();
2625
+ let onAbort;
2626
+ const cleanupWithSignal = (error) => {
2531
2627
  if (completed) {
2532
2628
  return;
2533
2629
  }
2534
2630
  completed = true;
2631
+ registry.cleanup();
2632
+ if (onAbort && options.signal) {
2633
+ options.signal.removeEventListener("abort", onAbort);
2634
+ }
2535
2635
  // Destroy all streams on error
2536
2636
  if (error) {
2537
2637
  for (const stream of allStreams) {
@@ -2548,12 +2648,11 @@ function pipeline(...args) {
2548
2648
  // Handle abort signal
2549
2649
  if (options.signal) {
2550
2650
  if (options.signal.aborted) {
2551
- cleanup(new Error("Pipeline aborted"));
2651
+ cleanupWithSignal(new Error("Pipeline aborted"));
2552
2652
  return;
2553
2653
  }
2554
- options.signal.addEventListener("abort", () => {
2555
- cleanup(new Error("Pipeline aborted"));
2556
- });
2654
+ onAbort = () => cleanupWithSignal(new Error("Pipeline aborted"));
2655
+ options.signal.addEventListener("abort", onAbort);
2557
2656
  }
2558
2657
  // Chain the streams
2559
2658
  let current = source;
@@ -2567,13 +2666,35 @@ function pipeline(...args) {
2567
2666
  }
2568
2667
  else {
2569
2668
  // Don't end destination
2570
- current.on("data", chunk => destination.write(chunk));
2669
+ let paused = false;
2670
+ let waitingForDrain = false;
2671
+ const onDrain = () => {
2672
+ waitingForDrain = false;
2673
+ if (paused && typeof current.resume === "function") {
2674
+ paused = false;
2675
+ current.resume();
2676
+ }
2677
+ };
2678
+ const onData = (chunk) => {
2679
+ const ok = destination.write(chunk);
2680
+ if (!ok && !waitingForDrain) {
2681
+ waitingForDrain = true;
2682
+ if (!paused && typeof current.pause === "function") {
2683
+ paused = true;
2684
+ current.pause();
2685
+ }
2686
+ registry.once(destination, "drain", onDrain);
2687
+ }
2688
+ };
2689
+ const onEnd = () => cleanupWithSignal();
2690
+ registry.add(current, "data", onData);
2691
+ registry.once(current, "end", onEnd);
2571
2692
  }
2572
2693
  // Handle completion
2573
- destination.on("finish", () => cleanup());
2694
+ registry.once(destination, "finish", () => cleanupWithSignal());
2574
2695
  // Handle errors on all streams
2575
2696
  for (const stream of allStreams) {
2576
- stream.on("error", (err) => cleanup(err));
2697
+ registry.once(stream, "error", (err) => cleanupWithSignal(err));
2577
2698
  }
2578
2699
  });
2579
2700
  // If callback provided, use it
@@ -2613,11 +2734,20 @@ function finished(stream, optionsOrCallback, callback) {
2613
2734
  const promise = new Promise((resolve, reject) => {
2614
2735
  const normalizedStream = toBrowserPipelineStream(stream);
2615
2736
  let resolved = false;
2737
+ const registry = createListenerRegistry();
2738
+ let onAbort;
2739
+ const cleanup = () => {
2740
+ registry.cleanup();
2741
+ if (onAbort && options.signal) {
2742
+ options.signal.removeEventListener("abort", onAbort);
2743
+ }
2744
+ };
2616
2745
  const done = (err) => {
2617
2746
  if (resolved) {
2618
2747
  return;
2619
2748
  }
2620
2749
  resolved = true;
2750
+ cleanup();
2621
2751
  if (err && !options.error) {
2622
2752
  reject(err);
2623
2753
  }
@@ -2631,9 +2761,8 @@ function finished(stream, optionsOrCallback, callback) {
2631
2761
  done(new Error("Aborted"));
2632
2762
  return;
2633
2763
  }
2634
- options.signal.addEventListener("abort", () => {
2635
- done(new Error("Aborted"));
2636
- });
2764
+ onAbort = () => done(new Error("Aborted"));
2765
+ options.signal.addEventListener("abort", onAbort);
2637
2766
  }
2638
2767
  const checkReadable = options.readable !== false;
2639
2768
  const checkWritable = options.writable !== false;
@@ -2648,13 +2777,13 @@ function finished(stream, optionsOrCallback, callback) {
2648
2777
  }
2649
2778
  // Listen for events
2650
2779
  if (checkWritable) {
2651
- normalizedStream.on("finish", () => done());
2780
+ registry.once(normalizedStream, "finish", () => done());
2652
2781
  }
2653
2782
  if (checkReadable) {
2654
- normalizedStream.on("end", () => done());
2783
+ registry.once(normalizedStream, "end", () => done());
2655
2784
  }
2656
- normalizedStream.on("error", (err) => done(err));
2657
- normalizedStream.on("close", () => done());
2785
+ registry.once(normalizedStream, "error", (err) => done(err));
2786
+ registry.once(normalizedStream, "close", () => done());
2658
2787
  });
2659
2788
  // If callback provided, use it
2660
2789
  if (cb) {
@@ -2676,38 +2805,8 @@ async function streamToPromise(stream) {
2676
2805
  * (Browser equivalent of Node.js streamToBuffer)
2677
2806
  */
2678
2807
  async function streamToUint8Array(stream) {
2679
- let iterable;
2680
- if (isReadableStream(stream)) {
2681
- iterable = Readable.fromWeb(stream);
2682
- }
2683
- else if (isAsyncIterable(stream)) {
2684
- iterable = stream;
2685
- }
2686
- else {
2687
- throw new Error("streamToUint8Array: unsupported stream type");
2688
- }
2689
- const chunks = [];
2690
- let totalLength = 0;
2691
- for await (const chunk of iterable) {
2692
- chunks.push(chunk);
2693
- totalLength += chunk.length;
2694
- }
2695
- // Fast paths
2696
- const len = chunks.length;
2697
- if (len === 0) {
2698
- return new Uint8Array(0);
2699
- }
2700
- if (len === 1) {
2701
- return chunks[0];
2702
- }
2703
- // Use precalculated total length
2704
- const result = new Uint8Array(totalLength);
2705
- let offset = 0;
2706
- for (let i = 0; i < len; i++) {
2707
- result.set(chunks[i], offset);
2708
- offset += chunks[i].length;
2709
- }
2710
- return result;
2808
+ const [chunks, totalLength] = await collectStreamChunks(stream);
2809
+ return (0, shared_1.concatUint8Arrays)(chunks, totalLength);
2711
2810
  }
2712
2811
  /**
2713
2812
  * Alias for streamToUint8Array (Node.js compatibility)
@@ -2717,23 +2816,16 @@ exports.streamToBuffer = streamToUint8Array;
2717
2816
  * Collect all data from a readable stream into a string
2718
2817
  */
2719
2818
  async function streamToString(stream, encoding) {
2720
- const buffer = await streamToUint8Array(stream);
2721
- return (0, shared_1.getTextDecoder)(encoding).decode(buffer);
2819
+ const [chunks, totalLength] = await collectStreamChunks(stream);
2820
+ const combined = (0, shared_1.concatUint8Arrays)(chunks, totalLength);
2821
+ const decoder = encoding ? (0, shared_1.getTextDecoder)(encoding) : shared_1.textDecoder;
2822
+ return decoder.decode(combined);
2722
2823
  }
2723
2824
  /**
2724
2825
  * Drain a stream (consume all data without processing)
2725
2826
  */
2726
2827
  async function drainStream(stream) {
2727
- let iterable;
2728
- if (isReadableStream(stream)) {
2729
- iterable = Readable.fromWeb(stream);
2730
- }
2731
- else if (isAsyncIterable(stream)) {
2732
- iterable = stream;
2733
- }
2734
- else {
2735
- throw new Error("drainStream: unsupported stream type");
2736
- }
2828
+ const iterable = toReadableAsyncIterable(stream, "drainStream");
2737
2829
  for await (const _chunk of iterable) {
2738
2830
  // Consume data
2739
2831
  }
@@ -2806,14 +2898,19 @@ function addAbortSignal(signal, stream) {
2806
2898
  stream.destroy(new Error("Aborted"));
2807
2899
  return stream;
2808
2900
  }
2901
+ const cleanup = () => {
2902
+ signal.removeEventListener("abort", onAbort);
2903
+ removeEmitterListener(stream, "close", onClose);
2904
+ };
2809
2905
  const onAbort = () => {
2906
+ cleanup();
2810
2907
  stream.destroy(new Error("Aborted"));
2811
2908
  };
2812
- signal.addEventListener("abort", onAbort, { once: true });
2813
- // Clean up when stream is destroyed
2814
- stream.on("close", () => {
2815
- signal.removeEventListener("abort", onAbort);
2816
- });
2909
+ const onClose = () => {
2910
+ cleanup();
2911
+ };
2912
+ signal.addEventListener("abort", onAbort);
2913
+ addEmitterListener(stream, "close", onClose, { once: true });
2817
2914
  return stream;
2818
2915
  }
2819
2916
  /**
@@ -2822,60 +2919,68 @@ function addAbortSignal(signal, stream) {
2822
2919
  function createDuplex(options) {
2823
2920
  const readableObjectMode = options?.readableObjectMode ?? options?.objectMode;
2824
2921
  const writableObjectMode = options?.writableObjectMode ?? options?.objectMode;
2922
+ const underlyingWritable = options?.writable;
2825
2923
  const duplex = new Duplex({
2826
2924
  allowHalfOpen: options?.allowHalfOpen,
2827
2925
  readableHighWaterMark: options?.readableHighWaterMark,
2828
2926
  writableHighWaterMark: options?.writableHighWaterMark,
2829
2927
  readableObjectMode,
2830
- writableObjectMode
2928
+ writableObjectMode,
2929
+ read: options?.read,
2930
+ write: options?.write ??
2931
+ (underlyingWritable
2932
+ ? (chunk, encoding, callback) => {
2933
+ if (typeof underlyingWritable.write === "function") {
2934
+ underlyingWritable.write(chunk, encoding, callback);
2935
+ return;
2936
+ }
2937
+ // Best-effort sync sink
2938
+ try {
2939
+ underlyingWritable.write?.(chunk);
2940
+ callback(null);
2941
+ }
2942
+ catch (err) {
2943
+ callback(err);
2944
+ }
2945
+ }
2946
+ : undefined),
2947
+ final: options?.final ??
2948
+ (underlyingWritable
2949
+ ? (callback) => {
2950
+ if (typeof underlyingWritable.end === "function") {
2951
+ underlyingWritable.end((err) => callback(err ?? null));
2952
+ }
2953
+ else {
2954
+ underlyingWritable.end?.();
2955
+ callback(null);
2956
+ }
2957
+ }
2958
+ : undefined)
2831
2959
  });
2832
- // If custom readable/writable provided, pipe them
2960
+ // If an underlying readable is provided, forward it into the duplex readable side.
2833
2961
  if (options?.readable) {
2834
2962
  const readable = options.readable;
2835
- readable.on?.("data", (chunk) => duplex.push(chunk));
2836
- readable.on?.("end", () => duplex.push(null));
2837
- readable.on?.("error", (err) => duplex.destroy(err));
2838
- }
2839
- if (options?.writable) {
2840
- const writable = options.writable;
2841
- duplex.on("data", (chunk) => writable.write?.(chunk));
2842
- duplex.on("finish", () => writable.end?.());
2843
- }
2844
- // If custom read/write/final provided, override methods
2845
- if (options?.write) {
2846
- const _originalWrite = duplex.write.bind(duplex); // Keep bound reference for potential future use
2847
- duplex.write = function (chunk, encodingOrCallback, callback) {
2848
- const encoding = typeof encodingOrCallback === "string" ? encodingOrCallback : "utf8";
2849
- const cb = typeof encodingOrCallback === "function" ? encodingOrCallback : (callback ?? (() => { }));
2850
- options.write.call(duplex, chunk, encoding, cb);
2851
- return true;
2852
- };
2853
- }
2854
- if (options?.final) {
2855
- const originalEnd = duplex.end.bind(duplex);
2856
- duplex.end = function (chunkOrCallback, encodingOrCallback, callback) {
2857
- const cb = typeof chunkOrCallback === "function"
2858
- ? chunkOrCallback
2859
- : typeof encodingOrCallback === "function"
2860
- ? encodingOrCallback
2861
- : (callback ?? (() => { }));
2862
- if (chunkOrCallback !== undefined && typeof chunkOrCallback !== "function") {
2863
- duplex.write(chunkOrCallback);
2864
- }
2865
- // Call custom final handler
2866
- options.final.call(duplex, (err) => {
2867
- if (err) {
2868
- duplex.emit("error", err);
2869
- }
2870
- else {
2871
- duplex.emit("finish");
2872
- }
2873
- // Call original end to properly close writable side
2874
- originalEnd();
2875
- cb();
2876
- });
2877
- return duplex;
2878
- };
2963
+ const sink = new Writable({
2964
+ objectMode: duplex.readableObjectMode,
2965
+ write(chunk, _encoding, callback) {
2966
+ duplex.push(chunk);
2967
+ callback(null);
2968
+ },
2969
+ final(callback) {
2970
+ duplex.push(null);
2971
+ callback(null);
2972
+ }
2973
+ });
2974
+ if (typeof readable?.on === "function") {
2975
+ const onError = (err) => {
2976
+ duplex.destroy(err);
2977
+ };
2978
+ const cleanupError = addEmitterListener(readable, "error", onError);
2979
+ addEmitterListener(readable, "end", cleanupError, { once: true });
2980
+ addEmitterListener(readable, "close", cleanupError, { once: true });
2981
+ addEmitterListener(sink, "finish", cleanupError, { once: true });
2982
+ }
2983
+ readable.pipe?.(sink);
2879
2984
  }
2880
2985
  if (options?.destroy) {
2881
2986
  const originalDestroy = duplex.destroy.bind(duplex);
@@ -2899,20 +3004,7 @@ function createDuplex(options) {
2899
3004
  */
2900
3005
  function createReadableFromGenerator(generator, options) {
2901
3006
  const readable = new Readable({ ...options, objectMode: options?.objectMode ?? true });
2902
- (async () => {
2903
- try {
2904
- for await (const chunk of generator()) {
2905
- if (!readable.push(chunk)) {
2906
- // Backpressure
2907
- await new Promise(resolve => setTimeout(resolve, 0));
2908
- }
2909
- }
2910
- readable.push(null);
2911
- }
2912
- catch (err) {
2913
- readable.destroy(err);
2914
- }
2915
- })();
3007
+ pumpAsyncIterableToReadable(readable, generator());
2916
3008
  return readable;
2917
3009
  }
2918
3010
  /**
@@ -2942,8 +3034,8 @@ function compose(...transforms) {
2942
3034
  transform: chunk => chunk
2943
3035
  });
2944
3036
  }
2945
- const isNativeTransform = (stream) => stream instanceof Transform;
2946
- if (len === 1 && isNativeTransform(transforms[0])) {
3037
+ // Preserve identity: compose(single) returns the same transform.
3038
+ if (len === 1) {
2947
3039
  return transforms[0];
2948
3040
  }
2949
3041
  // Chain the transforms: first → second → ... → last
@@ -2953,74 +3045,118 @@ function compose(...transforms) {
2953
3045
  for (let i = 0; i < len - 1; i++) {
2954
3046
  transforms[i].pipe(transforms[i + 1]);
2955
3047
  }
2956
- class ComposedTransform extends Transform {
2957
- constructor() {
2958
- super(...arguments);
2959
- this._dataForwarding = false;
2960
- this._endForwarding = false;
3048
+ // A lightweight Transform wrapper that delegates:
3049
+ // - writable side to `first`
3050
+ // - readable side to `last`
3051
+ // It forwards relevant events lazily to avoid per-chunk overhead when unused.
3052
+ const composed = new Transform({
3053
+ objectMode: first?.objectMode ?? true,
3054
+ transform: chunk => chunk
3055
+ });
3056
+ const registry = createListenerRegistry();
3057
+ // Always forward errors; they are critical for pipeline semantics.
3058
+ for (const t of transforms) {
3059
+ registry.add(t, "error", (err) => composed.emit("error", err));
3060
+ }
3061
+ // Forward writable-side backpressure/completion events from `first`.
3062
+ registry.add(first, "drain", () => composed.emit("drain"));
3063
+ registry.once(first, "finish", () => composed.emit("finish"));
3064
+ // Forward readable-side events from `last` lazily.
3065
+ let forwardData = false;
3066
+ let forwardEnd = false;
3067
+ let forwardReadable = false;
3068
+ const ensureDataForwarding = () => {
3069
+ if (forwardData) {
3070
+ return;
2961
3071
  }
2962
- on(event, listener) {
2963
- if (event === "data" && !this._dataForwarding) {
2964
- this._dataForwarding = true;
2965
- last.on("data", (chunk) => this.emit("data", chunk));
2966
- }
2967
- if (event === "end" && !this._endForwarding) {
2968
- this._endForwarding = true;
2969
- last.on("end", () => this.emit("end"));
2970
- }
2971
- return super.on(event, listener);
3072
+ forwardData = true;
3073
+ registry.add(last, "data", (chunk) => composed.emit("data", chunk));
3074
+ };
3075
+ const ensureEndForwarding = () => {
3076
+ if (forwardEnd) {
3077
+ return;
2972
3078
  }
2973
- write(chunk, encodingOrCallback, callback) {
2974
- if (typeof encodingOrCallback === "function") {
2975
- return first.write(chunk, encodingOrCallback);
2976
- }
2977
- return first.write(chunk, encodingOrCallback, callback);
3079
+ forwardEnd = true;
3080
+ registry.once(last, "end", () => composed.emit("end"));
3081
+ };
3082
+ const ensureReadableForwarding = () => {
3083
+ if (forwardReadable) {
3084
+ return;
2978
3085
  }
2979
- end(chunkOrCallback, encodingOrCallback, callback) {
2980
- if (typeof chunkOrCallback === "function") {
2981
- first.end(chunkOrCallback);
2982
- return this;
2983
- }
2984
- if (typeof encodingOrCallback === "function") {
2985
- first.end(chunkOrCallback, encodingOrCallback);
2986
- return this;
2987
- }
2988
- first.end(chunkOrCallback, encodingOrCallback, callback);
2989
- return this;
3086
+ forwardReadable = true;
3087
+ registry.add(last, "readable", () => composed.emit("readable"));
3088
+ };
3089
+ const originalOn = composed.on.bind(composed);
3090
+ const originalOnce = composed.once.bind(composed);
3091
+ composed.on = (event, listener) => {
3092
+ if (event === "data") {
3093
+ ensureDataForwarding();
2990
3094
  }
2991
- pipe(destination) {
2992
- return last.pipe(destination);
3095
+ else if (event === "end") {
3096
+ ensureEndForwarding();
2993
3097
  }
2994
- destroy(error) {
2995
- for (const t of transforms) {
2996
- t.destroy(error);
2997
- }
2998
- super.destroy(error);
3098
+ else if (event === "readable") {
3099
+ ensureReadableForwarding();
3100
+ }
3101
+ return originalOn(event, listener);
3102
+ };
3103
+ composed.once = (event, listener) => {
3104
+ if (event === "data") {
3105
+ ensureDataForwarding();
2999
3106
  }
3000
- read(size) {
3001
- return typeof last.read === "function" ? last.read(size) : null;
3107
+ else if (event === "end") {
3108
+ ensureEndForwarding();
3002
3109
  }
3003
- async *[Symbol.asyncIterator]() {
3004
- const it = last?.[Symbol.asyncIterator]?.();
3005
- if (it) {
3006
- for await (const chunk of it) {
3007
- yield chunk;
3008
- }
3009
- return;
3110
+ else if (event === "readable") {
3111
+ ensureReadableForwarding();
3112
+ }
3113
+ return originalOnce(event, listener);
3114
+ };
3115
+ // Delegate core stream methods
3116
+ const firstAny = first;
3117
+ const lastAny = last;
3118
+ composed.write = (chunk, encodingOrCallback, callback) => {
3119
+ if (typeof encodingOrCallback === "function") {
3120
+ return firstAny.write(chunk, encodingOrCallback);
3121
+ }
3122
+ return firstAny.write(chunk, encodingOrCallback, callback);
3123
+ };
3124
+ composed.end = (chunkOrCallback, encodingOrCallback, callback) => {
3125
+ if (typeof chunkOrCallback === "function") {
3126
+ firstAny.end(chunkOrCallback);
3127
+ return composed;
3128
+ }
3129
+ if (typeof encodingOrCallback === "function") {
3130
+ firstAny.end(chunkOrCallback, encodingOrCallback);
3131
+ return composed;
3132
+ }
3133
+ firstAny.end(chunkOrCallback, encodingOrCallback, callback);
3134
+ return composed;
3135
+ };
3136
+ composed.pipe = (destination) => {
3137
+ return lastAny.pipe(destination);
3138
+ };
3139
+ composed.read = (size) => {
3140
+ return typeof lastAny.read === "function" ? lastAny.read(size) : null;
3141
+ };
3142
+ composed[Symbol.asyncIterator] = async function* () {
3143
+ const it = lastAny?.[Symbol.asyncIterator]?.();
3144
+ if (it) {
3145
+ for await (const chunk of it) {
3146
+ yield chunk;
3010
3147
  }
3011
- yield* super[Symbol.asyncIterator]();
3148
+ return;
3012
3149
  }
3013
- }
3014
- const composed = new ComposedTransform({
3015
- objectMode: first?.objectMode ?? true,
3016
- transform: chunk => chunk
3150
+ yield* Transform.prototype[Symbol.asyncIterator].call(composed);
3151
+ };
3152
+ const originalDestroy = composed.destroy.bind(composed);
3153
+ composed.destroy = ((error) => {
3154
+ registry.cleanup();
3155
+ for (const t of transforms) {
3156
+ t.destroy(error);
3157
+ }
3158
+ originalDestroy(error);
3017
3159
  });
3018
- // Forward errors from any transform
3019
- for (const t of transforms) {
3020
- t.on("error", (err) => {
3021
- composed.emit("error", err);
3022
- });
3023
- }
3024
3160
  // Reflect underlying readability/writability like the previous duck-typed wrapper
3025
3161
  Object.defineProperty(composed, "readable", {
3026
3162
  get: () => last.readable
@@ -3266,77 +3402,54 @@ function duplexPair(options) {
3266
3402
  async function collectStreamChunks(stream) {
3267
3403
  const chunks = [];
3268
3404
  let totalLength = 0;
3269
- let iterable;
3270
- if (isReadableStream(stream)) {
3271
- iterable = Readable.fromWeb(stream);
3272
- }
3273
- else if (isAsyncIterable(stream)) {
3274
- iterable = stream;
3275
- }
3276
- else {
3277
- throw new Error("collectStreamChunks: unsupported stream type");
3278
- }
3405
+ const iterable = toReadableAsyncIterable(stream, "collectStreamChunks");
3279
3406
  for await (const chunk of iterable) {
3280
3407
  chunks.push(chunk);
3281
3408
  totalLength += chunk.length;
3282
3409
  }
3283
- return { chunks, totalLength };
3410
+ return [chunks, totalLength];
3284
3411
  }
3285
- // Helper to concatenate with known length (faster)
3286
- function concatWithLength(chunks, totalLength) {
3287
- const len = chunks.length;
3288
- if (len === 0) {
3289
- return new Uint8Array(0);
3290
- }
3291
- if (len === 1) {
3292
- return chunks[0];
3412
+ function toReadableAsyncIterable(stream, name) {
3413
+ if ((0, type_guards_1.isReadableStream)(stream)) {
3414
+ return Readable.fromWeb(stream);
3293
3415
  }
3294
- const result = new Uint8Array(totalLength);
3295
- let offset = 0;
3296
- for (let i = 0; i < len; i++) {
3297
- result.set(chunks[i], offset);
3298
- offset += chunks[i].length;
3416
+ if ((0, type_guards_1.isAsyncIterable)(stream)) {
3417
+ return stream;
3299
3418
  }
3300
- return result;
3419
+ throw new Error(`${name}: unsupported stream type`);
3301
3420
  }
3302
3421
  exports.consumers = {
3303
3422
  /**
3304
3423
  * Consume entire stream as ArrayBuffer
3305
3424
  */
3306
3425
  async arrayBuffer(stream) {
3307
- const { chunks, totalLength } = await collectStreamChunks(stream);
3308
- const combined = concatWithLength(chunks, totalLength);
3309
- return combined.buffer.slice(combined.byteOffset, combined.byteOffset + combined.byteLength);
3426
+ const bytes = await streamToUint8Array(stream);
3427
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
3310
3428
  },
3311
3429
  /**
3312
3430
  * Consume entire stream as Blob
3313
3431
  */
3314
3432
  async blob(stream, options) {
3315
- const { chunks } = await collectStreamChunks(stream);
3433
+ const [chunks] = await collectStreamChunks(stream);
3316
3434
  return new Blob(chunks, options);
3317
3435
  },
3318
3436
  /**
3319
3437
  * Consume entire stream as Buffer (Uint8Array in browser)
3320
3438
  */
3321
3439
  async buffer(stream) {
3322
- const { chunks, totalLength } = await collectStreamChunks(stream);
3323
- return concatWithLength(chunks, totalLength);
3440
+ return streamToUint8Array(stream);
3324
3441
  },
3325
3442
  /**
3326
3443
  * Consume entire stream as JSON
3327
3444
  */
3328
3445
  async json(stream) {
3329
- const text = await exports.consumers.text(stream);
3330
- return JSON.parse(text);
3446
+ return JSON.parse(await streamToString(stream));
3331
3447
  },
3332
3448
  /**
3333
3449
  * Consume entire stream as text
3334
3450
  */
3335
3451
  async text(stream, encoding) {
3336
- const { chunks, totalLength } = await collectStreamChunks(stream);
3337
- const combined = concatWithLength(chunks, totalLength);
3338
- const decoder = encoding ? (0, shared_1.getTextDecoder)(encoding) : shared_1.textDecoder;
3339
- return decoder.decode(combined);
3452
+ return streamToString(stream, encoding);
3340
3453
  }
3341
3454
  };
3342
3455
  // =============================================================================