@push.rocks/smartstream 3.4.2 → 3.5.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.
package/.smartconfig.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "@git.zone/cli": {
3
+ "schemaVersion": 2,
3
4
  "projectType": "npm",
4
5
  "module": {
5
6
  "githost": "code.foss.global",
@@ -11,17 +12,26 @@
11
12
  "projectDomain": "push.rocks"
12
13
  },
13
14
  "release": {
14
- "registries": [
15
- "https://verdaccio.lossless.digital",
16
- "https://registry.npmjs.org"
17
- ],
18
- "accessLevel": "public"
15
+ "targets": {
16
+ "git": {
17
+ "enabled": true,
18
+ "remote": "origin",
19
+ "pushBranch": true,
20
+ "pushTags": true
21
+ },
22
+ "npm": {
23
+ "enabled": true,
24
+ "registries": [
25
+ "https://verdaccio.lossless.digital",
26
+ "https://registry.npmjs.org"
27
+ ],
28
+ "accessLevel": "public",
29
+ "alreadyPublished": "success"
30
+ }
31
+ }
19
32
  }
20
33
  },
21
34
  "@git.zone/tsdoc": {
22
- "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
23
- },
24
- "@ship.zone/szci": {
25
- "npmGlobalTools": []
35
+ "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license.md) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
26
36
  }
27
37
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartstream',
6
- version: '3.4.2',
6
+ version: '3.5.0',
7
7
  description: 'A library to simplify the creation and manipulation of Node.js streams, providing utilities for handling transform, duplex, and readable/writable streams effectively in TypeScript.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHNMQUFzTDtDQUNwTSxDQUFBIn0=
@@ -34,3 +34,16 @@ export declare function convertWebWritableToNodeWritable(webWritable: WritableSt
34
34
  * @returns A Web WritableStream that writes data to the Node.js Writable stream
35
35
  */
36
36
  export declare function convertNodeWritableToWebWritable(nodeWritable: plugins.stream.Writable): WritableStream<Uint8Array>;
37
+ /**
38
+ * Converts a Node.js Duplex stream to a Web readable/writable pair that can be
39
+ * passed to `ReadableStream.pipeThrough()`.
40
+ *
41
+ * Both sides share the duplex: the readable side reads with pull-based
42
+ * backpressure and closes on `end`, the writable side resolves each write on the
43
+ * Node.js write callback and ends the duplex on close. Cancelling the readable
44
+ * or aborting the writable destroys the duplex for both sides.
45
+ *
46
+ * @param nodeDuplex - The Node.js Duplex stream to convert
47
+ * @returns A Web readable/writable pair backed by the Node.js Duplex stream
48
+ */
49
+ export declare function convertNodeDuplexToWebDuplex(nodeDuplex: plugins.stream.Duplex): ReadableWritablePair<Uint8Array, Uint8Array>;
@@ -66,17 +66,89 @@ export function createWebReadableStreamFromFile(filePath) {
66
66
  */
67
67
  export function convertWebReadableToNodeReadable(webStream) {
68
68
  const reader = webStream.getReader();
69
+ let readInProgress = false;
70
+ let sourceTerminal = false;
71
+ let releaseAttempted = false;
72
+ let cleanupPromise;
73
+ const toError = (errorArg) => errorArg instanceof Error ? errorArg : new Error(String(errorArg));
74
+ const combineErrors = (primaryErrorArg, cleanupErrorsArg) => {
75
+ if (cleanupErrorsArg.length === 0) {
76
+ return primaryErrorArg;
77
+ }
78
+ if (!primaryErrorArg && cleanupErrorsArg.length === 1) {
79
+ return cleanupErrorsArg[0];
80
+ }
81
+ return new AggregateError(primaryErrorArg
82
+ ? [primaryErrorArg, ...cleanupErrorsArg]
83
+ : cleanupErrorsArg, 'Web readable cleanup failed');
84
+ };
85
+ const cleanupReader = (cancelActiveSourceArg, cancelReasonArg) => {
86
+ if (cleanupPromise) {
87
+ return cleanupPromise;
88
+ }
89
+ const shouldCancel = cancelActiveSourceArg && !sourceTerminal;
90
+ sourceTerminal = true;
91
+ cleanupPromise = (async () => {
92
+ const cleanupErrors = [];
93
+ if (shouldCancel) {
94
+ try {
95
+ await reader.cancel(cancelReasonArg ?? undefined);
96
+ }
97
+ catch (error) {
98
+ cleanupErrors.push(toError(error));
99
+ }
100
+ }
101
+ if (!releaseAttempted) {
102
+ releaseAttempted = true;
103
+ try {
104
+ reader.releaseLock();
105
+ }
106
+ catch (error) {
107
+ cleanupErrors.push(toError(error));
108
+ }
109
+ }
110
+ return cleanupErrors;
111
+ })();
112
+ return cleanupPromise;
113
+ };
69
114
  return new plugins.stream.Readable({
70
115
  read() {
71
- reader.read().then(({ value, done }) => {
116
+ if (readInProgress || sourceTerminal) {
117
+ return;
118
+ }
119
+ readInProgress = true;
120
+ void reader.read().then(({ value, done }) => {
121
+ readInProgress = false;
122
+ if (this.destroyed || sourceTerminal) {
123
+ return;
124
+ }
72
125
  if (done) {
73
- this.push(null);
126
+ void cleanupReader(false).then((cleanupErrors) => {
127
+ if (cleanupErrors.length > 0) {
128
+ this.destroy();
129
+ }
130
+ else if (!this.destroyed) {
131
+ this.push(null);
132
+ }
133
+ });
74
134
  }
75
135
  else {
76
136
  this.push(Buffer.from(value));
77
137
  }
78
- }, (err) => {
79
- this.destroy(err);
138
+ }, (error) => {
139
+ readInProgress = false;
140
+ if (this.destroyed || sourceTerminal) {
141
+ return;
142
+ }
143
+ const primaryError = toError(error);
144
+ void cleanupReader(false).then(() => {
145
+ this.destroy(primaryError);
146
+ });
147
+ });
148
+ },
149
+ destroy(error, callback) {
150
+ void cleanupReader(true, error).then((cleanupErrors) => {
151
+ callback(combineErrors(error, cleanupErrors));
80
152
  });
81
153
  }
82
154
  });
@@ -203,4 +275,22 @@ export function convertNodeWritableToWebWritable(nodeWritable) {
203
275
  }
204
276
  });
205
277
  }
206
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdHJlYW0ubm9kZXdlYmhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHN0cmVhbS5ub2Rld2ViaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBRXBEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLCtCQUErQixDQUFDLFFBQWdCO0lBQzlELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFekQsT0FBTyxJQUFJLGNBQWMsQ0FBQztRQUN4QixLQUFLLENBQUMsVUFBVTtZQUNkLFVBQVUsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUU7Z0JBQzdCLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDeEIsQ0FBQyxDQUFDLENBQUM7WUFFSCxVQUFVLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxHQUFHLEVBQUU7Z0JBQ3hCLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNyQixDQUFDLENBQUMsQ0FBQztZQUVILDhDQUE4QztZQUM5QyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDckIsQ0FBQztRQUNELElBQUksQ0FBQyxVQUFVO1lBQ2IsT0FBTyxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtnQkFDM0MsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNoQyxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztvQkFDbkIsVUFBVSxDQUFDLE9BQU8sQ0FBQyxLQUFtQixDQUFDLENBQUM7b0JBQ3hDLE9BQU8sRUFBRSxDQUFDO29CQUNWLE9BQU87Z0JBQ1QsQ0FBQztnQkFDRCx1REFBdUQ7Z0JBQ3ZELE1BQU0sVUFBVSxHQUFHLEdBQUcsRUFB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
278
+ /**
279
+ * Converts a Node.js Duplex stream to a Web readable/writable pair that can be
280
+ * passed to `ReadableStream.pipeThrough()`.
281
+ *
282
+ * Both sides share the duplex: the readable side reads with pull-based
283
+ * backpressure and closes on `end`, the writable side resolves each write on the
284
+ * Node.js write callback and ends the duplex on close. Cancelling the readable
285
+ * or aborting the writable destroys the duplex for both sides.
286
+ *
287
+ * @param nodeDuplex - The Node.js Duplex stream to convert
288
+ * @returns A Web readable/writable pair backed by the Node.js Duplex stream
289
+ */
290
+ export function convertNodeDuplexToWebDuplex(nodeDuplex) {
291
+ return {
292
+ readable: convertNodeReadableToWebReadable(nodeDuplex),
293
+ writable: convertNodeWritableToWebWritable(nodeDuplex),
294
+ };
295
+ }
296
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdHJlYW0ubm9kZXdlYmhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHN0cmVhbS5ub2Rld2ViaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBRXBEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLCtCQUErQixDQUFDLFFBQWdCO0lBQzlELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFekQsT0FBTyxJQUFJLGNBQWMsQ0FBQztRQUN4QixLQUFLLENBQUMsVUFBVTtZQUNkLFVBQVUsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUU7Z0JBQzdCLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDeEIsQ0FBQyxDQUFDLENBQUM7WUFFSCxVQUFVLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxHQUFHLEVBQUU7Z0JBQ3hCLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNyQixDQUFDLENBQUMsQ0FBQztZQUVILDhDQUE4QztZQUM5QyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDckIsQ0FBQztRQUNELElBQUksQ0FBQyxVQUFVO1lBQ2IsT0FBTyxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtnQkFDM0MsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNoQyxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztvQkFDbkIsVUFBVSxDQUFDLE9BQU8sQ0FBQyxLQUFtQixDQUFDLENBQUM7b0JBQ3hDLE9BQU8sRUFBRSxDQUFDO29CQUNWLE9BQU87Z0JBQ1QsQ0FBQztnQkFDRCx1REFBdUQ7Z0JBQ3ZELE1BQU0sVUFBVSxHQUFHLEdBQUcsRUFB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
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartstream',
6
- version: '3.4.2',
6
+ version: '3.5.0',
7
7
  description: 'A library to simplify the creation and manipulation of Node.js streams, providing utilities for handling transform, duplex, and readable/writable streams effectively in TypeScript.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfd2ViLzAwX2NvbW1pdGluZm9fZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRztJQUN4QixJQUFJLEVBQUUseUJBQXlCO0lBQy9CLE9BQU8sRUFBRSxPQUFPO0lBQ2hCLFdBQVcsRUFBRSxzTEFBc0w7Q0FDcE0sQ0FBQSJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartstream",
3
- "version": "3.4.2",
3
+ "version": "3.5.0",
4
4
  "private": false,
5
5
  "description": "A library to simplify the creation and manipulation of Node.js streams, providing utilities for handling transform, duplex, and readable/writable streams effectively in TypeScript.",
6
6
  "type": "module",
@@ -8,10 +8,6 @@
8
8
  ".": "./dist_ts/index.js",
9
9
  "./web": "./dist_ts_web/index.js"
10
10
  },
11
- "scripts": {
12
- "test": "(tstest test/ --verbose --logfile --timeout 60)",
13
- "build": "(tsbuild tsfolders)"
14
- },
15
11
  "repository": {
16
12
  "type": "git",
17
13
  "url": "https://code.foss.global/push.rocks/smartstream.git"
@@ -23,16 +19,16 @@
23
19
  },
24
20
  "homepage": "https://code.foss.global/push.rocks/smartstream",
25
21
  "devDependencies": {
26
- "@git.zone/tsbuild": "^4.4.0",
27
- "@git.zone/tsrun": "^2.0.2",
28
- "@git.zone/tstest": "^3.6.3",
29
- "@types/node": "^25.6.0"
22
+ "@git.zone/tsbuild": "^5.1.0",
23
+ "@git.zone/tsrun": "^3.0.2",
24
+ "@git.zone/tstest": "^6.3.2",
25
+ "@types/node": "^26.6.2"
30
26
  },
31
27
  "dependencies": {
32
28
  "@push.rocks/lik": "^6.4.1",
33
- "@push.rocks/smartenv": "^6.0.0",
34
- "@push.rocks/smartpromise": "^4.2.3",
35
- "@push.rocks/smartrx": "^3.0.10"
29
+ "@push.rocks/smartenv": "^6.1.0",
30
+ "@push.rocks/smartpromise": "^4.2.5",
31
+ "@push.rocks/smartrx": "^3.0.12"
36
32
  },
37
33
  "browserslist": [
38
34
  "last 1 chrome versions"
@@ -47,15 +43,9 @@
47
43
  "assets/**/*",
48
44
  "cli.js",
49
45
  ".smartconfig.json",
50
- "license",
51
- "npmextra.json",
46
+ "license.md",
52
47
  "readme.md"
53
48
  ],
54
- "pnpm": {
55
- "overrides": {
56
- "agentkeepalive": "^4.6.0"
57
- }
58
- },
59
49
  "keywords": [
60
50
  "stream",
61
51
  "node.js",
@@ -75,5 +65,8 @@
75
65
  "stream utilities",
76
66
  "esm"
77
67
  ],
78
- "packageManager": "pnpm@10.28.2"
79
- }
68
+ "scripts": {
69
+ "test": "(tstest test/ --verbose --logfile --timeout 60)",
70
+ "build": "(tsbuild tsfolders)"
71
+ }
72
+ }
package/readme.md CHANGED
@@ -399,7 +399,7 @@ const stream = new WebDuplexStream<string, string>({
399
399
 
400
400
  ### 🔀 Node ↔ Web Stream Converters
401
401
 
402
- The `nodewebhelpers` namespace provides bidirectional converters between Node.js and Web Streams with proper backpressure handling:
402
+ The `nodewebhelpers` namespace provides bidirectional converters between Node.js and Web Streams with proper backpressure and lifecycle ownership. Destroying a Node readable created by `convertWebReadableToNodeReadable()` awaits cancellation of its active Web reader and releases the reader lock; normal EOF and source errors also release the lock. Sole source or cleanup errors retain their identity, while concurrent primary and cleanup failures are reported as an `AggregateError` with the primary error first. Read completions that settle after teardown are discarded.
403
403
 
404
404
  ```typescript
405
405
  import { nodewebhelpers } from '@push.rocks/smartstream';
@@ -412,6 +412,7 @@ import { nodewebhelpers } from '@push.rocks/smartstream';
412
412
  | `convertNodeReadableToWebReadable(nodeStream)` | Node.js `Readable` | Web `ReadableStream` |
413
413
  | `convertWebWritableToNodeWritable(webWritable)` | Web `WritableStream` | Node.js `Writable` |
414
414
  | `convertNodeWritableToWebWritable(nodeWritable)` | Node.js `Writable` | Web `WritableStream` |
415
+ | `convertNodeDuplexToWebDuplex(nodeDuplex)` | Node.js `Duplex` | Web `{ readable, writable }` pair (usable with `pipeThrough()`) |
415
416
 
416
417
  #### Example: Serve a File as a Web ReadableStream
417
418
 
@@ -439,6 +440,19 @@ const nodeReadable2 = nodewebhelpers.convertWebReadableToNodeReadable(webReadabl
439
440
  nodeReadable2.pipe(fs.createWriteStream('./copy.bin'));
440
441
  ```
441
442
 
443
+ #### Example: Use a Node.js Duplex in a Web Pipeline
444
+
445
+ `convertNodeDuplexToWebDuplex()` returns a `ReadableWritablePair<Uint8Array, Uint8Array>` whose sides share the duplex. Closing the writable ends the duplex; cancelling the readable or aborting the writable destroys it for both sides.
446
+
447
+ ```typescript
448
+ import zlib from 'zlib';
449
+ import { nodewebhelpers } from '@push.rocks/smartstream';
450
+
451
+ const gzipped = webReadable.pipeThrough(
452
+ nodewebhelpers.convertNodeDuplexToWebDuplex(zlib.createGzip()),
453
+ );
454
+ ```
455
+
442
456
  #### Example: Round-Trip Conversion
443
457
 
444
458
  ```typescript
@@ -572,6 +586,7 @@ console.log('Error extraction complete');
572
586
  | `convertNodeReadableToWebReadable(ns)` | Node.js Readable → Web ReadableStream (pull-based backpressure) |
573
587
  | `convertWebWritableToNodeWritable(ws)` | Web WritableStream → Node.js Writable |
574
588
  | `convertNodeWritableToWebWritable(nw)` | Node.js Writable → Web WritableStream |
589
+ | `convertNodeDuplexToWebDuplex(nd)` | Node.js Duplex → Web `{ readable, writable }` pair |
575
590
 
576
591
  #### Utility Functions
577
592
 
@@ -580,9 +595,23 @@ console.log('Error extraction complete');
580
595
  | `createTransformFunction(fn, opts?)` | Create a SmartDuplex from an async mapping function |
581
596
  | `createPassThrough()` | Create an object-mode passthrough stream |
582
597
 
598
+ ## Migration from @push.rocks/webstream
599
+
600
+ `@push.rocks/webstream` is deprecated; its Web Streams surface lives in this package.
601
+
602
+ | `@push.rocks/webstream` | `@push.rocks/smartstream` |
603
+ |---|---|
604
+ | `import { WebDuplexStream } from '@push.rocks/webstream'` | `import { WebDuplexStream } from '@push.rocks/smartstream/web'` |
605
+ | `WebDuplexStream.fromUInt8Array(bytes)` | `WebDuplexStream.fromUInt8Array(bytes)` (unchanged) |
606
+ | `new WebDuplexStream({ writeFunction, finalFunction })` | unchanged; without a `writeFunction` chunks now pass through instead of erroring |
607
+ | `new WebDuplexStream({ readFunction })` + `stream.getCustomReadableStream()` | `new WebDuplexStream({ readFunction })` + `stream.readable`; the `readFunction` starts automatically, `await tools.write(chunk)` feeds the stream and `tools.done()` closes it |
608
+ | `convertDuplexToWebStream(duplex)` | `nodewebhelpers.convertNodeDuplexToWebDuplex(duplex)` from `@push.rocks/smartstream` (Node.js `Duplex`, `Uint8Array` chunks) |
609
+
610
+ `convertNodeDuplexToWebDuplex()` carries `Uint8Array` chunks only, like every `nodewebhelpers` converter; object-mode or string-encoded duplexes that `convertDuplexToWebStream()` passed through unchanged have no equivalent here.
611
+
583
612
  ## License and Legal Information
584
613
 
585
- This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
614
+ This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license](./license.md) file.
586
615
 
587
616
  **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
588
617
 
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartstream',
6
- version: '3.4.2',
6
+ version: '3.5.0',
7
7
  description: 'A library to simplify the creation and manipulation of Node.js streams, providing utilities for handling transform, duplex, and readable/writable streams effectively in TypeScript.'
8
8
  }
@@ -71,21 +71,104 @@ export function createWebReadableStreamFromFile(filePath: string): ReadableStrea
71
71
  */
72
72
  export function convertWebReadableToNodeReadable(webStream: ReadableStream<Uint8Array>): plugins.stream.Readable {
73
73
  const reader = webStream.getReader();
74
+ let readInProgress = false;
75
+ let sourceTerminal = false;
76
+ let releaseAttempted = false;
77
+ let cleanupPromise: Promise<Error[]> | undefined;
78
+
79
+ const toError = (errorArg: unknown): Error =>
80
+ errorArg instanceof Error ? errorArg : new Error(String(errorArg));
81
+
82
+ const combineErrors = (
83
+ primaryErrorArg: Error | null,
84
+ cleanupErrorsArg: Error[],
85
+ ): Error | null => {
86
+ if (cleanupErrorsArg.length === 0) {
87
+ return primaryErrorArg;
88
+ }
89
+ if (!primaryErrorArg && cleanupErrorsArg.length === 1) {
90
+ return cleanupErrorsArg[0];
91
+ }
92
+ return new AggregateError(
93
+ primaryErrorArg
94
+ ? [primaryErrorArg, ...cleanupErrorsArg]
95
+ : cleanupErrorsArg,
96
+ 'Web readable cleanup failed',
97
+ );
98
+ };
99
+
100
+ const cleanupReader = (
101
+ cancelActiveSourceArg: boolean,
102
+ cancelReasonArg?: Error | null,
103
+ ): Promise<Error[]> => {
104
+ if (cleanupPromise) {
105
+ return cleanupPromise;
106
+ }
107
+
108
+ const shouldCancel = cancelActiveSourceArg && !sourceTerminal;
109
+ sourceTerminal = true;
110
+ cleanupPromise = (async () => {
111
+ const cleanupErrors: Error[] = [];
112
+ if (shouldCancel) {
113
+ try {
114
+ await reader.cancel(cancelReasonArg ?? undefined);
115
+ } catch (error) {
116
+ cleanupErrors.push(toError(error));
117
+ }
118
+ }
119
+ if (!releaseAttempted) {
120
+ releaseAttempted = true;
121
+ try {
122
+ reader.releaseLock();
123
+ } catch (error) {
124
+ cleanupErrors.push(toError(error));
125
+ }
126
+ }
127
+ return cleanupErrors;
128
+ })();
129
+ return cleanupPromise;
130
+ };
74
131
 
75
132
  return new plugins.stream.Readable({
76
133
  read() {
77
- reader.read().then(
134
+ if (readInProgress || sourceTerminal) {
135
+ return;
136
+ }
137
+ readInProgress = true;
138
+ void reader.read().then(
78
139
  ({ value, done }) => {
140
+ readInProgress = false;
141
+ if (this.destroyed || sourceTerminal) {
142
+ return;
143
+ }
79
144
  if (done) {
80
- this.push(null);
145
+ void cleanupReader(false).then((cleanupErrors) => {
146
+ if (cleanupErrors.length > 0) {
147
+ this.destroy();
148
+ } else if (!this.destroyed) {
149
+ this.push(null);
150
+ }
151
+ });
81
152
  } else {
82
153
  this.push(Buffer.from(value));
83
154
  }
84
155
  },
85
- (err) => {
86
- this.destroy(err);
156
+ (error) => {
157
+ readInProgress = false;
158
+ if (this.destroyed || sourceTerminal) {
159
+ return;
160
+ }
161
+ const primaryError = toError(error);
162
+ void cleanupReader(false).then(() => {
163
+ this.destroy(primaryError);
164
+ });
87
165
  }
88
166
  );
167
+ },
168
+ destroy(error, callback) {
169
+ void cleanupReader(true, error).then((cleanupErrors) => {
170
+ callback(combineErrors(error, cleanupErrors));
171
+ });
89
172
  }
90
173
  });
91
174
  }
@@ -217,3 +300,24 @@ export function convertNodeWritableToWebWritable(nodeWritable: plugins.stream.Wr
217
300
  }
218
301
  });
219
302
  }
303
+
304
+ /**
305
+ * Converts a Node.js Duplex stream to a Web readable/writable pair that can be
306
+ * passed to `ReadableStream.pipeThrough()`.
307
+ *
308
+ * Both sides share the duplex: the readable side reads with pull-based
309
+ * backpressure and closes on `end`, the writable side resolves each write on the
310
+ * Node.js write callback and ends the duplex on close. Cancelling the readable
311
+ * or aborting the writable destroys the duplex for both sides.
312
+ *
313
+ * @param nodeDuplex - The Node.js Duplex stream to convert
314
+ * @returns A Web readable/writable pair backed by the Node.js Duplex stream
315
+ */
316
+ export function convertNodeDuplexToWebDuplex(
317
+ nodeDuplex: plugins.stream.Duplex,
318
+ ): ReadableWritablePair<Uint8Array, Uint8Array> {
319
+ return {
320
+ readable: convertNodeReadableToWebReadable(nodeDuplex),
321
+ writable: convertNodeWritableToWebWritable(nodeDuplex),
322
+ };
323
+ }
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartstream',
6
- version: '3.4.2',
6
+ version: '3.5.0',
7
7
  description: 'A library to simplify the creation and manipulation of Node.js streams, providing utilities for handling transform, duplex, and readable/writable streams effectively in TypeScript.'
8
8
  }
package/npmextra.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "@git.zone/cli": {
3
- "projectType": "npm",
4
- "module": {
5
- "githost": "code.foss.global",
6
- "gitscope": "push.rocks",
7
- "gitrepo": "smartstream",
8
- "description": "A library to simplify the creation and manipulation of Node.js streams, providing utilities for handling transform, duplex, and readable/writable streams effectively in TypeScript.",
9
- "npmPackagename": "@push.rocks/smartstream",
10
- "license": "MIT",
11
- "keywords": [
12
- "stream",
13
- "node.js",
14
- "typescript",
15
- "stream manipulation",
16
- "data processing",
17
- "pipeline",
18
- "async transformation",
19
- "event handling",
20
- "backpressure",
21
- "readable stream",
22
- "writable stream",
23
- "duplex stream",
24
- "transform stream",
25
- "file streaming",
26
- "buffer",
27
- "stream utilities",
28
- "esm"
29
- ]
30
- },
31
- "release": {
32
- "registries": [
33
- "https://verdaccio.lossless.digital",
34
- "https://registry.npmjs.org"
35
- ],
36
- "accessLevel": "public"
37
- }
38
- },
39
- "@git.zone/tsdoc": {
40
- "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
41
- },
42
- "@ship.zone/szci": {
43
- "npmGlobalTools": []
44
- }
45
- }
package/readme.hints.md DELETED
@@ -1 +0,0 @@
1
- - make sure to respect backpressure handling.
File without changes