@yume-chan/stream-extra 0.0.24 → 2.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 (88) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/LICENSE +1 -1
  3. package/esm/buffered-transform.d.ts +3 -3
  4. package/esm/buffered-transform.d.ts.map +1 -1
  5. package/esm/buffered-transform.js +14 -8
  6. package/esm/buffered-transform.js.map +1 -1
  7. package/esm/buffered.d.ts +3 -6
  8. package/esm/buffered.d.ts.map +1 -1
  9. package/esm/buffered.js +87 -75
  10. package/esm/buffered.js.map +1 -1
  11. package/esm/concat.js +2 -2
  12. package/esm/concat.js.map +1 -1
  13. package/esm/consumable.d.ts +15 -10
  14. package/esm/consumable.d.ts.map +1 -1
  15. package/esm/consumable.js +82 -86
  16. package/esm/consumable.js.map +1 -1
  17. package/esm/duplex.d.ts +2 -2
  18. package/esm/duplex.d.ts.map +1 -1
  19. package/esm/duplex.js +2 -6
  20. package/esm/duplex.js.map +1 -1
  21. package/esm/index.d.ts +1 -0
  22. package/esm/index.d.ts.map +1 -1
  23. package/esm/index.js +1 -0
  24. package/esm/index.js.map +1 -1
  25. package/esm/maybe-consumable-ns.d.ts +16 -0
  26. package/esm/maybe-consumable-ns.d.ts.map +1 -0
  27. package/esm/maybe-consumable-ns.js +44 -0
  28. package/esm/maybe-consumable-ns.js.map +1 -0
  29. package/esm/maybe-consumable.d.ts +2 -19
  30. package/esm/maybe-consumable.d.ts.map +1 -1
  31. package/esm/maybe-consumable.js +1 -61
  32. package/esm/maybe-consumable.js.map +1 -1
  33. package/esm/push-readable.d.ts +16 -2
  34. package/esm/push-readable.d.ts.map +1 -1
  35. package/esm/push-readable.js +176 -17
  36. package/esm/push-readable.js.map +1 -1
  37. package/esm/split-string.d.ts.map +1 -1
  38. package/esm/split-string.js +19 -14
  39. package/esm/split-string.js.map +1 -1
  40. package/esm/stream.d.ts +5 -5
  41. package/esm/stream.d.ts.map +1 -1
  42. package/esm/stream.js +54 -5
  43. package/esm/stream.js.map +1 -1
  44. package/esm/struct-deserialize.d.ts +3 -4
  45. package/esm/struct-deserialize.d.ts.map +1 -1
  46. package/esm/struct-deserialize.js.map +1 -1
  47. package/esm/struct-serialize.d.ts +2 -2
  48. package/esm/struct-serialize.d.ts.map +1 -1
  49. package/esm/struct-serialize.js.map +1 -1
  50. package/esm/task.d.ts.map +1 -1
  51. package/esm/task.js +2 -2
  52. package/esm/task.js.map +1 -1
  53. package/esm/try-close.d.ts +10 -0
  54. package/esm/try-close.d.ts.map +1 -0
  55. package/esm/try-close.js +19 -0
  56. package/esm/try-close.js.map +1 -0
  57. package/esm/types.d.ts +3 -3
  58. package/esm/types.d.ts.map +1 -1
  59. package/esm/types.js.map +1 -1
  60. package/esm/wrap-readable.d.ts +5 -4
  61. package/esm/wrap-readable.d.ts.map +1 -1
  62. package/esm/wrap-readable.js +14 -9
  63. package/esm/wrap-readable.js.map +1 -1
  64. package/esm/wrap-writable.d.ts +2 -2
  65. package/esm/wrap-writable.d.ts.map +1 -1
  66. package/esm/wrap-writable.js +4 -6
  67. package/esm/wrap-writable.js.map +1 -1
  68. package/package.json +11 -13
  69. package/src/buffered-transform.ts +21 -11
  70. package/src/buffered.ts +107 -83
  71. package/src/concat.ts +2 -2
  72. package/src/consumable.ts +117 -112
  73. package/src/duplex.ts +4 -7
  74. package/src/index.ts +1 -0
  75. package/src/maybe-consumable-ns.ts +75 -0
  76. package/src/maybe-consumable.ts +2 -98
  77. package/src/push-readable.ts +213 -19
  78. package/src/split-string.ts +22 -21
  79. package/src/stream.ts +68 -8
  80. package/src/struct-deserialize.ts +3 -6
  81. package/src/struct-serialize.ts +3 -3
  82. package/src/task.ts +2 -2
  83. package/src/try-close.ts +44 -0
  84. package/src/types.ts +3 -2
  85. package/src/wrap-readable.ts +20 -14
  86. package/src/wrap-writable.ts +6 -9
  87. package/tsconfig.build.tsbuildinfo +1 -1
  88. package/CHANGELOG.json +0 -104
package/esm/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAg3B5C,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAi3B5C,OAAO,EAAE,CAAC"}
@@ -1,11 +1,12 @@
1
- import type { ValueOrPromise } from "@yume-chan/struct";
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
2
2
  import type { QueuingStrategy, ReadableStreamDefaultController } from "./stream.js";
3
3
  import { ReadableStream } from "./stream.js";
4
- export type WrapReadableStreamStart<T> = (controller: ReadableStreamDefaultController<T>) => ValueOrPromise<ReadableStream<T>>;
4
+ export type WrapReadableStreamStart<T> = (controller: ReadableStreamDefaultController<T>) => MaybePromiseLike<ReadableStream<T>>;
5
5
  export interface ReadableStreamWrapper<T> {
6
6
  start: WrapReadableStreamStart<T>;
7
- cancel?(reason?: unknown): ValueOrPromise<void>;
8
- close?(): ValueOrPromise<void>;
7
+ cancel?: (reason?: unknown) => MaybePromiseLike<void>;
8
+ close?: () => MaybePromiseLike<void>;
9
+ error?: (reason?: unknown) => MaybePromiseLike<void>;
9
10
  }
10
11
  /**
11
12
  * This class has multiple usages:
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-readable.d.ts","sourceRoot":"","sources":["../src/wrap-readable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,KAAK,EACR,eAAe,EACf,+BAA+B,EAElC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,CACrC,UAAU,EAAE,+BAA+B,CAAC,CAAC,CAAC,KAC7C,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAEvC,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACpC,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAChD,KAAK,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;CAClC;AAoBD;;;;;;GAMG;AACH,qBAAa,kBAAkB,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;;IACxD,QAAQ,EAAG,cAAc,CAAC,CAAC,CAAC,CAAC;gBAKzB,OAAO,EACD,cAAc,CAAC,CAAC,CAAC,GACjB,uBAAuB,CAAC,CAAC,CAAC,GAC1B,qBAAqB,CAAC,CAAC,CAAC,EAC9B,QAAQ,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;CAsCpC"}
1
+ {"version":3,"file":"wrap-readable.d.ts","sourceRoot":"","sources":["../src/wrap-readable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EACR,eAAe,EACf,+BAA+B,EAElC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,CACrC,UAAU,EAAE,+BAA+B,CAAC,CAAC,CAAC,KAC7C,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzC,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACpC,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtD,KAAK,CAAC,EAAE,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,gBAAgB,CAAC,IAAI,CAAC,CAAC;CACxD;AAoBD;;;;;;GAMG;AACH,qBAAa,kBAAkB,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;;IACxD,QAAQ,EAAG,cAAc,CAAC,CAAC,CAAC,CAAC;gBAKzB,OAAO,EACD,cAAc,CAAC,CAAC,CAAC,GACjB,uBAAuB,CAAC,CAAC,CAAC,GAC1B,qBAAqB,CAAC,CAAC,CAAC,EAC9B,QAAQ,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;CA2CpC"}
@@ -25,24 +25,29 @@ export class WrapReadableStream extends ReadableStream {
25
25
  constructor(wrapper, strategy) {
26
26
  super({
27
27
  start: async (controller) => {
28
- // `start` is invoked before `ReadableStream`'s constructor finish,
29
- // so using `this` synchronously causes
30
- // "Must call super constructor in derived class before accessing 'this' or returning from derived constructor".
31
- // Queue a microtask to avoid this.
32
- await Promise.resolve();
33
- this.readable = await getWrappedReadableStream(wrapper, controller);
28
+ const readable = await getWrappedReadableStream(wrapper, controller);
29
+ // `start` is called in `super()`, so can't use `this` synchronously.
30
+ // but it's fine after the first `await`
31
+ this.readable = readable;
34
32
  this.#reader = this.readable.getReader();
35
33
  },
36
34
  pull: async (controller) => {
37
- const result = await this.#reader.read();
38
- if (result.done) {
35
+ const { done, value } = await this.#reader
36
+ .read()
37
+ .catch((e) => {
38
+ if ("error" in wrapper) {
39
+ wrapper.error(e);
40
+ }
41
+ throw e;
42
+ });
43
+ if (done) {
39
44
  controller.close();
40
45
  if ("close" in wrapper) {
41
46
  await wrapper.close?.();
42
47
  }
43
48
  }
44
49
  else {
45
- controller.enqueue(result.value);
50
+ controller.enqueue(value);
46
51
  }
47
52
  },
48
53
  cancel: async (reason) => {
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-readable.js","sourceRoot":"","sources":["../src/wrap-readable.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAY7C,SAAS,wBAAwB,CAC7B,OAG8B,EAC9B,UAA8C;IAE9C,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACrB,OAAO,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;SAAM,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QACvC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;SAAM,CAAC;QACJ,gDAAgD;QAChD,wEAAwE;QACxE,OAAO,OAAO,CAAC;IACnB,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,kBAAsB,SAAQ,cAAiB;IACxD,QAAQ,CAAqB;IAE7B,OAAO,CAAkC;IAEzC,YACI,OAG8B,EAC9B,QAA6B;QAE7B,KAAK,CACD;YACI,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE;gBACxB,mEAAmE;gBACnE,uCAAuC;gBACvC,gHAAgH;gBAChH,mCAAmC;gBACnC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;gBAExB,IAAI,CAAC,QAAQ,GAAG,MAAM,wBAAwB,CAC1C,OAAO,EACP,UAAU,CACb,CAAC;gBACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC7C,CAAC;YACD,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE;gBACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;gBACzC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;oBACd,UAAU,CAAC,KAAK,EAAE,CAAC;oBACnB,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;wBACrB,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;oBAC5B,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACJ,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACrC,CAAC;YACL,CAAC;YACD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACrB,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAClC,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;oBACtB,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;gBACnC,CAAC;YACL,CAAC;SACJ,EACD,QAAQ,CACX,CAAC;IACN,CAAC;CACJ"}
1
+ {"version":3,"file":"wrap-readable.js","sourceRoot":"","sources":["../src/wrap-readable.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAa7C,SAAS,wBAAwB,CAC7B,OAG8B,EAC9B,UAA8C;IAE9C,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACrB,OAAO,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;SAAM,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QACvC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;SAAM,CAAC;QACJ,gDAAgD;QAChD,wEAAwE;QACxE,OAAO,OAAO,CAAC;IACnB,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,kBAAsB,SAAQ,cAAiB;IACxD,QAAQ,CAAqB;IAE7B,OAAO,CAAkC;IAEzC,YACI,OAG8B,EAC9B,QAA6B;QAE7B,KAAK,CACD;YACI,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE;gBACxB,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC3C,OAAO,EACP,UAAU,CACb,CAAC;gBACF,qEAAqE;gBACrE,wCAAwC;gBACxC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;gBACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC7C,CAAC;YACD,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE;gBACvB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO;qBACrC,IAAI,EAAE;qBACN,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;oBACT,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;wBACrB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBACrB,CAAC;oBACD,MAAM,CAAC,CAAC;gBACZ,CAAC,CAAC,CAAC;gBAEP,IAAI,IAAI,EAAE,CAAC;oBACP,UAAU,CAAC,KAAK,EAAE,CAAC;oBACnB,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;wBACrB,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;oBAC5B,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACJ,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC9B,CAAC;YACL,CAAC;YACD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACrB,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAClC,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;oBACtB,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;gBACnC,CAAC;YACL,CAAC;SACJ,EACD,QAAQ,CACX,CAAC;IACN,CAAC;CACJ"}
@@ -1,7 +1,7 @@
1
- import type { ValueOrPromise } from "@yume-chan/struct";
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
2
2
  import type { TransformStream } from "./stream.js";
3
3
  import { WritableStream } from "./stream.js";
4
- export type WrapWritableStreamStart<T> = () => ValueOrPromise<WritableStream<T>>;
4
+ export type WrapWritableStreamStart<T> = () => MaybePromiseLike<WritableStream<T>>;
5
5
  export interface WritableStreamWrapper<T> {
6
6
  start: WrapWritableStreamStart<T>;
7
7
  close?(): void | Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-writable.d.ts","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAA+B,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,MAAM,cAAc,CACzD,cAAc,CAAC,CAAC,CAAC,CACpB,CAAC;AAEF,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACpC,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAClC,KAAK,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAmBD,qBAAa,kBAAkB,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;;IACxD,QAAQ,EAAG,cAAc,CAAC,CAAC,CAAC,CAAC;gBAKzB,KAAK,EACC,cAAc,CAAC,CAAC,CAAC,GACjB,uBAAuB,CAAC,CAAC,CAAC,GAC1B,qBAAqB,CAAC,CAAC,CAAC;IAmClC,kBAAkB,CAAC,CAAC,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC;CAY3D"}
1
+ {"version":3,"file":"wrap-writable.d.ts","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EAAE,eAAe,EAA+B,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,MAAM,gBAAgB,CAC3D,cAAc,CAAC,CAAC,CAAC,CACpB,CAAC;AAEF,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACpC,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAClC,KAAK,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAmBD,qBAAa,kBAAkB,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;;IACxD,QAAQ,EAAG,cAAc,CAAC,CAAC,CAAC,CAAC;gBAKzB,KAAK,EACC,cAAc,CAAC,CAAC,CAAC,GACjB,uBAAuB,CAAC,CAAC,CAAC,GAC1B,qBAAqB,CAAC,CAAC,CAAC;IAgClC,kBAAkB,CAAC,CAAC,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC;CAY3D"}
@@ -18,12 +18,10 @@ export class WrapWritableStream extends WritableStream {
18
18
  constructor(start) {
19
19
  super({
20
20
  start: async () => {
21
- // `start` is invoked before `ReadableStream`'s constructor finish,
22
- // so using `this` synchronously causes
23
- // "Must call super constructor in derived class before accessing 'this' or returning from derived constructor".
24
- // Queue a microtask to avoid this.
25
- await Promise.resolve();
26
- this.writable = await getWrappedWritableStream(start);
21
+ const writable = await getWrappedWritableStream(start);
22
+ // `start` is called in `super()`, so can't use `this` synchronously.
23
+ // but it's fine after the first `await`
24
+ this.writable = writable;
27
25
  this.#writer = this.writable.getWriter();
28
26
  },
29
27
  write: async (chunk) => {
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-writable.js","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAW7C,KAAK,UAAU,wBAAwB,CACnC,KAG8B;IAE9B,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;QACnB,OAAO,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;SAAM,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QACrC,OAAO,MAAM,KAAK,EAAE,CAAC;IACzB,CAAC;SAAM,CAAC;QACJ,gDAAgD;QAChD,wEAAwE;QACxE,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,MAAM,OAAO,kBAAsB,SAAQ,cAAiB;IACxD,QAAQ,CAAqB;IAE7B,OAAO,CAAkC;IAEzC,YACI,KAG8B;QAE9B,KAAK,CAAC;YACF,KAAK,EAAE,KAAK,IAAI,EAAE;gBACd,mEAAmE;gBACnE,uCAAuC;gBACvC,gHAAgH;gBAChH,mCAAmC;gBACnC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;gBAExB,IAAI,CAAC,QAAQ,GAAG,MAAM,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBACtD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC7C,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACnB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACpB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACjC,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;oBAC9C,MAAM,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC1B,CAAC;YACL,CAAC;YACD,KAAK,EAAE,KAAK,IAAI,EAAE;gBACd,gCAAgC;gBAChC,0EAA0E;gBAC1E,yEAAyE;gBACzE,uCAAuC;gBACvC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC3B,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;oBAC9C,MAAM,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC1B,CAAC;YACL,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;IAED,kBAAkB,CAAI,WAAkC;QACpD,IAAI,OAAsB,CAAC;QAC3B,OAAO,IAAI,kBAAkB,CAAI;YAC7B,KAAK,EAAE,GAAG,EAAE;gBACR,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC5C,OAAO,WAAW,CAAC,QAAQ,CAAC;YAChC,CAAC;YACD,KAAK,CAAC,KAAK;gBACP,MAAM,OAAO,CAAC;YAClB,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;CACJ"}
1
+ {"version":3,"file":"wrap-writable.js","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAW7C,KAAK,UAAU,wBAAwB,CACnC,KAG8B;IAE9B,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;QACnB,OAAO,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;SAAM,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QACrC,OAAO,MAAM,KAAK,EAAE,CAAC;IACzB,CAAC;SAAM,CAAC;QACJ,gDAAgD;QAChD,wEAAwE;QACxE,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,MAAM,OAAO,kBAAsB,SAAQ,cAAiB;IACxD,QAAQ,CAAqB;IAE7B,OAAO,CAAkC;IAEzC,YACI,KAG8B;QAE9B,KAAK,CAAC;YACF,KAAK,EAAE,KAAK,IAAI,EAAE;gBACd,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBACvD,qEAAqE;gBACrE,wCAAwC;gBACxC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;gBACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC7C,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACnB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACpB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACjC,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;oBAC9C,MAAM,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC1B,CAAC;YACL,CAAC;YACD,KAAK,EAAE,KAAK,IAAI,EAAE;gBACd,gCAAgC;gBAChC,0EAA0E;gBAC1E,yEAAyE;gBACzE,uCAAuC;gBACvC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC3B,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;oBAC9C,MAAM,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC1B,CAAC;YACL,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;IAED,kBAAkB,CAAI,WAAkC;QACpD,IAAI,OAAsB,CAAC;QAC3B,OAAO,IAAI,kBAAkB,CAAI;YAC7B,KAAK,EAAE,GAAG,EAAE;gBACR,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC5C,OAAO,WAAW,CAAC,QAAQ,CAAC;YAChC,CAAC;YACD,KAAK,CAAC,KAAK;gBACP,MAAM,OAAO,CAAC;YAClB,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;CACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yume-chan/stream-extra",
3
- "version": "0.0.24",
3
+ "version": "2.0.0",
4
4
  "description": "Extensions to Web Streams API",
5
5
  "keywords": [
6
6
  "stream",
@@ -24,24 +24,22 @@
24
24
  "type": "module",
25
25
  "main": "esm/index.js",
26
26
  "types": "esm/index.d.ts",
27
+ "sideEffects": false,
27
28
  "dependencies": {
28
- "@yume-chan/async": "^2.2.0",
29
- "@yume-chan/struct": "^0.0.24"
29
+ "@yume-chan/async": "^4.0.2",
30
+ "@yume-chan/struct": "^2.0.0"
30
31
  },
31
32
  "devDependencies": {
32
- "@jest/globals": "^30.0.0-alpha.4",
33
+ "@types/node": "^22.13.10",
34
+ "prettier": "^3.5.3",
35
+ "typescript": "^5.8.2",
33
36
  "@yume-chan/eslint-config": "^1.0.0",
34
- "@yume-chan/tsconfig": "^1.0.0",
35
- "cross-env": "^7.0.3",
36
- "jest": "^30.0.0-alpha.4",
37
- "prettier": "^3.3.2",
38
- "ts-jest": "^29.1.4",
39
- "typescript": "^5.4.5"
37
+ "@yume-chan/test-runner": "^1.0.0",
38
+ "@yume-chan/tsconfig": "^1.0.0"
40
39
  },
41
40
  "scripts": {
42
41
  "build": "tsc -b tsconfig.build.json",
43
- "build:watch": "tsc -b tsconfig.build.json",
44
- "test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" TS_JEST_DISABLE_VER_CHECKER=true jest --coverage",
45
- "lint": "run-eslint && prettier src/**/*.ts --write --tab-width 4"
42
+ "lint": "run-eslint && prettier src/**/*.ts --write --tab-width 4",
43
+ "test": "run-test"
46
44
  }
47
45
  }
@@ -1,10 +1,13 @@
1
- import type { ValueOrPromise } from "@yume-chan/struct";
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
2
2
  import { StructEmptyError } from "@yume-chan/struct";
3
3
 
4
4
  import { BufferedReadableStream } from "./buffered.js";
5
5
  import type { PushReadableStreamController } from "./push-readable.js";
6
6
  import { PushReadableStream } from "./push-readable.js";
7
- import type { ReadableWritablePair } from "./stream.js";
7
+ import type {
8
+ ReadableWritablePair,
9
+ WritableStreamDefaultController,
10
+ } from "./stream.js";
8
11
  import { ReadableStream, WritableStream } from "./stream.js";
9
12
 
10
13
  // TODO: BufferedTransformStream: find better implementation
@@ -22,14 +25,16 @@ export class BufferedTransformStream<T>
22
25
  }
23
26
 
24
27
  constructor(
25
- transform: (stream: BufferedReadableStream) => ValueOrPromise<T>,
28
+ transform: (stream: BufferedReadableStream) => MaybePromiseLike<T>,
26
29
  ) {
27
30
  // Convert incoming chunks to a `BufferedReadableStream`
28
- let sourceStreamController!: PushReadableStreamController<Uint8Array>;
31
+ let bufferedStreamController!: PushReadableStreamController<Uint8Array>;
32
+
33
+ let writableStreamController!: WritableStreamDefaultController;
29
34
 
30
35
  const buffered = new BufferedReadableStream(
31
36
  new PushReadableStream<Uint8Array>((controller) => {
32
- sourceStreamController = controller;
37
+ bufferedStreamController = controller;
33
38
  }),
34
39
  );
35
40
 
@@ -50,21 +55,26 @@ export class BufferedTransformStream<T>
50
55
  }
51
56
  },
52
57
  cancel: (reason) => {
53
- // Propagate cancel to the source stream
54
- // So future writes will be rejected
55
- return buffered.cancel(reason);
58
+ // If a `ReadableStream` is piping into `#writable`,
59
+ // This will cancel the `ReadableStream` immediately.
60
+ // If upstream is writing using `#writable`'s writer, this will
61
+ // throw errors for any future writes
62
+ return writableStreamController.error(reason);
56
63
  },
57
64
  });
58
65
 
59
66
  this.#writable = new WritableStream({
67
+ start(controller) {
68
+ writableStreamController = controller;
69
+ },
60
70
  async write(chunk) {
61
- await sourceStreamController.enqueue(chunk);
71
+ await bufferedStreamController.enqueue(chunk);
62
72
  },
63
73
  abort() {
64
- sourceStreamController.close();
74
+ bufferedStreamController.close();
65
75
  },
66
76
  close() {
67
- sourceStreamController.close();
77
+ bufferedStreamController.close();
68
78
  },
69
79
  });
70
80
  }
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]!;