@yume-chan/stream-extra 0.0.17 → 0.0.19

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 (104) hide show
  1. package/CHANGELOG.json +33 -9
  2. package/CHANGELOG.md +15 -2
  3. package/LICENSE +1 -1
  4. package/README.md +35 -3
  5. package/esm/buffered-transform.d.ts +11 -10
  6. package/esm/buffered-transform.d.ts.map +1 -1
  7. package/esm/buffered-transform.js +55 -49
  8. package/esm/buffered-transform.js.map +1 -1
  9. package/esm/buffered.d.ts +29 -27
  10. package/esm/buffered.d.ts.map +1 -1
  11. package/esm/buffered.js +128 -130
  12. package/esm/buffered.js.map +1 -1
  13. package/esm/chunk.d.ts +7 -4
  14. package/esm/chunk.d.ts.map +1 -1
  15. package/esm/chunk.js +48 -7
  16. package/esm/chunk.js.map +1 -1
  17. package/esm/consumable.d.ts +53 -0
  18. package/esm/consumable.d.ts.map +1 -0
  19. package/esm/consumable.js +178 -0
  20. package/esm/consumable.js.map +1 -0
  21. package/esm/decode-utf8.d.ts +4 -4
  22. package/esm/decode-utf8.d.ts.map +1 -1
  23. package/esm/decode-utf8.js +11 -11
  24. package/esm/decode-utf8.js.map +1 -1
  25. package/esm/distribution.d.ts +24 -0
  26. package/esm/distribution.d.ts.map +1 -0
  27. package/esm/distribution.js +99 -0
  28. package/esm/distribution.js.map +1 -0
  29. package/esm/duplex.d.ts +48 -47
  30. package/esm/duplex.d.ts.map +1 -1
  31. package/esm/duplex.js +90 -88
  32. package/esm/duplex.js.map +1 -1
  33. package/esm/gather-string.d.ts +6 -6
  34. package/esm/gather-string.d.ts.map +1 -1
  35. package/esm/gather-string.js +15 -13
  36. package/esm/gather-string.js.map +1 -1
  37. package/esm/index.d.ts +16 -15
  38. package/esm/index.d.ts.map +1 -1
  39. package/esm/index.js +16 -15
  40. package/esm/index.js.map +1 -1
  41. package/esm/inspect.d.ts +4 -4
  42. package/esm/inspect.js +11 -11
  43. package/esm/pipe-from.d.ts +12 -12
  44. package/esm/pipe-from.d.ts.map +1 -1
  45. package/esm/pipe-from.js +23 -26
  46. package/esm/pipe-from.js.map +1 -1
  47. package/esm/push-readable.d.ts +19 -11
  48. package/esm/push-readable.d.ts.map +1 -1
  49. package/esm/push-readable.js +61 -46
  50. package/esm/push-readable.js.map +1 -1
  51. package/esm/split-string.d.ts +4 -4
  52. package/esm/split-string.d.ts.map +1 -1
  53. package/esm/split-string.js +24 -24
  54. package/esm/split-string.js.map +1 -1
  55. package/esm/stream.d.ts +25 -17
  56. package/esm/stream.d.ts.map +1 -1
  57. package/esm/stream.js +26 -3
  58. package/esm/stream.js.map +1 -1
  59. package/esm/struct-deserialize.d.ts +6 -6
  60. package/esm/struct-deserialize.d.ts.map +1 -1
  61. package/esm/struct-deserialize.js +8 -8
  62. package/esm/struct-deserialize.js.map +1 -1
  63. package/esm/struct-serialize.d.ts +5 -5
  64. package/esm/struct-serialize.d.ts.map +1 -1
  65. package/esm/struct-serialize.js +10 -10
  66. package/esm/struct-serialize.js.map +1 -1
  67. package/esm/trace.d.ts +16 -0
  68. package/esm/trace.d.ts.map +1 -0
  69. package/esm/trace.js +131 -0
  70. package/esm/trace.js.map +1 -0
  71. package/esm/wrap-readable.d.ts +21 -20
  72. package/esm/wrap-readable.d.ts.map +1 -1
  73. package/esm/wrap-readable.js +56 -56
  74. package/esm/wrap-readable.js.map +1 -1
  75. package/esm/wrap-writable.d.ts +14 -12
  76. package/esm/wrap-writable.d.ts.map +1 -1
  77. package/esm/wrap-writable.js +62 -52
  78. package/esm/wrap-writable.js.map +1 -1
  79. package/package.json +13 -9
  80. package/src/buffered-transform.ts +32 -17
  81. package/src/buffered.ts +14 -15
  82. package/src/consumable.ts +281 -0
  83. package/src/decode-utf8.ts +3 -2
  84. package/src/distribution.ts +113 -0
  85. package/src/duplex.ts +27 -10
  86. package/src/gather-string.ts +5 -3
  87. package/src/index.ts +16 -15
  88. package/src/inspect.ts +1 -1
  89. package/src/pipe-from.ts +11 -10
  90. package/src/push-readable.ts +77 -46
  91. package/src/split-string.ts +5 -2
  92. package/src/stream.ts +48 -6
  93. package/src/struct-deserialize.ts +6 -4
  94. package/src/struct-serialize.ts +4 -2
  95. package/src/wrap-readable.ts +30 -12
  96. package/src/wrap-writable.ts +34 -11
  97. package/tsconfig.build.json +1 -1
  98. package/tsconfig.build.tsbuildinfo +1 -1
  99. package/esm/native.d.ts +0 -240
  100. package/esm/native.d.ts.map +0 -1
  101. package/esm/native.js +0 -60
  102. package/esm/native.js.map +0 -1
  103. package/src/chunk.ts +0 -15
  104. package/src/native.ts +0 -362
@@ -0,0 +1,113 @@
1
+ import { ConsumableTransformStream } from "./consumable.js";
2
+
3
+ /**
4
+ * Splits or combines buffers to specified size.
5
+ */
6
+ export class BufferCombiner {
7
+ private _capacity: number;
8
+ private readonly _buffer: Uint8Array;
9
+ private _offset: number;
10
+ private _available: number;
11
+
12
+ public constructor(size: number) {
13
+ this._capacity = size;
14
+ this._buffer = new Uint8Array(size);
15
+ this._offset = 0;
16
+ this._available = size;
17
+ }
18
+
19
+ /**
20
+ * Pushes data to the combiner.
21
+ * @param data The input data to be split or combined.
22
+ * @returns
23
+ * A generator that yields buffers of specified size.
24
+ * It may yield the same buffer multiple times, consume the data before calling `next`.
25
+ */
26
+ public *push(data: Uint8Array): Generator<Uint8Array, void, void> {
27
+ let offset = 0;
28
+ let available = data.byteLength;
29
+
30
+ if (this._offset !== 0) {
31
+ if (available >= this._available) {
32
+ this._buffer.set(
33
+ data.subarray(0, this._available),
34
+ this._offset
35
+ );
36
+ offset += this._available;
37
+ available -= this._available;
38
+
39
+ yield this._buffer;
40
+ this._offset = 0;
41
+ this._available = this._capacity;
42
+
43
+ if (available === 0) {
44
+ return;
45
+ }
46
+ } else {
47
+ this._buffer.set(data, this._offset);
48
+ this._offset += available;
49
+ this._available -= available;
50
+ return;
51
+ }
52
+ }
53
+
54
+ while (available >= this._capacity) {
55
+ const end = offset + this._capacity;
56
+ yield data.subarray(offset, end);
57
+ offset = end;
58
+ available -= this._capacity;
59
+ }
60
+
61
+ if (available > 0) {
62
+ this._buffer.set(data.subarray(offset), this._offset);
63
+ this._offset += available;
64
+ this._available -= available;
65
+ }
66
+ }
67
+
68
+ public flush(): Uint8Array | undefined {
69
+ if (this._offset === 0) {
70
+ return undefined;
71
+ }
72
+
73
+ const output = this._buffer.subarray(0, this._offset);
74
+ this._offset = 0;
75
+ this._available = this._capacity;
76
+ return output;
77
+ }
78
+ }
79
+
80
+ export class DistributionStream extends ConsumableTransformStream<
81
+ Uint8Array,
82
+ Uint8Array
83
+ > {
84
+ public constructor(size: number, combine = false) {
85
+ const combiner = combine ? new BufferCombiner(size) : undefined;
86
+ super({
87
+ async transform(chunk, controller) {
88
+ if (combiner) {
89
+ for (const buffer of combiner.push(chunk)) {
90
+ await controller.enqueue(buffer);
91
+ }
92
+ } else {
93
+ let offset = 0;
94
+ let available = chunk.byteLength;
95
+ while (available > 0) {
96
+ const end = offset + size;
97
+ await controller.enqueue(chunk.subarray(offset, end));
98
+ offset = end;
99
+ available -= size;
100
+ }
101
+ }
102
+ },
103
+ async flush(controller) {
104
+ if (combiner) {
105
+ const data = combiner.flush();
106
+ if (data) {
107
+ await controller.enqueue(data);
108
+ }
109
+ }
110
+ },
111
+ });
112
+ }
113
+ }
package/src/duplex.ts CHANGED
@@ -1,15 +1,25 @@
1
1
  import { PromiseResolver } from "@yume-chan/async";
2
2
  import type { ValueOrPromise } from "@yume-chan/struct";
3
- import { WritableStream, type ReadableStream, type ReadableStreamDefaultController, type WritableStreamDefaultWriter } from "./stream.js";
3
+
4
+ import type {
5
+ ReadableStream,
6
+ ReadableStreamDefaultController,
7
+ WritableStreamDefaultWriter,
8
+ } from "./stream.js";
9
+ import { WritableStream } from "./stream.js";
4
10
  import { WrapReadableStream } from "./wrap-readable.js";
5
11
 
12
+ const NOOP = () => {
13
+ // no-op
14
+ };
15
+
6
16
  export interface DuplexStreamFactoryOptions {
7
17
  /**
8
18
  * Callback when any `ReadableStream` is cancelled (the user doesn't need any more data),
9
19
  * or `WritableStream` is ended (the user won't produce any more data),
10
20
  * or `DuplexStreamFactory#close` is called.
11
21
  *
12
- * Usually you want to let the other peer know that the duplex stream should be clsoed.
22
+ * Usually you want to let the other peer know that the duplex stream should be closed.
13
23
  *
14
24
  * `dispose` will automatically be called after `close` completes,
15
25
  * but if you want to wait another peer for a close confirmation and call
@@ -40,10 +50,14 @@ export class DuplexStreamFactory<R, W> {
40
50
  private writers: WritableStreamDefaultWriter<W>[] = [];
41
51
 
42
52
  private _writableClosed = false;
43
- public get writableClosed() { return this._writableClosed; }
53
+ public get writableClosed() {
54
+ return this._writableClosed;
55
+ }
44
56
 
45
57
  private _closed = new PromiseResolver<void>();
46
- public get closed() { return this._closed.promise; }
58
+ public get closed() {
59
+ return this._closed.promise;
60
+ }
47
61
 
48
62
  private options: DuplexStreamFactoryOptions;
49
63
 
@@ -58,7 +72,7 @@ export class DuplexStreamFactory<R, W> {
58
72
  return readable;
59
73
  },
60
74
  cancel: async () => {
61
- // cancel means the local peer closes the connection first.
75
+ // cancel means the local peer wants to close the connection.
62
76
  await this.close();
63
77
  },
64
78
  close: async () => {
@@ -76,7 +90,6 @@ export class DuplexStreamFactory<R, W> {
76
90
  // So it only triggers `close`.
77
91
  return new WritableStream<W>({
78
92
  write: async (chunk) => {
79
- await writer.ready;
80
93
  await writer.write(chunk);
81
94
  },
82
95
  abort: async (reason) => {
@@ -84,7 +97,7 @@ export class DuplexStreamFactory<R, W> {
84
97
  await this.close();
85
98
  },
86
99
  close: async () => {
87
- try { await writer.close(); } catch { }
100
+ await writer.close().catch(NOOP);
88
101
  await this.close();
89
102
  },
90
103
  });
@@ -97,13 +110,13 @@ export class DuplexStreamFactory<R, W> {
97
110
  this._writableClosed = true;
98
111
 
99
112
  // Call `close` first, so it can still write data to `WritableStream`s.
100
- if (await this.options.close?.() !== false) {
113
+ if ((await this.options.close?.()) !== false) {
101
114
  // `close` can return `false` to disable automatic `dispose`.
102
115
  await this.dispose();
103
116
  }
104
117
 
105
118
  for (const writer of this.writers) {
106
- try { await writer.close(); } catch { }
119
+ await writer.close().catch(NOOP);
107
120
  }
108
121
  }
109
122
 
@@ -112,7 +125,11 @@ export class DuplexStreamFactory<R, W> {
112
125
  this._closed.resolve();
113
126
 
114
127
  for (const controller of this.readableControllers) {
115
- try { controller.close(); } catch { }
128
+ try {
129
+ controller.close();
130
+ } catch {
131
+ // ignore
132
+ }
116
133
  }
117
134
 
118
135
  await this.options.dispose?.();
@@ -1,9 +1,11 @@
1
1
  import { WritableStream } from "./stream.js";
2
2
 
3
- export class GatherStringStream extends WritableStream<string>{
3
+ export class GatherStringStream extends WritableStream<string> {
4
4
  // PERF: rope (concat strings) is faster than `[].join('')`
5
- private _result = '';
6
- public get result() { return this._result; }
5
+ private _result = "";
6
+ public get result() {
7
+ return this._result;
8
+ }
7
9
 
8
10
  public constructor() {
9
11
  super({
package/src/index.ts CHANGED
@@ -1,15 +1,16 @@
1
- export * from './buffered-transform.js';
2
- export * from './buffered.js';
3
- export * from './chunk.js';
4
- export * from './decode-utf8.js';
5
- export * from './duplex.js';
6
- export * from './gather-string.js';
7
- export * from './inspect.js';
8
- export * from './pipe-from.js';
9
- export * from './push-readable.js';
10
- export * from './split-string.js';
11
- export * from './stream.js';
12
- export * from './struct-deserialize.js';
13
- export * from './struct-serialize.js';
14
- export * from './wrap-readable.js';
15
- export * from './wrap-writable.js';
1
+ export * from "./buffered-transform.js";
2
+ export * from "./buffered.js";
3
+ export * from "./consumable.js";
4
+ export * from "./decode-utf8.js";
5
+ export * from "./distribution.js";
6
+ export * from "./duplex.js";
7
+ export * from "./gather-string.js";
8
+ export * from "./inspect.js";
9
+ export * from "./pipe-from.js";
10
+ export * from "./push-readable.js";
11
+ export * from "./split-string.js";
12
+ export * from "./stream.js";
13
+ export * from "./struct-deserialize.js";
14
+ export * from "./struct-serialize.js";
15
+ export * from "./wrap-readable.js";
16
+ export * from "./wrap-writable.js";
package/src/inspect.ts CHANGED
@@ -6,7 +6,7 @@ export class InspectStream<T> extends TransformStream<T, T> {
6
6
  transform(chunk, controller) {
7
7
  callback(chunk);
8
8
  controller.enqueue(chunk);
9
- }
9
+ },
10
10
  });
11
11
  }
12
12
  }
package/src/pipe-from.ts CHANGED
@@ -1,27 +1,28 @@
1
- import { WritableStream, type ReadableWritablePair } from "./stream.js";
1
+ import type { ReadableWritablePair } from "./stream.js";
2
+ import { WritableStream } from "./stream.js";
2
3
 
3
4
  /**
4
- * Create a new `WritableStream` that, when written to, will write that chunk to
5
- * `pair.writable`, when pipe `pair.readable` to `writable`.
5
+ * Pipe `pair.readable` to `writable`, then returns `pair.writable`.
6
6
  *
7
- * It's the opposite of `ReadableStream.pipeThrough`.
7
+ * This is the opposite of `ReadableStream#pipeThrough()`.
8
8
  *
9
9
  * @param writable The `WritableStream` to write to.
10
10
  * @param pair A `TransformStream` that converts chunks.
11
- * @returns A new `WritableStream`.
11
+ * @returns `pair`'s `writable` stream.
12
12
  */
13
- export function pipeFrom<W, T>(writable: WritableStream<W>, pair: ReadableWritablePair<W, T>) {
13
+ export function pipeFrom<W, T>(
14
+ writable: WritableStream<W>,
15
+ pair: ReadableWritablePair<W, T>
16
+ ) {
14
17
  const writer = pair.writable.getWriter();
15
- const pipe = pair.readable
16
- .pipeTo(writable);
18
+ const pipe = pair.readable.pipeTo(writable);
17
19
  return new WritableStream<T>({
18
20
  async write(chunk) {
19
- await writer.ready;
20
21
  await writer.write(chunk);
21
22
  },
22
23
  async close() {
23
24
  await writer.close();
24
25
  await pipe;
25
- }
26
+ },
26
27
  });
27
28
  }
@@ -1,5 +1,7 @@
1
- import { PromiseResolver } from '@yume-chan/async';
2
- import { AbortController, AbortSignal, QueuingStrategy, ReadableStream } from "./stream.js";
1
+ import { PromiseResolver } from "@yume-chan/async";
2
+
3
+ import type { AbortSignal, QueuingStrategy } from "./stream.js";
4
+ import { AbortController, ReadableStream } from "./stream.js";
3
5
 
4
6
  export interface PushReadableStreamController<T> {
5
7
  abortSignal: AbortSignal;
@@ -8,55 +10,84 @@ export interface PushReadableStreamController<T> {
8
10
 
9
11
  close(): void;
10
12
 
11
- error(e?: any): void;
13
+ error(e?: unknown): void;
12
14
  }
13
15
 
14
- export type PushReadableStreamSource<T> = (controller: PushReadableStreamController<T>) => void;
16
+ export type PushReadableStreamSource<T> = (
17
+ controller: PushReadableStreamController<T>
18
+ ) => void | Promise<void>;
15
19
 
16
20
  export class PushReadableStream<T> extends ReadableStream<T> {
17
- public constructor(source: PushReadableStreamSource<T>, strategy?: QueuingStrategy<T>) {
21
+ /**
22
+ * Create a new `PushReadableStream` from a source.
23
+ *
24
+ * @param source If `source` returns a `Promise`, the stream will be closed
25
+ * when the `Promise` is resolved, and be errored when the `Promise` is rejected.
26
+ * @param strategy
27
+ */
28
+ public constructor(
29
+ source: PushReadableStreamSource<T>,
30
+ strategy?: QueuingStrategy<T>
31
+ ) {
18
32
  let waterMarkLow: PromiseResolver<void> | undefined;
19
- const canceled: AbortController = new AbortController();
20
-
21
- super({
22
- start: (controller) => {
23
- source({
24
- abortSignal: canceled.signal,
25
- async enqueue(chunk) {
26
- if (canceled.signal.aborted) {
27
- // If the stream is already cancelled,
28
- // throw immediately.
29
- throw canceled.signal.reason ?? new Error('Aborted');
30
- }
31
-
32
- // Only when the stream is errored, `desiredSize` will be `null`.
33
- // But since `null <= 0` is `true`
34
- // (`null <= 0` is evaluated as `!(null > 0)` => `!false` => `true`),
35
- // not handling it will cause a deadlock.
36
- if ((controller.desiredSize ?? 1) <= 0) {
37
- waterMarkLow = new PromiseResolver<void>();
38
- await waterMarkLow.promise;
39
- }
40
-
41
- // `controller.enqueue` will throw error for us
42
- // if the stream is already errored.
43
- controller.enqueue(chunk);
44
- },
45
- close() {
46
- controller.close();
47
- },
48
- error(e) {
49
- controller.error(e);
50
- },
51
- });
52
- },
53
- pull: () => {
54
- waterMarkLow?.resolve();
55
- },
56
- cancel: async (reason) => {
57
- canceled.abort(reason);
58
- waterMarkLow?.reject(reason);
33
+ const canceled = new AbortController();
34
+
35
+ super(
36
+ {
37
+ start: (controller) => {
38
+ const result = source({
39
+ abortSignal: canceled.signal,
40
+ async enqueue(chunk) {
41
+ if (canceled.signal.aborted) {
42
+ // If the stream is already cancelled,
43
+ // throw immediately.
44
+ throw (
45
+ canceled.signal.reason ??
46
+ new Error("Aborted")
47
+ );
48
+ }
49
+
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) {
55
+ waterMarkLow = new PromiseResolver<void>();
56
+ await waterMarkLow.promise;
57
+ }
58
+
59
+ // `controller.enqueue` will throw error for us
60
+ // if the stream is already errored.
61
+ controller.enqueue(chunk);
62
+ },
63
+ close() {
64
+ controller.close();
65
+ },
66
+ error(e) {
67
+ controller.error(e);
68
+ },
69
+ });
70
+
71
+ if (result && "then" in result) {
72
+ result.then(
73
+ () => {
74
+ controller.close();
75
+ },
76
+ (e) => {
77
+ controller.error(e);
78
+ }
79
+ );
80
+ }
81
+ },
82
+ pull: () => {
83
+ waterMarkLow?.resolve();
84
+ },
85
+ cancel: (reason) => {
86
+ canceled.abort(reason);
87
+ waterMarkLow?.reject(reason);
88
+ },
59
89
  },
60
- }, strategy);
90
+ strategy
91
+ );
61
92
  }
62
93
  }
@@ -1,6 +1,9 @@
1
1
  import { TransformStream } from "./stream.js";
2
2
 
3
- function* split(input: string, separator: string): Generator<string, void, void> {
3
+ function* split(
4
+ input: string,
5
+ separator: string
6
+ ): Generator<string, void, void> {
4
7
  let start = 0;
5
8
 
6
9
  while (true) {
@@ -23,7 +26,7 @@ export class SplitStringStream extends TransformStream<string, string> {
23
26
  for (const part of split(chunk, separator)) {
24
27
  controller.enqueue(part);
25
28
  }
26
- }
29
+ },
27
30
  });
28
31
  }
29
32
  }
package/src/stream.ts CHANGED
@@ -1,22 +1,64 @@
1
1
  import type { AbortSignal } from "web-streams-polyfill";
2
- export * from 'web-streams-polyfill';
2
+ import {
3
+ ReadableStream as ReadableStreamPolyfill,
4
+ TransformStream as TransformStreamPolyfill,
5
+ WritableStream as WritableStreamPolyfill,
6
+ } from "web-streams-polyfill";
7
+ export * from "web-streams-polyfill";
3
8
 
4
9
  /** A controller object that allows you to abort one or more DOM requests as and when desired. */
5
10
  export interface AbortController {
6
11
  /**
7
12
  * Returns the AbortSignal object associated with this object.
8
13
  */
9
-
10
14
  readonly signal: AbortSignal;
15
+
11
16
  /**
12
17
  * Invoking this method will set this object's AbortSignal's aborted flag and signal to any observers that the associated activity is to be aborted.
13
18
  */
14
19
  abort(reason?: any): void;
15
20
  }
16
21
 
17
- export let AbortController: {
22
+ interface AbortControllerConstructor {
18
23
  prototype: AbortController;
19
- new(): AbortController;
20
- };
24
+ new (): AbortController;
25
+ }
26
+
27
+ interface GlobalExtension {
28
+ AbortController: AbortControllerConstructor;
29
+ ReadableStream: typeof ReadableStreamPolyfill;
30
+ WritableStream: typeof WritableStreamPolyfill;
31
+ TransformStream: typeof TransformStreamPolyfill;
32
+ }
33
+
34
+ const GLOBAL = globalThis as unknown as GlobalExtension;
21
35
 
22
- ({ AbortController } = globalThis as any);
36
+ export const AbortController = GLOBAL.AbortController;
37
+
38
+ export type ReadableStream<R = any> = ReadableStreamPolyfill<R>;
39
+ export let ReadableStream = ReadableStreamPolyfill;
40
+
41
+ export type WritableStream<W = any> = WritableStreamPolyfill<W>;
42
+ export let WritableStream = WritableStreamPolyfill;
43
+
44
+ export type TransformStream<I = any, O = any> = TransformStreamPolyfill<I, O>;
45
+ export let TransformStream = TransformStreamPolyfill;
46
+
47
+ if (GLOBAL.ReadableStream && GLOBAL.WritableStream && GLOBAL.TransformStream) {
48
+ // Use browser native implementation
49
+ ReadableStream = GLOBAL.ReadableStream;
50
+ WritableStream = GLOBAL.WritableStream;
51
+ 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
+ }
@@ -1,12 +1,14 @@
1
1
  import type Struct from "@yume-chan/struct";
2
2
  import type { StructValueType } from "@yume-chan/struct";
3
- import { BufferedTransformStream } from './buffered-transform.js';
4
3
 
5
- export class StructDeserializeStream<T extends Struct<any, any, any, any>>
6
- extends BufferedTransformStream<StructValueType<T>> {
4
+ import { BufferedTransformStream } from "./buffered-transform.js";
5
+
6
+ export class StructDeserializeStream<
7
+ T extends Struct<any, any, any, any>
8
+ > extends BufferedTransformStream<StructValueType<T>> {
7
9
  public constructor(struct: T) {
8
10
  super((stream) => {
9
- return struct.deserialize(stream)
11
+ return struct.deserialize(stream);
10
12
  });
11
13
  }
12
14
  }
@@ -1,8 +1,10 @@
1
1
  import type Struct from "@yume-chan/struct";
2
+
2
3
  import { TransformStream } from "./stream.js";
3
4
 
4
- export class StructSerializeStream<T extends Struct<any, any, any, any>>
5
- extends TransformStream<T['TInit'], Uint8Array>{
5
+ export class StructSerializeStream<
6
+ T extends Struct<any, any, any, any>
7
+ > extends TransformStream<T["TInit"], Uint8Array> {
6
8
  constructor(struct: T) {
7
9
  super({
8
10
  transform(chunk, controller) {
@@ -1,21 +1,31 @@
1
1
  import type { ValueOrPromise } from "@yume-chan/struct";
2
- import { ReadableStream, ReadableStreamDefaultController, ReadableStreamDefaultReader } from "./stream.js";
3
2
 
4
- export type WrapReadableStreamStart<T> = (controller: ReadableStreamDefaultController<T>) => ValueOrPromise<ReadableStream<T>>;
3
+ import type {
4
+ ReadableStreamDefaultController,
5
+ ReadableStreamDefaultReader,
6
+ } from "./stream.js";
7
+ import { ReadableStream } from "./stream.js";
8
+
9
+ export type WrapReadableStreamStart<T> = (
10
+ controller: ReadableStreamDefaultController<T>
11
+ ) => ValueOrPromise<ReadableStream<T>>;
5
12
 
6
13
  export interface ReadableStreamWrapper<T> {
7
14
  start: WrapReadableStreamStart<T>;
8
- cancel?(reason?: any): ValueOrPromise<void>;
15
+ cancel?(reason?: unknown): ValueOrPromise<void>;
9
16
  close?(): ValueOrPromise<void>;
10
17
  }
11
18
 
12
19
  function getWrappedReadableStream<T>(
13
- wrapper: ReadableStream<T> | WrapReadableStreamStart<T> | ReadableStreamWrapper<T>,
20
+ wrapper:
21
+ | ReadableStream<T>
22
+ | WrapReadableStreamStart<T>
23
+ | ReadableStreamWrapper<T>,
14
24
  controller: ReadableStreamDefaultController<T>
15
25
  ) {
16
- if ('start' in wrapper) {
26
+ if ("start" in wrapper) {
17
27
  return wrapper.start(controller);
18
- } else if (typeof wrapper === 'function') {
28
+ } else if (typeof wrapper === "function") {
19
29
  return wrapper(controller);
20
30
  } else {
21
31
  // Can't use `wrapper instanceof ReadableStream`
@@ -31,12 +41,17 @@ function getWrappedReadableStream<T>(
31
41
  * 2. Synchronously create a `ReadableStream` by asynchronously return another `ReadableStream`.
32
42
  * 3. Convert native `ReadableStream`s to polyfilled ones so they can `pipe` between.
33
43
  */
34
- export class WrapReadableStream<T> extends ReadableStream<T>{
44
+ export class WrapReadableStream<T> extends ReadableStream<T> {
35
45
  public readable!: ReadableStream<T>;
36
46
 
37
47
  private reader!: ReadableStreamDefaultReader<T>;
38
48
 
39
- public constructor(wrapper: ReadableStream<T> | WrapReadableStreamStart<T> | ReadableStreamWrapper<T>) {
49
+ public constructor(
50
+ wrapper:
51
+ | ReadableStream<T>
52
+ | WrapReadableStreamStart<T>
53
+ | ReadableStreamWrapper<T>
54
+ ) {
40
55
  super({
41
56
  start: async (controller) => {
42
57
  // `start` is invoked before `ReadableStream`'s constructor finish,
@@ -45,12 +60,15 @@ export class WrapReadableStream<T> extends ReadableStream<T>{
45
60
  // Queue a microtask to avoid this.
46
61
  await Promise.resolve();
47
62
 
48
- this.readable = await getWrappedReadableStream(wrapper, controller);
63
+ this.readable = await getWrappedReadableStream(
64
+ wrapper,
65
+ controller
66
+ );
49
67
  this.reader = this.readable.getReader();
50
68
  },
51
69
  cancel: async (reason) => {
52
70
  await this.reader.cancel(reason);
53
- if ('cancel' in wrapper) {
71
+ if ("cancel" in wrapper) {
54
72
  await wrapper.cancel?.(reason);
55
73
  }
56
74
  },
@@ -58,13 +76,13 @@ export class WrapReadableStream<T> extends ReadableStream<T>{
58
76
  const result = await this.reader.read();
59
77
  if (result.done) {
60
78
  controller.close();
61
- if ('close' in wrapper) {
79
+ if ("close" in wrapper) {
62
80
  await wrapper.close?.();
63
81
  }
64
82
  } else {
65
83
  controller.enqueue(result.value);
66
84
  }
67
- }
85
+ },
68
86
  });
69
87
  }
70
88
  }