@push.rocks/smartstream 2.0.7 → 3.0.2

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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartstream',
6
- version: '2.0.6',
6
+ version: '3.0.2',
7
7
  description: 'simplifies access to node streams'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLG1DQUFtQztDQUNqRCxDQUFBIn0=
@@ -1,4 +1,4 @@
1
- export * from './smartstream.classes.smartstream.js';
1
+ export * from './smartstream.classes.passthrough.js';
2
+ export * from './smartstream.classes.smartduplex.js';
2
3
  export * from './smartstream.classes.streamwrapper.js';
3
4
  export * from './smartstream.classes.streamintake.js';
4
- export * from './smartstream.duplex.js';
package/dist_ts/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export * from './smartstream.classes.smartstream.js';
1
+ export * from './smartstream.classes.passthrough.js';
2
+ export * from './smartstream.classes.smartduplex.js';
2
3
  export * from './smartstream.classes.streamwrapper.js';
3
4
  export * from './smartstream.classes.streamintake.js';
4
- export * from './smartstream.duplex.js';
5
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHNDQUFzQyxDQUFDO0FBQ3JELGNBQWMsd0NBQXdDLENBQUM7QUFDdkQsY0FBYyx1Q0FBdUMsQ0FBQztBQUN0RCxjQUFjLHlCQUF5QixDQUFDIn0=
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHNDQUFzQyxDQUFDO0FBQ3JELGNBQWMsc0NBQXNDLENBQUM7QUFDckQsY0FBYyx3Q0FBd0MsQ0FBQztBQUN2RCxjQUFjLHVDQUF1QyxDQUFDIn0=
@@ -0,0 +1,8 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ /// <reference types="node" resolution-mode="require"/>
3
+ import * as plugins from './smartstream.plugins.js';
4
+ export declare class PassThrough extends plugins.stream.Duplex {
5
+ constructor(options?: plugins.stream.DuplexOptions);
6
+ _read(size: number): void;
7
+ _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
8
+ }
@@ -0,0 +1,18 @@
1
+ import * as plugins from './smartstream.plugins.js';
2
+ export class PassThrough extends plugins.stream.Duplex {
3
+ constructor(options) {
4
+ super(options);
5
+ }
6
+ _read(size) {
7
+ // No-op: Data written will be automatically available for reading.
8
+ }
9
+ _write(chunk, encoding, callback) {
10
+ if (this.push(chunk, encoding)) {
11
+ callback();
12
+ }
13
+ else {
14
+ this.once('drain', callback);
15
+ }
16
+ }
17
+ }
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdHJlYW0uY2xhc3Nlcy5wYXNzdGhyb3VnaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c3RyZWFtLmNsYXNzZXMucGFzc3Rocm91Z2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUVwRCxNQUFNLE9BQU8sV0FBWSxTQUFRLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTTtJQUNwRCxZQUFZLE9BQXNDO1FBQ2hELEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNqQixDQUFDO0lBRUQsS0FBSyxDQUFDLElBQVk7UUFDaEIsbUVBQW1FO0lBQ3JFLENBQUM7SUFFRCxNQUFNLENBQUMsS0FBVSxFQUFFLFFBQXdCLEVBQUUsUUFBd0M7UUFDbkYsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsRUFBRTtZQUM5QixRQUFRLEVBQUUsQ0FBQztTQUNaO2FBQU07WUFDTCxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQztTQUM5QjtJQUNILENBQUM7Q0FDRiJ9
@@ -0,0 +1,32 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ /// <reference types="node" resolution-mode="require"/>
3
+ import * as plugins from './smartstream.plugins.js';
4
+ import { Duplex, type DuplexOptions } from 'stream';
5
+ export interface IStreamTools {
6
+ truncate: () => void;
7
+ push: (pipeObject: any) => void;
8
+ }
9
+ export interface IWriteAndTransformFunction<T, rT> {
10
+ (chunkArg: T, toolsArg: IStreamTools): Promise<rT>;
11
+ }
12
+ export interface IStreamEndFunction<rT> {
13
+ (toolsArg: IStreamTools): Promise<rT>;
14
+ }
15
+ export interface SmartStreamOptions<TInput, TOutput> extends DuplexOptions {
16
+ readFunction?: () => Promise<void>;
17
+ writeAndTransformFunction?: IWriteAndTransformFunction<TInput, TOutput>;
18
+ streamEndFunction?: IStreamEndFunction<TOutput>;
19
+ }
20
+ export declare class SmartDuplex<TInput = any, TOutput = any> extends Duplex {
21
+ static fromBuffer(buffer: Buffer, options?: DuplexOptions): SmartDuplex;
22
+ static fromObservable(observable: plugins.smartrx.rxjs.Observable<any>, options?: DuplexOptions): SmartDuplex;
23
+ static fromReplaySubject(replaySubject: plugins.smartrx.rxjs.ReplaySubject<any>, options?: DuplexOptions): SmartDuplex;
24
+ private readFunction?;
25
+ private writeAndTransformFunction?;
26
+ private streamEndFunction?;
27
+ private observableSubscription?;
28
+ constructor(optionsArg?: SmartStreamOptions<TInput, TOutput>);
29
+ _read(size: number): Promise<void>;
30
+ _write(chunk: TInput, encoding: string, callback: (error?: Error | null) => void): Promise<void>;
31
+ _final(callback: (error?: Error | null) => void): Promise<void>;
32
+ }
@@ -0,0 +1,135 @@
1
+ import * as plugins from './smartstream.plugins.js';
2
+ import { Duplex } from 'stream';
3
+ export class SmartDuplex extends Duplex {
4
+ // STATIC
5
+ static fromBuffer(buffer, options) {
6
+ const smartStream = new SmartDuplex(options);
7
+ process.nextTick(() => {
8
+ smartStream.push(buffer);
9
+ smartStream.push(null); // Signal the end of the data
10
+ });
11
+ return smartStream;
12
+ }
13
+ static fromObservable(observable, options) {
14
+ const smartStream = new SmartDuplex(options);
15
+ smartStream.observableSubscription = observable.subscribe({
16
+ next: (data) => {
17
+ if (!smartStream.push(data)) {
18
+ // Pause the observable if the stream buffer is full
19
+ smartStream.observableSubscription?.unsubscribe();
20
+ smartStream.once('drain', () => {
21
+ // Resume the observable when the stream buffer is drained
22
+ smartStream.observableSubscription?.unsubscribe();
23
+ smartStream.observableSubscription = observable.subscribe((data) => {
24
+ smartStream.push(data);
25
+ });
26
+ });
27
+ }
28
+ },
29
+ error: (err) => {
30
+ smartStream.emit('error', err);
31
+ },
32
+ complete: () => {
33
+ smartStream.push(null); // Signal the end of the data
34
+ },
35
+ });
36
+ return smartStream;
37
+ }
38
+ static fromReplaySubject(replaySubject, options) {
39
+ const smartStream = new SmartDuplex(options);
40
+ let isBackpressured = false;
41
+ // Subscribe to the ReplaySubject
42
+ const subscription = replaySubject.subscribe({
43
+ next: (data) => {
44
+ const canPush = smartStream.push(data);
45
+ if (!canPush) {
46
+ // If push returns false, pause the subscription because of backpressure
47
+ isBackpressured = true;
48
+ subscription.unsubscribe();
49
+ }
50
+ },
51
+ error: (err) => {
52
+ smartStream.emit('error', err);
53
+ },
54
+ complete: () => {
55
+ smartStream.push(null); // End the stream when the ReplaySubject completes
56
+ },
57
+ });
58
+ // Listen for 'drain' event to resume the subscription if it was paused
59
+ smartStream.on('drain', () => {
60
+ if (isBackpressured) {
61
+ isBackpressured = false;
62
+ // Resubscribe to the ReplaySubject since we previously paused
63
+ smartStream.observableSubscription = replaySubject.subscribe({
64
+ next: (data) => {
65
+ if (!smartStream.push(data)) {
66
+ smartStream.observableSubscription?.unsubscribe();
67
+ isBackpressured = true;
68
+ }
69
+ },
70
+ // No need to repeat error and complete handling here because it's already set up above
71
+ });
72
+ }
73
+ });
74
+ return smartStream;
75
+ }
76
+ constructor(optionsArg) {
77
+ super(optionsArg);
78
+ this.readFunction = optionsArg?.readFunction;
79
+ this.writeAndTransformFunction = optionsArg?.writeAndTransformFunction;
80
+ this.streamEndFunction = optionsArg?.streamEndFunction;
81
+ }
82
+ async _read(size) {
83
+ if (this.readFunction) {
84
+ await this.readFunction();
85
+ }
86
+ }
87
+ // Ensure the _write method types the chunk as TInput and encodes TOutput
88
+ async _write(chunk, encoding, callback) {
89
+ if (!this.writeAndTransformFunction) {
90
+ return callback(new Error('No stream function provided'));
91
+ }
92
+ const tools = {
93
+ truncate: () => {
94
+ this.push(null);
95
+ callback();
96
+ },
97
+ push: (pushArg) => this.push(pushArg),
98
+ };
99
+ try {
100
+ const modifiedChunk = await this.writeAndTransformFunction(chunk, tools);
101
+ if (modifiedChunk) {
102
+ if (!this.push(modifiedChunk)) {
103
+ // Handle backpressure if necessary
104
+ }
105
+ }
106
+ callback();
107
+ }
108
+ catch (err) {
109
+ callback(err);
110
+ }
111
+ }
112
+ async _final(callback) {
113
+ if (this.streamEndFunction) {
114
+ const tools = {
115
+ truncate: () => callback(),
116
+ push: (pipeObject) => this.push(pipeObject),
117
+ };
118
+ try {
119
+ const finalChunk = await this.streamEndFunction(tools);
120
+ if (finalChunk) {
121
+ this.push(finalChunk);
122
+ }
123
+ callback();
124
+ }
125
+ catch (err) {
126
+ callback(err);
127
+ }
128
+ }
129
+ else {
130
+ this.push(null),
131
+ callback();
132
+ }
133
+ }
134
+ }
135
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdHJlYW0uY2xhc3Nlcy5zbWFydGR1cGxleC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c3RyZWFtLmNsYXNzZXMuc21hcnRkdXBsZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsTUFBTSxFQUFzQixNQUFNLFFBQVEsQ0FBQztBQXNCcEQsTUFBTSxPQUFPLFdBQXlDLFNBQVEsTUFBTTtJQUNsRSxTQUFTO0lBQ1QsTUFBTSxDQUFDLFVBQVUsQ0FBQyxNQUFjLEVBQUUsT0FBdUI7UUFDdkQsTUFBTSxXQUFXLEdBQUcsSUFBSSxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDN0MsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUU7WUFDcEIsV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUN6QixXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsNkJBQTZCO1FBQ3ZELENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQztJQUVELE1BQU0sQ0FBQyxjQUFjLENBQ25CLFVBQWdELEVBQ2hELE9BQXVCO1FBRXZCLE1BQU0sV0FBVyxHQUFHLElBQUksV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzdDLFdBQVcsQ0FBQyxzQkFBc0IsR0FBRyxVQUFVLENBQUMsU0FBUyxDQUFDO1lBQ3hELElBQUksRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFO2dCQUNiLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFO29CQUMzQixvREFBb0Q7b0JBQ3BELFdBQVcsQ0FBQyxzQkFBc0IsRUFBRSxXQUFXLEVBQUUsQ0FBQztvQkFDbEQsV0FBVyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFO3dCQUM3QiwwREFBMEQ7d0JB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
@@ -1,21 +1,12 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="from2" />
3
2
  import * as plugins from './smartstream.plugins.js';
4
- export declare class StreamIntake<T> {
3
+ export declare class StreamIntake<T> extends plugins.stream.Readable {
5
4
  private signalEndBoolean;
6
5
  private chunkStore;
7
6
  pushNextObservable: plugins.smartrx.ObservableIntake<any>;
8
7
  private pushedNextDeferred;
9
- private readableStream;
10
- constructor();
11
- /**
12
- * returns a new style readble stream
13
- */
14
- getReadable(): plugins.stream.Readable;
15
- /**
16
- * returns an oldstyle readble stream
17
- */
18
- getReadableStream(): plugins.from2.Stream;
8
+ constructor(options?: plugins.stream.ReadableOptions);
9
+ _read(size: number): void;
19
10
  pushData(chunkData: T): void;
20
11
  signalEnd(): void;
21
12
  }
@@ -1,47 +1,38 @@
1
1
  import * as plugins from './smartstream.plugins.js';
2
- export class StreamIntake {
3
- constructor() {
2
+ export class StreamIntake extends plugins.stream.Readable {
3
+ constructor(options) {
4
+ super({ ...options, objectMode: true }); // Ensure that we are in object mode.
4
5
  this.signalEndBoolean = false;
5
6
  this.chunkStore = [];
6
7
  this.pushNextObservable = new plugins.smartrx.ObservableIntake();
7
8
  this.pushedNextDeferred = plugins.smartpromise.defer();
8
- this.readableStream = plugins.from2.obj(async (size, next) => {
9
- // console.log('get next');
10
- // execute without backpressure
11
- while (this.chunkStore.length > 0) {
12
- next(null, this.chunkStore.shift());
13
- }
14
- if (this.signalEndBoolean) {
15
- next(null, null);
16
- }
17
- // lets trigger backpressure handling
18
- this.pushNextObservable.push('please push next');
19
- await this.pushedNextDeferred.promise;
20
- this.pushedNextDeferred = plugins.smartpromise.defer();
21
- // execute with backpressure
22
- while (this.chunkStore.length > 0) {
23
- next(null, this.chunkStore.shift());
24
- }
25
- if (this.signalEndBoolean) {
26
- next(null, null);
27
- }
28
- });
29
9
  this.pushNextObservable.push('please push next');
30
10
  }
31
- /**
32
- * returns a new style readble stream
33
- */
34
- getReadable() {
35
- const readable = new plugins.stream.Readable({
36
- objectMode: true,
37
- });
38
- return readable.wrap(this.readableStream);
39
- }
40
- /**
41
- * returns an oldstyle readble stream
42
- */
43
- getReadableStream() {
44
- return this.readableStream;
11
+ _read(size) {
12
+ // console.log('get next');
13
+ const pushChunk = () => {
14
+ if (this.chunkStore.length > 0) {
15
+ // If push returns false, then we should stop reading
16
+ if (!this.push(this.chunkStore.shift())) {
17
+ return;
18
+ }
19
+ }
20
+ if (this.chunkStore.length === 0) {
21
+ if (this.signalEndBoolean) {
22
+ // If we're done, push null to signal the end of the stream
23
+ this.push(null);
24
+ }
25
+ else {
26
+ // Ask for more data and wait
27
+ this.pushNextObservable.push('please push next');
28
+ this.pushedNextDeferred.promise.then(() => {
29
+ this.pushedNextDeferred = plugins.smartpromise.defer(); // Reset the deferred
30
+ pushChunk(); // Try pushing the next chunk
31
+ });
32
+ }
33
+ }
34
+ };
35
+ pushChunk();
45
36
  }
46
37
  pushData(chunkData) {
47
38
  this.chunkStore.push(chunkData);
@@ -53,4 +44,4 @@ export class StreamIntake {
53
44
  this.pushNextObservable.signalComplete();
54
45
  }
55
46
  }
56
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdHJlYW0uY2xhc3Nlcy5zdHJlYW1pbnRha2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHN0cmVhbS5jbGFzc2VzLnN0cmVhbWludGFrZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBRXBELE1BQU0sT0FBTyxZQUFZO0lBZ0N2QjtRQS9CUSxxQkFBZ0IsR0FBRyxLQUFLLENBQUM7UUFDekIsZUFBVSxHQUFRLEVBQUUsQ0FBQztRQUV0Qix1QkFBa0IsR0FBRyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLEVBQU8sQ0FBQztRQUVoRSx1QkFBa0IsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRWxELG1CQUFjLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsRUFBRTtZQUM5RCwyQkFBMkI7WUFDM0IsK0JBQStCO1lBQy9CLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUNqQyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQzthQUNyQztZQUNELElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFO2dCQUN6QixJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO2FBQ2xCO1lBRUQscUNBQXFDO1lBQ3JDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztZQUNqRCxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUM7WUFDdEMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUM7WUFFdkQsNEJBQTRCO1lBQzVCLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUNqQyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQzthQUNyQztZQUNELElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFO2dCQUN6QixJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO2FBQ2xCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFHRCxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVEOztPQUVHO0lBQ0ksV0FBVztRQUNoQixNQUFNLFFBQVEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDO1lBQzNDLFVBQVUsRUFBRSxJQUFJO1NBQ2pCLENBQUMsQ0FBQztRQUNILE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksaUJBQWlCO1FBQ3RCLE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FBQztJQUM3QixDQUFDO0lBRU0sUUFBUSxDQUFDLFNBQVk7UUFDMUIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ3BDLENBQUM7SUFFTSxTQUFTO1FBQ2QsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQztRQUM3QixJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbEMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQzNDLENBQUM7Q0FDRiJ9
47
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdHJlYW0uY2xhc3Nlcy5zdHJlYW1pbnRha2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHN0cmVhbS5jbGFzc2VzLnN0cmVhbWludGFrZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBRXBELE1BQU0sT0FBTyxZQUFnQixTQUFRLE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUTtJQU0xRCxZQUFZLE9BQXdDO1FBQ2xELEtBQUssQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMscUNBQXFDO1FBTnhFLHFCQUFnQixHQUFHLEtBQUssQ0FBQztRQUN6QixlQUFVLEdBQVEsRUFBRSxDQUFDO1FBQ3RCLHVCQUFrQixHQUFHLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBTyxDQUFDO1FBQ2hFLHVCQUFrQixHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUM7UUFJeEQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRCxLQUFLLENBQUMsSUFBWTtRQUNoQiwyQkFBMkI7UUFDM0IsTUFBTSxTQUFTLEdBQUcsR0FBUyxFQUFFO1lBQzNCLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUM5QixxREFBcUQ7Z0JBQ3JELElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRTtvQkFDdkMsT0FBTztpQkFDUjthQUNGO1lBRUQsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7Z0JBQ2hDLElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFO29CQUN6QiwyREFBMkQ7b0JBQzNELElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7aUJBQ2pCO3FCQUFNO29CQUNMLDZCQUE2QjtvQkFDN0IsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO29CQUNqRCxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUU7d0JBQ3hDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMscUJBQXFCO3dCQUM3RSxTQUFTLEVBQUUsQ0FBQyxDQUFDLDZCQUE2QjtvQkFDNUMsQ0FBQyxDQUFDLENBQUM7aUJBQ0o7YUFDRjtRQUNILENBQUMsQ0FBQztRQUVGLFNBQVMsRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVNLFFBQVEsQ0FBQyxTQUFZO1FBQzFCLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2hDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNwQyxDQUFDO0lBRU0sU0FBUztRQUNkLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7UUFDN0IsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUMzQyxDQUFDO0NBQ0YifQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartstream",
3
- "version": "2.0.7",
3
+ "version": "3.0.2",
4
4
  "private": false,
5
5
  "description": "simplifies access to node streams",
6
6
  "main": "dist_ts/index.js",
@@ -8,18 +8,19 @@
8
8
  "type": "module",
9
9
  "scripts": {
10
10
  "test": "(tstest test/)",
11
- "build": "(tsbuild)"
11
+ "build": "(tsbuild)",
12
+ "buildDocs": "tsdoc"
12
13
  },
13
14
  "repository": {
14
15
  "type": "git",
15
- "url": "git+ssh://git@gitlab.com/pushrocks/smartstream.git"
16
+ "url": "git+https://gitlab.com/push.rocks/smartstream.git"
16
17
  },
17
18
  "author": "Lossless GmbH",
18
19
  "license": "MIT",
19
20
  "bugs": {
20
- "url": "https://gitlab.com/pushrocks/smartstream/issues"
21
+ "url": "https://gitlab.com/push.rocks/smartstream/issues"
21
22
  },
22
- "homepage": "https://gitlab.com/pushrocks/smartstream#README",
23
+ "homepage": "https://gitlab.com/push.rocks/smartstream#readme",
23
24
  "devDependencies": {
24
25
  "@git.zone/tsbuild": "^2.1.66",
25
26
  "@git.zone/tsrun": "^1.2.44",
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartstream',
6
- version: '2.0.7',
6
+ version: '3.0.2',
7
7
  description: 'simplifies access to node streams'
8
8
  }
package/ts/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './smartstream.classes.smartstream.js';
1
+ export * from './smartstream.classes.passthrough.js';
2
+ export * from './smartstream.classes.smartduplex.js';
2
3
  export * from './smartstream.classes.streamwrapper.js';
3
4
  export * from './smartstream.classes.streamintake.js';
4
- export * from './smartstream.duplex.js';
@@ -0,0 +1,19 @@
1
+ import * as plugins from './smartstream.plugins.js';
2
+
3
+ export class PassThrough extends plugins.stream.Duplex {
4
+ constructor(options?: plugins.stream.DuplexOptions) {
5
+ super(options);
6
+ }
7
+
8
+ _read(size: number): void {
9
+ // No-op: Data written will be automatically available for reading.
10
+ }
11
+
12
+ _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
13
+ if (this.push(chunk, encoding)) {
14
+ callback();
15
+ } else {
16
+ this.once('drain', callback);
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,177 @@
1
+ import * as plugins from './smartstream.plugins.js';
2
+ import { Duplex, type DuplexOptions } from 'stream';
3
+
4
+ export interface IStreamTools {
5
+ truncate: () => void;
6
+ push: (pipeObject: any) => void;
7
+ }
8
+
9
+ export interface IWriteAndTransformFunction<T, rT> {
10
+ (chunkArg: T, toolsArg: IStreamTools): Promise<rT>;
11
+ }
12
+
13
+ export interface IStreamEndFunction<rT> {
14
+ (toolsArg: IStreamTools): Promise<rT>;
15
+ }
16
+
17
+ export interface SmartStreamOptions<TInput, TOutput> extends DuplexOptions {
18
+ readFunction?: () => Promise<void>;
19
+ writeAndTransformFunction?: IWriteAndTransformFunction<TInput, TOutput>;
20
+ streamEndFunction?: IStreamEndFunction<TOutput>;
21
+ // Add other custom options if necessary
22
+ }
23
+
24
+ export class SmartDuplex<TInput = any, TOutput = any> extends Duplex {
25
+ // STATIC
26
+ static fromBuffer(buffer: Buffer, options?: DuplexOptions): SmartDuplex {
27
+ const smartStream = new SmartDuplex(options);
28
+ process.nextTick(() => {
29
+ smartStream.push(buffer);
30
+ smartStream.push(null); // Signal the end of the data
31
+ });
32
+ return smartStream;
33
+ }
34
+
35
+ static fromObservable(
36
+ observable: plugins.smartrx.rxjs.Observable<any>,
37
+ options?: DuplexOptions
38
+ ): SmartDuplex {
39
+ const smartStream = new SmartDuplex(options);
40
+ smartStream.observableSubscription = observable.subscribe({
41
+ next: (data) => {
42
+ if (!smartStream.push(data)) {
43
+ // Pause the observable if the stream buffer is full
44
+ smartStream.observableSubscription?.unsubscribe();
45
+ smartStream.once('drain', () => {
46
+ // Resume the observable when the stream buffer is drained
47
+ smartStream.observableSubscription?.unsubscribe();
48
+ smartStream.observableSubscription = observable.subscribe((data) => {
49
+ smartStream.push(data);
50
+ });
51
+ });
52
+ }
53
+ },
54
+ error: (err) => {
55
+ smartStream.emit('error', err);
56
+ },
57
+ complete: () => {
58
+ smartStream.push(null); // Signal the end of the data
59
+ },
60
+ });
61
+
62
+ return smartStream;
63
+ }
64
+
65
+ static fromReplaySubject(
66
+ replaySubject: plugins.smartrx.rxjs.ReplaySubject<any>,
67
+ options?: DuplexOptions
68
+ ): SmartDuplex {
69
+ const smartStream = new SmartDuplex(options);
70
+ let isBackpressured = false;
71
+
72
+ // Subscribe to the ReplaySubject
73
+ const subscription = replaySubject.subscribe({
74
+ next: (data) => {
75
+ const canPush = smartStream.push(data);
76
+ if (!canPush) {
77
+ // If push returns false, pause the subscription because of backpressure
78
+ isBackpressured = true;
79
+ subscription.unsubscribe();
80
+ }
81
+ },
82
+ error: (err) => {
83
+ smartStream.emit('error', err);
84
+ },
85
+ complete: () => {
86
+ smartStream.push(null); // End the stream when the ReplaySubject completes
87
+ },
88
+ });
89
+
90
+ // Listen for 'drain' event to resume the subscription if it was paused
91
+ smartStream.on('drain', () => {
92
+ if (isBackpressured) {
93
+ isBackpressured = false;
94
+ // Resubscribe to the ReplaySubject since we previously paused
95
+ smartStream.observableSubscription = replaySubject.subscribe({
96
+ next: (data) => {
97
+ if (!smartStream.push(data)) {
98
+ smartStream.observableSubscription?.unsubscribe();
99
+ isBackpressured = true;
100
+ }
101
+ },
102
+ // No need to repeat error and complete handling here because it's already set up above
103
+ });
104
+ }
105
+ });
106
+
107
+ return smartStream;
108
+ }
109
+
110
+ // INSTANCE
111
+ private readFunction?: () => Promise<void>;
112
+ private writeAndTransformFunction?: IWriteAndTransformFunction<TInput, TOutput>;
113
+ private streamEndFunction?: IStreamEndFunction<TOutput>;
114
+ private observableSubscription?: plugins.smartrx.rxjs.Subscription;
115
+
116
+ constructor(optionsArg?: SmartStreamOptions<TInput, TOutput>) {
117
+ super(optionsArg);
118
+ this.readFunction = optionsArg?.readFunction;
119
+ this.writeAndTransformFunction = optionsArg?.writeAndTransformFunction;
120
+ this.streamEndFunction = optionsArg?.streamEndFunction;
121
+ }
122
+
123
+ public async _read(size: number): Promise<void> {
124
+ if (this.readFunction) {
125
+ await this.readFunction();
126
+ }
127
+ }
128
+
129
+ // Ensure the _write method types the chunk as TInput and encodes TOutput
130
+ public async _write(chunk: TInput, encoding: string, callback: (error?: Error | null) => void) {
131
+ if (!this.writeAndTransformFunction) {
132
+ return callback(new Error('No stream function provided'));
133
+ }
134
+
135
+ const tools: IStreamTools = {
136
+ truncate: () => {
137
+ this.push(null);
138
+ callback();
139
+ },
140
+ push: (pushArg: TOutput) => this.push(pushArg),
141
+ };
142
+
143
+ try {
144
+ const modifiedChunk = await this.writeAndTransformFunction(chunk, tools);
145
+ if (modifiedChunk) {
146
+ if (!this.push(modifiedChunk)) {
147
+ // Handle backpressure if necessary
148
+ }
149
+ }
150
+ callback();
151
+ } catch (err) {
152
+ callback(err);
153
+ }
154
+ }
155
+
156
+ public async _final(callback: (error?: Error | null) => void) {
157
+ if (this.streamEndFunction) {
158
+ const tools: IStreamTools = {
159
+ truncate: () => callback(),
160
+ push: (pipeObject) => this.push(pipeObject),
161
+ };
162
+
163
+ try {
164
+ const finalChunk = await this.streamEndFunction(tools);
165
+ if (finalChunk) {
166
+ this.push(finalChunk);
167
+ }
168
+ callback();
169
+ } catch (err) {
170
+ callback(err);
171
+ }
172
+ } else {
173
+ this.push(null),
174
+ callback();
175
+ }
176
+ }
177
+ }
@@ -1,56 +1,42 @@
1
1
  import * as plugins from './smartstream.plugins.js';
2
2
 
3
- export class StreamIntake<T> {
3
+ export class StreamIntake<T> extends plugins.stream.Readable {
4
4
  private signalEndBoolean = false;
5
5
  private chunkStore: T[] = [];
6
-
7
6
  public pushNextObservable = new plugins.smartrx.ObservableIntake<any>();
8
-
9
7
  private pushedNextDeferred = plugins.smartpromise.defer();
10
8
 
11
- private readableStream = plugins.from2.obj(async (size, next) => {
12
- // console.log('get next');
13
- // execute without backpressure
14
- while (this.chunkStore.length > 0) {
15
- next(null, this.chunkStore.shift());
16
- }
17
- if (this.signalEndBoolean) {
18
- next(null, null);
19
- }
20
-
21
- // lets trigger backpressure handling
22
- this.pushNextObservable.push('please push next');
23
- await this.pushedNextDeferred.promise;
24
- this.pushedNextDeferred = plugins.smartpromise.defer();
25
-
26
- // execute with backpressure
27
- while (this.chunkStore.length > 0) {
28
- next(null, this.chunkStore.shift());
29
- }
30
- if (this.signalEndBoolean) {
31
- next(null, null);
32
- }
33
- });
34
-
35
- constructor() {
9
+ constructor(options?: plugins.stream.ReadableOptions) {
10
+ super({ ...options, objectMode: true }); // Ensure that we are in object mode.
36
11
  this.pushNextObservable.push('please push next');
37
12
  }
38
13
 
39
- /**
40
- * returns a new style readble stream
41
- */
42
- public getReadable() {
43
- const readable = new plugins.stream.Readable({
44
- objectMode: true,
45
- });
46
- return readable.wrap(this.readableStream);
47
- }
48
-
49
- /**
50
- * returns an oldstyle readble stream
51
- */
52
- public getReadableStream() {
53
- return this.readableStream;
14
+ _read(size: number): void {
15
+ // console.log('get next');
16
+ const pushChunk = (): void => {
17
+ if (this.chunkStore.length > 0) {
18
+ // If push returns false, then we should stop reading
19
+ if (!this.push(this.chunkStore.shift())) {
20
+ return;
21
+ }
22
+ }
23
+
24
+ if (this.chunkStore.length === 0) {
25
+ if (this.signalEndBoolean) {
26
+ // If we're done, push null to signal the end of the stream
27
+ this.push(null);
28
+ } else {
29
+ // Ask for more data and wait
30
+ this.pushNextObservable.push('please push next');
31
+ this.pushedNextDeferred.promise.then(() => {
32
+ this.pushedNextDeferred = plugins.smartpromise.defer(); // Reset the deferred
33
+ pushChunk(); // Try pushing the next chunk
34
+ });
35
+ }
36
+ }
37
+ };
38
+
39
+ pushChunk();
54
40
  }
55
41
 
56
42
  public pushData(chunkData: T) {
@@ -1,12 +0,0 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
- import * as plugins from './smartstream.plugins.js';
4
- import { Duplex, type DuplexOptions } from 'stream';
5
- export declare class SmartStream extends Duplex {
6
- private observableSubscription?;
7
- constructor(options?: DuplexOptions);
8
- _read(size: number): void;
9
- _write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
10
- static fromBuffer(buffer: Buffer, options?: DuplexOptions): SmartStream;
11
- static fromObservable(observable: plugins.smartrx.rxjs.Observable<any>, options?: DuplexOptions): SmartStream;
12
- }
@@ -1,48 +0,0 @@
1
- import * as plugins from './smartstream.plugins.js';
2
- import { Duplex } from 'stream';
3
- export class SmartStream extends Duplex {
4
- constructor(options) {
5
- super(options);
6
- }
7
- _read(size) {
8
- // Implement if you need custom behavior, otherwise leave it empty
9
- }
10
- _write(chunk, encoding, callback) {
11
- // Implement if you need custom behavior
12
- callback();
13
- }
14
- static fromBuffer(buffer, options) {
15
- const smartStream = new SmartStream(options);
16
- process.nextTick(() => {
17
- smartStream.push(buffer);
18
- smartStream.push(null); // Signal the end of the data
19
- });
20
- return smartStream;
21
- }
22
- static fromObservable(observable, options) {
23
- const smartStream = new SmartStream(options);
24
- smartStream.observableSubscription = observable.subscribe({
25
- next: (data) => {
26
- if (!smartStream.push(data)) {
27
- // Pause the observable if the stream buffer is full
28
- smartStream.observableSubscription?.unsubscribe();
29
- smartStream.once('drain', () => {
30
- // Resume the observable when the stream buffer is drained
31
- smartStream.observableSubscription?.unsubscribe();
32
- smartStream.observableSubscription = observable.subscribe(data => {
33
- smartStream.push(data);
34
- });
35
- });
36
- }
37
- },
38
- error: (err) => {
39
- smartStream.emit('error', err);
40
- },
41
- complete: () => {
42
- smartStream.push(null); // Signal the end of the data
43
- }
44
- });
45
- return smartStream;
46
- }
47
- }
48
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdHJlYW0uY2xhc3Nlcy5zbWFydHN0cmVhbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c3RyZWFtLmNsYXNzZXMuc21hcnRzdHJlYW0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsTUFBTSxFQUFzQixNQUFNLFFBQVEsQ0FBQztBQUVwRCxNQUFNLE9BQU8sV0FBWSxTQUFRLE1BQU07SUFHckMsWUFBWSxPQUF1QjtRQUNqQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDakIsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFZO1FBQ2hCLGtFQUFrRTtJQUNwRSxDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQVUsRUFBRSxRQUFnQixFQUFFLFFBQXdDO1FBQzNFLHdDQUF3QztRQUN4QyxRQUFRLEVBQUUsQ0FBQztJQUNiLENBQUM7SUFFRCxNQUFNLENBQUMsVUFBVSxDQUFDLE1BQWMsRUFBRSxPQUF1QjtRQUN2RCxNQUFNLFdBQVcsR0FBRyxJQUFJLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3QyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsRUFBRTtZQUNwQixXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3pCLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyw2QkFBNkI7UUFDdkQsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLFdBQVcsQ0FBQztJQUNyQixDQUFDO0lBRUQsTUFBTSxDQUFDLGNBQWMsQ0FBQyxVQUFnRCxFQUFFLE9BQXVCO1FBQzdGLE1BQU0sV0FBVyxHQUFHLElBQUksV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzdDLFdBQVcsQ0FBQyxzQkFBc0IsR0FBRyxVQUFVLENBQUMsU0FBUyxDQUFDO1lBQ3hELElBQUksRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFO2dCQUNiLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFO29CQUMzQixvREFBb0Q7b0JBQ3BELFdBQVcsQ0FBQyxzQkFBc0IsRUFBRSxXQUFXLEVBQUUsQ0FBQztvQkFDbEQsV0FBVyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFO3dCQUM3QiwwREFBMEQ7d0JBQzFELFdBQVcsQ0FBQyxzQkFBc0IsRUFBRSxXQUFXLEVBQUUsQ0FBQzt3QkFDbEQsV0FBVyxDQUFDLHNCQUFzQixHQUFHLFVBQVUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUU7NEJBQy9ELFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7d0JBQ3pCLENBQUMsQ0FBQyxDQUFDO29CQUNMLENBQUMsQ0FBQyxDQUFDO2lCQUNKO1lBQ0gsQ0FBQztZQUNELEtBQUssRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO2dCQUNiLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ2pDLENBQUM7WUFDRCxRQUFRLEVBQUUsR0FBRyxFQUFFO2dCQUNiLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyw2QkFBNkI7WUFDdkQsQ0FBQztTQUNGLENBQUMsQ0FBQztRQUVILE9BQU8sV0FBVyxDQUFDO0lBQ3JCLENBQUM7Q0FDRiJ9
@@ -1,23 +0,0 @@
1
- import * as plugins from './smartstream.plugins.js';
2
- export interface ITruncateFunc {
3
- (): void;
4
- }
5
- export interface IPipeMoreFunc {
6
- (pipeObject: any): void;
7
- }
8
- export interface IStreamTools {
9
- truncate: ITruncateFunc;
10
- pipeMore: IPipeMoreFunc;
11
- }
12
- export interface IStreamFunction<T, rT> {
13
- (chunkArg: T, toolsArg: IStreamTools): Promise<rT>;
14
- }
15
- export interface IStreamEndFunction<rT> {
16
- (toolsArg: IStreamTools): Promise<rT>;
17
- }
18
- export interface IStreamOptions {
19
- objectMode?: boolean;
20
- readableObjectMode?: boolean;
21
- writableObjectMode?: boolean;
22
- }
23
- export declare let createDuplexStream: <T, rT>(funcArg: IStreamFunction<T, rT>, endFuncArg?: IStreamEndFunction<rT>, optionsArg?: IStreamOptions) => plugins.stream.Transform;
@@ -1,48 +0,0 @@
1
- import * as plugins from './smartstream.plugins.js';
2
- export let createDuplexStream = (funcArg, endFuncArg, optionsArg = {
3
- objectMode: false,
4
- readableObjectMode: true,
5
- writableObjectMode: true,
6
- }) => {
7
- return plugins.through2(optionsArg, function (chunk, enc, cb) {
8
- let truncated = false;
9
- const tools = {
10
- truncate: () => {
11
- truncated = true;
12
- cb(null, null);
13
- },
14
- pipeMore: (pipeObject) => {
15
- this.push(pipeObject);
16
- },
17
- };
18
- const asyncWrapper = async () => {
19
- const resultChunk = await funcArg(chunk, tools);
20
- if (!truncated) {
21
- cb(null, resultChunk);
22
- }
23
- };
24
- asyncWrapper().catch((err) => {
25
- console.log(err);
26
- });
27
- }, function (cb) {
28
- const tools = {
29
- truncate: () => {
30
- cb();
31
- },
32
- pipeMore: (pushArg) => {
33
- this.push(pushArg);
34
- },
35
- };
36
- const asyncWrapper = async () => {
37
- if (endFuncArg) {
38
- const result = await endFuncArg(tools);
39
- this.push(result);
40
- }
41
- cb();
42
- };
43
- asyncWrapper().catch((err) => {
44
- console.log(err);
45
- });
46
- });
47
- };
48
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdHJlYW0uZHVwbGV4LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRzdHJlYW0uZHVwbGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sMEJBQTBCLENBQUM7QUE2QnBELE1BQU0sQ0FBQyxJQUFJLGtCQUFrQixHQUFHLENBQzlCLE9BQStCLEVBQy9CLFVBQW1DLEVBQ25DLGFBQTZCO0lBQzNCLFVBQVUsRUFBRSxLQUFLO0lBQ2pCLGtCQUFrQixFQUFFLElBQUk7SUFDeEIsa0JBQWtCLEVBQUUsSUFBSTtDQUN6QixFQUNELEVBQUU7SUFDRixPQUFPLE9BQU8sQ0FBQyxRQUFRLENBQ3JCLFVBQVUsRUFDVixVQUFVLEtBQUssRUFBRSxHQUFHLEVBQUUsRUFBRTtRQUN0QixJQUFJLFNBQVMsR0FBRyxLQUFLLENBQUM7UUFDdEIsTUFBTSxLQUFLLEdBQWlCO1lBQzFCLFFBQVEsRUFBRSxHQUFHLEVBQUU7Z0JBQ2IsU0FBUyxHQUFHLElBQUksQ0FBQztnQkFDakIsRUFBRSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNqQixDQUFDO1lBQ0QsUUFBUSxFQUFFLENBQUMsVUFBVSxFQUFFLEVBQUU7Z0JBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDeEIsQ0FBQztTQUNGLENBQUM7UUFDRixNQUFNLFlBQVksR0FBRyxLQUFLLElBQUksRUFBRTtZQUM5QixNQUFNLFdBQVcsR0FBTyxNQUFNLE9BQU8sQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDcEQsSUFBSSxDQUFDLFNBQVMsRUFBRTtnQkFDZCxFQUFFLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDO2FBQ3ZCO1FBQ0gsQ0FBQyxDQUFDO1FBQ0YsWUFBWSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7WUFDM0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsRUFDRCxVQUFVLEVBQUU7UUFDVixNQUFNLEtBQUssR0FBaUI7WUFDMUIsUUFBUSxFQUFFLEdBQUcsRUFBRTtnQkFDYixFQUFFLEVBQUUsQ0FBQztZQUNQLENBQUM7WUFDRCxRQUFRLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRTtnQkFDcEIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNyQixDQUFDO1NBQ0YsQ0FBQztRQUNGLE1BQU0sWUFBWSxHQUFHLEtBQUssSUFBSSxFQUFFO1lBQzlCLElBQUksVUFBVSxFQUFFO2dCQUNkLE1BQU0sTUFBTSxHQUFHLE1BQU0sVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN2QyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2FBQ25CO1lBQ0QsRUFBRSxFQUFFLENBQUM7UUFDUCxDQUFDLENBQUM7UUFDRixZQUFZLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtZQUMzQixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ25CLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUNGLENBQUM7QUFDSixDQUFDLENBQUMifQ==
@@ -1,55 +0,0 @@
1
- import * as plugins from './smartstream.plugins.js';
2
- import { Duplex, type DuplexOptions } from 'stream';
3
-
4
- export class SmartStream extends Duplex {
5
- private observableSubscription?: plugins.smartrx.rxjs.Subscription;
6
-
7
- constructor(options?: DuplexOptions) {
8
- super(options);
9
- }
10
-
11
- _read(size: number) {
12
- // Implement if you need custom behavior, otherwise leave it empty
13
- }
14
-
15
- _write(chunk: any, encoding: string, callback: (error?: Error | null) => void) {
16
- // Implement if you need custom behavior
17
- callback();
18
- }
19
-
20
- static fromBuffer(buffer: Buffer, options?: DuplexOptions): SmartStream {
21
- const smartStream = new SmartStream(options);
22
- process.nextTick(() => {
23
- smartStream.push(buffer);
24
- smartStream.push(null); // Signal the end of the data
25
- });
26
- return smartStream;
27
- }
28
-
29
- static fromObservable(observable: plugins.smartrx.rxjs.Observable<any>, options?: DuplexOptions): SmartStream {
30
- const smartStream = new SmartStream(options);
31
- smartStream.observableSubscription = observable.subscribe({
32
- next: (data) => {
33
- if (!smartStream.push(data)) {
34
- // Pause the observable if the stream buffer is full
35
- smartStream.observableSubscription?.unsubscribe();
36
- smartStream.once('drain', () => {
37
- // Resume the observable when the stream buffer is drained
38
- smartStream.observableSubscription?.unsubscribe();
39
- smartStream.observableSubscription = observable.subscribe(data => {
40
- smartStream.push(data);
41
- });
42
- });
43
- }
44
- },
45
- error: (err) => {
46
- smartStream.emit('error', err);
47
- },
48
- complete: () => {
49
- smartStream.push(null); // Signal the end of the data
50
- }
51
- });
52
-
53
- return smartStream;
54
- }
55
- }
@@ -1,83 +0,0 @@
1
- import * as plugins from './smartstream.plugins.js';
2
-
3
- export interface ITruncateFunc {
4
- (): void;
5
- }
6
-
7
- export interface IPipeMoreFunc {
8
- (pipeObject: any): void;
9
- }
10
-
11
- export interface IStreamTools {
12
- truncate: ITruncateFunc;
13
- pipeMore: IPipeMoreFunc;
14
- }
15
-
16
- export interface IStreamFunction<T, rT> {
17
- (chunkArg: T, toolsArg: IStreamTools): Promise<rT>;
18
- }
19
-
20
- export interface IStreamEndFunction<rT> {
21
- (toolsArg: IStreamTools): Promise<rT>;
22
- }
23
-
24
- export interface IStreamOptions {
25
- objectMode?: boolean;
26
- readableObjectMode?: boolean;
27
- writableObjectMode?: boolean;
28
- }
29
-
30
- export let createDuplexStream = <T, rT>(
31
- funcArg: IStreamFunction<T, rT>,
32
- endFuncArg?: IStreamEndFunction<rT>,
33
- optionsArg: IStreamOptions = {
34
- objectMode: false,
35
- readableObjectMode: true,
36
- writableObjectMode: true,
37
- }
38
- ) => {
39
- return plugins.through2(
40
- optionsArg,
41
- function (chunk, enc, cb) {
42
- let truncated = false;
43
- const tools: IStreamTools = {
44
- truncate: () => {
45
- truncated = true;
46
- cb(null, null);
47
- },
48
- pipeMore: (pipeObject) => {
49
- this.push(pipeObject);
50
- },
51
- };
52
- const asyncWrapper = async () => {
53
- const resultChunk: rT = await funcArg(chunk, tools);
54
- if (!truncated) {
55
- cb(null, resultChunk);
56
- }
57
- };
58
- asyncWrapper().catch((err) => {
59
- console.log(err);
60
- });
61
- },
62
- function (cb) {
63
- const tools: IStreamTools = {
64
- truncate: () => {
65
- cb();
66
- },
67
- pipeMore: (pushArg) => {
68
- this.push(pushArg);
69
- },
70
- };
71
- const asyncWrapper = async () => {
72
- if (endFuncArg) {
73
- const result = await endFuncArg(tools);
74
- this.push(result);
75
- }
76
- cb();
77
- };
78
- asyncWrapper().catch((err) => {
79
- console.log(err);
80
- });
81
- }
82
- );
83
- };