@push.rocks/smartstream 3.0.35 → 3.0.36
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/dist_ts/00_commitinfo_data.js +3 -3
- package/npmextra.json +11 -11
- package/package.json +12 -12
- package/readme.hints.md +1 -1
- package/readme.md +235 -7
- package/ts/00_commitinfo_data.ts +2 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartstream',
|
|
6
|
-
version: '3.0.
|
|
7
|
-
description: '
|
|
6
|
+
version: '3.0.36',
|
|
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
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLHNMQUFzTDtDQUNwTSxDQUFBIn0=
|
package/npmextra.json
CHANGED
|
@@ -9,27 +9,27 @@
|
|
|
9
9
|
"githost": "code.foss.global",
|
|
10
10
|
"gitscope": "push.rocks",
|
|
11
11
|
"gitrepo": "smartstream",
|
|
12
|
-
"description": "
|
|
12
|
+
"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.",
|
|
13
13
|
"npmPackagename": "@push.rocks/smartstream",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"keywords": [
|
|
16
|
+
"stream",
|
|
16
17
|
"node.js",
|
|
17
|
-
"
|
|
18
|
+
"typescript",
|
|
18
19
|
"stream manipulation",
|
|
19
|
-
"pipeline",
|
|
20
20
|
"data processing",
|
|
21
|
+
"pipeline",
|
|
21
22
|
"async transformation",
|
|
22
23
|
"event handling",
|
|
23
|
-
"backpressure
|
|
24
|
-
"readable
|
|
25
|
-
"writable
|
|
26
|
-
"duplex
|
|
27
|
-
"transform
|
|
24
|
+
"backpressure",
|
|
25
|
+
"readable stream",
|
|
26
|
+
"writable stream",
|
|
27
|
+
"duplex stream",
|
|
28
|
+
"transform stream",
|
|
28
29
|
"file streaming",
|
|
29
|
-
"buffer
|
|
30
|
+
"buffer",
|
|
30
31
|
"stream utilities",
|
|
31
|
-
"
|
|
32
|
-
"stream output"
|
|
32
|
+
"esm"
|
|
33
33
|
]
|
|
34
34
|
}
|
|
35
35
|
},
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartstream",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.36",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "
|
|
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
|
"main": "dist_ts/index.js",
|
|
7
7
|
"typings": "dist_ts/index.d.ts",
|
|
8
8
|
"type": "module",
|
|
@@ -46,23 +46,23 @@
|
|
|
46
46
|
"readme.md"
|
|
47
47
|
],
|
|
48
48
|
"keywords": [
|
|
49
|
+
"stream",
|
|
49
50
|
"node.js",
|
|
50
|
-
"
|
|
51
|
+
"typescript",
|
|
51
52
|
"stream manipulation",
|
|
52
|
-
"pipeline",
|
|
53
53
|
"data processing",
|
|
54
|
+
"pipeline",
|
|
54
55
|
"async transformation",
|
|
55
56
|
"event handling",
|
|
56
|
-
"backpressure
|
|
57
|
-
"readable
|
|
58
|
-
"writable
|
|
59
|
-
"duplex
|
|
60
|
-
"transform
|
|
57
|
+
"backpressure",
|
|
58
|
+
"readable stream",
|
|
59
|
+
"writable stream",
|
|
60
|
+
"duplex stream",
|
|
61
|
+
"transform stream",
|
|
61
62
|
"file streaming",
|
|
62
|
-
"buffer
|
|
63
|
+
"buffer",
|
|
63
64
|
"stream utilities",
|
|
64
|
-
"
|
|
65
|
-
"stream output"
|
|
65
|
+
"esm"
|
|
66
66
|
],
|
|
67
67
|
"scripts": {
|
|
68
68
|
"test": "(tstest test/)",
|
package/readme.hints.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
- make sure to respect backpressure handling.
|
package/readme.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
```markdown
|
|
1
2
|
# @push.rocks/smartstream
|
|
2
|
-
|
|
3
|
+
A TypeScript library to simplify the creation and manipulation of Node.js streams, providing utilities for transform, duplex, and readable/writable stream handling while managing backpressure effectively.
|
|
3
4
|
|
|
4
5
|
## Install
|
|
5
6
|
To install `@push.rocks/smartstream`, you can use npm or yarn as follows:
|
|
@@ -14,7 +15,7 @@ This will add `@push.rocks/smartstream` to your project's dependencies.
|
|
|
14
15
|
|
|
15
16
|
## Usage
|
|
16
17
|
|
|
17
|
-
The `@push.rocks/smartstream` module is designed to simplify working with Node.js streams by providing a set of utilities for creating and manipulating streams. This module makes
|
|
18
|
+
The `@push.rocks/smartstream` module is designed to simplify working with Node.js streams by providing a set of utilities for creating and manipulating streams. This module makes extensive use of TypeScript for improved code quality, readability, and maintenance. ESM syntax is utilized throughout the examples.
|
|
18
19
|
|
|
19
20
|
### Importing the Module
|
|
20
21
|
|
|
@@ -24,6 +25,12 @@ Start by importing the module into your TypeScript file:
|
|
|
24
25
|
import * as smartstream from '@push.rocks/smartstream';
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
For a more specific import, you may do the following:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { SmartDuplex, StreamWrapper, StreamIntake, createTransformFunction, createPassThrough } from '@push.rocks/smartstream';
|
|
32
|
+
```
|
|
33
|
+
|
|
27
34
|
### Creating Basic Transform Streams
|
|
28
35
|
|
|
29
36
|
The module provides utilities for creating transform streams. For example, to create a transform stream that modifies chunks of data, you can use the `createTransformFunction` utility:
|
|
@@ -58,7 +65,7 @@ const processDataDuplex = new SmartDuplex({
|
|
|
58
65
|
sourceStream.pipe(processDataDuplex).pipe(destinationStream);
|
|
59
66
|
```
|
|
60
67
|
|
|
61
|
-
###
|
|
68
|
+
### Combining Multiple Streams
|
|
62
69
|
|
|
63
70
|
`Smartstream` facilitates easy combining of multiple streams into a single pipeline, handling errors and cleanup automatically. Here's how you can combine multiple streams:
|
|
64
71
|
|
|
@@ -101,7 +108,7 @@ Consider a scenario where you need to process a large CSV file, transform the da
|
|
|
101
108
|
```typescript
|
|
102
109
|
import { SmartDuplex, createTransformFunction } from '@push.rocks/smartstream';
|
|
103
110
|
import fs from 'fs';
|
|
104
|
-
import csvParser from 'csv-parser';
|
|
111
|
+
import csvParser from 'csv-parser';
|
|
105
112
|
|
|
106
113
|
const csvReadTransform = createTransformFunction<any, any>(async (row) => {
|
|
107
114
|
// Process row
|
|
@@ -121,11 +128,232 @@ fs.createReadStream('path/to/largeFile.csv')
|
|
|
121
128
|
|
|
122
129
|
This example demonstrates reading a large CSV file, transforming each row with `createTransformFunction`, and using a `SmartDuplex` to manage the processed data flow efficiently, ensuring no data is lost due to backpressure issues.
|
|
123
130
|
|
|
124
|
-
###
|
|
131
|
+
### Advanced Use Case: Backpressure Handling
|
|
132
|
+
|
|
133
|
+
Effective backpressure handling is crucial when working with streams to avoid overwhelming the downstream consumers. Here’s a comprehensive example that demonstrates handling backpressure in a pipeline with multiple `SmartDuplex` instances:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { SmartDuplex } from '@push.rocks/smartstream';
|
|
137
|
+
|
|
138
|
+
// Define the first SmartDuplex, which writes data slowly to simulate backpressure
|
|
139
|
+
const slowProcessingStream = new SmartDuplex({
|
|
140
|
+
name: 'SlowProcessor',
|
|
141
|
+
objectMode: true,
|
|
142
|
+
writeFunction: async (chunk, { push }) => {
|
|
143
|
+
await new Promise(resolve => setTimeout(resolve, 100)); // Simulated delay
|
|
144
|
+
console.log('Processed chunk:', chunk);
|
|
145
|
+
push(chunk);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Define the second SmartDuplex as a fast processor
|
|
150
|
+
const fastProcessingStream = new SmartDuplex({
|
|
151
|
+
name: 'FastProcessor',
|
|
152
|
+
objectMode: true,
|
|
153
|
+
writeFunction: async (chunk, { push }) => {
|
|
154
|
+
console.log('Fast processing chunk:', chunk);
|
|
155
|
+
push(chunk);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Create a StreamIntake to dynamically handle incoming data
|
|
160
|
+
const streamIntake = new StreamIntake<string>();
|
|
161
|
+
|
|
162
|
+
// Chain the streams together and handle the backpressure scenario
|
|
163
|
+
streamIntake
|
|
164
|
+
.pipe(fastProcessingStream)
|
|
165
|
+
.pipe(slowProcessingStream)
|
|
166
|
+
.pipe(createPassThrough()) // Use Pass-Through to provide intermediary handling
|
|
167
|
+
.on('data', data => console.log('Final output:', data))
|
|
168
|
+
.on('error', error => console.error('Stream encountered an error:', error));
|
|
169
|
+
|
|
170
|
+
// Simulate data pushing with intervals to observe backpressure handling
|
|
171
|
+
let counter = 0;
|
|
172
|
+
const interval = setInterval(() => {
|
|
173
|
+
if (counter >= 10) {
|
|
174
|
+
streamIntake.signalEnd();
|
|
175
|
+
clearInterval(interval);
|
|
176
|
+
} else {
|
|
177
|
+
streamIntake.pushData(`Chunk ${counter}`);
|
|
178
|
+
counter++;
|
|
179
|
+
}
|
|
180
|
+
}, 50);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
In this advanced use case, a `SlowProcessor` and `FastProcessor` are created using `SmartDuplex`, simulating a situation where one stream is slower than another. The `StreamIntake` dynamically handles incoming chunks of data and the intermediary Pass-Through handles any potential interruptions.
|
|
184
|
+
|
|
185
|
+
### Transform Streams in Parallel
|
|
186
|
+
|
|
187
|
+
For scenarios where you need to process data in parallel:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { SmartDuplex, createTransformFunction } from '@push.rocks/smartstream';
|
|
191
|
+
|
|
192
|
+
const parallelTransform = createTransformFunction<any, any>(async (chunk) => {
|
|
193
|
+
// Parallel Processing
|
|
194
|
+
const results = await Promise.all(chunk.map(async item => await processItem(item)));
|
|
195
|
+
return results;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const streamIntake = new StreamIntake<any[]>();
|
|
199
|
+
|
|
200
|
+
streamIntake
|
|
201
|
+
.pipe(parallelTransform)
|
|
202
|
+
.pipe(new SmartDuplex({
|
|
203
|
+
async writeFunction(chunk, { push }) {
|
|
204
|
+
console.log('Processed parallel chunk:', chunk);
|
|
205
|
+
push(chunk);
|
|
206
|
+
}
|
|
207
|
+
}))
|
|
208
|
+
.on('finish', () => console.log('Parallel processing completed.'));
|
|
209
|
+
|
|
210
|
+
// Simulate data pushing
|
|
211
|
+
streamIntake.pushData([1, 2, 3, 4]);
|
|
212
|
+
streamIntake.pushData([5, 6, 7, 8]);
|
|
213
|
+
streamIntake.signalEnd();
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Error Handling in Stream Pipelines
|
|
217
|
+
|
|
218
|
+
Error handling is an essential part of working with streams. The `StreamWrapper` assists in combining multiple streams while managing errors seamlessly:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { StreamWrapper } from '@push.rocks/smartstream';
|
|
222
|
+
|
|
223
|
+
const faultyStream = new SmartDuplex({
|
|
224
|
+
async writeFunction(chunk, { push }) {
|
|
225
|
+
if (chunk === 'bad data') {
|
|
226
|
+
throw new Error('Faulty data encountered');
|
|
227
|
+
}
|
|
228
|
+
push(chunk);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
125
231
|
|
|
126
|
-
|
|
232
|
+
const readStream = new StreamIntake<string>();
|
|
233
|
+
const writeStream = new SmartDuplex({
|
|
234
|
+
async writeFunction(chunk) {
|
|
235
|
+
console.log('Written chunk:', chunk);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const combinedStream = new StreamWrapper([readStream, faultyStream, writeStream]);
|
|
240
|
+
|
|
241
|
+
combinedStream.run()
|
|
242
|
+
.then(() => console.log('Stream processing completed.'))
|
|
243
|
+
.catch(err => console.error('Stream error:', err.message));
|
|
244
|
+
|
|
245
|
+
// Push Data
|
|
246
|
+
readStream.pushData('good data');
|
|
247
|
+
readStream.pushData('bad data'); // This will throw an error
|
|
248
|
+
readStream.pushData('more good data');
|
|
249
|
+
readStream.signalEnd();
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Testing Streams
|
|
253
|
+
|
|
254
|
+
Here's an example test case using the `tap` testing framework to verify the integrity of the `SmartDuplex` from a buffer:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { expect, tap } from '@push.rocks/tapbundle';
|
|
258
|
+
import { SmartDuplex } from '@push.rocks/smartstream';
|
|
259
|
+
|
|
260
|
+
tap.test('should create a SmartStream from a Buffer', async () => {
|
|
261
|
+
const bufferData = Buffer.from('This is a test buffer');
|
|
262
|
+
const smartStream = SmartDuplex.fromBuffer(bufferData, {});
|
|
263
|
+
|
|
264
|
+
let receivedData = Buffer.alloc(0);
|
|
265
|
+
|
|
266
|
+
return new Promise<void>((resolve) => {
|
|
267
|
+
smartStream.on('data', (chunk: Buffer) => {
|
|
268
|
+
receivedData = Buffer.concat([receivedData, chunk]);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
smartStream.on('end', () => {
|
|
272
|
+
expect(receivedData.toString()).toEqual(bufferData.toString());
|
|
273
|
+
resolve();
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
tap.start();
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Working with Files and Buffers
|
|
282
|
+
|
|
283
|
+
You can easily stream files and buffers with `smartstream`. Here’s a test illustrating reading and writing with file streams using `smartfile` combined with `smartstream` utilities:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
import { tap } from '@push.rocks/tapbundle';
|
|
287
|
+
import * as smartfile from '@push.rocks/smartfile';
|
|
288
|
+
import { SmartDuplex, StreamWrapper } from '@push.rocks/smartstream';
|
|
289
|
+
|
|
290
|
+
tap.test('should handle file read and write streams', async () => {
|
|
291
|
+
const readStream = smartfile.fsStream.createReadStream('./test/assets/readabletext.txt');
|
|
292
|
+
const writeStream = smartfile.fsStream.createWriteStream('./test/assets/writabletext.txt');
|
|
293
|
+
|
|
294
|
+
const transformStream = new SmartDuplex({
|
|
295
|
+
async writeFunction(chunk, { push }) {
|
|
296
|
+
const transformedChunk = chunk.toString().toUpperCase();
|
|
297
|
+
push(transformedChunk);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const streamWrapper = new StreamWrapper([readStream, transformStream, writeStream]);
|
|
302
|
+
|
|
303
|
+
await streamWrapper.run();
|
|
304
|
+
|
|
305
|
+
const outputContent = await smartfile.fs.promises.readFile('./test/assets/writabletext.txt', 'utf-8');
|
|
306
|
+
console.log('Output Content:', outputContent);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
tap.start();
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Modular and Scoped Transformations
|
|
313
|
+
|
|
314
|
+
Creating modular and scoped transformations is straightforward with `SmartDuplex`:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { SmartDuplex } from '@push.rocks/smartstream';
|
|
318
|
+
|
|
319
|
+
type DataChunk = {
|
|
320
|
+
id: number;
|
|
321
|
+
data: string;
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const transformationStream1 = new SmartDuplex<DataChunk, DataChunk>({
|
|
325
|
+
async writeFunction(chunk, { push }) {
|
|
326
|
+
chunk.data = chunk.data.toUpperCase();
|
|
327
|
+
push(chunk);
|
|
328
|
+
}
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
const transformationStream2 = new SmartDuplex<DataChunk, DataChunk>({
|
|
332
|
+
async writeFunction(chunk, { push }) {
|
|
333
|
+
chunk.data = `${chunk.data} processed with transformation 2`;
|
|
334
|
+
push(chunk);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const initialData: DataChunk[] = [
|
|
339
|
+
{ id: 1, data: 'first' },
|
|
340
|
+
{ id: 2, data: 'second' }
|
|
341
|
+
];
|
|
342
|
+
|
|
343
|
+
const intakeStream = new StreamIntake<DataChunk>();
|
|
344
|
+
|
|
345
|
+
intakeStream
|
|
346
|
+
.pipe(transformationStream1)
|
|
347
|
+
.pipe(transformationStream2)
|
|
348
|
+
.on('data', data => console.log('Transformed Data:', data));
|
|
349
|
+
|
|
350
|
+
initialData.forEach(item => intakeStream.pushData(item));
|
|
351
|
+
intakeStream.signalEnd();
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
By leveraging `SmartDuplex`, `StreamWrapper`, and `StreamIntake`, you can streamline and enhance your data transformation pipelines in Node.js with a clear, efficient, and backpressure-friendly approach.
|
|
355
|
+
```
|
|
127
356
|
|
|
128
|
-
For more detailed examples and documentation, visit the [GitLab Repository](https://gitlab.com/push.rocks/smartstream) or the [GitHub Mirror](https://github.com/pushrocks/smartstream).
|
|
129
357
|
|
|
130
358
|
## License and Legal Information
|
|
131
359
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartstream',
|
|
6
|
-
version: '3.0.
|
|
7
|
-
description: '
|
|
6
|
+
version: '3.0.36',
|
|
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
|
}
|