@nlozgachev/pipelined 0.48.0 → 0.49.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/README.md +58 -5
- package/dist/{chunk-UGVU2RTM.mjs → chunk-EPT3GYGN.mjs} +1 -1
- package/dist/{chunk-LR63GW6J.mjs → chunk-IHLH2XYQ.mjs} +107 -0
- package/dist/core.d.mts +153 -1
- package/dist/core.d.ts +153 -1
- package/dist/core.js +108 -0
- package/dist/core.mjs +3 -1
- package/dist/data.mjs +2 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +108 -0
- package/dist/index.mjs +4 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -18,11 +18,12 @@ In mainstream TypeScript, code is often burdened by implicit control flow: unche
|
|
|
18
18
|
manual null propagation, and unhandled asynchronous failures. `pipelined` turns these complex
|
|
19
19
|
runtime states into simple, transparent data structures that compose. By representing optionality as
|
|
20
20
|
`Maybe`, failures as `Result`, lazy asynchronous pipelines as `Task.Result`, and repeated stateful
|
|
21
|
-
interactions as `Op`, the library helps disentangle business logic from control
|
|
21
|
+
interactions as `Op` and `Stream`, the library helps disentangle business logic from control
|
|
22
|
+
mechanics.
|
|
22
23
|
|
|
23
24
|
To support these patterns without introducing bloat, the library is designed to be lightweight,
|
|
24
|
-
zero-dependency, and fully tree-shakeable. The core module (`/core`) is under
|
|
25
|
-
entire toolkit is under
|
|
25
|
+
zero-dependency, and fully tree-shakeable. The core module (`/core`) is under 16 KB gzipped, and the
|
|
26
|
+
entire toolkit is under 25 KB gzipped, making it equally suitable for client and server
|
|
26
27
|
environments.
|
|
27
28
|
|
|
28
29
|
## Documentation
|
|
@@ -303,6 +304,57 @@ The system supports a variety of built-in strategies — `restartable`, `exclusi
|
|
|
303
304
|
`throttled`, `queue`, `buffered`, `concurrent`, `keyed`, and `once` — making the integration of
|
|
304
305
|
complex async scenarios highly predictable.
|
|
305
306
|
|
|
307
|
+
## Example: typed event streaming and sequence reduction
|
|
308
|
+
|
|
309
|
+
Decoupling event producers from stateful event consumers often leads to untyped event emitters or
|
|
310
|
+
complex ad-hoc state machines. `Stream` models event pipelines with typed message schemas, sequence
|
|
311
|
+
pattern matching, and state reduction:
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
import { Stream } from "@nlozgachev/pipelined/core";
|
|
315
|
+
|
|
316
|
+
type UserFlowMessages = {
|
|
317
|
+
sessionStarted: { sessionId: string };
|
|
318
|
+
stepCompleted: { stepName: string };
|
|
319
|
+
flowFinished: { totalTimeMs: number };
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const flowStream = Stream.make<UserFlowMessages>();
|
|
323
|
+
|
|
324
|
+
// Match sequence: sessionStarted -> stepCompleted -> flowFinished
|
|
325
|
+
const sub = Stream.listen(
|
|
326
|
+
flowStream,
|
|
327
|
+
["sessionStarted", "stepCompleted", "flowFinished"],
|
|
328
|
+
{ ordered: true },
|
|
329
|
+
).reduce(
|
|
330
|
+
(msg, state) => {
|
|
331
|
+
if (msg.kind === "flowFinished") {
|
|
332
|
+
return { completedFlows: state.completedFlows + 1 };
|
|
333
|
+
}
|
|
334
|
+
return state;
|
|
335
|
+
},
|
|
336
|
+
{ completedFlows: 0 },
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
// Emit typed messages to the stream
|
|
340
|
+
Stream.emit(flowStream, {
|
|
341
|
+
kind: "sessionStarted",
|
|
342
|
+
value: { sessionId: "sess-101" },
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
Stream.emit(flowStream, {
|
|
346
|
+
kind: "stepCompleted",
|
|
347
|
+
value: { stepName: "onboarding" },
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
Stream.emit(flowStream, {
|
|
351
|
+
kind: "flowFinished",
|
|
352
|
+
value: { totalTimeMs: 4200 },
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
sub.getState(); // { completedFlows: 1 }
|
|
356
|
+
```
|
|
357
|
+
|
|
306
358
|
## What is included
|
|
307
359
|
|
|
308
360
|
The library covers the full spectrum of state and control flow scenarios encountered in production
|
|
@@ -322,8 +374,9 @@ provides a strongly-typed, immutable two-element pair.
|
|
|
322
374
|
handled by `Task.Result`, `Task.Maybe`, and `Task.Validation`. For managing stateful, recurring
|
|
323
375
|
asynchronous operations with complex scheduling, `Op` implements named concurrency strategies such
|
|
324
376
|
as `restartable`, `exclusive`, `debounced`, `throttled`, and `queue`, handling retries, timeouts,
|
|
325
|
-
and signal propagation automatically. `
|
|
326
|
-
|
|
377
|
+
and signal propagation automatically. `Stream` provides typed event streaming, sequence pattern
|
|
378
|
+
matching, state reduction, and structural forwarding across channels. `Deferred` represents a
|
|
379
|
+
lightweight, infallible asynchronous value that is guaranteed to always resolve without rejection.
|
|
327
380
|
|
|
328
381
|
### Optics and environment state
|
|
329
382
|
|
|
@@ -1732,6 +1732,112 @@ var State;
|
|
|
1732
1732
|
};
|
|
1733
1733
|
})(State || (State = {}));
|
|
1734
1734
|
|
|
1735
|
+
// src/Core/Stream.ts
|
|
1736
|
+
var Stream;
|
|
1737
|
+
((Stream2) => {
|
|
1738
|
+
Stream2.make = (options) => ({
|
|
1739
|
+
options,
|
|
1740
|
+
_listeners: /* @__PURE__ */ new Set()
|
|
1741
|
+
});
|
|
1742
|
+
Stream2.emit = (target, message) => {
|
|
1743
|
+
const targets = Array.isArray(target) ? target : [target];
|
|
1744
|
+
const msg = message;
|
|
1745
|
+
for (const stream of targets) {
|
|
1746
|
+
const listeners = Array.from(stream._listeners);
|
|
1747
|
+
for (const listener of listeners) {
|
|
1748
|
+
try {
|
|
1749
|
+
listener(msg);
|
|
1750
|
+
} catch (err2) {
|
|
1751
|
+
if (stream.options?.onError) {
|
|
1752
|
+
stream.options.onError(err2);
|
|
1753
|
+
} else {
|
|
1754
|
+
throw err2;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
Stream2.forward = (options) => {
|
|
1761
|
+
const targets = Array.isArray(options.to) ? options.to : [options.to];
|
|
1762
|
+
const filterSet = options.only ? new Set(options.only) : null;
|
|
1763
|
+
const handler = (msg) => {
|
|
1764
|
+
if (filterSet !== null && !filterSet.has(msg.kind)) {
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1767
|
+
for (const target of targets) {
|
|
1768
|
+
(0, Stream2.emit)(target, msg);
|
|
1769
|
+
}
|
|
1770
|
+
};
|
|
1771
|
+
options.from._listeners.add(handler);
|
|
1772
|
+
return () => {
|
|
1773
|
+
options.from._listeners.delete(handler);
|
|
1774
|
+
};
|
|
1775
|
+
};
|
|
1776
|
+
Stream2.listen = (stream, events, options) => {
|
|
1777
|
+
const eventList = Array.isArray(events) ? events : [events];
|
|
1778
|
+
const isOrdered = options?.ordered ?? false;
|
|
1779
|
+
const isStrict = options?.strict ?? false;
|
|
1780
|
+
const isOnce = options?.once ?? false;
|
|
1781
|
+
const resetKinds = options?.reset ? new Set(Array.isArray(options.reset) ? options.reset : [options.reset]) : null;
|
|
1782
|
+
const createMatcher = (onMatch) => {
|
|
1783
|
+
let sequenceIndex = 0;
|
|
1784
|
+
return (msg) => {
|
|
1785
|
+
if (resetKinds !== null && resetKinds.has(msg.kind)) {
|
|
1786
|
+
sequenceIndex = 0;
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1789
|
+
if (!isOrdered) {
|
|
1790
|
+
if (eventList.includes(msg.kind)) {
|
|
1791
|
+
onMatch(msg);
|
|
1792
|
+
}
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1795
|
+
const expectedKind = eventList[sequenceIndex];
|
|
1796
|
+
if (msg.kind === expectedKind) {
|
|
1797
|
+
sequenceIndex++;
|
|
1798
|
+
if (sequenceIndex === eventList.length) {
|
|
1799
|
+
sequenceIndex = 0;
|
|
1800
|
+
onMatch(msg);
|
|
1801
|
+
}
|
|
1802
|
+
} else if (isStrict) {
|
|
1803
|
+
sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
|
|
1804
|
+
} else if (eventList.includes(msg.kind)) {
|
|
1805
|
+
sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
|
|
1806
|
+
}
|
|
1807
|
+
};
|
|
1808
|
+
};
|
|
1809
|
+
return {
|
|
1810
|
+
reduce: (reducer, initialState) => {
|
|
1811
|
+
let currentState = initialState;
|
|
1812
|
+
const listenerFn = createMatcher((msg) => {
|
|
1813
|
+
currentState = reducer(msg, currentState);
|
|
1814
|
+
if (isOnce) {
|
|
1815
|
+
stream._listeners.delete(listenerFn);
|
|
1816
|
+
}
|
|
1817
|
+
});
|
|
1818
|
+
const unsubscribe = () => {
|
|
1819
|
+
stream._listeners.delete(listenerFn);
|
|
1820
|
+
};
|
|
1821
|
+
stream._listeners.add(listenerFn);
|
|
1822
|
+
return { unsubscribe, getState: () => currentState };
|
|
1823
|
+
},
|
|
1824
|
+
tap: (effect) => {
|
|
1825
|
+
const listenerFn = createMatcher((msg) => {
|
|
1826
|
+
effect(msg);
|
|
1827
|
+
if (isOnce) {
|
|
1828
|
+
stream._listeners.delete(listenerFn);
|
|
1829
|
+
}
|
|
1830
|
+
});
|
|
1831
|
+
const unsubscribe = () => {
|
|
1832
|
+
stream._listeners.delete(listenerFn);
|
|
1833
|
+
};
|
|
1834
|
+
stream._listeners.add(listenerFn);
|
|
1835
|
+
return unsubscribe;
|
|
1836
|
+
}
|
|
1837
|
+
};
|
|
1838
|
+
};
|
|
1839
|
+
})(Stream || (Stream = {}));
|
|
1840
|
+
|
|
1735
1841
|
// src/Core/TaskMaybe.ts
|
|
1736
1842
|
var TaskMaybe;
|
|
1737
1843
|
((TaskMaybe2) => {
|
|
@@ -2478,6 +2584,7 @@ export {
|
|
|
2478
2584
|
Resource,
|
|
2479
2585
|
Result,
|
|
2480
2586
|
State,
|
|
2587
|
+
Stream,
|
|
2481
2588
|
TaskMaybe,
|
|
2482
2589
|
TaskResult,
|
|
2483
2590
|
isNonEmptyArr,
|
package/dist/core.d.mts
CHANGED
|
@@ -2451,6 +2451,158 @@ declare namespace State {
|
|
|
2451
2451
|
const focus: <S, A>(lens: Lens<S, A>) => <B>(stateOp: State<A, B>) => State<S, B>;
|
|
2452
2452
|
}
|
|
2453
2453
|
|
|
2454
|
+
/**
|
|
2455
|
+
* An event stream pipeline for a typed message schema `S`.
|
|
2456
|
+
*
|
|
2457
|
+
* `Stream` provides typed event emission, sequence matching, state reduction,
|
|
2458
|
+
* and structural stream forwarding.
|
|
2459
|
+
*
|
|
2460
|
+
* @example
|
|
2461
|
+
* ```ts
|
|
2462
|
+
* type AppMessages = {
|
|
2463
|
+
* userLoggedIn: { userId: string };
|
|
2464
|
+
* checkoutStarted: { amount: number };
|
|
2465
|
+
* };
|
|
2466
|
+
*
|
|
2467
|
+
* const appStream = Stream.make<AppMessages>();
|
|
2468
|
+
*
|
|
2469
|
+
* const subscription = Stream.listen(
|
|
2470
|
+
* appStream,
|
|
2471
|
+
* ["userLoggedIn", "checkoutStarted"],
|
|
2472
|
+
* { ordered: true }
|
|
2473
|
+
* ).reduce(
|
|
2474
|
+
* (msg, state) => {
|
|
2475
|
+
* if (msg.kind === "checkoutStarted") {
|
|
2476
|
+
* return { count: state.count + 1 };
|
|
2477
|
+
* }
|
|
2478
|
+
* return state;
|
|
2479
|
+
* },
|
|
2480
|
+
* { count: 0 }
|
|
2481
|
+
* );
|
|
2482
|
+
*
|
|
2483
|
+
* Stream.emit(appStream, {
|
|
2484
|
+
* kind: "userLoggedIn",
|
|
2485
|
+
* value: { userId: "user-1" },
|
|
2486
|
+
* });
|
|
2487
|
+
* ```
|
|
2488
|
+
*/
|
|
2489
|
+
type Stream<S extends Record<string, unknown>> = {
|
|
2490
|
+
readonly options?: Stream.Options;
|
|
2491
|
+
/** @internal */
|
|
2492
|
+
readonly _listeners: Set<(msg: Stream.Message<S>) => void>;
|
|
2493
|
+
};
|
|
2494
|
+
declare namespace Stream {
|
|
2495
|
+
/**
|
|
2496
|
+
* Message payload emitted across a Stream.
|
|
2497
|
+
*/
|
|
2498
|
+
type Message<S extends Record<string, unknown>> = {
|
|
2499
|
+
[K in keyof S & string]: WithKind<K> & WithValue<S[K]>;
|
|
2500
|
+
}[keyof S & string];
|
|
2501
|
+
/**
|
|
2502
|
+
* Options for constructing a `Stream` instance.
|
|
2503
|
+
*/
|
|
2504
|
+
type Options = {
|
|
2505
|
+
readonly name?: string;
|
|
2506
|
+
readonly onError?: (error: unknown) => void;
|
|
2507
|
+
};
|
|
2508
|
+
/**
|
|
2509
|
+
* Options for sequence matching and listener execution.
|
|
2510
|
+
*/
|
|
2511
|
+
type SequenceOptions<S extends Record<string, unknown>> = {
|
|
2512
|
+
/** Match events in exact array sequence order (default: false). */
|
|
2513
|
+
readonly ordered?: boolean;
|
|
2514
|
+
/** Match sequence strictly consecutively without intermediary events (default: false). */
|
|
2515
|
+
readonly strict?: boolean;
|
|
2516
|
+
/** Automatically unsubscribe after the first match/cycle completes (default: false). */
|
|
2517
|
+
readonly once?: boolean;
|
|
2518
|
+
/** Event kind(s) that reset sequence tracking to index 0. */
|
|
2519
|
+
readonly reset?: (keyof S & string) | ReadonlyArray<keyof S & string>;
|
|
2520
|
+
};
|
|
2521
|
+
/**
|
|
2522
|
+
* Handle for an active stateful subscription.
|
|
2523
|
+
*/
|
|
2524
|
+
type Subscription<State> = {
|
|
2525
|
+
readonly unsubscribe: () => void;
|
|
2526
|
+
readonly getState: () => State;
|
|
2527
|
+
};
|
|
2528
|
+
/**
|
|
2529
|
+
* Options for structural stream forwarding.
|
|
2530
|
+
*/
|
|
2531
|
+
type ForwardOptions<S extends Record<string, unknown>> = {
|
|
2532
|
+
readonly from: Stream<S>;
|
|
2533
|
+
readonly to: Stream<S> | ReadonlyArray<Stream<S>>;
|
|
2534
|
+
readonly only?: ReadonlyArray<keyof S & string>;
|
|
2535
|
+
};
|
|
2536
|
+
/**
|
|
2537
|
+
* Builder handle returned by `Stream.listen`.
|
|
2538
|
+
*/
|
|
2539
|
+
type ListenerBuilder<S extends Record<string, unknown>> = {
|
|
2540
|
+
/**
|
|
2541
|
+
* Stateful reduction over events/sequences.
|
|
2542
|
+
*/
|
|
2543
|
+
readonly reduce: <State>(reducer: (msg: Message<S>, state: State) => State, initialState: State) => Subscription<State>;
|
|
2544
|
+
/**
|
|
2545
|
+
* Stateless side-effect execution.
|
|
2546
|
+
*/
|
|
2547
|
+
readonly tap: (effect: (msg: Message<S>) => void) => () => void;
|
|
2548
|
+
};
|
|
2549
|
+
/**
|
|
2550
|
+
* Constructs a new `Stream` instance.
|
|
2551
|
+
*
|
|
2552
|
+
* @example
|
|
2553
|
+
* ```ts
|
|
2554
|
+
* const stream = Stream.make<AppMessages>({ name: "app" });
|
|
2555
|
+
* ```
|
|
2556
|
+
*/
|
|
2557
|
+
const make: <S extends Record<string, unknown>>(options?: Options) => Stream<S>;
|
|
2558
|
+
/**
|
|
2559
|
+
* Emits a message payload to one or more target streams.
|
|
2560
|
+
*
|
|
2561
|
+
* @example
|
|
2562
|
+
* ```ts
|
|
2563
|
+
* Stream.emit(streamA, {
|
|
2564
|
+
* kind: "userLoggedIn",
|
|
2565
|
+
* value: { userId: "user-1" },
|
|
2566
|
+
* });
|
|
2567
|
+
*
|
|
2568
|
+
* Stream.emit([streamA, streamB], {
|
|
2569
|
+
* kind: "userLoggedIn",
|
|
2570
|
+
* value: { userId: "user-1" },
|
|
2571
|
+
* });
|
|
2572
|
+
* ```
|
|
2573
|
+
*/
|
|
2574
|
+
const emit: <S extends Record<string, unknown>, K extends keyof S & string>(target: Stream<S> | ReadonlyArray<Stream<S>>, message: WithKind<K> & WithValue<S[K]>) => void;
|
|
2575
|
+
/**
|
|
2576
|
+
* Forwards messages from one stream to another (or multiple).
|
|
2577
|
+
*
|
|
2578
|
+
* @example
|
|
2579
|
+
* ```ts
|
|
2580
|
+
* const stop = Stream.forward({
|
|
2581
|
+
* from: authStream,
|
|
2582
|
+
* to: analyticsStream,
|
|
2583
|
+
* only: ["userLoggedIn"],
|
|
2584
|
+
* });
|
|
2585
|
+
* ```
|
|
2586
|
+
*/
|
|
2587
|
+
const forward: <S extends Record<string, unknown>>(options: ForwardOptions<S>) => () => void;
|
|
2588
|
+
/**
|
|
2589
|
+
* Initiates listener registration on a stream for specific event kind(s) or sequence.
|
|
2590
|
+
*
|
|
2591
|
+
* @example
|
|
2592
|
+
* ```ts
|
|
2593
|
+
* const sub = Stream.listen(
|
|
2594
|
+
* appStream,
|
|
2595
|
+
* ["userLoggedIn", "checkoutStarted"],
|
|
2596
|
+
* { ordered: true }
|
|
2597
|
+
* ).reduce(
|
|
2598
|
+
* (msg, state) => ({ count: state.count + 1 }),
|
|
2599
|
+
* { count: 0 }
|
|
2600
|
+
* );
|
|
2601
|
+
* ```
|
|
2602
|
+
*/
|
|
2603
|
+
const listen: <S extends Record<string, unknown>, K extends keyof S & string>(stream: Stream<S>, events: K | ReadonlyArray<K>, options?: SequenceOptions<S>) => ListenerBuilder<S>;
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2454
2606
|
type TheseFirst<T> = WithKind<"First"> & WithFirst<T>;
|
|
2455
2607
|
type TheseSecond<T> = WithKind<"Second"> & WithSecond<T>;
|
|
2456
2608
|
type TheseBoth<First, Second> = WithKind<"Both"> & WithFirst<First> & WithSecond<Second>;
|
|
@@ -2859,4 +3011,4 @@ declare namespace Tuple {
|
|
|
2859
3011
|
const tap: <A, B>(f: (a: A, b: B) => void) => (tuple: Tuple<A, B>) => Tuple<A, B>;
|
|
2860
3012
|
}
|
|
2861
3013
|
|
|
2862
|
-
export { Combinable, Deferred, type Failure, Lazy, Lens, type Loading, Logged, Maybe, type NotAsked, Op, Optional, Predicate, Reader, Refinement, RemoteData, Resource, Result, State, type Success, Task, These, type TheseBoth, type TheseFirst, type TheseSecond, Tuple };
|
|
3014
|
+
export { Combinable, Deferred, type Failure, Lazy, Lens, type Loading, Logged, Maybe, type NotAsked, Op, Optional, Predicate, Reader, Refinement, RemoteData, Resource, Result, State, Stream, type Success, Task, These, type TheseBoth, type TheseFirst, type TheseSecond, Tuple };
|
package/dist/core.d.ts
CHANGED
|
@@ -2451,6 +2451,158 @@ declare namespace State {
|
|
|
2451
2451
|
const focus: <S, A>(lens: Lens<S, A>) => <B>(stateOp: State<A, B>) => State<S, B>;
|
|
2452
2452
|
}
|
|
2453
2453
|
|
|
2454
|
+
/**
|
|
2455
|
+
* An event stream pipeline for a typed message schema `S`.
|
|
2456
|
+
*
|
|
2457
|
+
* `Stream` provides typed event emission, sequence matching, state reduction,
|
|
2458
|
+
* and structural stream forwarding.
|
|
2459
|
+
*
|
|
2460
|
+
* @example
|
|
2461
|
+
* ```ts
|
|
2462
|
+
* type AppMessages = {
|
|
2463
|
+
* userLoggedIn: { userId: string };
|
|
2464
|
+
* checkoutStarted: { amount: number };
|
|
2465
|
+
* };
|
|
2466
|
+
*
|
|
2467
|
+
* const appStream = Stream.make<AppMessages>();
|
|
2468
|
+
*
|
|
2469
|
+
* const subscription = Stream.listen(
|
|
2470
|
+
* appStream,
|
|
2471
|
+
* ["userLoggedIn", "checkoutStarted"],
|
|
2472
|
+
* { ordered: true }
|
|
2473
|
+
* ).reduce(
|
|
2474
|
+
* (msg, state) => {
|
|
2475
|
+
* if (msg.kind === "checkoutStarted") {
|
|
2476
|
+
* return { count: state.count + 1 };
|
|
2477
|
+
* }
|
|
2478
|
+
* return state;
|
|
2479
|
+
* },
|
|
2480
|
+
* { count: 0 }
|
|
2481
|
+
* );
|
|
2482
|
+
*
|
|
2483
|
+
* Stream.emit(appStream, {
|
|
2484
|
+
* kind: "userLoggedIn",
|
|
2485
|
+
* value: { userId: "user-1" },
|
|
2486
|
+
* });
|
|
2487
|
+
* ```
|
|
2488
|
+
*/
|
|
2489
|
+
type Stream<S extends Record<string, unknown>> = {
|
|
2490
|
+
readonly options?: Stream.Options;
|
|
2491
|
+
/** @internal */
|
|
2492
|
+
readonly _listeners: Set<(msg: Stream.Message<S>) => void>;
|
|
2493
|
+
};
|
|
2494
|
+
declare namespace Stream {
|
|
2495
|
+
/**
|
|
2496
|
+
* Message payload emitted across a Stream.
|
|
2497
|
+
*/
|
|
2498
|
+
type Message<S extends Record<string, unknown>> = {
|
|
2499
|
+
[K in keyof S & string]: WithKind<K> & WithValue<S[K]>;
|
|
2500
|
+
}[keyof S & string];
|
|
2501
|
+
/**
|
|
2502
|
+
* Options for constructing a `Stream` instance.
|
|
2503
|
+
*/
|
|
2504
|
+
type Options = {
|
|
2505
|
+
readonly name?: string;
|
|
2506
|
+
readonly onError?: (error: unknown) => void;
|
|
2507
|
+
};
|
|
2508
|
+
/**
|
|
2509
|
+
* Options for sequence matching and listener execution.
|
|
2510
|
+
*/
|
|
2511
|
+
type SequenceOptions<S extends Record<string, unknown>> = {
|
|
2512
|
+
/** Match events in exact array sequence order (default: false). */
|
|
2513
|
+
readonly ordered?: boolean;
|
|
2514
|
+
/** Match sequence strictly consecutively without intermediary events (default: false). */
|
|
2515
|
+
readonly strict?: boolean;
|
|
2516
|
+
/** Automatically unsubscribe after the first match/cycle completes (default: false). */
|
|
2517
|
+
readonly once?: boolean;
|
|
2518
|
+
/** Event kind(s) that reset sequence tracking to index 0. */
|
|
2519
|
+
readonly reset?: (keyof S & string) | ReadonlyArray<keyof S & string>;
|
|
2520
|
+
};
|
|
2521
|
+
/**
|
|
2522
|
+
* Handle for an active stateful subscription.
|
|
2523
|
+
*/
|
|
2524
|
+
type Subscription<State> = {
|
|
2525
|
+
readonly unsubscribe: () => void;
|
|
2526
|
+
readonly getState: () => State;
|
|
2527
|
+
};
|
|
2528
|
+
/**
|
|
2529
|
+
* Options for structural stream forwarding.
|
|
2530
|
+
*/
|
|
2531
|
+
type ForwardOptions<S extends Record<string, unknown>> = {
|
|
2532
|
+
readonly from: Stream<S>;
|
|
2533
|
+
readonly to: Stream<S> | ReadonlyArray<Stream<S>>;
|
|
2534
|
+
readonly only?: ReadonlyArray<keyof S & string>;
|
|
2535
|
+
};
|
|
2536
|
+
/**
|
|
2537
|
+
* Builder handle returned by `Stream.listen`.
|
|
2538
|
+
*/
|
|
2539
|
+
type ListenerBuilder<S extends Record<string, unknown>> = {
|
|
2540
|
+
/**
|
|
2541
|
+
* Stateful reduction over events/sequences.
|
|
2542
|
+
*/
|
|
2543
|
+
readonly reduce: <State>(reducer: (msg: Message<S>, state: State) => State, initialState: State) => Subscription<State>;
|
|
2544
|
+
/**
|
|
2545
|
+
* Stateless side-effect execution.
|
|
2546
|
+
*/
|
|
2547
|
+
readonly tap: (effect: (msg: Message<S>) => void) => () => void;
|
|
2548
|
+
};
|
|
2549
|
+
/**
|
|
2550
|
+
* Constructs a new `Stream` instance.
|
|
2551
|
+
*
|
|
2552
|
+
* @example
|
|
2553
|
+
* ```ts
|
|
2554
|
+
* const stream = Stream.make<AppMessages>({ name: "app" });
|
|
2555
|
+
* ```
|
|
2556
|
+
*/
|
|
2557
|
+
const make: <S extends Record<string, unknown>>(options?: Options) => Stream<S>;
|
|
2558
|
+
/**
|
|
2559
|
+
* Emits a message payload to one or more target streams.
|
|
2560
|
+
*
|
|
2561
|
+
* @example
|
|
2562
|
+
* ```ts
|
|
2563
|
+
* Stream.emit(streamA, {
|
|
2564
|
+
* kind: "userLoggedIn",
|
|
2565
|
+
* value: { userId: "user-1" },
|
|
2566
|
+
* });
|
|
2567
|
+
*
|
|
2568
|
+
* Stream.emit([streamA, streamB], {
|
|
2569
|
+
* kind: "userLoggedIn",
|
|
2570
|
+
* value: { userId: "user-1" },
|
|
2571
|
+
* });
|
|
2572
|
+
* ```
|
|
2573
|
+
*/
|
|
2574
|
+
const emit: <S extends Record<string, unknown>, K extends keyof S & string>(target: Stream<S> | ReadonlyArray<Stream<S>>, message: WithKind<K> & WithValue<S[K]>) => void;
|
|
2575
|
+
/**
|
|
2576
|
+
* Forwards messages from one stream to another (or multiple).
|
|
2577
|
+
*
|
|
2578
|
+
* @example
|
|
2579
|
+
* ```ts
|
|
2580
|
+
* const stop = Stream.forward({
|
|
2581
|
+
* from: authStream,
|
|
2582
|
+
* to: analyticsStream,
|
|
2583
|
+
* only: ["userLoggedIn"],
|
|
2584
|
+
* });
|
|
2585
|
+
* ```
|
|
2586
|
+
*/
|
|
2587
|
+
const forward: <S extends Record<string, unknown>>(options: ForwardOptions<S>) => () => void;
|
|
2588
|
+
/**
|
|
2589
|
+
* Initiates listener registration on a stream for specific event kind(s) or sequence.
|
|
2590
|
+
*
|
|
2591
|
+
* @example
|
|
2592
|
+
* ```ts
|
|
2593
|
+
* const sub = Stream.listen(
|
|
2594
|
+
* appStream,
|
|
2595
|
+
* ["userLoggedIn", "checkoutStarted"],
|
|
2596
|
+
* { ordered: true }
|
|
2597
|
+
* ).reduce(
|
|
2598
|
+
* (msg, state) => ({ count: state.count + 1 }),
|
|
2599
|
+
* { count: 0 }
|
|
2600
|
+
* );
|
|
2601
|
+
* ```
|
|
2602
|
+
*/
|
|
2603
|
+
const listen: <S extends Record<string, unknown>, K extends keyof S & string>(stream: Stream<S>, events: K | ReadonlyArray<K>, options?: SequenceOptions<S>) => ListenerBuilder<S>;
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2454
2606
|
type TheseFirst<T> = WithKind<"First"> & WithFirst<T>;
|
|
2455
2607
|
type TheseSecond<T> = WithKind<"Second"> & WithSecond<T>;
|
|
2456
2608
|
type TheseBoth<First, Second> = WithKind<"Both"> & WithFirst<First> & WithSecond<Second>;
|
|
@@ -2859,4 +3011,4 @@ declare namespace Tuple {
|
|
|
2859
3011
|
const tap: <A, B>(f: (a: A, b: B) => void) => (tuple: Tuple<A, B>) => Tuple<A, B>;
|
|
2860
3012
|
}
|
|
2861
3013
|
|
|
2862
|
-
export { Combinable, Deferred, type Failure, Lazy, Lens, type Loading, Logged, Maybe, type NotAsked, Op, Optional, Predicate, Reader, Refinement, RemoteData, Resource, Result, State, type Success, Task, These, type TheseBoth, type TheseFirst, type TheseSecond, Tuple };
|
|
3014
|
+
export { Combinable, Deferred, type Failure, Lazy, Lens, type Loading, Logged, Maybe, type NotAsked, Op, Optional, Predicate, Reader, Refinement, RemoteData, Resource, Result, State, Stream, type Success, Task, These, type TheseBoth, type TheseFirst, type TheseSecond, Tuple };
|
package/dist/core.js
CHANGED
|
@@ -37,6 +37,7 @@ __export(Core_exports, {
|
|
|
37
37
|
Resource: () => Resource,
|
|
38
38
|
Result: () => Result,
|
|
39
39
|
State: () => State,
|
|
40
|
+
Stream: () => Stream,
|
|
40
41
|
Task: () => Task,
|
|
41
42
|
TaskMaybe: () => TaskMaybe,
|
|
42
43
|
TaskResult: () => TaskResult,
|
|
@@ -1805,6 +1806,112 @@ var State;
|
|
|
1805
1806
|
};
|
|
1806
1807
|
})(State || (State = {}));
|
|
1807
1808
|
|
|
1809
|
+
// src/Core/Stream.ts
|
|
1810
|
+
var Stream;
|
|
1811
|
+
((Stream2) => {
|
|
1812
|
+
Stream2.make = (options) => ({
|
|
1813
|
+
options,
|
|
1814
|
+
_listeners: /* @__PURE__ */ new Set()
|
|
1815
|
+
});
|
|
1816
|
+
Stream2.emit = (target, message) => {
|
|
1817
|
+
const targets = Array.isArray(target) ? target : [target];
|
|
1818
|
+
const msg = message;
|
|
1819
|
+
for (const stream of targets) {
|
|
1820
|
+
const listeners = Array.from(stream._listeners);
|
|
1821
|
+
for (const listener of listeners) {
|
|
1822
|
+
try {
|
|
1823
|
+
listener(msg);
|
|
1824
|
+
} catch (err2) {
|
|
1825
|
+
if (stream.options?.onError) {
|
|
1826
|
+
stream.options.onError(err2);
|
|
1827
|
+
} else {
|
|
1828
|
+
throw err2;
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
Stream2.forward = (options) => {
|
|
1835
|
+
const targets = Array.isArray(options.to) ? options.to : [options.to];
|
|
1836
|
+
const filterSet = options.only ? new Set(options.only) : null;
|
|
1837
|
+
const handler = (msg) => {
|
|
1838
|
+
if (filterSet !== null && !filterSet.has(msg.kind)) {
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
for (const target of targets) {
|
|
1842
|
+
(0, Stream2.emit)(target, msg);
|
|
1843
|
+
}
|
|
1844
|
+
};
|
|
1845
|
+
options.from._listeners.add(handler);
|
|
1846
|
+
return () => {
|
|
1847
|
+
options.from._listeners.delete(handler);
|
|
1848
|
+
};
|
|
1849
|
+
};
|
|
1850
|
+
Stream2.listen = (stream, events, options) => {
|
|
1851
|
+
const eventList = Array.isArray(events) ? events : [events];
|
|
1852
|
+
const isOrdered = options?.ordered ?? false;
|
|
1853
|
+
const isStrict = options?.strict ?? false;
|
|
1854
|
+
const isOnce = options?.once ?? false;
|
|
1855
|
+
const resetKinds = options?.reset ? new Set(Array.isArray(options.reset) ? options.reset : [options.reset]) : null;
|
|
1856
|
+
const createMatcher = (onMatch) => {
|
|
1857
|
+
let sequenceIndex = 0;
|
|
1858
|
+
return (msg) => {
|
|
1859
|
+
if (resetKinds !== null && resetKinds.has(msg.kind)) {
|
|
1860
|
+
sequenceIndex = 0;
|
|
1861
|
+
return;
|
|
1862
|
+
}
|
|
1863
|
+
if (!isOrdered) {
|
|
1864
|
+
if (eventList.includes(msg.kind)) {
|
|
1865
|
+
onMatch(msg);
|
|
1866
|
+
}
|
|
1867
|
+
return;
|
|
1868
|
+
}
|
|
1869
|
+
const expectedKind = eventList[sequenceIndex];
|
|
1870
|
+
if (msg.kind === expectedKind) {
|
|
1871
|
+
sequenceIndex++;
|
|
1872
|
+
if (sequenceIndex === eventList.length) {
|
|
1873
|
+
sequenceIndex = 0;
|
|
1874
|
+
onMatch(msg);
|
|
1875
|
+
}
|
|
1876
|
+
} else if (isStrict) {
|
|
1877
|
+
sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
|
|
1878
|
+
} else if (eventList.includes(msg.kind)) {
|
|
1879
|
+
sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
|
|
1880
|
+
}
|
|
1881
|
+
};
|
|
1882
|
+
};
|
|
1883
|
+
return {
|
|
1884
|
+
reduce: (reducer, initialState) => {
|
|
1885
|
+
let currentState = initialState;
|
|
1886
|
+
const listenerFn = createMatcher((msg) => {
|
|
1887
|
+
currentState = reducer(msg, currentState);
|
|
1888
|
+
if (isOnce) {
|
|
1889
|
+
stream._listeners.delete(listenerFn);
|
|
1890
|
+
}
|
|
1891
|
+
});
|
|
1892
|
+
const unsubscribe = () => {
|
|
1893
|
+
stream._listeners.delete(listenerFn);
|
|
1894
|
+
};
|
|
1895
|
+
stream._listeners.add(listenerFn);
|
|
1896
|
+
return { unsubscribe, getState: () => currentState };
|
|
1897
|
+
},
|
|
1898
|
+
tap: (effect) => {
|
|
1899
|
+
const listenerFn = createMatcher((msg) => {
|
|
1900
|
+
effect(msg);
|
|
1901
|
+
if (isOnce) {
|
|
1902
|
+
stream._listeners.delete(listenerFn);
|
|
1903
|
+
}
|
|
1904
|
+
});
|
|
1905
|
+
const unsubscribe = () => {
|
|
1906
|
+
stream._listeners.delete(listenerFn);
|
|
1907
|
+
};
|
|
1908
|
+
stream._listeners.add(listenerFn);
|
|
1909
|
+
return unsubscribe;
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
};
|
|
1913
|
+
})(Stream || (Stream = {}));
|
|
1914
|
+
|
|
1808
1915
|
// src/Core/TaskMaybe.ts
|
|
1809
1916
|
var TaskMaybe;
|
|
1810
1917
|
((TaskMaybe2) => {
|
|
@@ -2551,6 +2658,7 @@ var Validation;
|
|
|
2551
2658
|
Resource,
|
|
2552
2659
|
Result,
|
|
2553
2660
|
State,
|
|
2661
|
+
Stream,
|
|
2554
2662
|
Task,
|
|
2555
2663
|
TaskMaybe,
|
|
2556
2664
|
TaskResult,
|
package/dist/core.mjs
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
Resource,
|
|
17
17
|
Result,
|
|
18
18
|
State,
|
|
19
|
+
Stream,
|
|
19
20
|
Task,
|
|
20
21
|
TaskMaybe,
|
|
21
22
|
TaskResult,
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
These,
|
|
24
25
|
Tuple,
|
|
25
26
|
Validation
|
|
26
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-IHLH2XYQ.mjs";
|
|
27
28
|
import "./chunk-DENXUTKL.mjs";
|
|
28
29
|
export {
|
|
29
30
|
Combinable,
|
|
@@ -43,6 +44,7 @@ export {
|
|
|
43
44
|
Resource,
|
|
44
45
|
Result,
|
|
45
46
|
State,
|
|
47
|
+
Stream,
|
|
46
48
|
Task,
|
|
47
49
|
TaskMaybe,
|
|
48
50
|
TaskResult,
|
package/dist/data.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { and, compose, constFalse, constNull, constTrue, constUndefined, constVoid, constant, converge, curry, curry3, curry4, defaultTo, flip, flow, identity, juxt, memoize, memoizeWeak, not, on, once, or, pipe, tap, tuple, uncurry, uncurry3, uncurry4, untuple } from './composition.mjs';
|
|
2
|
-
export { Combinable, Failure, Lazy, Lens, Loading, Logged, NotAsked, Op, Optional, Predicate, Reader, Refinement, RemoteData, Resource, State, Success, These, TheseBoth, TheseFirst, TheseSecond, Tuple } from './core.mjs';
|
|
2
|
+
export { Combinable, Failure, Lazy, Lens, Loading, Logged, NotAsked, Op, Optional, Predicate, Reader, Refinement, RemoteData, Resource, State, Stream, Success, These, TheseBoth, TheseFirst, TheseSecond, Tuple } from './core.mjs';
|
|
3
3
|
export { D as Deferred } from './InternalTypes-CDiDBAY4.mjs';
|
|
4
4
|
export { E as Equality, a as Err, F as Failed, M as Maybe, N as None, O as Ok, b as Ordering, P as Passed, R as Result, S as Some, T as Task, c as TaskMaybe, d as TaskResult, e as TaskValidation, V as Validation } from './Validation-D-aARYlP.mjs';
|
|
5
5
|
export { Arr, BigNum, Dict, Json, NonEmptyMap, NonEmptyRecord, NonEmptySet, NonEmptyString, Num, Rec, Str, Uniq } from './data.mjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { and, compose, constFalse, constNull, constTrue, constUndefined, constVoid, constant, converge, curry, curry3, curry4, defaultTo, flip, flow, identity, juxt, memoize, memoizeWeak, not, on, once, or, pipe, tap, tuple, uncurry, uncurry3, uncurry4, untuple } from './composition.js';
|
|
2
|
-
export { Combinable, Failure, Lazy, Lens, Loading, Logged, NotAsked, Op, Optional, Predicate, Reader, Refinement, RemoteData, Resource, State, Success, These, TheseBoth, TheseFirst, TheseSecond, Tuple } from './core.js';
|
|
2
|
+
export { Combinable, Failure, Lazy, Lens, Loading, Logged, NotAsked, Op, Optional, Predicate, Reader, Refinement, RemoteData, Resource, State, Stream, Success, These, TheseBoth, TheseFirst, TheseSecond, Tuple } from './core.js';
|
|
3
3
|
export { D as Deferred } from './InternalTypes-LdhLQx3N.js';
|
|
4
4
|
export { E as Equality, a as Err, F as Failed, M as Maybe, N as None, O as Ok, b as Ordering, P as Passed, R as Result, S as Some, T as Task, c as TaskMaybe, d as TaskResult, e as TaskValidation, V as Validation } from './Validation-1OgJJdeA.js';
|
|
5
5
|
export { Arr, BigNum, Dict, Json, NonEmptyMap, NonEmptyRecord, NonEmptySet, NonEmptyString, Num, Rec, Str, Uniq } from './data.js';
|
package/dist/index.js
CHANGED
|
@@ -47,6 +47,7 @@ __export(src_exports, {
|
|
|
47
47
|
RetryPolicy: () => RetryPolicy,
|
|
48
48
|
State: () => State,
|
|
49
49
|
Str: () => Str,
|
|
50
|
+
Stream: () => Stream,
|
|
50
51
|
Task: () => Task,
|
|
51
52
|
TaskMaybe: () => TaskMaybe,
|
|
52
53
|
TaskResult: () => TaskResult,
|
|
@@ -2287,6 +2288,112 @@ var State;
|
|
|
2287
2288
|
};
|
|
2288
2289
|
})(State || (State = {}));
|
|
2289
2290
|
|
|
2291
|
+
// src/Core/Stream.ts
|
|
2292
|
+
var Stream;
|
|
2293
|
+
((Stream2) => {
|
|
2294
|
+
Stream2.make = (options) => ({
|
|
2295
|
+
options,
|
|
2296
|
+
_listeners: /* @__PURE__ */ new Set()
|
|
2297
|
+
});
|
|
2298
|
+
Stream2.emit = (target, message) => {
|
|
2299
|
+
const targets = Array.isArray(target) ? target : [target];
|
|
2300
|
+
const msg = message;
|
|
2301
|
+
for (const stream of targets) {
|
|
2302
|
+
const listeners = Array.from(stream._listeners);
|
|
2303
|
+
for (const listener of listeners) {
|
|
2304
|
+
try {
|
|
2305
|
+
listener(msg);
|
|
2306
|
+
} catch (err2) {
|
|
2307
|
+
if (stream.options?.onError) {
|
|
2308
|
+
stream.options.onError(err2);
|
|
2309
|
+
} else {
|
|
2310
|
+
throw err2;
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2316
|
+
Stream2.forward = (options) => {
|
|
2317
|
+
const targets = Array.isArray(options.to) ? options.to : [options.to];
|
|
2318
|
+
const filterSet = options.only ? new Set(options.only) : null;
|
|
2319
|
+
const handler = (msg) => {
|
|
2320
|
+
if (filterSet !== null && !filterSet.has(msg.kind)) {
|
|
2321
|
+
return;
|
|
2322
|
+
}
|
|
2323
|
+
for (const target of targets) {
|
|
2324
|
+
(0, Stream2.emit)(target, msg);
|
|
2325
|
+
}
|
|
2326
|
+
};
|
|
2327
|
+
options.from._listeners.add(handler);
|
|
2328
|
+
return () => {
|
|
2329
|
+
options.from._listeners.delete(handler);
|
|
2330
|
+
};
|
|
2331
|
+
};
|
|
2332
|
+
Stream2.listen = (stream, events, options) => {
|
|
2333
|
+
const eventList = Array.isArray(events) ? events : [events];
|
|
2334
|
+
const isOrdered = options?.ordered ?? false;
|
|
2335
|
+
const isStrict = options?.strict ?? false;
|
|
2336
|
+
const isOnce = options?.once ?? false;
|
|
2337
|
+
const resetKinds = options?.reset ? new Set(Array.isArray(options.reset) ? options.reset : [options.reset]) : null;
|
|
2338
|
+
const createMatcher = (onMatch) => {
|
|
2339
|
+
let sequenceIndex = 0;
|
|
2340
|
+
return (msg) => {
|
|
2341
|
+
if (resetKinds !== null && resetKinds.has(msg.kind)) {
|
|
2342
|
+
sequenceIndex = 0;
|
|
2343
|
+
return;
|
|
2344
|
+
}
|
|
2345
|
+
if (!isOrdered) {
|
|
2346
|
+
if (eventList.includes(msg.kind)) {
|
|
2347
|
+
onMatch(msg);
|
|
2348
|
+
}
|
|
2349
|
+
return;
|
|
2350
|
+
}
|
|
2351
|
+
const expectedKind = eventList[sequenceIndex];
|
|
2352
|
+
if (msg.kind === expectedKind) {
|
|
2353
|
+
sequenceIndex++;
|
|
2354
|
+
if (sequenceIndex === eventList.length) {
|
|
2355
|
+
sequenceIndex = 0;
|
|
2356
|
+
onMatch(msg);
|
|
2357
|
+
}
|
|
2358
|
+
} else if (isStrict) {
|
|
2359
|
+
sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
|
|
2360
|
+
} else if (eventList.includes(msg.kind)) {
|
|
2361
|
+
sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
|
|
2362
|
+
}
|
|
2363
|
+
};
|
|
2364
|
+
};
|
|
2365
|
+
return {
|
|
2366
|
+
reduce: (reducer, initialState) => {
|
|
2367
|
+
let currentState = initialState;
|
|
2368
|
+
const listenerFn = createMatcher((msg) => {
|
|
2369
|
+
currentState = reducer(msg, currentState);
|
|
2370
|
+
if (isOnce) {
|
|
2371
|
+
stream._listeners.delete(listenerFn);
|
|
2372
|
+
}
|
|
2373
|
+
});
|
|
2374
|
+
const unsubscribe = () => {
|
|
2375
|
+
stream._listeners.delete(listenerFn);
|
|
2376
|
+
};
|
|
2377
|
+
stream._listeners.add(listenerFn);
|
|
2378
|
+
return { unsubscribe, getState: () => currentState };
|
|
2379
|
+
},
|
|
2380
|
+
tap: (effect) => {
|
|
2381
|
+
const listenerFn = createMatcher((msg) => {
|
|
2382
|
+
effect(msg);
|
|
2383
|
+
if (isOnce) {
|
|
2384
|
+
stream._listeners.delete(listenerFn);
|
|
2385
|
+
}
|
|
2386
|
+
});
|
|
2387
|
+
const unsubscribe = () => {
|
|
2388
|
+
stream._listeners.delete(listenerFn);
|
|
2389
|
+
};
|
|
2390
|
+
stream._listeners.add(listenerFn);
|
|
2391
|
+
return unsubscribe;
|
|
2392
|
+
}
|
|
2393
|
+
};
|
|
2394
|
+
};
|
|
2395
|
+
})(Stream || (Stream = {}));
|
|
2396
|
+
|
|
2290
2397
|
// src/Core/TaskMaybe.ts
|
|
2291
2398
|
var TaskMaybe;
|
|
2292
2399
|
((TaskMaybe2) => {
|
|
@@ -4350,6 +4457,7 @@ var Uniq;
|
|
|
4350
4457
|
RetryPolicy,
|
|
4351
4458
|
State,
|
|
4352
4459
|
Str,
|
|
4460
|
+
Stream,
|
|
4353
4461
|
Task,
|
|
4354
4462
|
TaskMaybe,
|
|
4355
4463
|
TaskResult,
|
package/dist/index.mjs
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
Rec,
|
|
40
40
|
Str,
|
|
41
41
|
Uniq
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-EPT3GYGN.mjs";
|
|
43
43
|
import {
|
|
44
44
|
Combinable,
|
|
45
45
|
Deferred,
|
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
Resource,
|
|
59
59
|
Result,
|
|
60
60
|
State,
|
|
61
|
+
Stream,
|
|
61
62
|
Task,
|
|
62
63
|
TaskMaybe,
|
|
63
64
|
TaskResult,
|
|
@@ -65,7 +66,7 @@ import {
|
|
|
65
66
|
These,
|
|
66
67
|
Tuple,
|
|
67
68
|
Validation
|
|
68
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-IHLH2XYQ.mjs";
|
|
69
70
|
import {
|
|
70
71
|
Brand,
|
|
71
72
|
Duration,
|
|
@@ -99,6 +100,7 @@ export {
|
|
|
99
100
|
RetryPolicy,
|
|
100
101
|
State,
|
|
101
102
|
Str,
|
|
103
|
+
Stream,
|
|
102
104
|
Task,
|
|
103
105
|
TaskMaybe,
|
|
104
106
|
TaskResult,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nlozgachev/pipelined",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.0",
|
|
4
4
|
"description": "Opinionated functional abstractions for TypeScript",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
6
|
"homepage": "https://pipelined.lozgachev.dev",
|
|
@@ -82,10 +82,10 @@
|
|
|
82
82
|
},
|
|
83
83
|
"size-limit": [
|
|
84
84
|
{ "path": "dist/index.js", "limit": "25 KB", "gzip": true },
|
|
85
|
-
{ "path": "dist/core.js", "limit": "
|
|
85
|
+
{ "path": "dist/core.js", "limit": "16 KB", "gzip": true },
|
|
86
86
|
{ "path": "dist/composition.js", "limit": "4 KB", "gzip": true },
|
|
87
|
-
{ "path": "dist/data.js", "limit": "
|
|
88
|
-
{ "path": "dist/types.js", "limit": "
|
|
87
|
+
{ "path": "dist/data.js", "limit": "13 KB", "gzip": true },
|
|
88
|
+
{ "path": "dist/types.js", "limit": "2 KB", "gzip": true }
|
|
89
89
|
],
|
|
90
90
|
"packageManager": "pnpm@11.6.0+sha512.9a36518224080c6fe5165afdcfe79bfa118c29be703f3f462b1e32efe1e98e47e8750b148e08286250aad4113cc7993ca413c4e2cd447752708c2ee5751bc95f"
|
|
91
91
|
}
|