@yume-chan/stream-extra 0.0.24 → 1.0.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 (81) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/esm/buffered-transform.d.ts +3 -3
  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 +3 -6
  6. package/esm/buffered.d.ts.map +1 -1
  7. package/esm/buffered.js +87 -75
  8. package/esm/buffered.js.map +1 -1
  9. package/esm/concat.js +2 -2
  10. package/esm/concat.js.map +1 -1
  11. package/esm/consumable.d.ts +15 -10
  12. package/esm/consumable.d.ts.map +1 -1
  13. package/esm/consumable.js +82 -86
  14. package/esm/consumable.js.map +1 -1
  15. package/esm/duplex.d.ts +2 -2
  16. package/esm/duplex.d.ts.map +1 -1
  17. package/esm/duplex.js +2 -6
  18. package/esm/duplex.js.map +1 -1
  19. package/esm/index.d.ts +1 -0
  20. package/esm/index.d.ts.map +1 -1
  21. package/esm/index.js +1 -0
  22. package/esm/index.js.map +1 -1
  23. package/esm/maybe-consumable-ns.d.ts +16 -0
  24. package/esm/maybe-consumable-ns.d.ts.map +1 -0
  25. package/esm/maybe-consumable-ns.js +44 -0
  26. package/esm/maybe-consumable-ns.js.map +1 -0
  27. package/esm/maybe-consumable.d.ts +2 -19
  28. package/esm/maybe-consumable.d.ts.map +1 -1
  29. package/esm/maybe-consumable.js +1 -61
  30. package/esm/maybe-consumable.js.map +1 -1
  31. package/esm/push-readable.d.ts +16 -2
  32. package/esm/push-readable.d.ts.map +1 -1
  33. package/esm/push-readable.js +176 -17
  34. package/esm/push-readable.js.map +1 -1
  35. package/esm/stream.d.ts +5 -5
  36. package/esm/stream.d.ts.map +1 -1
  37. package/esm/stream.js +54 -5
  38. package/esm/stream.js.map +1 -1
  39. package/esm/struct-deserialize.d.ts +3 -4
  40. package/esm/struct-deserialize.d.ts.map +1 -1
  41. package/esm/struct-deserialize.js.map +1 -1
  42. package/esm/struct-serialize.d.ts +2 -2
  43. package/esm/struct-serialize.d.ts.map +1 -1
  44. package/esm/struct-serialize.js.map +1 -1
  45. package/esm/task.d.ts.map +1 -1
  46. package/esm/task.js +2 -2
  47. package/esm/task.js.map +1 -1
  48. package/esm/try-close.d.ts +10 -0
  49. package/esm/try-close.d.ts.map +1 -0
  50. package/esm/try-close.js +19 -0
  51. package/esm/try-close.js.map +1 -0
  52. package/esm/types.d.ts +2 -3
  53. package/esm/types.d.ts.map +1 -1
  54. package/esm/wrap-readable.d.ts +5 -4
  55. package/esm/wrap-readable.d.ts.map +1 -1
  56. package/esm/wrap-readable.js +14 -9
  57. package/esm/wrap-readable.js.map +1 -1
  58. package/esm/wrap-writable.d.ts +2 -2
  59. package/esm/wrap-writable.d.ts.map +1 -1
  60. package/esm/wrap-writable.js +4 -6
  61. package/esm/wrap-writable.js.map +1 -1
  62. package/package.json +11 -13
  63. package/src/buffered-transform.ts +2 -2
  64. package/src/buffered.ts +107 -83
  65. package/src/concat.ts +2 -2
  66. package/src/consumable.ts +117 -112
  67. package/src/duplex.ts +4 -7
  68. package/src/index.ts +1 -0
  69. package/src/maybe-consumable-ns.ts +75 -0
  70. package/src/maybe-consumable.ts +2 -98
  71. package/src/push-readable.ts +213 -19
  72. package/src/stream.ts +68 -8
  73. package/src/struct-deserialize.ts +3 -6
  74. package/src/struct-serialize.ts +3 -3
  75. package/src/task.ts +2 -2
  76. package/src/try-close.ts +44 -0
  77. package/src/types.ts +2 -2
  78. package/src/wrap-readable.ts +20 -14
  79. package/src/wrap-writable.ts +6 -9
  80. package/tsconfig.build.tsbuildinfo +1 -1
  81. package/CHANGELOG.json +0 -104
package/src/buffered.ts CHANGED
@@ -1,15 +1,15 @@
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
1
2
  import type { AsyncExactReadable } from "@yume-chan/struct";
2
- import { ExactReadableEndedError } from "@yume-chan/struct";
3
+ import { bipedal, ExactReadableEndedError } from "@yume-chan/struct";
3
4
 
4
5
  import { PushReadableStream } from "./push-readable.js";
5
6
  import type { ReadableStream, ReadableStreamDefaultReader } from "./stream.js";
6
-
7
- const NOOP = () => {
8
- // no-op
9
- };
7
+ import { tryCancel } from "./try-close.js";
10
8
 
11
9
  export class BufferedReadableStream implements AsyncExactReadable {
12
10
  #buffered: Uint8Array | undefined;
11
+ // PERF: `subarray` is slow
12
+ // don't use it until absolutely necessary
13
13
  #bufferedOffset = 0;
14
14
  #bufferedLength = 0;
15
15
 
@@ -26,99 +26,124 @@ export class BufferedReadableStream implements AsyncExactReadable {
26
26
  this.reader = stream.getReader();
27
27
  }
28
28
 
29
- async #readSource() {
29
+ #readBuffered(length: number) {
30
+ if (!this.#buffered) {
31
+ return undefined;
32
+ }
33
+
34
+ const value = this.#buffered.subarray(
35
+ this.#bufferedOffset,
36
+ this.#bufferedOffset + length,
37
+ );
38
+
39
+ // PERF: Synchronous path for reading from internal buffer
40
+ if (this.#bufferedLength > length) {
41
+ this.#position += length;
42
+ this.#bufferedOffset += length;
43
+ this.#bufferedLength -= length;
44
+ return value;
45
+ }
46
+
47
+ this.#position += this.#bufferedLength;
48
+ this.#buffered = undefined;
49
+ this.#bufferedOffset = 0;
50
+ this.#bufferedLength = 0;
51
+ return value;
52
+ }
53
+
54
+ async #readSource(length: number): Promise<Uint8Array> {
30
55
  const { done, value } = await this.reader.read();
31
56
  if (done) {
32
57
  throw new ExactReadableEndedError();
33
58
  }
59
+
60
+ if (value.length > length) {
61
+ this.#buffered = value;
62
+ this.#bufferedOffset = length;
63
+ this.#bufferedLength = value.length - length;
64
+ this.#position += length;
65
+ return value.subarray(0, length);
66
+ }
67
+
68
+ this.#position += value.length;
34
69
  return value;
35
70
  }
36
71
 
37
- async #readAsync(length: number, initial?: Uint8Array) {
38
- let result: Uint8Array;
39
- let index: number;
72
+ iterateExactly(
73
+ length: number,
74
+ ): Iterator<MaybePromiseLike<Uint8Array>, void, void> {
75
+ let state = this.#buffered ? 0 : 1;
76
+ return {
77
+ next: () => {
78
+ switch (state) {
79
+ case 0: {
80
+ const value = this.#readBuffered(length)!;
81
+ if (value.length === length) {
82
+ state = 2;
83
+ } else {
84
+ length -= value.length;
85
+ state = 1;
86
+ }
87
+ return { done: false, value };
88
+ }
89
+ case 1:
90
+ state = 3;
91
+ return {
92
+ done: false,
93
+ value: this.#readSource(length).then((value) => {
94
+ if (value.length === length) {
95
+ state = 2;
96
+ } else {
97
+ length -= value.length;
98
+ state = 1;
99
+ }
100
+ return value;
101
+ }),
102
+ };
103
+ case 2:
104
+ return { done: true, value: undefined };
105
+ case 3:
106
+ throw new Error(
107
+ "Can't call `next` before previous Promise resolves",
108
+ );
109
+ default:
110
+ throw new Error("unreachable");
111
+ }
112
+ },
113
+ };
114
+ }
40
115
 
116
+ readExactly = bipedal(function* (
117
+ this: BufferedReadableStream,
118
+ then,
119
+ length: number,
120
+ ) {
121
+ let result: Uint8Array | undefined;
122
+ let index = 0;
123
+
124
+ const initial = this.#readBuffered(length);
41
125
  if (initial) {
126
+ if (initial.length === length) {
127
+ return initial;
128
+ }
129
+
42
130
  result = new Uint8Array(length);
43
- result.set(initial);
44
- index = initial.length;
131
+ result.set(initial, index);
132
+ index += initial.length;
45
133
  length -= initial.length;
46
134
  } else {
47
- const array = await this.#readSource();
48
- if (array.length === length) {
49
- this.#position += length;
50
- return array;
51
- }
52
-
53
- if (array.length > length) {
54
- this.#buffered = array;
55
- this.#bufferedOffset = length;
56
- this.#bufferedLength = array.length - length;
57
- this.#position += length;
58
- return array.subarray(0, length);
59
- }
60
-
61
135
  result = new Uint8Array(length);
62
- result.set(array);
63
- index = array.length;
64
- length -= array.length;
65
- this.#position += array.length;
66
136
  }
67
137
 
68
138
  while (length > 0) {
69
- const array = await this.#readSource();
70
- if (array.length === length) {
71
- result.set(array, index);
72
- this.#position += length;
73
- return result;
74
- }
75
-
76
- if (array.length > length) {
77
- this.#buffered = array;
78
- this.#bufferedOffset = length;
79
- this.#bufferedLength = array.length - length;
80
- result.set(array.subarray(0, length), index);
81
- this.#position += length;
82
- return result;
83
- }
84
-
85
- result.set(array, index);
86
- index += array.length;
87
- length -= array.length;
88
- this.#position += array.length;
139
+ const value = yield* then(this.#readSource(length));
140
+ result.set(value, index);
141
+ index += value.length;
142
+ length -= value.length;
89
143
  }
90
144
 
91
145
  return result;
92
- }
93
-
94
- /**
95
- *
96
- * @param length
97
- * @returns
98
- */
99
- readExactly(length: number): Uint8Array | Promise<Uint8Array> {
100
- // PERF: Add a synchronous path for reading from internal buffer
101
- if (this.#buffered) {
102
- const array = this.#buffered;
103
- const offset = this.#bufferedOffset;
104
- if (this.#bufferedLength > length) {
105
- // PERF: `subarray` is slow
106
- // don't use it until absolutely necessary
107
- this.#bufferedOffset += length;
108
- this.#bufferedLength -= length;
109
- this.#position += length;
110
- return array.subarray(offset, offset + length);
111
- }
112
-
113
- this.#buffered = undefined;
114
- this.#bufferedLength = 0;
115
- this.#bufferedOffset = 0;
116
- this.#position += array.length - offset;
117
- return this.#readAsync(length, array.subarray(offset));
118
- }
119
-
120
- return this.#readAsync(length);
121
- }
146
+ });
122
147
 
123
148
  /**
124
149
  * Return a readable stream with unconsumed data (if any) and
@@ -133,8 +158,7 @@ export class BufferedReadableStream implements AsyncExactReadable {
133
158
  await controller.enqueue(buffered);
134
159
 
135
160
  controller.abortSignal.addEventListener("abort", () => {
136
- // NOOP: the reader might already be released
137
- this.reader.cancel().catch(NOOP);
161
+ void tryCancel(this.reader);
138
162
  });
139
163
 
140
164
  // Manually pipe the stream
@@ -142,9 +166,9 @@ export class BufferedReadableStream implements AsyncExactReadable {
142
166
  const { done, value } = await this.reader.read();
143
167
  if (done) {
144
168
  return;
145
- } else {
146
- await controller.enqueue(value);
147
169
  }
170
+
171
+ await controller.enqueue(value);
148
172
  }
149
173
  });
150
174
  } else {
package/src/concat.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PromiseResolver } from "@yume-chan/async";
2
- import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
2
+ import { EmptyUint8Array } from "@yume-chan/struct";
3
3
 
4
4
  import type { ReadableStreamDefaultController } from "./stream.js";
5
5
  import { ReadableStream, WritableStream } from "./stream.js";
@@ -101,7 +101,7 @@ export class ConcatBufferStream {
101
101
  let offset = 0;
102
102
  switch (this.#segments.length) {
103
103
  case 0:
104
- result = EMPTY_UINT8_ARRAY;
104
+ result = EmptyUint8Array;
105
105
  break;
106
106
  case 1:
107
107
  result = this.#segments[0]!;
package/src/consumable.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PromiseResolver } from "@yume-chan/async";
1
+ import { PromiseResolver, isPromiseLike } from "@yume-chan/async";
2
2
 
3
3
  import type {
4
4
  QueuingStrategy,
@@ -12,11 +12,123 @@ import {
12
12
  import type { Task } from "./task.js";
13
13
  import { createTask } from "./task.js";
14
14
 
15
- function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
16
- return typeof value === "object" && value !== null && "then" in value;
15
+ // Workaround https://github.com/evanw/esbuild/issues/3923
16
+ class WritableStream<in T> extends NativeWritableStream<Consumable<T>> {
17
+ static async write<T>(
18
+ writer: WritableStreamDefaultWriter<Consumable<T>>,
19
+ value: T,
20
+ ) {
21
+ const consumable = new Consumable(value);
22
+ await writer.write(consumable);
23
+ await consumable.consumed;
24
+ }
25
+
26
+ constructor(
27
+ sink: Consumable.WritableStreamSink<T>,
28
+ strategy?: QueuingStrategy<T>,
29
+ ) {
30
+ let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
31
+ if (strategy) {
32
+ wrappedStrategy = {};
33
+ if ("highWaterMark" in strategy) {
34
+ wrappedStrategy.highWaterMark = strategy.highWaterMark;
35
+ }
36
+ if ("size" in strategy) {
37
+ wrappedStrategy.size = (chunk) => {
38
+ return strategy.size!(
39
+ chunk instanceof Consumable ? chunk.value : chunk,
40
+ );
41
+ };
42
+ }
43
+ }
44
+
45
+ super(
46
+ {
47
+ start(controller) {
48
+ return sink.start?.(controller);
49
+ },
50
+ async write(chunk, controller) {
51
+ await chunk.tryConsume((chunk) =>
52
+ sink.write?.(chunk, controller),
53
+ );
54
+ },
55
+ abort(reason) {
56
+ return sink.abort?.(reason);
57
+ },
58
+ close() {
59
+ return sink.close?.();
60
+ },
61
+ },
62
+ wrappedStrategy,
63
+ );
64
+ }
65
+ }
66
+
67
+ class ReadableStream<T> extends NativeReadableStream<Consumable<T>> {
68
+ static async enqueue<T>(
69
+ controller: { enqueue: (chunk: Consumable<T>) => void },
70
+ chunk: T,
71
+ ) {
72
+ const output = new Consumable(chunk);
73
+ controller.enqueue(output);
74
+ await output.consumed;
75
+ }
76
+
77
+ constructor(
78
+ source: Consumable.ReadableStreamSource<T>,
79
+ strategy?: QueuingStrategy<T>,
80
+ ) {
81
+ let wrappedController:
82
+ | Consumable.ReadableStreamController<T>
83
+ | undefined;
84
+
85
+ let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
86
+ if (strategy) {
87
+ wrappedStrategy = {};
88
+ if ("highWaterMark" in strategy) {
89
+ wrappedStrategy.highWaterMark = strategy.highWaterMark;
90
+ }
91
+ if ("size" in strategy) {
92
+ wrappedStrategy.size = (chunk) => {
93
+ return strategy.size!(chunk.value);
94
+ };
95
+ }
96
+ }
97
+
98
+ super(
99
+ {
100
+ async start(controller) {
101
+ wrappedController = {
102
+ async enqueue(chunk) {
103
+ await ReadableStream.enqueue(controller, chunk);
104
+ },
105
+ close() {
106
+ controller.close();
107
+ },
108
+ error(reason) {
109
+ controller.error(reason);
110
+ },
111
+ };
112
+
113
+ await source.start?.(wrappedController);
114
+ },
115
+ async pull() {
116
+ await source.pull?.(wrappedController!);
117
+ },
118
+ async cancel(reason) {
119
+ await source.cancel?.(reason);
120
+ },
121
+ },
122
+ wrappedStrategy,
123
+ );
124
+ }
17
125
  }
18
126
 
19
127
  export class Consumable<T> {
128
+ static readonly WritableStream = WritableStream;
129
+
130
+ static readonly ReadableStream = ReadableStream;
131
+
20
132
  readonly #task: Task;
21
133
  readonly #resolver: PromiseResolver<void>;
22
134
 
@@ -76,58 +188,7 @@ export namespace Consumable {
76
188
  close?(): void | PromiseLike<void>;
77
189
  }
78
190
 
79
- export class WritableStream<in T> extends NativeWritableStream<
80
- Consumable<T>
81
- > {
82
- static async write<T>(
83
- writer: WritableStreamDefaultWriter<Consumable<T>>,
84
- value: T,
85
- ) {
86
- const consumable = new Consumable(value);
87
- await writer.write(consumable);
88
- await consumable.consumed;
89
- }
90
-
91
- constructor(
92
- sink: WritableStreamSink<T>,
93
- strategy?: QueuingStrategy<T>,
94
- ) {
95
- let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
96
- if (strategy) {
97
- wrappedStrategy = {};
98
- if ("highWaterMark" in strategy) {
99
- wrappedStrategy.highWaterMark = strategy.highWaterMark;
100
- }
101
- if ("size" in strategy) {
102
- wrappedStrategy.size = (chunk) => {
103
- return strategy.size!(
104
- chunk instanceof Consumable ? chunk.value : chunk,
105
- );
106
- };
107
- }
108
- }
109
-
110
- super(
111
- {
112
- start(controller) {
113
- return sink.start?.(controller);
114
- },
115
- async write(chunk, controller) {
116
- await chunk.tryConsume((chunk) =>
117
- sink.write?.(chunk, controller),
118
- );
119
- },
120
- abort(reason) {
121
- return sink.abort?.(reason);
122
- },
123
- close() {
124
- return sink.close?.();
125
- },
126
- },
127
- wrappedStrategy,
128
- );
129
- }
130
- }
191
+ export type WritableStream<in T> = typeof Consumable.WritableStream<T>;
131
192
 
132
193
  export interface ReadableStreamController<T> {
133
194
  enqueue(chunk: T): Promise<void>;
@@ -145,61 +206,5 @@ export namespace Consumable {
145
206
  cancel?(reason: unknown): void | PromiseLike<void>;
146
207
  }
147
208
 
148
- export class ReadableStream<T> extends NativeReadableStream<Consumable<T>> {
149
- static async enqueue<T>(
150
- controller: { enqueue: (chunk: Consumable<T>) => void },
151
- chunk: T,
152
- ) {
153
- const output = new Consumable(chunk);
154
- controller.enqueue(output);
155
- await output.consumed;
156
- }
157
-
158
- constructor(
159
- source: ReadableStreamSource<T>,
160
- strategy?: QueuingStrategy<T>,
161
- ) {
162
- let wrappedController: ReadableStreamController<T> | undefined;
163
-
164
- let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
165
- if (strategy) {
166
- wrappedStrategy = {};
167
- if ("highWaterMark" in strategy) {
168
- wrappedStrategy.highWaterMark = strategy.highWaterMark;
169
- }
170
- if ("size" in strategy) {
171
- wrappedStrategy.size = (chunk) => {
172
- return strategy.size!(chunk.value);
173
- };
174
- }
175
- }
176
-
177
- super(
178
- {
179
- async start(controller) {
180
- wrappedController = {
181
- async enqueue(chunk) {
182
- await ReadableStream.enqueue(controller, chunk);
183
- },
184
- close() {
185
- controller.close();
186
- },
187
- error(reason) {
188
- controller.error(reason);
189
- },
190
- };
191
-
192
- await source.start?.(wrappedController);
193
- },
194
- async pull() {
195
- await source.pull?.(wrappedController!);
196
- },
197
- async cancel(reason) {
198
- await source.cancel?.(reason);
199
- },
200
- },
201
- wrappedStrategy,
202
- );
203
- }
204
- }
209
+ export type ReadableStream<T> = typeof Consumable.ReadableStream<T>;
205
210
  }
package/src/duplex.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
1
2
  import { PromiseResolver } from "@yume-chan/async";
2
- import type { ValueOrPromise } from "@yume-chan/struct";
3
3
 
4
4
  import type {
5
5
  QueuingStrategy,
@@ -8,6 +8,7 @@ import type {
8
8
  WritableStreamDefaultWriter,
9
9
  } from "./stream.js";
10
10
  import { WritableStream } from "./stream.js";
11
+ import { tryClose } from "./try-close.js";
11
12
  import { WrapReadableStream } from "./wrap-readable.js";
12
13
 
13
14
  const NOOP = () => {
@@ -27,7 +28,7 @@ export interface DuplexStreamFactoryOptions {
27
28
  * `DuplexStreamFactory#dispose` yourself, you can return `false`
28
29
  * (or a `Promise` that resolves to `false`) to disable the automatic call.
29
30
  */
30
- close?: (() => ValueOrPromise<boolean | void>) | undefined;
31
+ close?: (() => MaybePromiseLike<boolean | void>) | undefined;
31
32
 
32
33
  /**
33
34
  * Callback when any `ReadableStream` is closed (the other peer doesn't produce any more data),
@@ -134,11 +135,7 @@ export class DuplexStreamFactory<R, W> {
134
135
  this.#closed.resolve();
135
136
 
136
137
  for (const controller of this.#readableControllers) {
137
- try {
138
- controller.close();
139
- } catch {
140
- // ignore
141
- }
138
+ tryClose(controller);
142
139
  }
143
140
 
144
141
  await this.#options.dispose?.();
package/src/index.ts CHANGED
@@ -14,5 +14,6 @@ export * from "./stream.js";
14
14
  export * from "./struct-deserialize.js";
15
15
  export * from "./struct-serialize.js";
16
16
  export * from "./task.js";
17
+ export * from "./try-close.js";
17
18
  export * from "./wrap-readable.js";
18
19
  export * from "./wrap-writable.js";
@@ -0,0 +1,75 @@
1
+ import { Consumable } from "./consumable.js";
2
+ import type { MaybeConsumable } from "./maybe-consumable.js";
3
+ import type {
4
+ QueuingStrategy,
5
+ WritableStreamDefaultController,
6
+ } from "./stream.js";
7
+ import { WritableStream as NativeWritableStream } from "./stream.js";
8
+
9
+ export function getValue<T>(value: MaybeConsumable<T>): T {
10
+ return value instanceof Consumable ? value.value : value;
11
+ }
12
+
13
+ export function tryConsume<T, R>(
14
+ value: T,
15
+ callback: (value: T extends Consumable<infer U> ? U : T) => R,
16
+ ): R {
17
+ if (value instanceof Consumable) {
18
+ return value.tryConsume(callback);
19
+ } else {
20
+ return callback(value as never);
21
+ }
22
+ }
23
+
24
+ export interface WritableStreamSink<in T> {
25
+ start?(
26
+ controller: WritableStreamDefaultController,
27
+ ): void | PromiseLike<void>;
28
+ write?(
29
+ chunk: T,
30
+ controller: WritableStreamDefaultController,
31
+ ): void | PromiseLike<void>;
32
+ abort?(reason: unknown): void | PromiseLike<void>;
33
+ close?(): void | PromiseLike<void>;
34
+ }
35
+
36
+ export class WritableStream<in T> extends NativeWritableStream<
37
+ MaybeConsumable<T>
38
+ > {
39
+ constructor(sink: WritableStreamSink<T>, strategy?: QueuingStrategy<T>) {
40
+ let wrappedStrategy: QueuingStrategy<MaybeConsumable<T>> | undefined;
41
+ if (strategy) {
42
+ wrappedStrategy = {};
43
+ if ("highWaterMark" in strategy) {
44
+ wrappedStrategy.highWaterMark = strategy.highWaterMark;
45
+ }
46
+ if ("size" in strategy) {
47
+ wrappedStrategy.size = (chunk) => {
48
+ return strategy.size!(
49
+ chunk instanceof Consumable ? chunk.value : chunk,
50
+ );
51
+ };
52
+ }
53
+ }
54
+
55
+ super(
56
+ {
57
+ start(controller) {
58
+ return sink.start?.(controller);
59
+ },
60
+ async write(chunk, controller) {
61
+ await tryConsume(chunk, (chunk) =>
62
+ sink.write?.(chunk as T, controller),
63
+ );
64
+ },
65
+ abort(reason) {
66
+ return sink.abort?.(reason);
67
+ },
68
+ close() {
69
+ return sink.close?.();
70
+ },
71
+ },
72
+ wrappedStrategy,
73
+ );
74
+ }
75
+ }