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
@@ -10,7 +10,12 @@
10
10
  * - `write(chunk)` resolves once the chunk has been accepted by the
11
11
  * sink (after awaiting `drain` for Node-style sinks under
12
12
  * backpressure, or `writer.ready` for Web streams).
13
- * - `end()` finalises the sink and resolves on close.
13
+ * - `end()` finalises the sink and resolves once it has really finished
14
+ * (`'finish'` for a Node-style sink — a `'close'` before it is a
15
+ * premature close). Calling it again returns the same promise.
16
+ * - `abort(reason)` gives the sink up after a producer failure.
17
+ * - A Web sink's writer is released once the sink is closed, aborted or
18
+ * errored, so the stream is not left locked.
14
19
  * - The first sink error is captured and re-thrown from the next
15
20
  * `write` / `end` so callers can't lose it.
16
21
  *
@@ -39,13 +44,19 @@ export class SinkAdapter {
39
44
  constructor(sink) {
40
45
  this._error = null;
41
46
  this._ended = false;
47
+ this._ending = null;
48
+ this._writerReleased = false;
42
49
  if (isWebWritable(sink)) {
43
50
  this._kind = "web";
44
51
  this._webWriter = sink.getWriter();
45
52
  // Web writers expose .closed; surface termination errors through
46
53
  // the same _error channel so producers see them.
47
54
  this._webWriter.closed.catch((err) => {
48
- this._captureError(err);
55
+ // Releasing our own lock rejects `closed` too; that is not a sink error.
56
+ if (!this._writerReleased) {
57
+ this._captureError(err);
58
+ this._releaseWriter();
59
+ }
49
60
  });
50
61
  }
51
62
  else if (isNodeWritable(sink)) {
@@ -109,53 +120,70 @@ export class SinkAdapter {
109
120
  drain?.cancel();
110
121
  }
111
122
  }
112
- async end() {
113
- if (this._ended) {
114
- return;
123
+ /** Finish the sink. Every call returns the same promise. */
124
+ end() {
125
+ if (!this._ending) {
126
+ this._ended = true;
127
+ this._ending = this._finish();
115
128
  }
129
+ return this._ending;
130
+ }
131
+ /**
132
+ * Give the sink up after a producer failure: a Web sink is aborted and its
133
+ * lock released, a Node-style one destroyed with `reason`.
134
+ */
135
+ async abort(reason) {
116
136
  this._ended = true;
137
+ const error = reason instanceof Error ? reason : new Error(String(reason ?? "aborted"));
138
+ this._captureError(error);
139
+ if (this._kind === "web") {
140
+ if (!this._writerReleased) {
141
+ await this._webWriter.abort(error).catch(() => { });
142
+ this._releaseWriter();
143
+ }
144
+ return;
145
+ }
146
+ const sink = (this._kind === "node" ? this._nodeSink : this._duckSink);
147
+ if (typeof sink.destroy === "function" && !sink.destroyed) {
148
+ sink.destroy(error);
149
+ }
150
+ }
151
+ async _finish() {
117
152
  this._throwIfErrored();
118
153
  if (this._kind === "web") {
119
154
  // close() rejects if the stream has already errored — we let that
120
155
  // propagate so callers see the underlying failure.
121
- await this._webWriter.close();
122
- return;
123
- }
124
- if (this._kind === "node") {
125
- const sink = this._nodeSink;
126
- // Prefer the close event when available; some Node writables emit
127
- // 'finish' first and only emit 'close' on `destroy()`. We listen
128
- // for both.
129
- const finished = createEventWaiter(sink, ["close", "finish"]);
130
156
  try {
131
- await sink.end();
132
- await finished.promise;
157
+ await this._webWriter.close();
133
158
  }
134
- catch (error) {
135
- finished.cancel();
136
- throw error;
159
+ finally {
160
+ this._releaseWriter();
137
161
  }
138
- this._throwIfErrored();
139
162
  return;
140
163
  }
141
- // duck
142
- const sink = this._duckSink;
164
+ const sink = this._kind === "node" ? this._nodeSink : this._duckSink;
143
165
  if (hasEvents(sink)) {
144
- const finished = createEventWaiter(sink, ["close", "finish"]);
166
+ const finished = waitForFinish(sink);
145
167
  try {
146
168
  await sink.end();
147
- await finished.promise;
148
169
  }
149
170
  catch (error) {
150
171
  finished.cancel();
151
172
  throw error;
152
173
  }
174
+ await finished.promise;
153
175
  }
154
176
  else {
155
177
  await sink.end();
156
178
  }
157
179
  this._throwIfErrored();
158
180
  }
181
+ _releaseWriter() {
182
+ if (!this._writerReleased) {
183
+ this._writerReleased = true;
184
+ this._webWriter.releaseLock();
185
+ }
186
+ }
159
187
  _captureError(err) {
160
188
  if (this._error) {
161
189
  return;
@@ -184,3 +212,45 @@ export class SinkAdapter {
184
212
  function hasEvents(sink) {
185
213
  return typeof sink.once === "function" || typeof sink.on === "function";
186
214
  }
215
+ /**
216
+ * Resolve on `'finish'`; reject on `'error'`, or on a `'close'` that comes
217
+ * first while the sink reports it has not finished — that is a premature
218
+ * close, not a successful end.
219
+ */
220
+ function waitForFinish(sink) {
221
+ let cleanup = () => { };
222
+ const promise = new Promise((resolve, reject) => {
223
+ const onFinish = () => {
224
+ cleanup();
225
+ resolve();
226
+ };
227
+ const onError = (err) => {
228
+ cleanup();
229
+ reject(err instanceof Error ? err : new Error(String(err)));
230
+ };
231
+ const onClose = () => {
232
+ cleanup();
233
+ // A sink that reports no finished state (a duck sink signalling with
234
+ // 'close' alone) is taken at its word; one that does must have finished.
235
+ const finished = sink.writableFinished;
236
+ if (typeof finished !== "boolean" || finished) {
237
+ resolve();
238
+ return;
239
+ }
240
+ const err = new Error("Premature close");
241
+ err.code = "ERR_STREAM_PREMATURE_CLOSE";
242
+ reject(err);
243
+ };
244
+ const on = (sink.on ?? sink.once).bind(sink);
245
+ on("finish", onFinish);
246
+ on("error", onError);
247
+ on("close", onClose);
248
+ cleanup = () => {
249
+ const off = (sink.off ?? sink.removeListener)?.bind(sink);
250
+ off?.("finish", onFinish);
251
+ off?.("error", onError);
252
+ off?.("close", onClose);
253
+ };
254
+ });
255
+ return { promise, cancel: () => cleanup() };
256
+ }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Stream helpers shared by the Node and browser entry points.
3
+ *
4
+ * Everything here works on the public shape of a stream — async iteration,
5
+ * a Web `ReadableStream`'s reader, the `readable*` / `writable*` getters — so
6
+ * it is the same code on both platforms. A Web stream is read through its own
7
+ * reader; it is not wrapped in a Node-style stream first.
8
+ */
9
+ import { toStreamBytes } from "./binary-chunk.js";
10
+ import { isAsyncIterable, isReadableStream } from "./type-guards.js";
11
+ import { UnsupportedStreamTypeError } from "../errors.js";
12
+ import { concatUint8Arrays, createTextDecoder } from "../../../utils/binary.js";
13
+ /** `true` for an object with a Web `ReadableStream`'s `getReader()`. */
14
+ export const isReadableStreamLike = isReadableStream;
15
+ /**
16
+ * Read a Web `ReadableStream` with `for await`, whether or not the platform's
17
+ * `ReadableStream` is async-iterable itself. Every value is yielded as read —
18
+ * `null` and `undefined` included, as `ReadableStream.prototype.values()` does —
19
+ * so the caller decides what a value it cannot use means. Leaving the loop
20
+ * early cancels the stream; the lock is released either way.
21
+ */
22
+ export async function* readableStreamToAsyncIterable(stream) {
23
+ const reader = stream.getReader();
24
+ let done = false;
25
+ try {
26
+ while (true) {
27
+ const result = await reader.read();
28
+ if (result.done) {
29
+ done = true;
30
+ return;
31
+ }
32
+ yield result.value;
33
+ }
34
+ }
35
+ finally {
36
+ if (!done) {
37
+ await Promise.resolve(reader.cancel?.()).catch(() => { });
38
+ }
39
+ reader.releaseLock?.();
40
+ }
41
+ }
42
+ /** Every chunk of a stream, in an array. */
43
+ export async function collect(stream) {
44
+ const result = [];
45
+ for await (const chunk of stream) {
46
+ result.push(chunk);
47
+ }
48
+ return result;
49
+ }
50
+ /** A whole stream decoded as UTF-8 text. */
51
+ export function text(stream) {
52
+ return streamToString(stream);
53
+ }
54
+ /** A whole stream parsed as JSON. */
55
+ export async function json(stream) {
56
+ return JSON.parse(await text(stream));
57
+ }
58
+ /** A whole stream's bytes. */
59
+ export function bytes(stream) {
60
+ return streamToUint8Array(stream);
61
+ }
62
+ function toAsyncIterable(stream, name) {
63
+ if (isReadableStream(stream)) {
64
+ return readableStreamToAsyncIterable(stream);
65
+ }
66
+ if (isAsyncIterable(stream)) {
67
+ return stream;
68
+ }
69
+ throw new UnsupportedStreamTypeError(name, typeof stream);
70
+ }
71
+ /** Collect every byte of a stream. */
72
+ export async function streamToUint8Array(stream) {
73
+ const chunks = [];
74
+ let totalLength = 0;
75
+ for await (const chunk of toAsyncIterable(stream, "streamToUint8Array")) {
76
+ const bytes = toStreamBytes(chunk);
77
+ if (!bytes) {
78
+ throw new UnsupportedStreamTypeError("streamToUint8Array", typeof chunk);
79
+ }
80
+ chunks.push(bytes);
81
+ totalLength += bytes.byteLength;
82
+ }
83
+ return concatUint8Arrays(chunks, totalLength);
84
+ }
85
+ /** Alias of {@link streamToUint8Array}, named after Node's `Buffer`. */
86
+ export function streamToBuffer(stream) {
87
+ return streamToUint8Array(stream);
88
+ }
89
+ /** Decode a whole stream as text. */
90
+ export async function streamToString(stream, encoding) {
91
+ const decoder = createTextDecoder(encoding);
92
+ let text = "";
93
+ for await (const chunk of toAsyncIterable(stream, "streamToString")) {
94
+ const bytes = toStreamBytes(chunk);
95
+ if (!bytes) {
96
+ throw new UnsupportedStreamTypeError("streamToString", typeof chunk);
97
+ }
98
+ text += decoder.decode(bytes, { stream: true });
99
+ }
100
+ return text + decoder.decode();
101
+ }
102
+ /** Consume a stream to its end, discarding the data. */
103
+ export async function drainStream(stream) {
104
+ for await (const _chunk of toAsyncIterable(stream, "drainStream")) {
105
+ // discard
106
+ }
107
+ }
108
+ /** `true` for a Node-style readable stream that can still be read from. */
109
+ export function isReadable(stream) {
110
+ const s = stream;
111
+ return (!!s &&
112
+ typeof s.read === "function" &&
113
+ typeof s.pipe === "function" &&
114
+ !s.destroyed &&
115
+ s.readable !== false &&
116
+ s.readableEnded !== true);
117
+ }
118
+ /** `true` for a Node-style writable stream that can still be written to. */
119
+ export function isWritable(stream) {
120
+ const s = stream;
121
+ return (!!s &&
122
+ typeof s.write === "function" &&
123
+ typeof s.end === "function" &&
124
+ !s.destroyed &&
125
+ s.writable !== false &&
126
+ s.writableEnded !== true);
127
+ }
128
+ const kIsDisturbed = Symbol.for("nodejs.stream.disturbed");
129
+ /**
130
+ * `true` once a readable stream has been read from or aborted.
131
+ *
132
+ * Node's own Web streams answer through an internal symbol, which is consulted
133
+ * first. Elsewhere a Web `ReadableStream` has no public "disturbed" flag, but
134
+ * the Fetch spec makes it observable: `new Response(stream)` must throw for a
135
+ * stream that is disturbed or locked, and does nothing to one that is neither —
136
+ * it takes no lock and reads nothing. So an unlocked stream gets an exact
137
+ * answer. A locked one cannot be told apart (locked-and-read and
138
+ * locked-but-unread both throw) and reports `false`, as Node does for a stream
139
+ * that is locked but not yet read.
140
+ */
141
+ export function isDisturbed(stream) {
142
+ const s = stream;
143
+ if (!s) {
144
+ return false;
145
+ }
146
+ const known = s[kIsDisturbed] ?? (s.readableDidRead || s.readableAborted);
147
+ if (known !== undefined) {
148
+ return !!known;
149
+ }
150
+ if (isReadableStream(s) && !s.locked && typeof Response === "function") {
151
+ try {
152
+ new Response(s);
153
+ return false;
154
+ }
155
+ catch {
156
+ return true;
157
+ }
158
+ }
159
+ return false;
160
+ }
@@ -4,7 +4,6 @@
4
4
  * Platform-neutral utility functions shared by Node.js and Browser implementations:
5
5
  * - Stream state inspection (isDestroyed, isErrored)
6
6
  * - Callback-to-promise conversion (promisify)
7
- * - High water mark management (getDefaultHighWaterMark, setDefaultHighWaterMark)
8
7
  */
9
8
  // =============================================================================
10
9
  // State Inspection
@@ -39,25 +38,3 @@ export function promisify(fn) {
39
38
  });
40
39
  });
41
40
  }
42
- // =============================================================================
43
- // High Water Mark
44
- // =============================================================================
45
- let _defaultHighWaterMark = 65536; // 64KB default (matches Node's own on every supported line)
46
- let _defaultHighWaterMarkObjectMode = 16; // 16 objects default
47
- /**
48
- * Get the default high water mark for streams
49
- */
50
- export function getDefaultHighWaterMark(objectMode) {
51
- return objectMode ? _defaultHighWaterMarkObjectMode : _defaultHighWaterMark;
52
- }
53
- /**
54
- * Set the default high water mark for streams
55
- */
56
- export function setDefaultHighWaterMark(objectMode, value) {
57
- if (objectMode) {
58
- _defaultHighWaterMarkObjectMode = value;
59
- }
60
- else {
61
- _defaultHighWaterMark = value;
62
- }
63
- }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Web Streams conversions with the module's guarantees, on both entry points.
3
+ *
4
+ * `Readable.fromWeb` / `.toWeb` and friends stay exactly what each platform's
5
+ * classes provide — on the Node entry, Node's own, with Node's known defects
6
+ * (see the README). These functions run the module's adapters instead, with
7
+ * that platform's classes, so the same call behaves the same on both:
8
+ *
9
+ * - no chunk is lost: a write made while `'drain'` is pending still reaches the
10
+ * Node-style stream, and a `null` read from a Web stream fails it rather than
11
+ * ending it early;
12
+ * - strings from `setEncoding()` can be queued;
13
+ * - the lock on a Web stream is handed back once the adapted stream ends,
14
+ * errors or is destroyed, and is never taken at all when adapting fails;
15
+ * - the adapters remove their own listeners when they are done.
16
+ */
17
+ import { readableFromWeb as adaptReadableFromWeb, readableToWeb as adaptReadableToWeb, writableFromWeb as adaptWritableFromWeb, writableToWeb as adaptWritableToWeb } from "../kernel/web-adapters.js";
18
+ export function makeReadableFromWeb(Readable) {
19
+ return (stream, options) => adaptReadableFromWeb(Readable, stream, options);
20
+ }
21
+ export function makeWritableFromWeb(Writable) {
22
+ return (stream, options) => adaptWritableFromWeb(Writable, stream, options);
23
+ }
24
+ /** A Node-style Readable as a Web `ReadableStream`. */
25
+ export function readableToWeb(stream, options) {
26
+ return adaptReadableToWeb(stream, options);
27
+ }
28
+ /** A Node-style Writable as a Web `WritableStream`. */
29
+ export function writableToWeb(stream) {
30
+ return adaptWritableToWeb(stream);
31
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * An all-Web pipeline, run by the platform.
3
+ *
4
+ * When every stage is a Web stream, both entry points hand the pipeline to the
5
+ * platform's own `pipeThrough` / `pipeTo` instead of pumping chunks in
6
+ * JavaScript. That carries backpressure, cancellation and abort natively — and
7
+ * on Node it also avoids `stream.pipeline`, which never settles when such a
8
+ * pipeline is aborted while its source is waiting for data.
9
+ */
10
+ import { isReadableStream, isTransformStream, isWritableStream } from "../kernel/stream-utils.js";
11
+ import { createAbortError } from "../../../utils/errors.js";
12
+ /** `ReadableStream → TransformStream* → WritableStream`: nothing but Web streams. */
13
+ export function isWebOnlyPipeline(streams) {
14
+ if (!isReadableStream(streams[0]) || !isWritableStream(streams[streams.length - 1])) {
15
+ return false;
16
+ }
17
+ for (let i = 1; i < streams.length - 1; i++) {
18
+ if (!isTransformStream(streams[i])) {
19
+ return false;
20
+ }
21
+ }
22
+ return true;
23
+ }
24
+ /**
25
+ * Run an all-Web pipeline with the platform's own `pipeTo`.
26
+ *
27
+ * The data moves natively, but the pipeline is managed here: every stage is
28
+ * checked for a lock before anything starts, each connection is its own
29
+ * `pipeTo`, and the promise settles only once every connection has finished
30
+ * tearing down — with the first error that occurred.
31
+ *
32
+ * A failure travels along the chain by the Streams spec's own propagation
33
+ * (error forwards, cancel backwards); only the caller's abort uses a signal.
34
+ * Aborting the other connections on the first failure as well looks tidier
35
+ * but races that propagation: Node's `pipeTo` then skips cancelling the
36
+ * source once there are two or more transforms.
37
+ */
38
+ export async function pipeWebStreams(streams, options) {
39
+ const source = streams[0];
40
+ const transforms = streams.slice(1, -1);
41
+ const destination = streams[streams.length - 1];
42
+ if (source.locked ||
43
+ destination.locked ||
44
+ transforms.some(t => t.readable.locked || t.writable.locked)) {
45
+ throw new TypeError("pipeline: a stream is locked, so it cannot be piped");
46
+ }
47
+ // Every port must be distinct: a stage used twice would be connected twice,
48
+ // the second connection would fail to take its lock and never be made, and
49
+ // the rest would wait forever for an error that has no path to them.
50
+ const ports = [source, destination, ...transforms.flatMap(t => [t.readable, t.writable])];
51
+ if (new Set(ports).size !== ports.length) {
52
+ throw new TypeError("pipeline: the same stream appears more than once");
53
+ }
54
+ // The caller's abort, reported as the AbortError the rest of the module uses.
55
+ let signal;
56
+ let detach = () => { };
57
+ const outer = options?.signal;
58
+ if (outer) {
59
+ const controller = new AbortController();
60
+ const onAbort = () => controller.abort(createAbortError(outer.reason));
61
+ if (outer.aborted) {
62
+ onAbort();
63
+ }
64
+ else {
65
+ outer.addEventListener("abort", onAbort, { once: true });
66
+ detach = () => outer.removeEventListener("abort", onAbort);
67
+ }
68
+ signal = controller.signal;
69
+ }
70
+ const connections = [];
71
+ let upstream = source;
72
+ for (const transform of transforms) {
73
+ connections.push(upstream.pipeTo(transform.writable, { signal }));
74
+ upstream = transform.readable;
75
+ }
76
+ connections.push(upstream.pipeTo(destination, { signal, preventClose: options?.end === false }));
77
+ // Wait for every connection to settle, then report the failure seen first.
78
+ let failed = false;
79
+ let firstError;
80
+ await Promise.all(connections.map(connection => connection.catch((err) => {
81
+ if (!failed) {
82
+ failed = true;
83
+ firstError = err;
84
+ }
85
+ })));
86
+ detach();
87
+ if (failed) {
88
+ throw firstError;
89
+ }
90
+ }
@@ -5,9 +5,9 @@
5
5
  * `index.ts` (Node) and `index.browser.ts`.
6
6
  */
7
7
  // Common re-exports (shared between Node.js and browser)
8
- export { isDestroyed, isErrored, getDefaultHighWaterMark, setDefaultHighWaterMark, promisify } from "./core/utils.js";
8
+ export { isDestroyed, isErrored, promisify } from "./core/utils.js";
9
9
  export { ChunkedBuilder, TransactionalChunkedBuilder } from "./chunked-builder.js";
10
- export { collect, text, json, bytes, fromString, fromJSON, fromBytes, transform, filter, isReadableStreamLike, readableStreamToAsyncIterable } from "#platform/modules/stream/utils";
10
+ export { bytes, collect, isReadableStreamLike, json, readableStreamToAsyncIterable, text } from "./core/stream-helpers.js";
11
11
  export { StreamError, StreamStateError, StreamTypeError, UnsupportedStreamTypeError, isStreamError } from "./errors.js";
12
12
  // Internal utilities exposed for cross-module use (e.g. archive, word/excel writers)
13
13
  export { isReadableStream, isWritableStream, isAsyncIterable, isTransformStream } from "./core/type-guards.js";
@@ -1,31 +1,25 @@
1
1
  /**
2
2
  * Stream Module (browser entry)
3
3
  *
4
- * Mirrors the public surface of `./index.ts`, but exports the browser
5
- * implementation from `./streams.browser`.
6
- *
7
- * This file is intentionally export-only (tree-shaking friendly).
4
+ * The same names as `index.ts`, backed by the browser kernel in `./browser`,
5
+ * a port of Node's `lib/internal/streams`.
8
6
  */
9
7
  // Shared type + platform-independent exports
10
8
  export * from "./index.base.js";
11
- // Core stream classes (browser implementations)
12
- import { Readable } from "./browser/readable.js";
13
- export { Writable, toWritable } from "./browser/writable.js";
14
- export { Transform } from "./browser/transform.js";
15
- import { Duplex } from "./browser/duplex.js";
16
- export { PassThrough } from "./browser/passthrough.js";
17
- export { Collector } from "./browser/collector.js";
18
- export { Readable, Duplex };
19
- // Late-binding injection: break circular Readable ↔ Duplex
20
- import { registerDuplexFrom } from "./browser/_lazy.js";
21
- // The registry is type-erased (`source: unknown`); re-project onto Duplex.from's
22
- // accepted source union at this single boundary.
23
- registerDuplexFrom(source => Duplex.from(source));
9
+ // Core stream classes
10
+ export { Readable, Duplex, Transform, PassThrough } from "./kernel/classes.js";
11
+ export { Writable } from "./kernel/writable.js";
12
+ export { getDefaultHighWaterMark, setDefaultHighWaterMark } from "./kernel/state.js";
13
+ // Collector
14
+ export { Collector, createCollector } from "./browser/collector.js";
24
15
  // Factory functions + re-exported helpers
25
- export { PullStream, BufferedStream, createStringChunk, createByteChunk, createReadable, createReadableFromAsyncIterable, createReadableFromArray, createWritable, createTransform, createCollector, createPassThrough, createPullStream, createBufferedStream, createDuplex, createReadableFromGenerator, createReadableFromPromise, createEmptyReadable, createNullWritable } from "./browser/factories.js";
16
+ export { PullStream, BufferedStream, createStringChunk, createByteChunk, createReadable, createReadableFromAsyncIterable, createReadableFromArray, createWritable, createTransform, createPassThrough, createPullStream, createBufferedStream, createDuplex, createReadableFromGenerator, createReadableFromPromise, createEmptyReadable, createNullWritable, filter, fromBytes, fromJSON, fromString, transform } from "./browser/factories.js";
26
17
  // Pipeline & Finished
27
18
  export { pipeline, finished, finishedAll } from "./browser/pipeline.js";
28
19
  // Compose
29
20
  export { compose } from "./browser/compose.js";
30
21
  // Utilities
31
- export { streamToPromise, streamToUint8Array, streamToBuffer, streamToString, drainStream, copyStream, isTransform, isDuplex, isStream, addAbortSignal, isDisturbed, isReadable, isWritable, duplexPair, consumers, promises } from "./browser/utils.js";
22
+ export { streamToPromise, streamToUint8Array, streamToBuffer, streamToString, drainStream, copyStream, isTransform, isDuplex, isStream, addAbortSignal, isDisturbed, isReadable, isWritable, consumers, promises } from "./browser/utils.js";
23
+ // Web Streams conversions
24
+ export { duplexPair } from "./browser/duplex-pair.js";
25
+ export { readableFromWeb, readableToWeb, toWritable, writableFromWeb, writableToWeb } from "./browser/web.js";
@@ -1,11 +1,8 @@
1
1
  /**
2
2
  * Stream Module (Node.js entry)
3
3
  *
4
- * Public entrypoint for stream utilities and classes.
5
- *
6
- * Notes:
7
- * - This file is intentionally export-only (tree-shaking friendly).
8
- * - Browser builds should import from `@stream/index.browser`.
4
+ * Node's own `node:stream` classes, plus the module's helpers around them.
5
+ * `index.browser.ts` exports the same names backed by the browser kernel.
9
6
  *
10
7
  * @example
11
8
  * ```ts
@@ -19,17 +16,16 @@
19
16
  // Shared type + platform-independent exports
20
17
  export * from "./index.base.js";
21
18
  // Core stream classes (native Node.js)
22
- import { Readable, Transform, Duplex, PassThrough } from "stream";
23
- export { Readable, Transform, Duplex, PassThrough };
24
- // Writable (extended with browser-compatible API)
25
- export { Writable, toWritable } from "./node/writable.js";
19
+ export { Readable, Writable, Duplex, Transform, PassThrough, getDefaultHighWaterMark, setDefaultHighWaterMark } from "stream";
26
20
  // Collector
27
21
  export { Collector, createCollector } from "./node/collector.js";
28
22
  // Factory functions + re-exported helpers
29
- export { PullStream, BufferedStream, createStringChunk, createByteChunk, createReadable, createReadableFromAsyncIterable, createReadableFromArray, createWritable, createTransform, createPassThrough, createPullStream, createBufferedStream, createDuplex, createReadableFromGenerator, createReadableFromPromise, createEmptyReadable, createNullWritable } from "./node/factories.js";
23
+ export { PullStream, BufferedStream, createStringChunk, createByteChunk, createReadable, createReadableFromAsyncIterable, createReadableFromArray, createWritable, createTransform, createPassThrough, createPullStream, createBufferedStream, createDuplex, createReadableFromGenerator, createReadableFromPromise, createEmptyReadable, createNullWritable, filter, fromBytes, fromJSON, fromString, transform } from "./node/factories.js";
30
24
  // Pipeline & Finished
31
25
  export { pipeline, finished, finishedAll } from "./node/pipeline.js";
32
26
  // Compose
33
27
  export { compose } from "./node/compose.js";
34
28
  // Utilities
35
29
  export { streamToPromise, streamToUint8Array, streamToBuffer, streamToString, drainStream, copyStream, isTransform, isDuplex, isStream, addAbortSignal, isDisturbed, isReadable, isWritable, duplexPair, consumers, promises } from "./node/utils.js";
30
+ // Web Streams conversions
31
+ export { readableFromWeb, readableToWeb, toWritable, writableFromWeb, writableToWeb } from "./node/web.js";