@yume-chan/stream-extra 0.0.20 → 0.0.22

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 (65) hide show
  1. package/CHANGELOG.json +18 -0
  2. package/CHANGELOG.md +13 -1
  3. package/esm/buffered-transform.d.ts.map +1 -1
  4. package/esm/buffered-transform.js.map +1 -1
  5. package/esm/buffered.d.ts +0 -2
  6. package/esm/buffered.d.ts.map +1 -1
  7. package/esm/buffered.js +28 -21
  8. package/esm/buffered.js.map +1 -1
  9. package/esm/concat.d.ts +35 -0
  10. package/esm/concat.d.ts.map +1 -0
  11. package/esm/concat.js +128 -0
  12. package/esm/concat.js.map +1 -0
  13. package/esm/consumable.d.ts +3 -3
  14. package/esm/consumable.d.ts.map +1 -1
  15. package/esm/consumable.js +4 -4
  16. package/esm/consumable.js.map +1 -1
  17. package/esm/distribution.d.ts.map +1 -1
  18. package/esm/distribution.js.map +1 -1
  19. package/esm/duplex.d.ts +2 -2
  20. package/esm/duplex.d.ts.map +1 -1
  21. package/esm/duplex.js +2 -2
  22. package/esm/duplex.js.map +1 -1
  23. package/esm/index.d.ts +1 -1
  24. package/esm/index.d.ts.map +1 -1
  25. package/esm/index.js +1 -1
  26. package/esm/index.js.map +1 -1
  27. package/esm/push-readable.d.ts +1 -0
  28. package/esm/push-readable.d.ts.map +1 -1
  29. package/esm/push-readable.js +24 -10
  30. package/esm/push-readable.js.map +1 -1
  31. package/esm/split-string.d.ts.map +1 -1
  32. package/esm/split-string.js.map +1 -1
  33. package/esm/stream.js +0 -14
  34. package/esm/stream.js.map +1 -1
  35. package/esm/struct-deserialize.d.ts.map +1 -1
  36. package/esm/struct-deserialize.js.map +1 -1
  37. package/esm/wrap-readable.d.ts +2 -2
  38. package/esm/wrap-readable.d.ts.map +1 -1
  39. package/esm/wrap-readable.js +8 -8
  40. package/esm/wrap-readable.js.map +1 -1
  41. package/esm/wrap-writable.d.ts.map +1 -1
  42. package/esm/wrap-writable.js.map +1 -1
  43. package/package.json +9 -9
  44. package/src/buffered-transform.ts +4 -4
  45. package/src/buffered.ts +32 -25
  46. package/src/concat.ts +160 -0
  47. package/src/consumable.ts +45 -33
  48. package/src/decode-utf8.ts +1 -1
  49. package/src/distribution.ts +5 -5
  50. package/src/duplex.ts +27 -20
  51. package/src/index.ts +1 -1
  52. package/src/pipe-from.ts +1 -1
  53. package/src/push-readable.ts +33 -17
  54. package/src/split-string.ts +2 -2
  55. package/src/stream.ts +0 -13
  56. package/src/struct-deserialize.ts +2 -2
  57. package/src/struct-serialize.ts +1 -1
  58. package/src/wrap-readable.ts +39 -34
  59. package/src/wrap-writable.ts +5 -5
  60. package/tsconfig.build.tsbuildinfo +1 -1
  61. package/esm/gather-string.d.ts +0 -7
  62. package/esm/gather-string.d.ts.map +0 -1
  63. package/esm/gather-string.js +0 -16
  64. package/esm/gather-string.js.map +0 -1
  65. package/src/gather-string.ts +0 -17
package/src/consumable.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { PromiseResolver } from "@yume-chan/async";
2
2
 
3
- import type { QueuingStrategy, WritableStreamDefaultWriter } from "./stream.js";
3
+ import type {
4
+ QueuingStrategy,
5
+ WritableStreamDefaultController,
6
+ WritableStreamDefaultWriter,
7
+ } from "./stream.js";
4
8
  import { ReadableStream, TransformStream, WritableStream } from "./stream.js";
5
9
 
6
10
  interface Task {
@@ -29,25 +33,25 @@ export class Consumable<T> {
29
33
  readonly #task: Task;
30
34
  readonly #resolver: PromiseResolver<void>;
31
35
 
32
- public readonly value: T;
33
- public readonly consumed: Promise<void>;
36
+ readonly value: T;
37
+ readonly consumed: Promise<void>;
34
38
 
35
- public constructor(value: T) {
39
+ constructor(value: T) {
36
40
  this.#task = createTask("Consumable");
37
41
  this.value = value;
38
42
  this.#resolver = new PromiseResolver<void>();
39
43
  this.consumed = this.#resolver.promise;
40
44
  }
41
45
 
42
- public consume() {
46
+ consume() {
43
47
  this.#resolver.resolve();
44
48
  }
45
49
 
46
- public error(error: any) {
50
+ error(error: any) {
47
51
  this.#resolver.reject(error);
48
52
  }
49
53
 
50
- public async tryConsume<U>(callback: (value: T) => U) {
54
+ async tryConsume<U>(callback: (value: T) => U) {
51
55
  try {
52
56
  // eslint-disable-next-line @typescript-eslint/await-thenable
53
57
  const result = await this.#task.run(() => callback(this.value));
@@ -62,7 +66,7 @@ export class Consumable<T> {
62
66
 
63
67
  async function enqueue<T>(
64
68
  controller: { enqueue: (chunk: Consumable<T>) => void },
65
- chunk: T
69
+ chunk: T,
66
70
  ) {
67
71
  const output = new Consumable(chunk);
68
72
  controller.enqueue(output);
@@ -70,7 +74,7 @@ async function enqueue<T>(
70
74
  }
71
75
 
72
76
  export class WrapConsumableStream<T> extends TransformStream<T, Consumable<T>> {
73
- public constructor() {
77
+ constructor() {
74
78
  super({
75
79
  async transform(chunk, controller) {
76
80
  await enqueue(controller, chunk);
@@ -83,7 +87,7 @@ export class UnwrapConsumableStream<T> extends TransformStream<
83
87
  Consumable<T>,
84
88
  T
85
89
  > {
86
- public constructor() {
90
+ constructor() {
87
91
  super({
88
92
  transform(chunk, controller) {
89
93
  controller.enqueue(chunk.value);
@@ -101,18 +105,18 @@ export interface ConsumableReadableStreamController<T> {
101
105
 
102
106
  export interface ConsumableReadableStreamSource<T> {
103
107
  start?(
104
- controller: ConsumableReadableStreamController<T>
108
+ controller: ConsumableReadableStreamController<T>,
105
109
  ): void | PromiseLike<void>;
106
110
  pull?(
107
- controller: ConsumableReadableStreamController<T>
111
+ controller: ConsumableReadableStreamController<T>,
108
112
  ): void | PromiseLike<void>;
109
113
  cancel?(reason: any): void | PromiseLike<void>;
110
114
  }
111
115
 
112
116
  export class ConsumableReadableStream<T> extends ReadableStream<Consumable<T>> {
113
- public constructor(
117
+ constructor(
114
118
  source: ConsumableReadableStreamSource<T>,
115
- strategy?: QueuingStrategy<T>
119
+ strategy?: QueuingStrategy<T>,
116
120
  ) {
117
121
  let wrappedController:
118
122
  | ConsumableReadableStreamController<T>
@@ -155,31 +159,36 @@ export class ConsumableReadableStream<T> extends ReadableStream<Consumable<T>> {
155
159
  await source.cancel?.(reason);
156
160
  },
157
161
  },
158
- wrappedStrategy
162
+ wrappedStrategy,
159
163
  );
160
164
  }
161
165
  }
162
166
 
163
167
  export interface ConsumableWritableStreamSink<T> {
164
- start?(): void | PromiseLike<void>;
165
- write?(chunk: T): void | PromiseLike<void>;
168
+ start?(
169
+ controller: WritableStreamDefaultController,
170
+ ): void | PromiseLike<void>;
171
+ write?(
172
+ chunk: T,
173
+ controller: WritableStreamDefaultController,
174
+ ): void | PromiseLike<void>;
166
175
  abort?(reason: any): void | PromiseLike<void>;
167
176
  close?(): void | PromiseLike<void>;
168
177
  }
169
178
 
170
179
  export class ConsumableWritableStream<T> extends WritableStream<Consumable<T>> {
171
- public static async write<T>(
180
+ static async write<T>(
172
181
  writer: WritableStreamDefaultWriter<Consumable<T>>,
173
- value: T
182
+ value: T,
174
183
  ) {
175
184
  const consumable = new Consumable(value);
176
185
  await writer.write(consumable);
177
186
  await consumable.consumed;
178
187
  }
179
188
 
180
- public constructor(
189
+ constructor(
181
190
  sink: ConsumableWritableStreamSink<T>,
182
- strategy?: QueuingStrategy<T>
191
+ strategy?: QueuingStrategy<T>,
183
192
  ) {
184
193
  let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
185
194
  if (strategy) {
@@ -196,11 +205,13 @@ export class ConsumableWritableStream<T> extends WritableStream<Consumable<T>> {
196
205
 
197
206
  super(
198
207
  {
199
- start() {
200
- return sink.start?.();
208
+ start(controller) {
209
+ return sink.start?.(controller);
201
210
  },
202
- async write(chunk) {
203
- await chunk.tryConsume((value) => sink.write?.(value));
211
+ async write(chunk, controller) {
212
+ await chunk.tryConsume(
213
+ (value) => sink.write?.(value, controller),
214
+ );
204
215
  chunk.consume();
205
216
  },
206
217
  abort(reason) {
@@ -210,21 +221,21 @@ export class ConsumableWritableStream<T> extends WritableStream<Consumable<T>> {
210
221
  return sink.close?.();
211
222
  },
212
223
  },
213
- wrappedStrategy
224
+ wrappedStrategy,
214
225
  );
215
226
  }
216
227
  }
217
228
 
218
229
  export interface ConsumableTransformer<I, O> {
219
230
  start?(
220
- controller: ConsumableReadableStreamController<O>
231
+ controller: ConsumableReadableStreamController<O>,
221
232
  ): void | PromiseLike<void>;
222
233
  transform?(
223
234
  chunk: I,
224
- controller: ConsumableReadableStreamController<O>
235
+ controller: ConsumableReadableStreamController<O>,
225
236
  ): void | PromiseLike<void>;
226
237
  flush?(
227
- controller: ConsumableReadableStreamController<O>
238
+ controller: ConsumableReadableStreamController<O>,
228
239
  ): void | PromiseLike<void>;
229
240
  }
230
241
 
@@ -232,7 +243,7 @@ export class ConsumableTransformStream<I, O> extends TransformStream<
232
243
  Consumable<I>,
233
244
  Consumable<O>
234
245
  > {
235
- public constructor(transformer: ConsumableTransformer<I, O>) {
246
+ constructor(transformer: ConsumableTransformer<I, O>) {
236
247
  let wrappedController:
237
248
  | ConsumableReadableStreamController<O>
238
249
  | undefined;
@@ -254,8 +265,9 @@ export class ConsumableTransformStream<I, O> extends TransformStream<
254
265
  await transformer.start?.(wrappedController);
255
266
  },
256
267
  async transform(chunk) {
257
- await chunk.tryConsume((value) =>
258
- transformer.transform?.(value, wrappedController!)
268
+ await chunk.tryConsume(
269
+ (value) =>
270
+ transformer.transform?.(value, wrappedController!),
259
271
  );
260
272
  chunk.consume();
261
273
  },
@@ -270,7 +282,7 @@ export class ConsumableInspectStream<T> extends TransformStream<
270
282
  Consumable<T>,
271
283
  Consumable<T>
272
284
  > {
273
- public constructor(callback: (value: T) => void) {
285
+ constructor(callback: (value: T) => void) {
274
286
  super({
275
287
  transform(chunk, controller) {
276
288
  callback(chunk.value);
@@ -3,7 +3,7 @@ import { decodeUtf8 } from "@yume-chan/struct";
3
3
  import { TransformStream } from "./stream.js";
4
4
 
5
5
  export class DecodeUtf8Stream extends TransformStream<Uint8Array, string> {
6
- public constructor() {
6
+ constructor() {
7
7
  super({
8
8
  transform(chunk, controller) {
9
9
  controller.enqueue(decodeUtf8(chunk));
@@ -9,7 +9,7 @@ export class BufferCombiner {
9
9
  #offset: number;
10
10
  #available: number;
11
11
 
12
- public constructor(size: number) {
12
+ constructor(size: number) {
13
13
  this.#capacity = size;
14
14
  this.#buffer = new Uint8Array(size);
15
15
  this.#offset = 0;
@@ -23,7 +23,7 @@ export class BufferCombiner {
23
23
  * A generator that yields buffers of specified size.
24
24
  * It may yield the same buffer multiple times, consume the data before calling `next`.
25
25
  */
26
- public *push(data: Uint8Array): Generator<Uint8Array, void, void> {
26
+ *push(data: Uint8Array): Generator<Uint8Array, void, void> {
27
27
  let offset = 0;
28
28
  let available = data.byteLength;
29
29
 
@@ -31,7 +31,7 @@ export class BufferCombiner {
31
31
  if (available >= this.#available) {
32
32
  this.#buffer.set(
33
33
  data.subarray(0, this.#available),
34
- this.#offset
34
+ this.#offset,
35
35
  );
36
36
  offset += this.#available;
37
37
  available -= this.#available;
@@ -65,7 +65,7 @@ export class BufferCombiner {
65
65
  }
66
66
  }
67
67
 
68
- public flush(): Uint8Array | undefined {
68
+ flush(): Uint8Array | undefined {
69
69
  if (this.#offset === 0) {
70
70
  return undefined;
71
71
  }
@@ -81,7 +81,7 @@ export class DistributionStream extends ConsumableTransformStream<
81
81
  Uint8Array,
82
82
  Uint8Array
83
83
  > {
84
- public constructor(size: number, combine = false) {
84
+ constructor(size: number, combine = false) {
85
85
  const combiner = combine ? new BufferCombiner(size) : undefined;
86
86
  super({
87
87
  async transform(chunk, controller) {
package/src/duplex.ts CHANGED
@@ -2,6 +2,7 @@ import { PromiseResolver } from "@yume-chan/async";
2
2
  import type { ValueOrPromise } from "@yume-chan/struct";
3
3
 
4
4
  import type {
5
+ QueuingStrategy,
5
6
  ReadableStream,
6
7
  ReadableStreamDefaultController,
7
8
  WritableStreamDefaultWriter,
@@ -50,39 +51,45 @@ export class DuplexStreamFactory<R, W> {
50
51
  #writers: WritableStreamDefaultWriter<W>[] = [];
51
52
 
52
53
  #writableClosed = false;
53
- public get writableClosed() {
54
+ get writableClosed() {
54
55
  return this.#writableClosed;
55
56
  }
56
57
 
57
58
  #closed = new PromiseResolver<void>();
58
- public get closed() {
59
+ get closed() {
59
60
  return this.#closed.promise;
60
61
  }
61
62
 
62
63
  readonly #options: DuplexStreamFactoryOptions;
63
64
 
64
- public constructor(options?: DuplexStreamFactoryOptions) {
65
+ constructor(options?: DuplexStreamFactoryOptions) {
65
66
  this.#options = options ?? {};
66
67
  }
67
68
 
68
- public wrapReadable(readable: ReadableStream<R>): WrapReadableStream<R> {
69
- return new WrapReadableStream<R>({
70
- start: (controller) => {
71
- this.#readableControllers.push(controller);
72
- return readable;
69
+ wrapReadable(
70
+ readable: ReadableStream<R>,
71
+ strategy?: QueuingStrategy<R>,
72
+ ): WrapReadableStream<R> {
73
+ return new WrapReadableStream<R>(
74
+ {
75
+ start: (controller) => {
76
+ this.#readableControllers.push(controller);
77
+ return readable;
78
+ },
79
+ cancel: async () => {
80
+ // cancel means the local peer wants to close the connection.
81
+ await this.close();
82
+ },
83
+ close: async () => {
84
+ // stream end means the remote peer closed the connection first.
85
+ await this.dispose();
86
+ },
73
87
  },
74
- cancel: async () => {
75
- // cancel means the local peer wants to close the connection.
76
- await this.close();
77
- },
78
- close: async () => {
79
- // stream end means the remote peer closed the connection first.
80
- await this.dispose();
81
- },
82
- });
88
+ strategy,
89
+ );
83
90
  }
84
91
 
85
- public createWritable(stream: WritableStream<W>): WritableStream<W> {
92
+ createWritable(stream: WritableStream<W>): WritableStream<W> {
86
93
  const writer = stream.getWriter();
87
94
  this.#writers.push(writer);
88
95
 
@@ -104,7 +111,7 @@ export class DuplexStreamFactory<R, W> {
104
111
  });
105
112
  }
106
113
 
107
- public async close() {
114
+ async close() {
108
115
  if (this.#writableClosed) {
109
116
  return;
110
117
  }
@@ -122,7 +129,7 @@ export class DuplexStreamFactory<R, W> {
122
129
  }
123
130
  }
124
131
 
125
- public async dispose() {
132
+ async dispose() {
126
133
  this.#writableClosed = true;
127
134
  this.#closed.resolve();
128
135
 
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export * from "./buffered-transform.js";
2
2
  export * from "./buffered.js";
3
+ export * from "./concat.js";
3
4
  export * from "./consumable.js";
4
5
  export * from "./decode-utf8.js";
5
6
  export * from "./distribution.js";
6
7
  export * from "./duplex.js";
7
- export * from "./gather-string.js";
8
8
  export * from "./inspect.js";
9
9
  export * from "./pipe-from.js";
10
10
  export * from "./push-readable.js";
package/src/pipe-from.ts CHANGED
@@ -12,7 +12,7 @@ import { WritableStream } from "./stream.js";
12
12
  */
13
13
  export function pipeFrom<W, T>(
14
14
  writable: WritableStream<W>,
15
- pair: ReadableWritablePair<W, T>
15
+ pair: ReadableWritablePair<W, T>,
16
16
  ) {
17
17
  const writer = pair.writable.getWriter();
18
18
  const pipe = pair.readable.pipeTo(writable);
@@ -14,10 +14,12 @@ export interface PushReadableStreamController<T> {
14
14
  }
15
15
 
16
16
  export type PushReadableStreamSource<T> = (
17
- controller: PushReadableStreamController<T>
17
+ controller: PushReadableStreamController<T>,
18
18
  ) => void | Promise<void>;
19
19
 
20
20
  export class PushReadableStream<T> extends ReadableStream<T> {
21
+ #zeroHighWaterMarkAllowEnqueue = false;
22
+
21
23
  /**
22
24
  * Create a new `PushReadableStream` from a source.
23
25
  *
@@ -25,33 +27,41 @@ export class PushReadableStream<T> extends ReadableStream<T> {
25
27
  * when the `Promise` is resolved, and be errored when the `Promise` is rejected.
26
28
  * @param strategy
27
29
  */
28
- public constructor(
30
+ constructor(
29
31
  source: PushReadableStreamSource<T>,
30
- strategy?: QueuingStrategy<T>
32
+ strategy?: QueuingStrategy<T>,
31
33
  ) {
32
34
  let waterMarkLow: PromiseResolver<void> | undefined;
33
35
  const abortController = new AbortController();
34
36
 
35
37
  super(
36
38
  {
37
- start: (controller) => {
39
+ start: async (controller) => {
40
+ await Promise.resolve();
41
+
38
42
  const result = source({
39
43
  abortSignal: abortController.signal,
40
- async enqueue(chunk) {
44
+ enqueue: async (chunk) => {
41
45
  if (abortController.signal.aborted) {
42
46
  // If the stream is already cancelled,
43
47
  // throw immediately.
44
- throw (
45
- abortController.signal.reason ??
46
- new Error("Aborted")
47
- );
48
+ throw abortController.signal.reason;
49
+ }
50
+
51
+ if (controller.desiredSize === null) {
52
+ // `desiredSize` being `null` means the stream is in error state,
53
+ // `controller.enqueue` will throw an error for us.
54
+ controller.enqueue(chunk);
55
+ return;
56
+ }
57
+
58
+ if (this.#zeroHighWaterMarkAllowEnqueue) {
59
+ this.#zeroHighWaterMarkAllowEnqueue = false;
60
+ controller.enqueue(chunk);
61
+ return;
48
62
  }
49
63
 
50
- // Only when the stream is errored, `desiredSize` will be `null`.
51
- // But since `null <= 0` is `true`
52
- // (`null <= 0` is evaluated as `!(null > 0)` => `!false` => `true`),
53
- // not handling it will cause a deadlock.
54
- if ((controller.desiredSize ?? 1) <= 0) {
64
+ if (controller.desiredSize <= 0) {
55
65
  waterMarkLow = new PromiseResolver<void>();
56
66
  await waterMarkLow.promise;
57
67
  }
@@ -79,19 +89,25 @@ export class PushReadableStream<T> extends ReadableStream<T> {
79
89
  },
80
90
  (e) => {
81
91
  controller.error(e);
82
- }
92
+ },
83
93
  );
84
94
  }
85
95
  },
86
96
  pull: () => {
87
- waterMarkLow?.resolve();
97
+ if (waterMarkLow) {
98
+ waterMarkLow.resolve();
99
+ return;
100
+ }
101
+ if (strategy?.highWaterMark === 0) {
102
+ this.#zeroHighWaterMarkAllowEnqueue = true;
103
+ }
88
104
  },
89
105
  cancel: (reason) => {
90
106
  abortController.abort(reason);
91
107
  waterMarkLow?.reject(reason);
92
108
  },
93
109
  },
94
- strategy
110
+ strategy,
95
111
  );
96
112
  }
97
113
  }
@@ -2,7 +2,7 @@ import { TransformStream } from "./stream.js";
2
2
 
3
3
  function* split(
4
4
  input: string,
5
- separator: string
5
+ separator: string,
6
6
  ): Generator<string, void, void> {
7
7
  let start = 0;
8
8
 
@@ -20,7 +20,7 @@ function* split(
20
20
  }
21
21
 
22
22
  export class SplitStringStream extends TransformStream<string, string> {
23
- public constructor(separator: string) {
23
+ constructor(separator: string) {
24
24
  super({
25
25
  transform(chunk, controller) {
26
26
  for (const part of split(chunk, separator)) {
package/src/stream.ts CHANGED
@@ -45,20 +45,7 @@ export type TransformStream<I = any, O = any> = TransformStreamPolyfill<I, O>;
45
45
  export let TransformStream = TransformStreamPolyfill;
46
46
 
47
47
  if (GLOBAL.ReadableStream && GLOBAL.WritableStream && GLOBAL.TransformStream) {
48
- // Use browser native implementation
49
48
  ReadableStream = GLOBAL.ReadableStream;
50
49
  WritableStream = GLOBAL.WritableStream;
51
50
  TransformStream = GLOBAL.TransformStream;
52
- } else {
53
- // TODO: enable loading Node.js stream implementation when bundler supports Top Level Await
54
- // try {
55
- // // Use Node.js native implementation
56
- // const MODULE_NAME = "node:stream/web";
57
- // const StreamWeb = (await import(MODULE_NAME)) as GlobalExtension;
58
- // ReadableStream = StreamWeb.ReadableStream;
59
- // WritableStream = StreamWeb.WritableStream;
60
- // TransformStream = StreamWeb.TransformStream;
61
- // } catch {
62
- // // ignore
63
- // }
64
51
  }
@@ -4,9 +4,9 @@ import type { StructValueType } from "@yume-chan/struct";
4
4
  import { BufferedTransformStream } from "./buffered-transform.js";
5
5
 
6
6
  export class StructDeserializeStream<
7
- T extends Struct<any, any, any, any>
7
+ T extends Struct<any, any, any, any>,
8
8
  > extends BufferedTransformStream<StructValueType<T>> {
9
- public constructor(struct: T) {
9
+ constructor(struct: T) {
10
10
  super((stream) => {
11
11
  return struct.deserialize(stream);
12
12
  });
@@ -3,7 +3,7 @@ import type Struct from "@yume-chan/struct";
3
3
  import { TransformStream } from "./stream.js";
4
4
 
5
5
  export class StructSerializeStream<
6
- T extends Struct<any, any, any, any>
6
+ T extends Struct<any, any, any, any>,
7
7
  > extends TransformStream<T["TInit"], Uint8Array> {
8
8
  constructor(struct: T) {
9
9
  super({
@@ -1,13 +1,14 @@
1
1
  import type { ValueOrPromise } from "@yume-chan/struct";
2
2
 
3
3
  import type {
4
+ QueuingStrategy,
4
5
  ReadableStreamDefaultController,
5
6
  ReadableStreamDefaultReader,
6
7
  } from "./stream.js";
7
8
  import { ReadableStream } from "./stream.js";
8
9
 
9
10
  export type WrapReadableStreamStart<T> = (
10
- controller: ReadableStreamDefaultController<T>
11
+ controller: ReadableStreamDefaultController<T>,
11
12
  ) => ValueOrPromise<ReadableStream<T>>;
12
13
 
13
14
  export interface ReadableStreamWrapper<T> {
@@ -21,7 +22,7 @@ function getWrappedReadableStream<T>(
21
22
  | ReadableStream<T>
22
23
  | WrapReadableStreamStart<T>
23
24
  | ReadableStreamWrapper<T>,
24
- controller: ReadableStreamDefaultController<T>
25
+ controller: ReadableStreamDefaultController<T>,
25
26
  ) {
26
27
  if ("start" in wrapper) {
27
28
  return wrapper.start(controller);
@@ -42,47 +43,51 @@ function getWrappedReadableStream<T>(
42
43
  * 3. Convert native `ReadableStream`s to polyfilled ones so they can `pipe` between.
43
44
  */
44
45
  export class WrapReadableStream<T> extends ReadableStream<T> {
45
- public readable!: ReadableStream<T>;
46
+ readable!: ReadableStream<T>;
46
47
 
47
48
  #reader!: ReadableStreamDefaultReader<T>;
48
49
 
49
- public constructor(
50
+ constructor(
50
51
  wrapper:
51
52
  | ReadableStream<T>
52
53
  | WrapReadableStreamStart<T>
53
- | ReadableStreamWrapper<T>
54
+ | ReadableStreamWrapper<T>,
55
+ strategy?: QueuingStrategy<T>,
54
56
  ) {
55
- super({
56
- start: async (controller) => {
57
- // `start` is invoked before `ReadableStream`'s constructor finish,
58
- // so using `this` synchronously causes
59
- // "Must call super constructor in derived class before accessing 'this' or returning from derived constructor".
60
- // Queue a microtask to avoid this.
61
- await Promise.resolve();
57
+ super(
58
+ {
59
+ start: async (controller) => {
60
+ // `start` is invoked before `ReadableStream`'s constructor finish,
61
+ // so using `this` synchronously causes
62
+ // "Must call super constructor in derived class before accessing 'this' or returning from derived constructor".
63
+ // Queue a microtask to avoid this.
64
+ await Promise.resolve();
62
65
 
63
- this.readable = await getWrappedReadableStream(
64
- wrapper,
65
- controller
66
- );
67
- this.#reader = this.readable.getReader();
68
- },
69
- cancel: async (reason) => {
70
- await this.#reader.cancel(reason);
71
- if ("cancel" in wrapper) {
72
- await wrapper.cancel?.(reason);
73
- }
74
- },
75
- pull: async (controller) => {
76
- const result = await this.#reader.read();
77
- if (result.done) {
78
- controller.close();
79
- if ("close" in wrapper) {
80
- await wrapper.close?.();
66
+ this.readable = await getWrappedReadableStream(
67
+ wrapper,
68
+ controller,
69
+ );
70
+ this.#reader = this.readable.getReader();
71
+ },
72
+ pull: async (controller) => {
73
+ const result = await this.#reader.read();
74
+ if (result.done) {
75
+ controller.close();
76
+ if ("close" in wrapper) {
77
+ await wrapper.close?.();
78
+ }
79
+ } else {
80
+ controller.enqueue(result.value);
81
+ }
82
+ },
83
+ cancel: async (reason) => {
84
+ await this.#reader.cancel(reason);
85
+ if ("cancel" in wrapper) {
86
+ await wrapper.cancel?.(reason);
81
87
  }
82
- } else {
83
- controller.enqueue(result.value);
84
- }
88
+ },
85
89
  },
86
- });
90
+ strategy,
91
+ );
87
92
  }
88
93
  }