documonster 0.20.2 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/README.md +1 -1
  2. package/README_zh.md +1 -1
  3. package/THIRD_PARTY_NOTICES.md +34 -2
  4. package/dist/esm/modules/archive/core/byte-queue.js +2 -1
  5. package/dist/esm/modules/archive/unzip/stream.browser.js +6 -0
  6. package/dist/esm/modules/csv/parse/async.js +2 -1
  7. package/dist/esm/modules/excel/bridge/csv-bridge.js +1 -1
  8. package/dist/esm/modules/excel/core/xlsx-io.browser.js +5 -9
  9. package/dist/esm/modules/excel/core/xlsx-io.js +1 -3
  10. package/dist/esm/modules/excel/core/xlsx-stream.js +3 -1
  11. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +10 -10
  12. package/dist/esm/modules/excel/stream/workbook-reader.js +30 -6
  13. package/dist/esm/modules/stream/browser/collector.js +3 -5
  14. package/dist/esm/modules/stream/browser/compose.js +13 -228
  15. package/dist/esm/modules/stream/browser/duplex-pair.js +71 -0
  16. package/dist/esm/modules/stream/browser/factories.js +35 -217
  17. package/dist/esm/modules/stream/browser/pipeline.js +43 -478
  18. package/dist/esm/modules/stream/browser/utils.js +21 -247
  19. package/dist/esm/modules/stream/browser/web.js +25 -0
  20. package/dist/esm/modules/stream/buffered-stream.js +8 -6
  21. package/dist/esm/modules/stream/core/factories.js +166 -0
  22. package/dist/esm/modules/stream/core/pipeline-api.js +32 -0
  23. package/dist/esm/modules/stream/core/sink-adapter.js +94 -24
  24. package/dist/esm/modules/stream/core/stream-helpers.js +160 -0
  25. package/dist/esm/modules/stream/core/utils.js +0 -23
  26. package/dist/esm/modules/stream/core/web-conversions.js +31 -0
  27. package/dist/esm/modules/stream/core/web-pipeline.js +90 -0
  28. package/dist/esm/modules/stream/index.base.js +2 -2
  29. package/dist/esm/modules/stream/index.browser.js +13 -19
  30. package/dist/esm/modules/stream/index.js +6 -10
  31. package/dist/esm/modules/stream/kernel/classes.js +618 -0
  32. package/dist/esm/modules/stream/kernel/compose-impl.js +225 -0
  33. package/dist/esm/modules/stream/kernel/destroy.js +255 -0
  34. package/dist/esm/modules/stream/kernel/duplexify.js +355 -0
  35. package/dist/esm/modules/stream/kernel/end-of-stream.js +212 -0
  36. package/dist/esm/modules/stream/kernel/errors.js +215 -0
  37. package/dist/esm/modules/stream/kernel/from.js +202 -0
  38. package/dist/esm/modules/stream/kernel/legacy.js +35 -0
  39. package/dist/esm/modules/stream/kernel/operators.js +285 -0
  40. package/dist/esm/modules/stream/kernel/pipeline-impl.js +561 -0
  41. package/dist/esm/modules/stream/kernel/readable-impl.js +963 -0
  42. package/dist/esm/modules/stream/kernel/state.js +253 -0
  43. package/dist/esm/modules/stream/kernel/stream-utils.js +212 -0
  44. package/dist/esm/modules/stream/kernel/web-adapters.js +584 -0
  45. package/dist/esm/modules/stream/kernel/writable.js +651 -0
  46. package/dist/esm/modules/stream/node/collector.js +7 -1
  47. package/dist/esm/modules/stream/node/compose.js +21 -206
  48. package/dist/esm/modules/stream/node/factories.js +34 -238
  49. package/dist/esm/modules/stream/node/pipeline.js +40 -94
  50. package/dist/esm/modules/stream/node/utils.js +15 -239
  51. package/dist/esm/modules/stream/node/web.js +27 -0
  52. package/dist/esm/modules/stream/pull-stream.js +15 -9
  53. package/dist/esm/modules/word/writer/streaming-writer.js +3 -0
  54. package/dist/iife/THIRD_PARTY_NOTICES.md +34 -2
  55. package/dist/iife/documonster.archive.iife.min.js +4 -4
  56. package/dist/iife/documonster.csv.iife.min.js +19 -19
  57. package/dist/iife/documonster.draw.iife.min.js +1 -1
  58. package/dist/iife/documonster.excel.iife.min.js +50 -50
  59. package/dist/iife/documonster.formula.iife.min.js +1 -1
  60. package/dist/iife/documonster.markdown.iife.min.js +1 -1
  61. package/dist/iife/documonster.mermaid.iife.min.js +1 -1
  62. package/dist/iife/documonster.pdf.iife.min.js +1 -1
  63. package/dist/iife/documonster.stream.iife.min.js +2 -2
  64. package/dist/iife/documonster.word.iife.min.js +60 -60
  65. package/dist/iife/documonster.xml.iife.min.js +1 -1
  66. package/dist/types/modules/excel/core/xlsx-io.browser.d.ts +5 -9
  67. package/dist/types/modules/excel/core/xlsx-io.d.ts +1 -3
  68. package/dist/types/modules/excel/core/xlsx-stream.d.ts +3 -2
  69. package/dist/types/modules/excel/stream/workbook-reader.browser.d.ts +2 -1
  70. package/dist/types/modules/excel/stream/workbook-reader.d.ts +2 -1
  71. package/dist/types/modules/stream/browser/collector.d.ts +1 -1
  72. package/dist/types/modules/stream/browser/compose.d.ts +14 -15
  73. package/dist/types/modules/stream/browser/duplex-pair.d.ts +10 -0
  74. package/dist/types/modules/stream/browser/factories.d.ts +22 -79
  75. package/dist/types/modules/stream/browser/pipeline.d.ts +8 -40
  76. package/dist/types/modules/stream/browser/utils.d.ts +6 -47
  77. package/dist/types/modules/stream/browser/web.d.ts +18 -0
  78. package/dist/types/modules/stream/core/add-abort-signal.d.ts +2 -1
  79. package/dist/types/modules/stream/core/consumers.d.ts +1 -1
  80. package/dist/types/modules/stream/core/event-utils.d.ts +2 -1
  81. package/dist/types/modules/stream/core/factories.d.ts +129 -0
  82. package/dist/types/modules/stream/core/pipeline-api.d.ts +10 -0
  83. package/dist/types/modules/stream/core/sink-adapter.d.ts +18 -1
  84. package/dist/types/modules/stream/core/stream-helpers.d.ts +76 -0
  85. package/dist/types/modules/stream/core/utils.d.ts +0 -9
  86. package/dist/types/modules/stream/core/web-conversions.d.ts +68 -0
  87. package/dist/types/modules/stream/core/web-pipeline.d.ts +27 -0
  88. package/dist/types/modules/stream/index.base.d.ts +6 -4
  89. package/dist/types/modules/stream/index.browser.d.ts +13 -14
  90. package/dist/types/modules/stream/index.d.ts +7 -10
  91. package/dist/types/modules/stream/kernel/classes.d.ts +220 -0
  92. package/dist/types/modules/stream/kernel/compose-impl.d.ts +10 -0
  93. package/dist/types/modules/stream/kernel/destroy.d.ts +21 -0
  94. package/dist/types/modules/stream/kernel/duplexify.d.ts +31 -0
  95. package/dist/types/modules/stream/kernel/end-of-stream.d.ts +28 -0
  96. package/dist/types/modules/stream/kernel/errors.d.ts +42 -0
  97. package/dist/types/modules/stream/kernel/from.d.ts +17 -0
  98. package/dist/types/modules/stream/kernel/legacy.d.ts +20 -0
  99. package/dist/types/modules/stream/kernel/operators.d.ts +44 -0
  100. package/dist/types/modules/stream/kernel/pipeline-impl.d.ts +32 -0
  101. package/dist/types/modules/stream/kernel/readable-impl.d.ts +34 -0
  102. package/dist/types/modules/stream/kernel/state.d.ts +223 -0
  103. package/dist/types/modules/stream/kernel/stream-utils.d.ts +34 -0
  104. package/dist/types/modules/stream/kernel/web-adapters.d.ts +65 -0
  105. package/dist/types/modules/stream/kernel/writable.d.ts +107 -0
  106. package/dist/types/modules/stream/node/collector.d.ts +7 -2
  107. package/dist/types/modules/stream/node/compose.d.ts +31 -5
  108. package/dist/types/modules/stream/node/factories.d.ts +22 -85
  109. package/dist/types/modules/stream/node/pipeline.d.ts +4 -15
  110. package/dist/types/modules/stream/node/utils.d.ts +9 -49
  111. package/dist/types/modules/stream/node/web.d.ts +18 -0
  112. package/dist/types/modules/stream/pull-stream.d.ts +2 -2
  113. package/dist/types/modules/stream/types.d.ts +24 -6
  114. package/package.json +5 -3
  115. package/dist/esm/modules/stream/browser/_lazy.js +0 -30
  116. package/dist/esm/modules/stream/browser/chunk-buffer.js +0 -223
  117. package/dist/esm/modules/stream/browser/duplex.js +0 -979
  118. package/dist/esm/modules/stream/browser/helpers.js +0 -44
  119. package/dist/esm/modules/stream/browser/microtask-context.js +0 -60
  120. package/dist/esm/modules/stream/browser/passthrough.js +0 -16
  121. package/dist/esm/modules/stream/browser/pipe-manager.js +0 -161
  122. package/dist/esm/modules/stream/browser/readable.js +0 -2208
  123. package/dist/esm/modules/stream/browser/transform.js +0 -1241
  124. package/dist/esm/modules/stream/browser/writable.js +0 -1316
  125. package/dist/esm/modules/stream/core/end-args.js +0 -24
  126. package/dist/esm/modules/stream/node/writable.js +0 -125
  127. package/dist/esm/modules/stream/utils.base.js +0 -126
  128. package/dist/esm/modules/stream/utils.browser.js +0 -80
  129. package/dist/esm/modules/stream/utils.js +0 -81
  130. package/dist/types/modules/stream/browser/_lazy.d.ts +0 -20
  131. package/dist/types/modules/stream/browser/chunk-buffer.d.ts +0 -61
  132. package/dist/types/modules/stream/browser/duplex.d.ts +0 -299
  133. package/dist/types/modules/stream/browser/helpers.d.ts +0 -13
  134. package/dist/types/modules/stream/browser/microtask-context.d.ts +0 -44
  135. package/dist/types/modules/stream/browser/passthrough.d.ts +0 -11
  136. package/dist/types/modules/stream/browser/pipe-manager.d.ts +0 -38
  137. package/dist/types/modules/stream/browser/readable.d.ts +0 -379
  138. package/dist/types/modules/stream/browser/transform.d.ts +0 -314
  139. package/dist/types/modules/stream/browser/writable.d.ts +0 -238
  140. package/dist/types/modules/stream/core/end-args.d.ts +0 -20
  141. package/dist/types/modules/stream/node/writable.d.ts +0 -53
  142. package/dist/types/modules/stream/utils.base.d.ts +0 -63
  143. package/dist/types/modules/stream/utils.browser.d.ts +0 -23
  144. package/dist/types/modules/stream/utils.d.ts +0 -24
@@ -1,257 +1,31 @@
1
1
  /**
2
- * Browser Stream - Utilities
2
+ * Browser Stream - utilities
3
3
  */
4
- import { Duplex } from "./duplex.js";
5
- import { removeEmitterListener, addEmitterListener } from "./helpers.js";
6
- import { pipeline, finished } from "./pipeline.js";
7
- import { Readable } from "./readable.js";
8
- import { Transform } from "./transform.js";
9
- import { Writable } from "./writable.js";
4
+ import { finished, pipeline } from "./pipeline.js";
10
5
  import { createAddAbortSignal } from "../core/add-abort-signal.js";
11
- import { toStreamBytes } from "../core/binary-chunk.js";
12
6
  import { createConsumers } from "../core/consumers.js";
13
- import { createIsTransform, createIsDuplex, createIsStream, isAsyncIterable, isReadableStream } from "../core/type-guards.js";
14
- import { getDefaultHighWaterMark } from "../core/utils.js";
15
- import { UnsupportedStreamTypeError } from "../errors.js";
16
- import { concatUint8Arrays, createTextDecoder } from "../../../utils/binary.js";
17
- // =============================================================================
18
- // Utility Functions
19
- // =============================================================================
20
- /** Convert a stream to a promise that resolves when finished */
7
+ import { streamToString, streamToUint8Array } from "../core/stream-helpers.js";
8
+ import { createIsDuplex, createIsStream, createIsTransform } from "../core/type-guards.js";
9
+ import { Duplex, Readable, Transform } from "../kernel/classes.js";
10
+ import { Writable } from "../kernel/writable.js";
11
+ export { drainStream, isDisturbed, isReadable, isWritable, streamToBuffer, streamToString, streamToUint8Array } from "../core/stream-helpers.js";
12
+ /** Resolve when a stream has finished. */
21
13
  export const streamToPromise = finished;
22
- /** Copy from a readable stream to a writable stream */
14
+ /** Copy from a readable stream to a writable stream. */
23
15
  export const copyStream = pipeline;
24
- /**
25
- * Collect all data from a readable stream into a Uint8Array
26
- * (Browser equivalent of Node.js streamToBuffer)
27
- */
28
- export async function streamToUint8Array(stream) {
29
- const [chunks, totalLength] = await collectStreamChunks(stream);
30
- return concatUint8Arrays(chunks, totalLength);
31
- }
32
- /**
33
- * Alias for streamToUint8Array (Node.js compatibility)
34
- */
35
- export async function streamToBuffer(stream) {
36
- return streamToUint8Array(stream);
37
- }
38
- /**
39
- * Collect all data from a readable stream into a string
40
- */
41
- export async function streamToString(stream, encoding) {
42
- const iterable = toReadableAsyncIterable(stream, "streamToString");
43
- const decoder = createTextDecoder(encoding);
44
- let text = "";
45
- for await (const chunk of iterable) {
46
- const bytes = toStreamBytes(chunk);
47
- if (!bytes) {
48
- throw new UnsupportedStreamTypeError("streamToString", typeof chunk);
49
- }
50
- text += decoder.decode(bytes, { stream: true });
51
- }
52
- text += decoder.decode();
53
- return text;
54
- }
55
- /**
56
- * Drain a stream (consume all data without processing)
57
- */
58
- export async function drainStream(stream) {
59
- const iterable = toReadableAsyncIterable(stream, "drainStream");
60
- for await (const _chunk of iterable) {
61
- // Consume data
62
- }
63
- }
64
- // =============================================================================
65
- // Type Guards
66
- // =============================================================================
67
- /** Check if an object is a transform stream */
68
- export const isTransform = createIsTransform(Transform);
69
- /** Check if an object is a duplex stream */
70
- export const isDuplex = createIsDuplex(Duplex, Transform);
71
- /** Check if an object is any kind of stream */
72
- export const isStream = createIsStream(Readable, Writable);
73
- // =============================================================================
74
- // Additional Utility Functions (Node.js Compatibility)
75
- // =============================================================================
76
- /** Add abort signal handling to any stream */
77
- export const addAbortSignal = createAddAbortSignal({
16
+ export const isTransform =
17
+ /* @__PURE__ */ createIsTransform(Transform);
18
+ export const isDuplex =
19
+ /* @__PURE__ */ createIsDuplex(Duplex);
20
+ export const isStream =
21
+ /* @__PURE__ */ createIsStream(Readable, Writable);
22
+ export const addAbortSignal = /* @__PURE__ */ createAddAbortSignal({
78
23
  add(emitter, event, listener) {
79
- addEmitterListener(emitter, event, listener, { once: true });
24
+ emitter.once?.(event, listener);
80
25
  },
81
- remove: removeEmitterListener
82
- });
83
- // =============================================================================
84
- // Stream State Inspection Functions
85
- // =============================================================================
86
- /**
87
- * Check if a readable stream has been disturbed (read from or cancelled).
88
- * Matches Node.js native: readableDidRead || readableAborted.
89
- * For Web ReadableStreams, returns `locked` (matches Node.js behaviour).
90
- */
91
- export function isDisturbed(stream) {
92
- if (stream instanceof Readable) {
93
- return Readable.isDisturbed(stream);
26
+ remove(emitter, event, listener) {
27
+ (emitter.off ?? emitter.removeListener)?.call(emitter, event, listener);
94
28
  }
95
- if (stream instanceof Duplex) {
96
- return Readable.isDisturbed(stream._readable);
97
- }
98
- // Web ReadableStream: `locked` is the closest indicator of disturbance
99
- // (a reader has been acquired). Matches the Node.js isDisturbed check.
100
- if (stream?.locked !== undefined) {
101
- return !!stream.locked;
102
- }
103
- const s = stream;
104
- return !!(s?.readableDidRead || s?._didRead || s?.readableAborted);
105
- }
106
- /**
107
- * Check if an object is a readable stream that is still in a readable state.
108
- * Returns false for destroyed or ended/finished streams (matches Node.js behavior).
109
- */
110
- export function isReadable(stream) {
111
- if (stream == null) {
112
- return false;
113
- }
114
- const s = stream;
115
- // Check if destroyed
116
- if (s.destroyed) {
117
- return false;
118
- }
119
- // Must be a readable stream type
120
- if (!(stream instanceof Readable || stream instanceof Transform || stream instanceof Duplex)) {
121
- if (!(typeof s.read === "function" && typeof s.pipe === "function")) {
122
- return false;
123
- }
124
- }
125
- // Check if reading has finished (readableEnded or equivalent)
126
- if (s.readableEnded === true) {
127
- return false;
128
- }
129
- return true;
130
- }
131
- /**
132
- * Check if an object is a writable stream that is still in a writable state.
133
- * Returns false for destroyed or ended/finished streams (matches Node.js behavior).
134
- */
135
- export function isWritable(stream) {
136
- if (stream == null) {
137
- return false;
138
- }
139
- const s = stream;
140
- // Check if destroyed
141
- if (s.destroyed) {
142
- return false;
143
- }
144
- // Must be a writable stream type
145
- if (!(stream instanceof Writable || stream instanceof Transform || stream instanceof Duplex)) {
146
- if (!(typeof s.write === "function" && typeof s.end === "function")) {
147
- return false;
148
- }
149
- }
150
- // Check if writing has ended (writableEnded or equivalent)
151
- if (s.writableEnded === true) {
152
- return false;
153
- }
154
- return true;
155
- }
156
- // =============================================================================
157
- // Duplex Pair
158
- // =============================================================================
159
- /**
160
- * Create a pair of connected Duplex streams
161
- * Data written to one stream can be read from the other
162
- */
163
- export function duplexPair(options) {
164
- const objectMode = options?.readableObjectMode ?? options?.writableObjectMode ?? options?.objectMode ?? false;
165
- const highWaterMark = options?.readableHighWaterMark ??
166
- options?.writableHighWaterMark ??
167
- options?.highWaterMark ??
168
- getDefaultHighWaterMark(objectMode);
169
- const duplexOpts = {
170
- readableHighWaterMark: options?.readableHighWaterMark ?? highWaterMark,
171
- writableHighWaterMark: options?.writableHighWaterMark ?? highWaterMark,
172
- readableObjectMode: options?.readableObjectMode ?? objectMode,
173
- writableObjectMode: options?.writableObjectMode ?? objectMode,
174
- allowHalfOpen: options?.allowHalfOpen
175
- };
176
- // Holder object allows both streams to reference each other via closure
177
- // while satisfying the `const` constraint (each variable is assigned once).
178
- const pair = {};
179
- const stream1 = new Duplex({
180
- ...duplexOpts,
181
- read() {
182
- // Data will be pushed from stream2's write()
183
- },
184
- write(chunk, _encoding, callback) {
185
- // Push to peer; if peer signals backpressure, defer callback until drain.
186
- if (!pair.s2.push(chunk)) {
187
- pair.s2.once("drain", () => callback());
188
- }
189
- else {
190
- callback();
191
- }
192
- },
193
- final(callback) {
194
- pair.s2.push(null);
195
- callback();
196
- }
197
- });
198
- const stream2 = new Duplex({
199
- ...duplexOpts,
200
- read() {
201
- // Data will be pushed from stream1's write()
202
- },
203
- write(chunk, _encoding, callback) {
204
- // Push to peer; if peer signals backpressure, defer callback until drain.
205
- if (!stream1.push(chunk)) {
206
- stream1.once("drain", () => callback());
207
- }
208
- else {
209
- callback();
210
- }
211
- },
212
- final(callback) {
213
- stream1.push(null);
214
- callback();
215
- }
216
- });
217
- pair.s1 = stream1;
218
- pair.s2 = stream2;
219
- return [stream1, stream2];
220
- }
221
- // =============================================================================
222
- // Private Helpers
223
- // =============================================================================
224
- // Helper function to collect stream chunks with total length tracking
225
- async function collectStreamChunks(stream) {
226
- const chunks = [];
227
- let totalLength = 0;
228
- const iterable = toReadableAsyncIterable(stream, "collectStreamChunks");
229
- for await (const chunk of iterable) {
230
- const bytes = toStreamBytes(chunk);
231
- if (!bytes) {
232
- throw new UnsupportedStreamTypeError("streamToBuffer", typeof chunk);
233
- }
234
- chunks.push(bytes);
235
- totalLength += bytes.length;
236
- }
237
- return [chunks, totalLength];
238
- }
239
- function toReadableAsyncIterable(stream, name) {
240
- if (isReadableStream(stream)) {
241
- // Boundary: `isReadableStream` erases the Web stream's element type; the
242
- // caller-supplied T is reasserted for the wrapped Readable.
243
- return Readable.fromWeb(stream);
244
- }
245
- if (isAsyncIterable(stream)) {
246
- return stream;
247
- }
248
- throw new UnsupportedStreamTypeError(name, typeof stream);
249
- }
250
- // =============================================================================
251
- // Stream Consumers (like stream.consumers in Node.js)
252
- // =============================================================================
253
- export const consumers = createConsumers({ streamToUint8Array, streamToString });
254
- // =============================================================================
255
- // Promises API (like stream/promises in Node.js)
256
- // =============================================================================
29
+ });
30
+ export const consumers = /* @__PURE__ */ createConsumers({ streamToUint8Array, streamToString });
257
31
  export const promises = { pipeline, finished };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Browser Stream - Web Streams conversions and `toWritable`
3
+ *
4
+ * Its own module so that converting a Writable does not keep the Readable
5
+ * side of the kernel in a bundle.
6
+ */
7
+ import { makeReadableFromWeb, makeWritableFromWeb } from "../core/web-conversions.js";
8
+ import { Readable } from "../kernel/classes.js";
9
+ import { isWritableStream } from "../kernel/stream-utils.js";
10
+ import { Writable } from "../kernel/writable.js";
11
+ /** A Web `ReadableStream` as a Readable, with the module's guarantees; see `web-conversions`. */
12
+ export const readableFromWeb = /* @__PURE__ */ makeReadableFromWeb(Readable);
13
+ /** A Web `WritableStream` as a Writable, with the module's guarantees; see `web-conversions`. */
14
+ export const writableFromWeb = /* @__PURE__ */ makeWritableFromWeb(Writable);
15
+ export { readableToWeb, writableToWeb } from "../core/web-conversions.js";
16
+ /**
17
+ * Normalize a user-provided writable into one this module can drive: a Web
18
+ * `WritableStream` is adapted, anything Node-like is used as is.
19
+ */
20
+ export function toWritable(stream) {
21
+ if (isWritableStream(stream)) {
22
+ return writableFromWeb(stream);
23
+ }
24
+ return stream;
25
+ }
@@ -202,7 +202,8 @@ export class BufferedStream extends EventEmitter {
202
202
  while (this._bufferReadIndex < this._buffers.length) {
203
203
  const buf = this._buffers[this._bufferReadIndex];
204
204
  if (buf.isEOD) {
205
- this._bufferReadIndex++;
205
+ // Drop the reference so a consumed batch can be collected before compaction.
206
+ this._buffers[this._bufferReadIndex++] = undefined;
206
207
  continue;
207
208
  }
208
209
  // Track length reduction
@@ -210,7 +211,7 @@ export class BufferedStream extends EventEmitter {
210
211
  const data = buf.read(size);
211
212
  this._totalLength -= beforeLen - buf.length;
212
213
  if (buf.isEOD) {
213
- this._bufferReadIndex++;
214
+ this._buffers[this._bufferReadIndex++] = undefined;
214
215
  }
215
216
  // Reset/compact buffer queue occasionally
216
217
  if (this._bufferReadIndex === this._buffers.length) {
@@ -258,10 +259,7 @@ export class BufferedStream extends EventEmitter {
258
259
  // Allocate exactly once, then copy remaining chunks/buffers.
259
260
  const out = new Uint8Array(this._totalLength);
260
261
  let offset = 0;
261
- for (let i = this._chunkReadIndex; i < this._chunks.length; i++) {
262
- const chunk = this._chunks[i];
263
- offset += chunk.copy(out, offset, 0, chunk.length);
264
- }
262
+ // Older data first: what was already moved into buffers, then pending chunks.
265
263
  for (let i = this._bufferReadIndex; i < this._buffers.length; i++) {
266
264
  const buf = this._buffers[i];
267
265
  if (buf.isEOD) {
@@ -271,6 +269,10 @@ export class BufferedStream extends EventEmitter {
271
269
  out.set(view, offset);
272
270
  offset += view.length;
273
271
  }
272
+ for (let i = this._chunkReadIndex; i < this._chunks.length; i++) {
273
+ const chunk = this._chunks[i];
274
+ offset += chunk.copy(out, offset, 0, chunk.length);
275
+ }
274
276
  // Reset internal state — data has been consumed.
275
277
  this._chunks = [];
276
278
  this._chunkReadIndex = 0;
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Stream factory functions shared by the Node and browser entry points.
3
+ *
4
+ * The bodies are identical on both platforms; only the stream classes differ,
5
+ * so each entry point builds them with its own.
6
+ */
7
+ import { BufferedStream } from "../buffered-stream.js";
8
+ import { PullStream } from "../pull-stream.js";
9
+ import { stringToUint8Array } from "../../../utils/binary.js";
10
+ /**
11
+ * Deliver a value that may be a promise to a Node-style callback; `undefined`
12
+ * means "nothing to push".
13
+ *
14
+ * A promise is recognised as `await` recognises one — anything with a `then`
15
+ * method — not with `instanceof Promise`, which is false for a promise from
16
+ * another realm (an iframe, a `vm` context) and for any other thenable, and
17
+ * pushed the promise itself as the chunk. `Promise.resolve` then adopts it as
18
+ * `await` would, so a thenable that calls back twice or throws still settles
19
+ * once. A plain value keeps the synchronous path.
20
+ */
21
+ function settle(run, callback) {
22
+ let result;
23
+ try {
24
+ result = run();
25
+ }
26
+ catch (err) {
27
+ callback(err);
28
+ return;
29
+ }
30
+ if (typeof result?.then === "function") {
31
+ Promise.resolve(result).then(data => (data !== undefined ? callback(null, data) : callback()), err => callback(err));
32
+ }
33
+ else if (result !== undefined) {
34
+ callback(null, result);
35
+ }
36
+ else {
37
+ callback();
38
+ }
39
+ }
40
+ function emptyRead() {
41
+ this.push(null);
42
+ }
43
+ function nullWrite(_chunk, _encoding, callback) {
44
+ callback();
45
+ }
46
+ /** `createPullStream`; platform-independent. */
47
+ export function createPullStream(options) {
48
+ return new PullStream(options);
49
+ }
50
+ /** `createBufferedStream`; platform-independent. */
51
+ export function createBufferedStream(options) {
52
+ return new BufferedStream(options);
53
+ }
54
+ // One maker per factory, each called once per platform with the one class it
55
+ // needs. A shared object of every class would make each factory keep all of
56
+ // them — the whole Readable/compose kernel behind a lone `createWritable`.
57
+ export function makeCreateReadable(Readable) {
58
+ return options => new Readable(options);
59
+ }
60
+ export function makeCreateReadableFromAsyncIterable(Readable) {
61
+ return (iterable, options) => Readable.from(iterable, { ...options, objectMode: options?.objectMode ?? true });
62
+ }
63
+ /**
64
+ * `undefined` entries are skipped: a stream's end-of-data signal is a nullish
65
+ * push, so there is no in-band way to carry an undefined chunk, while `0`, `""`
66
+ * and `false` are ordinary values that must survive.
67
+ */
68
+ export function makeCreateReadableFromArray(Readable) {
69
+ return (data, options) => {
70
+ let index = 0;
71
+ return new Readable({
72
+ ...options,
73
+ objectMode: options?.objectMode ?? true,
74
+ read() {
75
+ while (index < data.length) {
76
+ const chunk = data[index++];
77
+ if (chunk === undefined) {
78
+ continue;
79
+ }
80
+ if (!this.push(chunk)) {
81
+ return;
82
+ }
83
+ }
84
+ this.push(null);
85
+ }
86
+ });
87
+ };
88
+ }
89
+ export function makeCreateReadableFromGenerator(Readable) {
90
+ return (generator, options) => Readable.from(generator(), { ...options, objectMode: options?.objectMode ?? true });
91
+ }
92
+ export function makeCreateReadableFromPromise(Readable) {
93
+ return (promise, options) => {
94
+ const readable = new Readable({
95
+ ...options,
96
+ objectMode: options?.objectMode ?? true,
97
+ read() { }
98
+ });
99
+ // Adopted as `await` would: a promise from another realm or any thenable
100
+ // works, one that calls back twice settles once, and a `then` that throws
101
+ // fails the stream rather than the call.
102
+ Promise.resolve()
103
+ .then(() => promise)
104
+ .then(value => {
105
+ readable.push(value);
106
+ readable.push(null);
107
+ }, err => readable.destroy(err));
108
+ return readable;
109
+ };
110
+ }
111
+ export function makeCreateEmptyReadable(Readable) {
112
+ return options => new Readable({ ...options, read: emptyRead });
113
+ }
114
+ export function makeCreateWritable(Writable) {
115
+ return options => new Writable(options);
116
+ }
117
+ export function makeCreateNullWritable(Writable) {
118
+ return options => new Writable({ ...options, write: nullWrite });
119
+ }
120
+ /** The shorthand `transformFn` returns its result; `undefined` pushes nothing. */
121
+ export function makeCreateTransform(Transform) {
122
+ return (transformFn, options) => {
123
+ const flush = options?.flush;
124
+ return new Transform({
125
+ ...options,
126
+ transform(chunk, encoding, callback) {
127
+ settle(() => transformFn(chunk, encoding), callback);
128
+ },
129
+ flush: flush
130
+ ? (callback) => settle(flush, callback)
131
+ : undefined
132
+ });
133
+ };
134
+ }
135
+ export function makeCreatePassThrough(PassThrough) {
136
+ return options => new PassThrough(options);
137
+ }
138
+ export function makeCreateDuplex(Duplex) {
139
+ return options => new Duplex(options);
140
+ }
141
+ export function makeFromBytes(Readable) {
142
+ return data => new Readable({
143
+ read() {
144
+ this.push(data);
145
+ this.push(null);
146
+ }
147
+ });
148
+ }
149
+ export function makeFromString(Readable) {
150
+ const fromBytes = makeFromBytes(Readable);
151
+ return str => fromBytes(stringToUint8Array(str));
152
+ }
153
+ export function makeFromJSON(Readable) {
154
+ const fromString = makeFromString(Readable);
155
+ return data => fromString(JSON.stringify(data));
156
+ }
157
+ export function makeTransform(Transform) {
158
+ const createTransform = makeCreateTransform(Transform);
159
+ return fn => createTransform(fn);
160
+ }
161
+ export function makeFilter(Transform) {
162
+ const createTransform = makeCreateTransform(Transform);
163
+ return (predicate) => createTransform(async (chunk) => ((await predicate(chunk)) ? chunk : undefined), {
164
+ objectMode: true
165
+ });
166
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The module's `pipeline()` calling convention, shared by both entry points:
3
+ * stages, then optional `{ signal, end }` options, then an optional callback;
4
+ * a promise is returned either way. Each entry supplies how to run the stages.
5
+ */
6
+ import { isPipelineOptions } from "./options.js";
7
+ export function createPipeline(run) {
8
+ return function pipeline(...args) {
9
+ let stages = args;
10
+ let options;
11
+ let callback;
12
+ if (typeof stages[stages.length - 1] === "function") {
13
+ // A trailing function is always the completion callback.
14
+ callback = stages[stages.length - 1];
15
+ stages = stages.slice(0, -1);
16
+ }
17
+ if (isPipelineOptions(stages[stages.length - 1])) {
18
+ options = stages[stages.length - 1];
19
+ stages = stages.slice(0, -1);
20
+ }
21
+ const promise = stages.length < 2
22
+ ? Promise.reject(new Error("Pipeline requires at least 2 streams"))
23
+ : new Promise((resolve, reject) => {
24
+ run(stages, options).then(resolve, reject);
25
+ });
26
+ if (callback) {
27
+ const cb = callback;
28
+ promise.then(() => cb(), err => cb(err));
29
+ }
30
+ return promise;
31
+ };
32
+ }