@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.
- package/THIRD_PARTY_NOTICES.md +0 -31
- package/dist/browser/index.browser.d.ts +1 -0
- package/dist/browser/index.browser.js +12 -0
- package/dist/{types/modules/archive → browser/modules/archive/compression}/compress.base.d.ts +1 -0
- package/dist/browser/modules/archive/{compress.base.js → compression/compress.base.js} +2 -1
- package/dist/{types/modules/archive → browser/modules/archive/compression}/compress.browser.d.ts +10 -8
- package/dist/{esm/modules/archive → browser/modules/archive/compression}/compress.browser.js +18 -19
- package/dist/browser/modules/archive/{compress.d.ts → compression/compress.d.ts} +2 -2
- package/dist/browser/modules/archive/{compress.js → compression/compress.js} +1 -1
- package/dist/browser/modules/archive/{crc32.browser.d.ts → compression/crc32.browser.d.ts} +1 -1
- package/dist/browser/modules/archive/{crc32.d.ts → compression/crc32.d.ts} +1 -1
- package/dist/browser/modules/archive/{crc32.js → compression/crc32.js} +1 -1
- package/dist/browser/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
- package/dist/browser/modules/archive/{streaming-compress.browser.d.ts → compression/streaming-compress.browser.d.ts} +2 -2
- package/dist/browser/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
- package/dist/browser/modules/archive/{streaming-compress.d.ts → compression/streaming-compress.d.ts} +2 -2
- package/dist/browser/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
- package/dist/browser/modules/archive/defaults.d.ts +1 -0
- package/dist/browser/modules/archive/defaults.js +6 -3
- package/dist/browser/modules/archive/index.base.d.ts +4 -4
- package/dist/browser/modules/archive/index.base.js +3 -6
- package/dist/browser/modules/archive/index.browser.d.ts +3 -4
- package/dist/browser/modules/archive/index.browser.js +3 -7
- package/dist/browser/modules/archive/index.d.ts +3 -4
- package/dist/browser/modules/archive/index.js +3 -5
- package/dist/browser/modules/archive/internal/byte-queue.d.ts +33 -0
- package/dist/browser/modules/archive/internal/byte-queue.js +407 -0
- package/dist/browser/modules/archive/io/archive-sink.d.ts +8 -0
- package/dist/browser/modules/archive/io/archive-sink.js +45 -0
- package/dist/browser/modules/archive/io/archive-source.d.ts +6 -0
- package/dist/browser/modules/archive/io/archive-source.js +100 -0
- package/dist/browser/modules/archive/{extract.d.ts → unzip/extract.d.ts} +2 -2
- package/dist/browser/modules/archive/unzip/index.d.ts +40 -0
- package/dist/browser/modules/archive/unzip/index.js +164 -0
- package/dist/browser/modules/archive/{parse.base.d.ts → unzip/stream.base.d.ts} +58 -3
- package/dist/browser/modules/archive/unzip/stream.base.js +1022 -0
- package/dist/browser/modules/archive/{parse.browser.d.ts → unzip/stream.browser.d.ts} +1 -1
- package/dist/browser/modules/archive/{parse.browser.js → unzip/stream.browser.js} +376 -110
- package/dist/browser/modules/archive/{parse.d.ts → unzip/stream.d.ts} +2 -2
- package/dist/{esm/modules/archive/parse.js → browser/modules/archive/unzip/stream.js} +7 -6
- package/dist/{types/modules/archive → browser/modules/archive/unzip}/zip-parser.d.ts +1 -1
- package/dist/{esm/modules/archive → browser/modules/archive/unzip}/zip-parser.js +38 -24
- package/dist/browser/modules/archive/utils/async-queue.d.ts +7 -0
- package/dist/browser/modules/archive/utils/async-queue.js +103 -0
- package/dist/browser/modules/archive/utils/bytes.js +16 -16
- package/dist/browser/modules/archive/utils/compressibility.d.ts +10 -0
- package/dist/browser/modules/archive/utils/compressibility.js +57 -0
- package/dist/browser/modules/archive/utils/parse-buffer.js +21 -23
- package/dist/browser/modules/archive/utils/pattern-scanner.d.ts +21 -0
- package/dist/browser/modules/archive/utils/pattern-scanner.js +27 -0
- package/dist/browser/modules/archive/utils/timestamps.js +62 -1
- package/dist/browser/modules/archive/utils/zip-extra-fields.d.ts +1 -1
- package/dist/browser/modules/archive/utils/zip-extra-fields.js +26 -14
- package/dist/browser/modules/archive/zip/index.d.ts +42 -0
- package/dist/browser/modules/archive/zip/index.js +157 -0
- package/dist/browser/modules/archive/{streaming-zip.d.ts → zip/stream.d.ts} +28 -5
- package/dist/browser/modules/archive/{streaming-zip.js → zip/stream.js} +192 -48
- package/dist/browser/modules/archive/zip/zip-bytes.d.ts +73 -0
- package/dist/browser/modules/archive/zip/zip-bytes.js +239 -0
- package/dist/{esm/modules/archive → browser/modules/archive/zip}/zip-entry-metadata.js +3 -3
- package/dist/browser/modules/archive/{zip-records.d.ts → zip-spec/zip-records.d.ts} +20 -0
- package/dist/browser/modules/archive/zip-spec/zip-records.js +126 -0
- package/dist/browser/modules/excel/form-control.d.ts +2 -0
- package/dist/browser/modules/excel/form-control.js +54 -16
- package/dist/browser/modules/excel/stream/workbook-reader.browser.js +1 -1
- package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +1 -1
- package/dist/browser/modules/excel/stream/workbook-writer.browser.js +1 -1
- package/dist/browser/modules/excel/utils/ooxml-validator.d.ts +48 -0
- package/dist/browser/modules/excel/utils/ooxml-validator.js +469 -0
- package/dist/browser/modules/excel/worksheet.js +5 -2
- package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
- package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +117 -5
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +3 -6
- package/dist/browser/modules/excel/xlsx/xlsx.js +1 -1
- package/dist/browser/modules/stream/base-transform.d.ts +3 -0
- package/dist/browser/modules/stream/base-transform.js +34 -20
- package/dist/browser/modules/stream/buffered-stream.d.ts +2 -12
- package/dist/browser/modules/stream/chunked-builder.js +4 -4
- package/dist/browser/modules/stream/index.browser.d.ts +13 -19
- package/dist/browser/modules/stream/index.browser.js +10 -22
- package/dist/browser/modules/stream/index.d.ts +18 -41
- package/dist/browser/modules/stream/index.js +15 -44
- package/dist/browser/modules/stream/internal/event-utils.d.ts +17 -0
- package/dist/browser/modules/stream/internal/event-utils.js +40 -0
- package/dist/browser/modules/stream/internal/type-guards.d.ts +9 -0
- package/dist/browser/modules/stream/internal/type-guards.js +24 -0
- package/dist/browser/modules/stream/pull-stream.d.ts +5 -6
- package/dist/browser/modules/stream/pull-stream.js +107 -43
- package/dist/browser/modules/stream/shared.d.ts +1 -1
- package/dist/browser/modules/stream/shared.js +7 -4
- package/dist/browser/modules/stream/streams.browser.d.ts +32 -42
- package/dist/browser/modules/stream/streams.browser.js +941 -823
- package/dist/browser/modules/stream/streams.d.ts +4 -20
- package/dist/browser/modules/stream/streams.js +146 -95
- package/dist/browser/modules/stream/utils.js +5 -38
- package/dist/cjs/modules/archive/{compress.base.js → compression/compress.base.js} +2 -1
- package/dist/cjs/modules/archive/{compress.browser.js → compression/compress.browser.js} +18 -19
- package/dist/cjs/modules/archive/{compress.js → compression/compress.js} +1 -1
- package/dist/cjs/modules/archive/{crc32.js → compression/crc32.js} +1 -1
- package/dist/cjs/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
- package/dist/cjs/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
- package/dist/cjs/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
- package/dist/cjs/modules/archive/defaults.js +7 -4
- package/dist/cjs/modules/archive/index.base.js +9 -19
- package/dist/cjs/modules/archive/index.browser.js +4 -10
- package/dist/cjs/modules/archive/index.js +4 -8
- package/dist/cjs/modules/archive/internal/byte-queue.js +411 -0
- package/dist/cjs/modules/archive/io/archive-sink.js +49 -0
- package/dist/cjs/modules/archive/io/archive-source.js +105 -0
- package/dist/cjs/modules/archive/unzip/index.js +170 -0
- package/dist/cjs/modules/archive/unzip/stream.base.js +1044 -0
- package/dist/cjs/modules/archive/{parse.browser.js → unzip/stream.browser.js} +377 -111
- package/dist/cjs/modules/archive/{parse.js → unzip/stream.js} +9 -8
- package/dist/cjs/modules/archive/{zip-parser.js → unzip/zip-parser.js} +47 -33
- package/dist/cjs/modules/archive/utils/async-queue.js +106 -0
- package/dist/cjs/modules/archive/utils/bytes.js +16 -16
- package/dist/cjs/modules/archive/utils/compressibility.js +60 -0
- package/dist/cjs/modules/archive/utils/parse-buffer.js +21 -23
- package/dist/cjs/modules/archive/utils/pattern-scanner.js +31 -0
- package/dist/cjs/modules/archive/utils/timestamps.js +64 -3
- package/dist/cjs/modules/archive/utils/zip-extra-fields.js +26 -14
- package/dist/cjs/modules/archive/zip/index.js +162 -0
- package/dist/cjs/modules/archive/{streaming-zip.js → zip/stream.js} +194 -50
- package/dist/cjs/modules/archive/zip/zip-bytes.js +242 -0
- package/dist/cjs/modules/archive/{zip-entry-metadata.js → zip/zip-entry-metadata.js} +5 -5
- package/dist/cjs/modules/archive/zip-spec/zip-records.js +136 -0
- package/dist/cjs/modules/excel/form-control.js +54 -16
- package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +2 -2
- package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +4 -4
- package/dist/cjs/modules/excel/utils/ooxml-validator.js +475 -0
- package/dist/cjs/modules/excel/worksheet.js +5 -2
- package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/sp-xform.js +115 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
- package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
- package/dist/cjs/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +117 -5
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +6 -9
- package/dist/cjs/modules/excel/xlsx/xlsx.js +2 -2
- package/dist/cjs/modules/stream/base-transform.js +34 -20
- package/dist/cjs/modules/stream/chunked-builder.js +4 -4
- package/dist/cjs/modules/stream/index.browser.js +10 -17
- package/dist/cjs/modules/stream/index.js +15 -39
- package/dist/cjs/modules/stream/internal/event-utils.js +43 -0
- package/dist/cjs/modules/stream/internal/type-guards.js +30 -0
- package/dist/cjs/modules/stream/pull-stream.js +107 -43
- package/dist/cjs/modules/stream/shared.js +7 -4
- package/dist/cjs/modules/stream/streams.browser.js +947 -834
- package/dist/cjs/modules/stream/streams.js +156 -107
- package/dist/cjs/modules/stream/utils.js +3 -36
- package/dist/esm/index.browser.js +12 -0
- package/dist/esm/modules/archive/{compress.base.js → compression/compress.base.js} +2 -1
- package/dist/{browser/modules/archive → esm/modules/archive/compression}/compress.browser.js +18 -19
- package/dist/esm/modules/archive/{compress.js → compression/compress.js} +1 -1
- package/dist/esm/modules/archive/{crc32.js → compression/crc32.js} +1 -1
- package/dist/esm/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
- package/dist/esm/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
- package/dist/esm/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
- package/dist/esm/modules/archive/defaults.js +6 -3
- package/dist/esm/modules/archive/index.base.js +3 -6
- package/dist/esm/modules/archive/index.browser.js +3 -7
- package/dist/esm/modules/archive/index.js +3 -5
- package/dist/esm/modules/archive/internal/byte-queue.js +407 -0
- package/dist/esm/modules/archive/io/archive-sink.js +45 -0
- package/dist/esm/modules/archive/io/archive-source.js +100 -0
- package/dist/esm/modules/archive/unzip/index.js +164 -0
- package/dist/esm/modules/archive/unzip/stream.base.js +1022 -0
- package/dist/esm/modules/archive/{parse.browser.js → unzip/stream.browser.js} +376 -110
- package/dist/{browser/modules/archive/parse.js → esm/modules/archive/unzip/stream.js} +7 -6
- package/dist/{browser/modules/archive → esm/modules/archive/unzip}/zip-parser.js +38 -24
- package/dist/esm/modules/archive/utils/async-queue.js +103 -0
- package/dist/esm/modules/archive/utils/bytes.js +16 -16
- package/dist/esm/modules/archive/utils/compressibility.js +57 -0
- package/dist/esm/modules/archive/utils/parse-buffer.js +21 -23
- package/dist/esm/modules/archive/utils/pattern-scanner.js +27 -0
- package/dist/esm/modules/archive/utils/timestamps.js +62 -1
- package/dist/esm/modules/archive/utils/zip-extra-fields.js +26 -14
- package/dist/esm/modules/archive/zip/index.js +157 -0
- package/dist/esm/modules/archive/{streaming-zip.js → zip/stream.js} +192 -48
- package/dist/esm/modules/archive/zip/zip-bytes.js +239 -0
- package/dist/{browser/modules/archive → esm/modules/archive/zip}/zip-entry-metadata.js +3 -3
- package/dist/esm/modules/archive/zip-spec/zip-records.js +126 -0
- package/dist/esm/modules/excel/form-control.js +54 -16
- package/dist/esm/modules/excel/stream/workbook-reader.browser.js +1 -1
- package/dist/esm/modules/excel/stream/workbook-writer.browser.js +1 -1
- package/dist/esm/modules/excel/utils/ooxml-validator.js +469 -0
- package/dist/esm/modules/excel/worksheet.js +5 -2
- package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
- package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
- package/dist/esm/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +117 -5
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +3 -6
- package/dist/esm/modules/excel/xlsx/xlsx.js +1 -1
- package/dist/esm/modules/stream/base-transform.js +34 -20
- package/dist/esm/modules/stream/chunked-builder.js +4 -4
- package/dist/esm/modules/stream/index.browser.js +10 -22
- package/dist/esm/modules/stream/index.js +15 -44
- package/dist/esm/modules/stream/internal/event-utils.js +40 -0
- package/dist/esm/modules/stream/internal/type-guards.js +24 -0
- package/dist/esm/modules/stream/pull-stream.js +107 -43
- package/dist/esm/modules/stream/shared.js +7 -4
- package/dist/esm/modules/stream/streams.browser.js +941 -823
- package/dist/esm/modules/stream/streams.js +146 -95
- package/dist/esm/modules/stream/utils.js +5 -38
- package/dist/iife/THIRD_PARTY_NOTICES.md +81 -0
- package/dist/iife/excelts.iife.js +4979 -2800
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +103 -31
- package/dist/types/index.browser.d.ts +1 -0
- package/dist/{browser/modules/archive → types/modules/archive/compression}/compress.base.d.ts +1 -0
- package/dist/{browser/modules/archive → types/modules/archive/compression}/compress.browser.d.ts +10 -8
- package/dist/types/modules/archive/{streaming-compress.browser.d.ts → compression/streaming-compress.browser.d.ts} +1 -1
- package/dist/types/modules/archive/defaults.d.ts +1 -0
- package/dist/types/modules/archive/index.base.d.ts +4 -4
- package/dist/types/modules/archive/index.browser.d.ts +3 -4
- package/dist/types/modules/archive/index.d.ts +3 -4
- package/dist/types/modules/archive/internal/byte-queue.d.ts +33 -0
- package/dist/types/modules/archive/io/archive-sink.d.ts +8 -0
- package/dist/types/modules/archive/io/archive-source.d.ts +6 -0
- package/dist/types/modules/archive/unzip/index.d.ts +40 -0
- package/dist/types/modules/archive/{parse.base.d.ts → unzip/stream.base.d.ts} +60 -5
- package/dist/types/modules/archive/{parse.browser.d.ts → unzip/stream.browser.d.ts} +2 -2
- package/dist/types/modules/archive/{parse.d.ts → unzip/stream.d.ts} +3 -3
- package/dist/{browser/modules/archive → types/modules/archive/unzip}/zip-parser.d.ts +1 -1
- package/dist/types/modules/archive/utils/async-queue.d.ts +7 -0
- package/dist/types/modules/archive/utils/compressibility.d.ts +10 -0
- package/dist/types/modules/archive/utils/pattern-scanner.d.ts +21 -0
- package/dist/types/modules/archive/utils/zip-extra-fields.d.ts +1 -1
- package/dist/types/modules/archive/zip/index.d.ts +42 -0
- package/dist/types/modules/archive/{streaming-zip.d.ts → zip/stream.d.ts} +29 -6
- package/dist/types/modules/archive/zip/zip-bytes.d.ts +73 -0
- package/dist/types/modules/archive/{zip-entry-metadata.d.ts → zip/zip-entry-metadata.d.ts} +1 -1
- package/dist/types/modules/archive/{zip-records.d.ts → zip-spec/zip-records.d.ts} +20 -0
- package/dist/types/modules/excel/form-control.d.ts +2 -0
- package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +1 -1
- package/dist/types/modules/excel/utils/ooxml-validator.d.ts +48 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
- package/dist/types/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
- package/dist/types/modules/stream/base-transform.d.ts +3 -0
- package/dist/types/modules/stream/buffered-stream.d.ts +2 -12
- package/dist/types/modules/stream/index.browser.d.ts +13 -19
- package/dist/types/modules/stream/index.d.ts +18 -41
- package/dist/types/modules/stream/internal/event-utils.d.ts +17 -0
- package/dist/types/modules/stream/internal/type-guards.d.ts +9 -0
- package/dist/types/modules/stream/pull-stream.d.ts +5 -6
- package/dist/types/modules/stream/shared.d.ts +1 -1
- package/dist/types/modules/stream/streams.browser.d.ts +32 -42
- package/dist/types/modules/stream/streams.d.ts +4 -20
- package/package.json +19 -15
- package/dist/browser/modules/archive/byte-queue.d.ts +0 -18
- package/dist/browser/modules/archive/byte-queue.js +0 -125
- package/dist/browser/modules/archive/parse.base.js +0 -610
- package/dist/browser/modules/archive/utils/zip-extra.d.ts +0 -18
- package/dist/browser/modules/archive/utils/zip-extra.js +0 -68
- package/dist/browser/modules/archive/zip-builder.d.ts +0 -117
- package/dist/browser/modules/archive/zip-builder.js +0 -292
- package/dist/browser/modules/archive/zip-constants.d.ts +0 -18
- package/dist/browser/modules/archive/zip-constants.js +0 -23
- package/dist/browser/modules/archive/zip-records.js +0 -84
- package/dist/cjs/modules/archive/byte-queue.js +0 -129
- package/dist/cjs/modules/archive/parse.base.js +0 -632
- package/dist/cjs/modules/archive/utils/zip-extra.js +0 -74
- package/dist/cjs/modules/archive/zip-builder.js +0 -297
- package/dist/cjs/modules/archive/zip-constants.js +0 -26
- package/dist/cjs/modules/archive/zip-records.js +0 -90
- package/dist/esm/modules/archive/byte-queue.js +0 -125
- package/dist/esm/modules/archive/parse.base.js +0 -610
- package/dist/esm/modules/archive/utils/zip-extra.js +0 -68
- package/dist/esm/modules/archive/zip-builder.js +0 -292
- package/dist/esm/modules/archive/zip-constants.js +0 -23
- package/dist/esm/modules/archive/zip-records.js +0 -84
- package/dist/types/modules/archive/byte-queue.d.ts +0 -18
- package/dist/types/modules/archive/utils/zip-extra.d.ts +0 -18
- package/dist/types/modules/archive/zip-builder.d.ts +0 -117
- package/dist/types/modules/archive/zip-constants.d.ts +0 -18
- /package/dist/browser/modules/archive/{crc32.base.d.ts → compression/crc32.base.d.ts} +0 -0
- /package/dist/browser/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
- /package/dist/browser/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
- /package/dist/browser/modules/archive/{deflate-fallback.d.ts → compression/deflate-fallback.d.ts} +0 -0
- /package/dist/browser/modules/archive/{streaming-compress.base.d.ts → compression/streaming-compress.base.d.ts} +0 -0
- /package/dist/browser/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
- /package/dist/browser/modules/archive/{extract.js → unzip/extract.js} +0 -0
- /package/dist/browser/modules/archive/{zip-entry-metadata.d.ts → zip/zip-entry-metadata.d.ts} +0 -0
- /package/dist/browser/modules/archive/{zip-entry-info.d.ts → zip-spec/zip-entry-info.d.ts} +0 -0
- /package/dist/browser/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
- /package/dist/cjs/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
- /package/dist/cjs/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
- /package/dist/cjs/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
- /package/dist/cjs/modules/archive/{extract.js → unzip/extract.js} +0 -0
- /package/dist/cjs/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
- /package/dist/esm/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
- /package/dist/esm/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
- /package/dist/esm/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
- /package/dist/esm/modules/archive/{extract.js → unzip/extract.js} +0 -0
- /package/dist/esm/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
- /package/dist/{LICENSE → iife/LICENSE} +0 -0
- /package/dist/types/modules/archive/{compress.d.ts → compression/compress.d.ts} +0 -0
- /package/dist/types/modules/archive/{crc32.base.d.ts → compression/crc32.base.d.ts} +0 -0
- /package/dist/types/modules/archive/{crc32.browser.d.ts → compression/crc32.browser.d.ts} +0 -0
- /package/dist/types/modules/archive/{crc32.d.ts → compression/crc32.d.ts} +0 -0
- /package/dist/types/modules/archive/{deflate-fallback.d.ts → compression/deflate-fallback.d.ts} +0 -0
- /package/dist/types/modules/archive/{streaming-compress.base.d.ts → compression/streaming-compress.base.d.ts} +0 -0
- /package/dist/types/modules/archive/{streaming-compress.d.ts → compression/streaming-compress.d.ts} +0 -0
- /package/dist/types/modules/archive/{extract.d.ts → unzip/extract.d.ts} +0 -0
- /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.
|
|
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
|
-
(
|
|
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
|
-
|
|
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:
|
|
223
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
//
|
|
429
|
-
//
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
const
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
const
|
|
436
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
-
|
|
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
|
-
|
|
531
|
+
dest.end();
|
|
465
532
|
};
|
|
466
533
|
const errorListener = (err) => {
|
|
467
|
-
if (typeof
|
|
468
|
-
|
|
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
|
-
|
|
539
|
+
eventTarget.emit?.("error", err);
|
|
473
540
|
}
|
|
474
541
|
};
|
|
475
542
|
// Store listeners for later removal in unpipe
|
|
476
|
-
this._pipeListeners.set(
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
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
|
-
|
|
744
|
-
|
|
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
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
1394
|
-
this.
|
|
1395
|
-
|
|
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
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
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
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
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
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
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
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
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
|
-
|
|
1488
|
-
|
|
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
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
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
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
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
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
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
|
-
|
|
1569
|
-
|
|
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
|
-
|
|
1585
|
-
}
|
|
1586
|
-
|
|
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
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
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
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
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
|
|
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",
|
|
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
|
|
1806
|
+
return super.on(event, listener);
|
|
1639
1807
|
}
|
|
1640
1808
|
write(chunk, encodingOrCallback, callback) {
|
|
1641
1809
|
const cb = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
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
|
|
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
|
|
2011
|
-
this._writable
|
|
2012
|
-
this._writable
|
|
2013
|
-
this._writable
|
|
2014
|
-
|
|
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
|
-
|
|
2307
|
-
//
|
|
2308
|
-
|
|
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
|
-
(
|
|
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
|
-
//
|
|
2365
|
-
|
|
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
|
|
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
|
-
|
|
2651
|
+
cleanupWithSignal(new Error("Pipeline aborted"));
|
|
2552
2652
|
return;
|
|
2553
2653
|
}
|
|
2554
|
-
|
|
2555
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2694
|
+
registry.once(destination, "finish", () => cleanupWithSignal());
|
|
2574
2695
|
// Handle errors on all streams
|
|
2575
2696
|
for (const stream of allStreams) {
|
|
2576
|
-
|
|
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
|
-
|
|
2635
|
-
|
|
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
|
-
|
|
2780
|
+
registry.once(normalizedStream, "finish", () => done());
|
|
2652
2781
|
}
|
|
2653
2782
|
if (checkReadable) {
|
|
2654
|
-
|
|
2783
|
+
registry.once(normalizedStream, "end", () => done());
|
|
2655
2784
|
}
|
|
2656
|
-
|
|
2657
|
-
|
|
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
|
-
|
|
2680
|
-
|
|
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
|
|
2721
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
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
|
|
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
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
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
|
-
(
|
|
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
|
-
|
|
2946
|
-
if (len === 1
|
|
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
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
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
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
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
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
3079
|
+
forwardEnd = true;
|
|
3080
|
+
registry.once(last, "end", () => composed.emit("end"));
|
|
3081
|
+
};
|
|
3082
|
+
const ensureReadableForwarding = () => {
|
|
3083
|
+
if (forwardReadable) {
|
|
3084
|
+
return;
|
|
2978
3085
|
}
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
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
|
-
|
|
2992
|
-
|
|
3095
|
+
else if (event === "end") {
|
|
3096
|
+
ensureEndForwarding();
|
|
2993
3097
|
}
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
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
|
-
|
|
3001
|
-
|
|
3107
|
+
else if (event === "end") {
|
|
3108
|
+
ensureEndForwarding();
|
|
3002
3109
|
}
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
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
|
-
|
|
3148
|
+
return;
|
|
3012
3149
|
}
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
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
|
-
|
|
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
|
|
3410
|
+
return [chunks, totalLength];
|
|
3284
3411
|
}
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
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
|
-
|
|
3295
|
-
|
|
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
|
-
|
|
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
|
|
3308
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
// =============================================================================
|