@robinpath/cli 1.74.0 → 1.75.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/modules/stream.js CHANGED
@@ -1,322 +1,322 @@
1
- /**
2
- * Native stream module for RobinPath.
3
- * Readable, Writable, Transform, Duplex, PassThrough, and pipeline.
4
- */
5
- import { Readable, Writable, Transform, Duplex, PassThrough, pipeline as _pipeline } from 'node:stream';
6
- import { toStr, toNum, requireArgs } from './_helpers.js';
7
-
8
- const _streams = new Map();
9
- let _nextId = 1;
10
-
11
- export const StreamFunctions = {
12
-
13
- readable: (args) => {
14
- const data = args[0];
15
- const id = `readable_${_nextId++}`;
16
- let chunks;
17
- if (typeof data === 'string') {
18
- chunks = [data];
19
- } else if (Array.isArray(data)) {
20
- chunks = data.map(c => toStr(c));
21
- } else {
22
- chunks = [toStr(data)];
23
- }
24
- const stream = new Readable({
25
- read() {
26
- if (chunks.length > 0) this.push(chunks.shift());
27
- else this.push(null);
28
- }
29
- });
30
- _streams.set(id, { stream, data: '' });
31
- stream.on('data', (chunk) => {
32
- const entry = _streams.get(id);
33
- if (entry) entry.data += chunk.toString();
34
- });
35
- return id;
36
- },
37
-
38
- writable: (args) => {
39
- const id = `writable_${_nextId++}`;
40
- let collected = '';
41
- const stream = new Writable({
42
- write(chunk, encoding, callback) {
43
- collected += chunk.toString();
44
- const entry = _streams.get(id);
45
- if (entry) entry.data = collected;
46
- callback();
47
- }
48
- });
49
- _streams.set(id, { stream, data: '' });
50
- return id;
51
- },
52
-
53
- transform: (args) => {
54
- const id = `transform_${_nextId++}`;
55
- const stream = new Transform({
56
- transform(chunk, encoding, callback) {
57
- callback(null, chunk);
58
- }
59
- });
60
- _streams.set(id, { stream, data: '' });
61
- stream.on('data', (chunk) => {
62
- const entry = _streams.get(id);
63
- if (entry) entry.data += chunk.toString();
64
- });
65
- return id;
66
- },
67
-
68
- duplex: (args) => {
69
- const id = `duplex_${_nextId++}`;
70
- const stream = new Duplex({
71
- read() {},
72
- write(chunk, encoding, callback) {
73
- this.push(chunk);
74
- callback();
75
- }
76
- });
77
- _streams.set(id, { stream, data: '' });
78
- stream.on('data', (chunk) => {
79
- const entry = _streams.get(id);
80
- if (entry) entry.data += chunk.toString();
81
- });
82
- return id;
83
- },
84
-
85
- passThrough: (args) => {
86
- const id = `passthrough_${_nextId++}`;
87
- const stream = new PassThrough();
88
- _streams.set(id, { stream, data: '' });
89
- stream.on('data', (chunk) => {
90
- const entry = _streams.get(id);
91
- if (entry) entry.data += chunk.toString();
92
- });
93
- return id;
94
- },
95
-
96
- write: (args) => {
97
- requireArgs('stream.write', args, 2);
98
- const id = toStr(args[0]);
99
- const data = toStr(args[1]);
100
- const entry = _streams.get(id);
101
- if (!entry) throw new Error(`stream.write: stream ${id} not found`);
102
- return new Promise((resolve, reject) => {
103
- entry.stream.write(data, (err) => {
104
- if (err) reject(err);
105
- else resolve(true);
106
- });
107
- });
108
- },
109
-
110
- read: (args) => {
111
- requireArgs('stream.read', args, 1);
112
- const id = toStr(args[0]);
113
- const entry = _streams.get(id);
114
- if (!entry) throw new Error(`stream.read: stream ${id} not found`);
115
- const data = entry.data;
116
- entry.data = '';
117
- return data;
118
- },
119
-
120
- end: (args) => {
121
- requireArgs('stream.end', args, 1);
122
- const id = toStr(args[0]);
123
- const entry = _streams.get(id);
124
- if (!entry) throw new Error(`stream.end: stream ${id} not found`);
125
- entry.stream.end();
126
- return true;
127
- },
128
-
129
- destroy: (args) => {
130
- requireArgs('stream.destroy', args, 1);
131
- const id = toStr(args[0]);
132
- const entry = _streams.get(id);
133
- if (entry) {
134
- entry.stream.destroy();
135
- _streams.delete(id);
136
- return true;
137
- }
138
- return false;
139
- },
140
-
141
- pipe: (args) => {
142
- requireArgs('stream.pipe', args, 2);
143
- const srcId = toStr(args[0]);
144
- const destId = toStr(args[1]);
145
- const src = _streams.get(srcId);
146
- const dest = _streams.get(destId);
147
- if (!src) throw new Error(`stream.pipe: source ${srcId} not found`);
148
- if (!dest) throw new Error(`stream.pipe: destination ${destId} not found`);
149
- src.stream.pipe(dest.stream);
150
- return destId;
151
- },
152
-
153
- pipeline: (args) => {
154
- if (!Array.isArray(args[0]) && args.length < 2) {
155
- throw new Error('stream.pipeline requires at least 2 stream IDs');
156
- }
157
- const ids = Array.isArray(args[0]) ? args[0] : args;
158
- const streams = ids.map(id => {
159
- const entry = _streams.get(toStr(id));
160
- if (!entry) throw new Error(`stream.pipeline: stream ${id} not found`);
161
- return entry.stream;
162
- });
163
- return new Promise((resolve, reject) => {
164
- _pipeline(...streams, (err) => {
165
- if (err) reject(err);
166
- else resolve(true);
167
- });
168
- });
169
- },
170
-
171
- toBuffer: (args) => {
172
- requireArgs('stream.toBuffer', args, 1);
173
- const id = toStr(args[0]);
174
- const entry = _streams.get(id);
175
- if (!entry) throw new Error(`stream.toBuffer: stream ${id} not found`);
176
- return new Promise((resolve) => {
177
- const chunks = [];
178
- entry.stream.on('data', (chunk) => chunks.push(chunk));
179
- entry.stream.on('end', () => {
180
- resolve(Buffer.concat(chunks).toString('base64'));
181
- });
182
- // If already ended
183
- if (entry.stream.readableEnded) {
184
- resolve(Buffer.from(entry.data).toString('base64'));
185
- }
186
- });
187
- },
188
-
189
- toString: (args) => {
190
- requireArgs('stream.toString', args, 1);
191
- const id = toStr(args[0]);
192
- const entry = _streams.get(id);
193
- if (!entry) throw new Error(`stream.toString: stream ${id} not found`);
194
- return new Promise((resolve) => {
195
- let data = '';
196
- entry.stream.on('data', (chunk) => { data += chunk.toString(); });
197
- entry.stream.on('end', () => resolve(data));
198
- if (entry.stream.readableEnded) resolve(entry.data);
199
- });
200
- },
201
-
202
- fromString: (args) => {
203
- requireArgs('stream.fromString', args, 1);
204
- const data = toStr(args[0]);
205
- const id = `readable_${_nextId++}`;
206
- const stream = Readable.from([data]);
207
- _streams.set(id, { stream, data });
208
- return id;
209
- },
210
-
211
- fromArray: (args) => {
212
- requireArgs('stream.fromArray', args, 1);
213
- const arr = Array.isArray(args[0]) ? args[0] : [args[0]];
214
- const id = `readable_${_nextId++}`;
215
- const stream = Readable.from(arr.map(a => toStr(a)));
216
- _streams.set(id, { stream, data: arr.join('') });
217
- return id;
218
- },
219
-
220
- active: () => Array.from(_streams.keys()),
221
-
222
- count: () => _streams.size
223
- };
224
-
225
- export const StreamFunctionMetadata = {
226
- readable: {
227
- description: 'Create a readable stream from data',
228
- parameters: [{ name: 'data', dataType: 'any', description: 'String or array of chunks', formInputType: 'textarea', required: true }],
229
- returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.readable "hello world"'
230
- },
231
- writable: {
232
- description: 'Create a writable stream that collects data',
233
- parameters: [],
234
- returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.writable'
235
- },
236
- transform: {
237
- description: 'Create a transform (pass-through) stream',
238
- parameters: [],
239
- returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.transform'
240
- },
241
- duplex: {
242
- description: 'Create a duplex (read/write) stream',
243
- parameters: [],
244
- returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.duplex'
245
- },
246
- passThrough: {
247
- description: 'Create a passthrough stream',
248
- parameters: [],
249
- returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.passThrough'
250
- },
251
- write: {
252
- description: 'Write data to a stream',
253
- parameters: [
254
- { name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true },
255
- { name: 'data', dataType: 'string', description: 'Data to write', formInputType: 'textarea', required: true }
256
- ],
257
- returnType: 'boolean', returnDescription: 'true on success', example: 'stream.write $s "data"'
258
- },
259
- read: {
260
- description: 'Read buffered data from a stream',
261
- parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
262
- returnType: 'string', returnDescription: 'Buffered data', example: 'stream.read $s'
263
- },
264
- end: {
265
- description: 'Signal end of stream',
266
- parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
267
- returnType: 'boolean', returnDescription: 'true', example: 'stream.end $s'
268
- },
269
- destroy: {
270
- description: 'Destroy a stream and free resources',
271
- parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
272
- returnType: 'boolean', returnDescription: 'true if destroyed', example: 'stream.destroy $s'
273
- },
274
- pipe: {
275
- description: 'Pipe one stream into another',
276
- parameters: [
277
- { name: 'sourceId', dataType: 'string', description: 'Source stream', formInputType: 'text', required: true },
278
- { name: 'destId', dataType: 'string', description: 'Destination stream', formInputType: 'text', required: true }
279
- ],
280
- returnType: 'string', returnDescription: 'Destination stream ID', example: 'stream.pipe $src $dest'
281
- },
282
- pipeline: {
283
- description: 'Chain multiple streams together with error propagation',
284
- parameters: [{ name: 'streamIds', dataType: 'array', description: 'Array of stream IDs to chain', formInputType: 'json', required: true }],
285
- returnType: 'boolean', returnDescription: 'true on completion', example: 'stream.pipeline [$s1, $s2, $s3]'
286
- },
287
- toBuffer: {
288
- description: 'Collect stream data as base64 buffer',
289
- parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
290
- returnType: 'string', returnDescription: 'Base64-encoded buffer', example: 'stream.toBuffer $s'
291
- },
292
- toString: {
293
- description: 'Collect stream data as string',
294
- parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
295
- returnType: 'string', returnDescription: 'Collected string', example: 'stream.toString $s'
296
- },
297
- fromString: {
298
- description: 'Create a readable stream from a string',
299
- parameters: [{ name: 'data', dataType: 'string', description: 'Input string', formInputType: 'textarea', required: true }],
300
- returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.fromString "hello"'
301
- },
302
- fromArray: {
303
- description: 'Create a readable stream from an array',
304
- parameters: [{ name: 'data', dataType: 'array', description: 'Array of chunks', formInputType: 'json', required: true }],
305
- returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.fromArray ["chunk1", "chunk2"]'
306
- },
307
- active: { description: 'List all active stream handles', parameters: [], returnType: 'array', returnDescription: 'Array of stream IDs', example: 'stream.active' },
308
- count: { description: 'Count active streams', parameters: [], returnType: 'number', returnDescription: 'Number of active streams', example: 'stream.count' }
309
- };
310
-
311
- export const StreamModuleMetadata = {
312
- description: 'Stream operations: Readable, Writable, Transform, Duplex, PassThrough, pipe, pipeline',
313
- methods: Object.keys(StreamFunctions)
314
- };
315
-
316
- export default {
317
- name: 'stream',
318
- functions: StreamFunctions,
319
- functionMetadata: StreamFunctionMetadata,
320
- moduleMetadata: StreamModuleMetadata,
321
- global: false
322
- };
1
+ /**
2
+ * Native stream module for RobinPath.
3
+ * Readable, Writable, Transform, Duplex, PassThrough, and pipeline.
4
+ */
5
+ import { Readable, Writable, Transform, Duplex, PassThrough, pipeline as _pipeline } from 'node:stream';
6
+ import { toStr, toNum, requireArgs } from './_helpers.js';
7
+
8
+ const _streams = new Map();
9
+ let _nextId = 1;
10
+
11
+ export const StreamFunctions = {
12
+
13
+ readable: (args) => {
14
+ const data = args[0];
15
+ const id = `readable_${_nextId++}`;
16
+ let chunks;
17
+ if (typeof data === 'string') {
18
+ chunks = [data];
19
+ } else if (Array.isArray(data)) {
20
+ chunks = data.map(c => toStr(c));
21
+ } else {
22
+ chunks = [toStr(data)];
23
+ }
24
+ const stream = new Readable({
25
+ read() {
26
+ if (chunks.length > 0) this.push(chunks.shift());
27
+ else this.push(null);
28
+ }
29
+ });
30
+ _streams.set(id, { stream, data: '' });
31
+ stream.on('data', (chunk) => {
32
+ const entry = _streams.get(id);
33
+ if (entry) entry.data += chunk.toString();
34
+ });
35
+ return id;
36
+ },
37
+
38
+ writable: (args) => {
39
+ const id = `writable_${_nextId++}`;
40
+ let collected = '';
41
+ const stream = new Writable({
42
+ write(chunk, encoding, callback) {
43
+ collected += chunk.toString();
44
+ const entry = _streams.get(id);
45
+ if (entry) entry.data = collected;
46
+ callback();
47
+ }
48
+ });
49
+ _streams.set(id, { stream, data: '' });
50
+ return id;
51
+ },
52
+
53
+ transform: (args) => {
54
+ const id = `transform_${_nextId++}`;
55
+ const stream = new Transform({
56
+ transform(chunk, encoding, callback) {
57
+ callback(null, chunk);
58
+ }
59
+ });
60
+ _streams.set(id, { stream, data: '' });
61
+ stream.on('data', (chunk) => {
62
+ const entry = _streams.get(id);
63
+ if (entry) entry.data += chunk.toString();
64
+ });
65
+ return id;
66
+ },
67
+
68
+ duplex: (args) => {
69
+ const id = `duplex_${_nextId++}`;
70
+ const stream = new Duplex({
71
+ read() {},
72
+ write(chunk, encoding, callback) {
73
+ this.push(chunk);
74
+ callback();
75
+ }
76
+ });
77
+ _streams.set(id, { stream, data: '' });
78
+ stream.on('data', (chunk) => {
79
+ const entry = _streams.get(id);
80
+ if (entry) entry.data += chunk.toString();
81
+ });
82
+ return id;
83
+ },
84
+
85
+ passThrough: (args) => {
86
+ const id = `passthrough_${_nextId++}`;
87
+ const stream = new PassThrough();
88
+ _streams.set(id, { stream, data: '' });
89
+ stream.on('data', (chunk) => {
90
+ const entry = _streams.get(id);
91
+ if (entry) entry.data += chunk.toString();
92
+ });
93
+ return id;
94
+ },
95
+
96
+ write: (args) => {
97
+ requireArgs('stream.write', args, 2);
98
+ const id = toStr(args[0]);
99
+ const data = toStr(args[1]);
100
+ const entry = _streams.get(id);
101
+ if (!entry) throw new Error(`stream.write: stream ${id} not found`);
102
+ return new Promise((resolve, reject) => {
103
+ entry.stream.write(data, (err) => {
104
+ if (err) reject(err);
105
+ else resolve(true);
106
+ });
107
+ });
108
+ },
109
+
110
+ read: (args) => {
111
+ requireArgs('stream.read', args, 1);
112
+ const id = toStr(args[0]);
113
+ const entry = _streams.get(id);
114
+ if (!entry) throw new Error(`stream.read: stream ${id} not found`);
115
+ const data = entry.data;
116
+ entry.data = '';
117
+ return data;
118
+ },
119
+
120
+ end: (args) => {
121
+ requireArgs('stream.end', args, 1);
122
+ const id = toStr(args[0]);
123
+ const entry = _streams.get(id);
124
+ if (!entry) throw new Error(`stream.end: stream ${id} not found`);
125
+ entry.stream.end();
126
+ return true;
127
+ },
128
+
129
+ destroy: (args) => {
130
+ requireArgs('stream.destroy', args, 1);
131
+ const id = toStr(args[0]);
132
+ const entry = _streams.get(id);
133
+ if (entry) {
134
+ entry.stream.destroy();
135
+ _streams.delete(id);
136
+ return true;
137
+ }
138
+ return false;
139
+ },
140
+
141
+ pipe: (args) => {
142
+ requireArgs('stream.pipe', args, 2);
143
+ const srcId = toStr(args[0]);
144
+ const destId = toStr(args[1]);
145
+ const src = _streams.get(srcId);
146
+ const dest = _streams.get(destId);
147
+ if (!src) throw new Error(`stream.pipe: source ${srcId} not found`);
148
+ if (!dest) throw new Error(`stream.pipe: destination ${destId} not found`);
149
+ src.stream.pipe(dest.stream);
150
+ return destId;
151
+ },
152
+
153
+ pipeline: (args) => {
154
+ if (!Array.isArray(args[0]) && args.length < 2) {
155
+ throw new Error('stream.pipeline requires at least 2 stream IDs');
156
+ }
157
+ const ids = Array.isArray(args[0]) ? args[0] : args;
158
+ const streams = ids.map(id => {
159
+ const entry = _streams.get(toStr(id));
160
+ if (!entry) throw new Error(`stream.pipeline: stream ${id} not found`);
161
+ return entry.stream;
162
+ });
163
+ return new Promise((resolve, reject) => {
164
+ _pipeline(...streams, (err) => {
165
+ if (err) reject(err);
166
+ else resolve(true);
167
+ });
168
+ });
169
+ },
170
+
171
+ toBuffer: (args) => {
172
+ requireArgs('stream.toBuffer', args, 1);
173
+ const id = toStr(args[0]);
174
+ const entry = _streams.get(id);
175
+ if (!entry) throw new Error(`stream.toBuffer: stream ${id} not found`);
176
+ return new Promise((resolve) => {
177
+ const chunks = [];
178
+ entry.stream.on('data', (chunk) => chunks.push(chunk));
179
+ entry.stream.on('end', () => {
180
+ resolve(Buffer.concat(chunks).toString('base64'));
181
+ });
182
+ // If already ended
183
+ if (entry.stream.readableEnded) {
184
+ resolve(Buffer.from(entry.data).toString('base64'));
185
+ }
186
+ });
187
+ },
188
+
189
+ toString: (args) => {
190
+ requireArgs('stream.toString', args, 1);
191
+ const id = toStr(args[0]);
192
+ const entry = _streams.get(id);
193
+ if (!entry) throw new Error(`stream.toString: stream ${id} not found`);
194
+ return new Promise((resolve) => {
195
+ let data = '';
196
+ entry.stream.on('data', (chunk) => { data += chunk.toString(); });
197
+ entry.stream.on('end', () => resolve(data));
198
+ if (entry.stream.readableEnded) resolve(entry.data);
199
+ });
200
+ },
201
+
202
+ fromString: (args) => {
203
+ requireArgs('stream.fromString', args, 1);
204
+ const data = toStr(args[0]);
205
+ const id = `readable_${_nextId++}`;
206
+ const stream = Readable.from([data]);
207
+ _streams.set(id, { stream, data });
208
+ return id;
209
+ },
210
+
211
+ fromArray: (args) => {
212
+ requireArgs('stream.fromArray', args, 1);
213
+ const arr = Array.isArray(args[0]) ? args[0] : [args[0]];
214
+ const id = `readable_${_nextId++}`;
215
+ const stream = Readable.from(arr.map(a => toStr(a)));
216
+ _streams.set(id, { stream, data: arr.join('') });
217
+ return id;
218
+ },
219
+
220
+ active: () => Array.from(_streams.keys()),
221
+
222
+ count: () => _streams.size
223
+ };
224
+
225
+ export const StreamFunctionMetadata = {
226
+ readable: {
227
+ description: 'Create a readable stream from data',
228
+ parameters: [{ name: 'data', dataType: 'any', description: 'String or array of chunks', formInputType: 'textarea', required: true }],
229
+ returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.readable "hello world"'
230
+ },
231
+ writable: {
232
+ description: 'Create a writable stream that collects data',
233
+ parameters: [],
234
+ returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.writable'
235
+ },
236
+ transform: {
237
+ description: 'Create a transform (pass-through) stream',
238
+ parameters: [],
239
+ returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.transform'
240
+ },
241
+ duplex: {
242
+ description: 'Create a duplex (read/write) stream',
243
+ parameters: [],
244
+ returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.duplex'
245
+ },
246
+ passThrough: {
247
+ description: 'Create a passthrough stream',
248
+ parameters: [],
249
+ returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.passThrough'
250
+ },
251
+ write: {
252
+ description: 'Write data to a stream',
253
+ parameters: [
254
+ { name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true },
255
+ { name: 'data', dataType: 'string', description: 'Data to write', formInputType: 'textarea', required: true }
256
+ ],
257
+ returnType: 'boolean', returnDescription: 'true on success', example: 'stream.write $s "data"'
258
+ },
259
+ read: {
260
+ description: 'Read buffered data from a stream',
261
+ parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
262
+ returnType: 'string', returnDescription: 'Buffered data', example: 'stream.read $s'
263
+ },
264
+ end: {
265
+ description: 'Signal end of stream',
266
+ parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
267
+ returnType: 'boolean', returnDescription: 'true', example: 'stream.end $s'
268
+ },
269
+ destroy: {
270
+ description: 'Destroy a stream and free resources',
271
+ parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
272
+ returnType: 'boolean', returnDescription: 'true if destroyed', example: 'stream.destroy $s'
273
+ },
274
+ pipe: {
275
+ description: 'Pipe one stream into another',
276
+ parameters: [
277
+ { name: 'sourceId', dataType: 'string', description: 'Source stream', formInputType: 'text', required: true },
278
+ { name: 'destId', dataType: 'string', description: 'Destination stream', formInputType: 'text', required: true }
279
+ ],
280
+ returnType: 'string', returnDescription: 'Destination stream ID', example: 'stream.pipe $src $dest'
281
+ },
282
+ pipeline: {
283
+ description: 'Chain multiple streams together with error propagation',
284
+ parameters: [{ name: 'streamIds', dataType: 'array', description: 'Array of stream IDs to chain', formInputType: 'json', required: true }],
285
+ returnType: 'boolean', returnDescription: 'true on completion', example: 'stream.pipeline [$s1, $s2, $s3]'
286
+ },
287
+ toBuffer: {
288
+ description: 'Collect stream data as base64 buffer',
289
+ parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
290
+ returnType: 'string', returnDescription: 'Base64-encoded buffer', example: 'stream.toBuffer $s'
291
+ },
292
+ toString: {
293
+ description: 'Collect stream data as string',
294
+ parameters: [{ name: 'streamId', dataType: 'string', description: 'Stream handle ID', formInputType: 'text', required: true }],
295
+ returnType: 'string', returnDescription: 'Collected string', example: 'stream.toString $s'
296
+ },
297
+ fromString: {
298
+ description: 'Create a readable stream from a string',
299
+ parameters: [{ name: 'data', dataType: 'string', description: 'Input string', formInputType: 'textarea', required: true }],
300
+ returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.fromString "hello"'
301
+ },
302
+ fromArray: {
303
+ description: 'Create a readable stream from an array',
304
+ parameters: [{ name: 'data', dataType: 'array', description: 'Array of chunks', formInputType: 'json', required: true }],
305
+ returnType: 'string', returnDescription: 'Stream handle ID', example: 'stream.fromArray ["chunk1", "chunk2"]'
306
+ },
307
+ active: { description: 'List all active stream handles', parameters: [], returnType: 'array', returnDescription: 'Array of stream IDs', example: 'stream.active' },
308
+ count: { description: 'Count active streams', parameters: [], returnType: 'number', returnDescription: 'Number of active streams', example: 'stream.count' }
309
+ };
310
+
311
+ export const StreamModuleMetadata = {
312
+ description: 'Stream operations: Readable, Writable, Transform, Duplex, PassThrough, pipe, pipeline',
313
+ methods: Object.keys(StreamFunctions)
314
+ };
315
+
316
+ export default {
317
+ name: 'stream',
318
+ functions: StreamFunctions,
319
+ functionMetadata: StreamFunctionMetadata,
320
+ moduleMetadata: StreamModuleMetadata,
321
+ global: false
322
+ };