lulz 1.0.3 → 2.0.1
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/AGENTS.md +609 -0
- package/README.md +242 -140
- package/TODO.md +132 -0
- package/examples.js +169 -197
- package/index.js +164 -14
- package/package.json +16 -17
- package/src/flow.js +362 -215
- package/src/red-lib.js +595 -0
- package/src/rx-lib.js +679 -0
- package/src/utils.js +270 -0
- package/src/workers.js +367 -0
- package/test.js +505 -279
- package/src/nodes.js +0 -520
package/examples.js
CHANGED
|
@@ -1,317 +1,289 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* lulz Examples
|
|
3
|
-
*
|
|
4
|
-
* Various patterns and
|
|
2
|
+
* lulz - Examples
|
|
3
|
+
*
|
|
4
|
+
* Various usage patterns and demonstrations.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
flow,
|
|
9
9
|
subflow,
|
|
10
10
|
compose,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
parallel,
|
|
12
|
+
series,
|
|
13
|
+
inject,
|
|
14
|
+
debug,
|
|
15
|
+
func,
|
|
16
|
+
change,
|
|
17
|
+
template,
|
|
18
|
+
delay,
|
|
19
|
+
map,
|
|
20
|
+
filter,
|
|
21
|
+
scan,
|
|
22
|
+
debounce,
|
|
23
|
+
take,
|
|
24
|
+
pairwise,
|
|
25
|
+
tap,
|
|
20
26
|
} from './index.js';
|
|
21
27
|
|
|
22
|
-
// Custom logger to capture output
|
|
23
|
-
const logs = [];
|
|
24
|
-
const logger = (...args) => {
|
|
25
|
-
logs.push(args.map(a => typeof a === 'object' ? JSON.stringify(a) : a).join(' '));
|
|
26
|
-
console.log(...args);
|
|
27
|
-
};
|
|
28
28
|
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
29
|
+
// ─────────────────────────────────────────────────────────────
|
|
30
|
+
// Example 1: Basic Inject → Debug
|
|
31
|
+
// ─────────────────────────────────────────────────────────────
|
|
32
32
|
|
|
33
|
-
console.log('\n
|
|
33
|
+
console.log('\n═══ Example 1: Basic Inject → Debug ═══\n');
|
|
34
34
|
|
|
35
35
|
const example1 = flow([
|
|
36
|
-
[
|
|
36
|
+
[inject({ payload: 'Hello lulz!', once: true }), debug({ name: 'output' })],
|
|
37
37
|
]);
|
|
38
38
|
|
|
39
39
|
example1.start();
|
|
40
40
|
|
|
41
|
-
// ============================================================
|
|
42
|
-
// EXAMPLE 2: Series processing with [a, b, c] syntax
|
|
43
|
-
// ============================================================
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
// ─────────────────────────────────────────────────────────────
|
|
43
|
+
// Example 2: EventEmitter API
|
|
44
|
+
// ─────────────────────────────────────────────────────────────
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
function addStep(name) {
|
|
49
|
-
return function(options) {
|
|
50
|
-
return (send, packet) => {
|
|
51
|
-
const steps = packet.steps || [];
|
|
52
|
-
logger(`[${name}] Processing...`);
|
|
53
|
-
send({ ...packet, steps: [...steps, name] });
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
}
|
|
46
|
+
console.log('\n═══ Example 2: EventEmitter API ═══\n');
|
|
57
47
|
|
|
58
48
|
const example2 = flow([
|
|
59
|
-
['input',
|
|
49
|
+
['input', func({ func: (msg) => ({ ...msg, payload: msg.payload.toUpperCase() }) }), 'output'],
|
|
60
50
|
]);
|
|
61
51
|
|
|
62
|
-
|
|
52
|
+
// Listen to output pipe
|
|
53
|
+
example2.on('output', (packet) => {
|
|
54
|
+
console.log('[Listener] Received:', packet.payload);
|
|
55
|
+
});
|
|
63
56
|
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
// ============================================================
|
|
57
|
+
// Inject via emit
|
|
58
|
+
example2.emit('input', { payload: 'hello via emit!' });
|
|
67
59
|
|
|
68
|
-
console.log('\n=== Example 3: Fan-out Processing ===\n');
|
|
69
60
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
send({ ...packet, processedBy: 'A' });
|
|
74
|
-
};
|
|
75
|
-
}
|
|
61
|
+
// ─────────────────────────────────────────────────────────────
|
|
62
|
+
// Example 3: Series Processing (Default)
|
|
63
|
+
// ─────────────────────────────────────────────────────────────
|
|
76
64
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
65
|
+
console.log('\n═══ Example 3: Series Processing ═══\n');
|
|
66
|
+
|
|
67
|
+
function addStep(name) {
|
|
68
|
+
return function(options) {
|
|
69
|
+
return (send, packet) => {
|
|
70
|
+
console.log(`[${name}] Processing...`);
|
|
71
|
+
send({ ...packet, steps: [...(packet.steps || []), name] });
|
|
72
|
+
};
|
|
81
73
|
};
|
|
82
74
|
}
|
|
83
75
|
|
|
84
76
|
const example3 = flow([
|
|
85
|
-
['input',
|
|
86
|
-
['output', Debug({ name: 'fan-out-result', logger })],
|
|
77
|
+
['input', addStep('validate'), addStep('transform'), addStep('save'), debug({ name: 'result', complete: true })],
|
|
87
78
|
]);
|
|
88
79
|
|
|
89
|
-
example3.
|
|
80
|
+
example3.emit('input', { payload: { data: 'test' } });
|
|
90
81
|
|
|
91
|
-
// ============================================================
|
|
92
|
-
// EXAMPLE 4: Mixed pre-configured and auto-configured functions
|
|
93
|
-
// ============================================================
|
|
94
82
|
|
|
95
|
-
|
|
83
|
+
// ─────────────────────────────────────────────────────────────
|
|
84
|
+
// Example 4: Parallel Processing with []
|
|
85
|
+
// ─────────────────────────────────────────────────────────────
|
|
96
86
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
console.log('\n═══ Example 4: Parallel Processing ═══\n');
|
|
88
|
+
|
|
89
|
+
function process(name, delay = 0) {
|
|
90
|
+
return function(options) {
|
|
91
|
+
return (send, packet) => {
|
|
92
|
+
setTimeout(() => {
|
|
93
|
+
console.log(`[${name}] Done`);
|
|
94
|
+
send({ ...packet, processor: name });
|
|
95
|
+
}, delay);
|
|
96
|
+
};
|
|
101
97
|
};
|
|
102
98
|
}
|
|
103
99
|
|
|
104
100
|
const example4 = flow([
|
|
105
|
-
['input', [
|
|
106
|
-
|
|
107
|
-
multiplier, // Auto-configured with {}: ×1
|
|
108
|
-
multiplier({ factor: 5 }), // Pre-configured: ×5
|
|
109
|
-
], Debug({ name: 'multiplied', logger })],
|
|
101
|
+
['input', [process('fast', 10), process('slow', 50), process('medium', 30)], 'output'],
|
|
102
|
+
['output', debug({ name: 'parallel-result' })],
|
|
110
103
|
]);
|
|
111
104
|
|
|
112
|
-
example4.
|
|
105
|
+
example4.emit('input', { payload: 'parallel test' });
|
|
106
|
+
|
|
113
107
|
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
//
|
|
108
|
+
// ─────────────────────────────────────────────────────────────
|
|
109
|
+
// Example 5: Helper Functions
|
|
110
|
+
// ─────────────────────────────────────────────────────────────
|
|
117
111
|
|
|
118
|
-
console.log('\n
|
|
112
|
+
console.log('\n═══ Example 5: series() and parallel() Helpers ═══\n');
|
|
113
|
+
|
|
114
|
+
function multiply(n) {
|
|
115
|
+
return function(options) {
|
|
116
|
+
return (send, packet) => {
|
|
117
|
+
send({ ...packet, payload: packet.payload * n });
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
}
|
|
119
121
|
|
|
120
122
|
const example5 = flow([
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
rules: [
|
|
124
|
-
{ type: 'gte', value: 30 },
|
|
125
|
-
]
|
|
126
|
-
}), 'hot'],
|
|
127
|
-
|
|
128
|
-
['input', Switch({
|
|
129
|
-
property: 'payload.temperature',
|
|
130
|
-
rules: [
|
|
131
|
-
{ type: 'lt', value: 30 },
|
|
132
|
-
]
|
|
133
|
-
}), 'cold'],
|
|
134
|
-
|
|
135
|
-
['hot', Debug({ name: '🔥 HOT', logger })],
|
|
136
|
-
['cold', Debug({ name: '❄️ COLD', logger })],
|
|
123
|
+
// series: 10 → 20 → 60 → 120
|
|
124
|
+
['input', series(multiply(2), multiply(3), multiply(2)), debug({ name: 'series-result' })],
|
|
137
125
|
]);
|
|
138
126
|
|
|
139
|
-
example5.
|
|
140
|
-
|
|
127
|
+
example5.emit('input', { payload: 10 });
|
|
128
|
+
|
|
141
129
|
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
//
|
|
130
|
+
// ─────────────────────────────────────────────────────────────
|
|
131
|
+
// Example 6: Subflows (Reusable Components)
|
|
132
|
+
// ─────────────────────────────────────────────────────────────
|
|
145
133
|
|
|
146
|
-
console.log('\n
|
|
134
|
+
console.log('\n═══ Example 6: Subflows ═══\n');
|
|
147
135
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
136
|
+
// Create reusable sanitizer
|
|
137
|
+
const sanitizer = subflow([
|
|
138
|
+
['in', func({ func: (msg) => ({
|
|
139
|
+
...msg,
|
|
140
|
+
payload: String(msg.payload).trim().toLowerCase()
|
|
141
|
+
})}), 'out'],
|
|
142
|
+
]);
|
|
143
|
+
|
|
144
|
+
// Create reusable validator
|
|
145
|
+
const validator = subflow([
|
|
146
|
+
['in', func({ func: (msg) => ({
|
|
147
|
+
...msg,
|
|
148
|
+
payload: msg.payload,
|
|
149
|
+
valid: msg.payload.length > 0
|
|
150
|
+
})}), 'out'],
|
|
152
151
|
]);
|
|
153
152
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
153
|
+
// Compose them
|
|
154
|
+
const pipeline = compose(sanitizer, validator);
|
|
155
|
+
|
|
156
|
+
pipeline.on('out', (packet) => {
|
|
157
|
+
console.log('[Pipeline Result]', packet);
|
|
160
158
|
});
|
|
161
159
|
|
|
162
|
-
|
|
163
|
-
// EXAMPLE 7: Subflow embedding
|
|
164
|
-
// ============================================================
|
|
160
|
+
pipeline.emit('in', { payload: ' HELLO WORLD ' });
|
|
165
161
|
|
|
166
|
-
console.log('\n=== Example 7: Subflow (Reusable Component) ===\n');
|
|
167
162
|
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
payload: String(msg.payload).trim().toLowerCase()
|
|
174
|
-
})
|
|
175
|
-
}), 'out'],
|
|
176
|
-
]);
|
|
163
|
+
// ─────────────────────────────────────────────────────────────
|
|
164
|
+
// Example 7: RxJS-Style Operators
|
|
165
|
+
// ─────────────────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
console.log('\n═══ Example 7: RxJS-Style Operators ═══\n');
|
|
177
168
|
|
|
178
|
-
// Use it in main flow
|
|
179
169
|
const example7 = flow([
|
|
180
|
-
['input',
|
|
181
|
-
|
|
170
|
+
['input',
|
|
171
|
+
map({ fn: (x) => x * 2 }),
|
|
172
|
+
filter({ predicate: (x) => x > 5 }),
|
|
173
|
+
scan({ reducer: (acc, x) => acc + x, initial: 0 }),
|
|
174
|
+
debug({ name: 'rx-result' })
|
|
175
|
+
],
|
|
182
176
|
]);
|
|
183
177
|
|
|
184
|
-
|
|
185
|
-
example7.
|
|
186
|
-
|
|
178
|
+
[1, 2, 3, 4, 5].forEach(n => {
|
|
179
|
+
example7.emit('input', { payload: n });
|
|
180
|
+
});
|
|
187
181
|
|
|
188
|
-
example7.inject('input', { payload: ' HELLO WORLD ' });
|
|
189
182
|
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
//
|
|
183
|
+
// ─────────────────────────────────────────────────────────────
|
|
184
|
+
// Example 8: Blog Builder Pattern
|
|
185
|
+
// ─────────────────────────────────────────────────────────────
|
|
193
186
|
|
|
194
|
-
console.log('\n
|
|
187
|
+
console.log('\n═══ Example 8: Blog Builder ═══\n');
|
|
195
188
|
|
|
196
|
-
// Simulated
|
|
189
|
+
// Simulated producers
|
|
197
190
|
function socket(channel) {
|
|
198
191
|
return (send) => {
|
|
199
|
-
|
|
200
|
-
// Simulate receiving data
|
|
192
|
+
console.log(`[socket] Listening: ${channel}`);
|
|
201
193
|
setTimeout(() => {
|
|
202
|
-
send({ payload: { type: 'new-post', id: 123 }, channel });
|
|
203
|
-
},
|
|
194
|
+
send({ payload: { type: 'new-post', id: 123 }, topic: channel });
|
|
195
|
+
}, 100);
|
|
204
196
|
};
|
|
205
197
|
}
|
|
206
198
|
|
|
207
199
|
function watch(folder) {
|
|
208
200
|
return (send) => {
|
|
209
|
-
|
|
210
|
-
// Simulate file change
|
|
201
|
+
console.log(`[watch] Watching: ${folder}`);
|
|
211
202
|
setTimeout(() => {
|
|
212
|
-
send({ payload: { type: 'file-changed', path: `${folder}/image.png` }, folder });
|
|
213
|
-
},
|
|
203
|
+
send({ payload: { type: 'file-changed', path: `${folder}/image.png` }, topic: folder });
|
|
204
|
+
}, 150);
|
|
214
205
|
};
|
|
215
206
|
}
|
|
216
207
|
|
|
217
208
|
// Processing functions
|
|
218
209
|
function cover(options) {
|
|
219
210
|
return (send, packet) => {
|
|
220
|
-
|
|
211
|
+
console.log('[cover] Generating cover...');
|
|
221
212
|
send({ ...packet, cover: true });
|
|
222
213
|
};
|
|
223
214
|
}
|
|
224
215
|
|
|
225
216
|
function audio(options) {
|
|
226
217
|
return (send, packet) => {
|
|
227
|
-
|
|
218
|
+
console.log('[audio] Processing audio...');
|
|
228
219
|
send({ ...packet, audio: true });
|
|
229
220
|
};
|
|
230
221
|
}
|
|
231
222
|
|
|
232
223
|
function post(options) {
|
|
233
224
|
return (send, packet) => {
|
|
234
|
-
|
|
225
|
+
console.log('[post] Building post...');
|
|
235
226
|
send({ ...packet, built: true });
|
|
236
227
|
};
|
|
237
228
|
}
|
|
238
229
|
|
|
239
230
|
function assets(options) {
|
|
240
231
|
return (send, packet) => {
|
|
241
|
-
|
|
232
|
+
console.log('[assets] Processing asset');
|
|
242
233
|
send(packet);
|
|
243
234
|
};
|
|
244
235
|
}
|
|
245
236
|
|
|
246
237
|
function pagerizer(options) {
|
|
247
238
|
return (send, packet) => {
|
|
248
|
-
|
|
249
|
-
send(
|
|
239
|
+
console.log('[pagerizer] Updating pagination');
|
|
240
|
+
send(packet);
|
|
250
241
|
};
|
|
251
242
|
}
|
|
252
243
|
|
|
253
244
|
const blogBuilder = flow([
|
|
254
|
-
[socket('post'), 'post'],
|
|
255
|
-
[watch('assets'), 'asset'],
|
|
256
|
-
['post',
|
|
257
|
-
['asset', assets],
|
|
258
|
-
|
|
259
|
-
['
|
|
245
|
+
[socket('post'), 'post'],
|
|
246
|
+
[watch('assets'), 'asset'],
|
|
247
|
+
['post', debug({ name: 'new-post' })],
|
|
248
|
+
['asset', assets],
|
|
249
|
+
// Fan-out: cover, audio, post all run in parallel
|
|
250
|
+
['post', [cover, audio, post], 'updated'],
|
|
251
|
+
['updated', pagerizer, debug({ name: 'updated' })],
|
|
260
252
|
], { username: 'alice' });
|
|
261
253
|
|
|
262
254
|
blogBuilder.start();
|
|
263
255
|
|
|
264
|
-
// ============================================================
|
|
265
|
-
// EXAMPLE 9: Series with mixed fan-out
|
|
266
|
-
// ============================================================
|
|
267
|
-
|
|
268
|
-
console.log('\n=== Example 9: Complex Pipeline ===\n');
|
|
269
|
-
|
|
270
|
-
function validate(options) {
|
|
271
|
-
return (send, packet) => {
|
|
272
|
-
if (packet.payload) {
|
|
273
|
-
logger('[validate] ✓ Valid');
|
|
274
|
-
send(packet);
|
|
275
|
-
} else {
|
|
276
|
-
logger('[validate] ✗ Invalid - dropped');
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function enrichA(options) {
|
|
282
|
-
return (send, packet) => {
|
|
283
|
-
logger('[enrichA] Adding metadata A');
|
|
284
|
-
send({ ...packet, metaA: true });
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
256
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
send({ ...packet, metaB: true });
|
|
292
|
-
};
|
|
293
|
-
}
|
|
257
|
+
// ─────────────────────────────────────────────────────────────
|
|
258
|
+
// Example 9: Temperature Monitor with Pairwise
|
|
259
|
+
// ─────────────────────────────────────────────────────────────
|
|
294
260
|
|
|
295
|
-
|
|
296
|
-
return (send, packet) => {
|
|
297
|
-
logger('[finalize] Completing...');
|
|
298
|
-
send({ ...packet, finalized: true });
|
|
299
|
-
};
|
|
300
|
-
}
|
|
261
|
+
console.log('\n═══ Example 9: Temperature Delta ═══\n');
|
|
301
262
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
263
|
+
const tempMonitor = flow([
|
|
264
|
+
['temp',
|
|
265
|
+
pairwise(),
|
|
266
|
+
func({ func: (msg) => ({
|
|
267
|
+
...msg,
|
|
268
|
+
payload: {
|
|
269
|
+
prev: msg.payload[0],
|
|
270
|
+
curr: msg.payload[1],
|
|
271
|
+
delta: msg.payload[1] - msg.payload[0]
|
|
272
|
+
}
|
|
273
|
+
})}),
|
|
274
|
+
debug({ name: 'temp-delta', complete: true })
|
|
275
|
+
],
|
|
307
276
|
]);
|
|
308
277
|
|
|
309
|
-
|
|
278
|
+
[20, 22, 21, 25, 23].forEach((temp, i) => {
|
|
279
|
+
setTimeout(() => tempMonitor.emit('temp', { payload: temp }), i * 10);
|
|
280
|
+
});
|
|
281
|
+
|
|
310
282
|
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
//
|
|
283
|
+
// ─────────────────────────────────────────────────────────────
|
|
284
|
+
// Cleanup
|
|
285
|
+
// ─────────────────────────────────────────────────────────────
|
|
314
286
|
|
|
315
287
|
setTimeout(() => {
|
|
316
|
-
console.log('\n
|
|
317
|
-
},
|
|
288
|
+
console.log('\n═══ All Examples Complete ═══\n');
|
|
289
|
+
}, 500);
|
package/index.js
CHANGED
|
@@ -1,21 +1,171 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* lulz - A reactive dataflow system
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* lulz - A reactive dataflow system that makes coders happy
|
|
3
|
+
*
|
|
4
|
+
* https://github.com/catpea/lulz
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { flow, inject, debug, series, parallel } from 'lulz';
|
|
8
|
+
*
|
|
9
|
+
* const app = flow([
|
|
10
|
+
* [inject({ payload: 'Hello!' }), debug({ name: 'out' })],
|
|
11
|
+
* ]);
|
|
12
|
+
*
|
|
13
|
+
* app.start();
|
|
5
14
|
*/
|
|
6
15
|
|
|
7
|
-
|
|
16
|
+
// ─────────────────────────────────────────────────────────────
|
|
17
|
+
// Core Flow Engine
|
|
18
|
+
// ─────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
flow,
|
|
22
|
+
subflow,
|
|
23
|
+
compose,
|
|
24
|
+
parallel,
|
|
25
|
+
series,
|
|
26
|
+
makeNode,
|
|
27
|
+
isOuter,
|
|
28
|
+
isInner,
|
|
29
|
+
isFlow,
|
|
30
|
+
} from './src/flow.js';
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
// ─────────────────────────────────────────────────────────────
|
|
34
|
+
// Node-RED Style Library
|
|
35
|
+
// ─────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
8
37
|
export {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
38
|
+
// Core nodes
|
|
39
|
+
inject,
|
|
40
|
+
debug,
|
|
41
|
+
func,
|
|
42
|
+
change,
|
|
43
|
+
switchNode as switch, // 'switch' is reserved, use switchNode
|
|
44
|
+
switchNode,
|
|
45
|
+
template,
|
|
46
|
+
delay,
|
|
47
|
+
split,
|
|
48
|
+
join,
|
|
49
|
+
filter,
|
|
50
|
+
linkIn,
|
|
51
|
+
linkOut,
|
|
52
|
+
catchError,
|
|
53
|
+
status,
|
|
54
|
+
|
|
55
|
+
// Property helpers
|
|
18
56
|
getProperty,
|
|
19
57
|
setProperty,
|
|
20
58
|
deleteProperty,
|
|
21
|
-
} from './src/
|
|
59
|
+
} from './src/red-lib.js';
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// ─────────────────────────────────────────────────────────────
|
|
63
|
+
// RxJS-Inspired Operators
|
|
64
|
+
// ─────────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
// Combination
|
|
68
|
+
combineLatest,
|
|
69
|
+
merge,
|
|
70
|
+
concat,
|
|
71
|
+
zip,
|
|
72
|
+
withLatestFrom,
|
|
73
|
+
|
|
74
|
+
// Transformation
|
|
75
|
+
map,
|
|
76
|
+
pluck,
|
|
77
|
+
scan,
|
|
78
|
+
buffer,
|
|
79
|
+
window,
|
|
80
|
+
pairwise,
|
|
81
|
+
|
|
82
|
+
// Filtering
|
|
83
|
+
filter as rxFilter,
|
|
84
|
+
distinct,
|
|
85
|
+
distinctUntilChanged,
|
|
86
|
+
take,
|
|
87
|
+
skip,
|
|
88
|
+
takeWhile,
|
|
89
|
+
skipWhile,
|
|
90
|
+
|
|
91
|
+
// Timing
|
|
92
|
+
debounce,
|
|
93
|
+
throttle,
|
|
94
|
+
delay as rxDelay,
|
|
95
|
+
timeout,
|
|
96
|
+
timestamp,
|
|
97
|
+
|
|
98
|
+
// Error handling
|
|
99
|
+
catchError as rxCatchError,
|
|
100
|
+
retry,
|
|
101
|
+
|
|
102
|
+
// Utility
|
|
103
|
+
tap,
|
|
104
|
+
log,
|
|
105
|
+
count,
|
|
106
|
+
toArray,
|
|
107
|
+
defaultIfEmpty,
|
|
108
|
+
share,
|
|
109
|
+
} from './src/rx-lib.js';
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
// ─────────────────────────────────────────────────────────────
|
|
113
|
+
// Worker Task Queue
|
|
114
|
+
// ─────────────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
export {
|
|
117
|
+
taskQueue,
|
|
118
|
+
worker,
|
|
119
|
+
parallelMap,
|
|
120
|
+
cpuTask,
|
|
121
|
+
} from './src/workers.js';
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
// ─────────────────────────────────────────────────────────────
|
|
125
|
+
// Utilities
|
|
126
|
+
// ─────────────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
// Packet helpers
|
|
130
|
+
packet,
|
|
131
|
+
clonePacket,
|
|
132
|
+
mergePackets,
|
|
133
|
+
|
|
134
|
+
// Function composition
|
|
135
|
+
pipe,
|
|
136
|
+
compose as composeF,
|
|
137
|
+
identity,
|
|
138
|
+
constant,
|
|
139
|
+
noop,
|
|
140
|
+
|
|
141
|
+
// Async helpers
|
|
142
|
+
sleep,
|
|
143
|
+
withTimeout,
|
|
144
|
+
withRetry,
|
|
145
|
+
|
|
146
|
+
// Collection helpers
|
|
147
|
+
chunk,
|
|
148
|
+
flatten,
|
|
149
|
+
unique,
|
|
150
|
+
groupBy,
|
|
151
|
+
partition,
|
|
152
|
+
|
|
153
|
+
// Object helpers
|
|
154
|
+
deepClone,
|
|
155
|
+
deepMerge,
|
|
156
|
+
pick,
|
|
157
|
+
omit,
|
|
158
|
+
|
|
159
|
+
// Debug helpers
|
|
160
|
+
createLogger,
|
|
161
|
+
measure,
|
|
162
|
+
assert,
|
|
163
|
+
} from './src/utils.js';
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
// ─────────────────────────────────────────────────────────────
|
|
167
|
+
// Default Export
|
|
168
|
+
// ─────────────────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
import { flow as flowFn } from './src/flow.js';
|
|
171
|
+
export default flowFn;
|