@nlozgachev/pipelined 0.65.0 → 0.66.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.
@@ -218,6 +218,145 @@ declare const Equality: {
218
218
  tuple: <T extends readonly unknown[]>(...equalities: { [K in keyof T]: Equality<T[K]>; }) => Equality<T>;
219
219
  };
220
220
  //#endregion
221
+ //#region src/Core/EventBus.d.ts
222
+ /**
223
+ * An event bus pipeline for a typed message schema `S`.
224
+ *
225
+ * `EventBus` provides typed event emission, sequence matching, state reduction,
226
+ * and structural event bus forwarding.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * type AppMessages = {
231
+ * userLoggedIn: { userId: string };
232
+ * checkoutStarted: { amount: number };
233
+ * };
234
+ *
235
+ * const appBus = EventBus.make<AppMessages>();
236
+ *
237
+ * const subscription = EventBus.listen(
238
+ * appBus,
239
+ * ["userLoggedIn", "checkoutStarted"],
240
+ * { ordered: true }
241
+ * ).reduce(
242
+ * (msg, state) => {
243
+ * if (msg.kind === "checkoutStarted") {
244
+ * return { count: state.count + 1 };
245
+ * }
246
+ * return state;
247
+ * },
248
+ * { count: 0 }
249
+ * );
250
+ *
251
+ * EventBus.emit(appBus, {
252
+ * kind: "userLoggedIn",
253
+ * value: { userId: "user-1" },
254
+ * });
255
+ * ```
256
+ */
257
+ type EventBus<S extends Record<string, unknown>> = {
258
+ readonly options?: EventBus.Options;
259
+ /** @internal */
260
+ readonly _listeners: Set<(msg: EventBus.Message<S>) => void>;
261
+ /**
262
+ * @internal
263
+ * Lazy array snapshot of `_listeners`. Avoids allocating new array objects on every `emit` call
264
+ * (2.98x emission speedup, 0 heap allocations). Rebuilt whenever `_listeners` is mutated,
265
+ * guaranteeing reentrancy safety and preventing listeners subscribed mid-emission from executing early.
266
+ */
267
+ _listenerArray: Array<(msg: EventBus.Message<S>) => void> | null;
268
+ /** @internal */
269
+ readonly _queue: Array<EventBus.Message<S>>;
270
+ /** @internal */
271
+ _isEmitting: boolean;
272
+ };
273
+ declare const EventBus: {
274
+ /**
275
+ * Constructs a new `EventBus` instance.
276
+ *
277
+ * @example
278
+ * ```ts
279
+ * const bus = EventBus.make<AppMessages>({ name: "app" });
280
+ * ```
281
+ */
282
+ make: <S extends Record<string, unknown>>(options?: EventBus.Options) => EventBus<S>;
283
+ /**
284
+ * Emits a message payload to one or more target event buses.
285
+ *
286
+ * Uses a synchronous breadth-first trampoline queue to handle re-entrant emissions deterministically.
287
+ *
288
+ * @example
289
+ * ```ts
290
+ * EventBus.emit(busA, {
291
+ * kind: "userLoggedIn",
292
+ * value: { userId: "user-1" },
293
+ * });
294
+ *
295
+ * EventBus.emit([busA, busB], {
296
+ * kind: "userLoggedIn",
297
+ * value: { userId: "user-1" },
298
+ * });
299
+ * ```
300
+ */
301
+ emit: <S extends Record<string, unknown>, K extends keyof S & string>(target: EventBus<S> | ReadonlyArray<EventBus<S>>, message: WithKind<K> & WithValue<S[K]>) => void;
302
+ /**
303
+ * Forwards messages from one event bus to another (or multiple).
304
+ *
305
+ * @example
306
+ * ```ts
307
+ * const stop = EventBus.forward({
308
+ * from: authBus,
309
+ * to: analyticsBus,
310
+ * only: ["userLoggedIn"],
311
+ * });
312
+ * ```
313
+ */
314
+ forward: <S extends Record<string, unknown>>(options: EventBus.ForwardOptions<S>) => () => void;
315
+ /**
316
+ * Initiates listener registration on an event bus for specific event kind(s) or sequence.
317
+ *
318
+ * @example
319
+ * ```ts
320
+ * const sub = EventBus.listen(
321
+ * appBus,
322
+ * ["userLoggedIn", "checkoutStarted"],
323
+ * { ordered: true }
324
+ * ).reduce(
325
+ * (msg, state) => ({ count: state.count + 1 }),
326
+ * { count: 0 }
327
+ * );
328
+ * ```
329
+ */
330
+ listen: <S extends Record<string, unknown>, K extends keyof S & string>(bus: EventBus<S>, events: K | ReadonlyArray<K>, options?: EventBus.SequenceOptions<S>) => EventBus.ListenerBuilder<S>;
331
+ };
332
+ declare namespace EventBus {
333
+ type Message<S extends Record<string, unknown>> = { [K in keyof S & string]: WithKind<K> & WithValue<S[K]>; }[keyof S & string];
334
+ type Options = {
335
+ readonly name?: string;
336
+ readonly onError?: (error: unknown) => void;
337
+ };
338
+ type SequenceOptions<S extends Record<string, unknown>> = {
339
+ readonly ordered?: boolean;
340
+ readonly strict?: boolean;
341
+ readonly once?: boolean;
342
+ readonly reset?: (keyof S & string) | ReadonlyArray<keyof S & string>;
343
+ readonly optional?: (keyof S & string) | ReadonlyArray<keyof S & string>;
344
+ };
345
+ type Subscription<State> = {
346
+ readonly unsubscribe: () => void;
347
+ readonly getState: () => State;
348
+ };
349
+ type ForwardOptions<S extends Record<string, unknown>> = {
350
+ readonly from: EventBus<S>;
351
+ readonly to: EventBus<S> | ReadonlyArray<EventBus<S>>;
352
+ readonly only?: ReadonlyArray<keyof S & string>;
353
+ };
354
+ type ListenerBuilder<S extends Record<string, unknown>> = {
355
+ readonly reduce: <State>(reducer: (msg: Message<S>, state: State) => State, initialState: State) => Subscription<State>;
356
+ readonly tap: (effect: (msg: Message<S>) => void) => () => void;
357
+ };
358
+ }
359
+ //#endregion
221
360
  //#region src/Core/Lazy.d.ts
222
361
  /**
223
362
  * A synchronous memoized computation. The factory function runs exactly once —
@@ -712,6 +851,18 @@ declare const Maybe: {
712
851
  */
713
852
  Result: <E, A>(data: Result<E, A>) => Maybe<A>;
714
853
  };
854
+ /**
855
+ * Wraps a synchronous operation that may throw, returning a `Maybe<A>`.
856
+ * Returns `Some(value)` if successful, or `None` if an exception is thrown.
857
+ *
858
+ * @example
859
+ * ```ts
860
+ * const safeParse = (s: string) => Maybe.tryCatch(() => JSON.parse(s));
861
+ * safeParse('{"a": 1}'); // Some({ a: 1 })
862
+ * safeParse('invalid'); // None
863
+ * ```
864
+ */
865
+ tryCatch: <A>(f: () => A) => Maybe<A>;
715
866
  /**
716
867
  * Transforms the value inside a Maybe if it exists.
717
868
  *
@@ -799,16 +950,32 @@ declare const Maybe: {
799
950
  */
800
951
  tap: <A>(f: (a: A) => void) => (data: Maybe<A>) => Maybe<A>;
801
952
  /**
802
- * Filters a Maybe based on a predicate.
953
+ * Executes a side effect when the Maybe is None, without changing the Maybe.
954
+ *
955
+ * @example
956
+ * ```ts
957
+ * pipe(
958
+ * Maybe.make.none(),
959
+ * Maybe.tapNone(() => console.log("Value missing")),
960
+ * );
961
+ * ```
962
+ */
963
+ tapNone: (f: () => void) => <A>(data: Maybe<A>) => Maybe<A>;
964
+ /**
965
+ * Filters a Maybe based on a predicate or type guard.
803
966
  * Returns None if the predicate returns false or if the Maybe is already None.
804
967
  *
805
968
  * @example
806
969
  * ```ts
807
970
  * pipe(Maybe.make.some(5), Maybe.filter(n => n > 3)); // Some(5)
808
971
  * pipe(Maybe.make.some(2), Maybe.filter(n => n > 3)); // None
972
+ * pipe(Maybe.make.some("hi"), Maybe.filter((x): x is string => typeof x === "string")); // Some("hi")
809
973
  * ```
810
974
  */
811
- filter: <A>(predicate: (a: A) => boolean) => (data: Maybe<A>) => Maybe<A>;
975
+ filter: {
976
+ <A, B extends A>(refinement: (a: A) => a is B): (data: Maybe<A>) => Maybe<B>;
977
+ <A>(predicate: (a: A) => boolean): (data: Maybe<A>) => Maybe<A>;
978
+ };
812
979
  /**
813
980
  * Recovers from a None by providing a fallback Maybe.
814
981
  * The fallback can produce a different type, widening the result to `Maybe<A | B>`.
@@ -3118,145 +3285,6 @@ declare const State$1: {
3118
3285
  focus: <S, A>(lens: Lens<S, A>) => <B>(stateOp: State$1<A, B>) => State$1<S, B>;
3119
3286
  };
3120
3287
  //#endregion
3121
- //#region src/Core/Stream.d.ts
3122
- /**
3123
- * An event stream pipeline for a typed message schema `S`.
3124
- *
3125
- * `Stream` provides typed event emission, sequence matching, state reduction,
3126
- * and structural stream forwarding.
3127
- *
3128
- * @example
3129
- * ```ts
3130
- * type AppMessages = {
3131
- * userLoggedIn: { userId: string };
3132
- * checkoutStarted: { amount: number };
3133
- * };
3134
- *
3135
- * const appStream = Stream.make<AppMessages>();
3136
- *
3137
- * const subscription = Stream.listen(
3138
- * appStream,
3139
- * ["userLoggedIn", "checkoutStarted"],
3140
- * { ordered: true }
3141
- * ).reduce(
3142
- * (msg, state) => {
3143
- * if (msg.kind === "checkoutStarted") {
3144
- * return { count: state.count + 1 };
3145
- * }
3146
- * return state;
3147
- * },
3148
- * { count: 0 }
3149
- * );
3150
- *
3151
- * Stream.emit(appStream, {
3152
- * kind: "userLoggedIn",
3153
- * value: { userId: "user-1" },
3154
- * });
3155
- * ```
3156
- */
3157
- type Stream<S extends Record<string, unknown>> = {
3158
- readonly options?: Stream.Options;
3159
- /** @internal */
3160
- readonly _listeners: Set<(msg: Stream.Message<S>) => void>;
3161
- /**
3162
- * @internal
3163
- * Lazy array snapshot of `_listeners`. Avoids allocating new array objects on every `emit` call
3164
- * (2.98x emission speedup, 0 heap allocations). Rebuilt whenever `_listeners` is mutated,
3165
- * guaranteeing reentrancy safety and preventing listeners subscribed mid-emission from executing early.
3166
- */
3167
- _listenerArray: Array<(msg: Stream.Message<S>) => void> | null;
3168
- /** @internal */
3169
- readonly _queue: Array<Stream.Message<S>>;
3170
- /** @internal */
3171
- _isEmitting: boolean;
3172
- };
3173
- declare const Stream: {
3174
- /**
3175
- * Constructs a new `Stream` instance.
3176
- *
3177
- * @example
3178
- * ```ts
3179
- * const stream = Stream.make<AppMessages>({ name: "app" });
3180
- * ```
3181
- */
3182
- make: <S extends Record<string, unknown>>(options?: Stream.Options) => Stream<S>;
3183
- /**
3184
- * Emits a message payload to one or more target streams.
3185
- *
3186
- * Uses a synchronous breadth-first trampoline queue to handle re-entrant emissions deterministically.
3187
- *
3188
- * @example
3189
- * ```ts
3190
- * Stream.emit(streamA, {
3191
- * kind: "userLoggedIn",
3192
- * value: { userId: "user-1" },
3193
- * });
3194
- *
3195
- * Stream.emit([streamA, streamB], {
3196
- * kind: "userLoggedIn",
3197
- * value: { userId: "user-1" },
3198
- * });
3199
- * ```
3200
- */
3201
- emit: <S extends Record<string, unknown>, K extends keyof S & string>(target: Stream<S> | ReadonlyArray<Stream<S>>, message: WithKind<K> & WithValue<S[K]>) => void;
3202
- /**
3203
- * Forwards messages from one stream to another (or multiple).
3204
- *
3205
- * @example
3206
- * ```ts
3207
- * const stop = Stream.forward({
3208
- * from: authStream,
3209
- * to: analyticsStream,
3210
- * only: ["userLoggedIn"],
3211
- * });
3212
- * ```
3213
- */
3214
- forward: <S extends Record<string, unknown>>(options: Stream.ForwardOptions<S>) => () => void;
3215
- /**
3216
- * Initiates listener registration on a stream for specific event kind(s) or sequence.
3217
- *
3218
- * @example
3219
- * ```ts
3220
- * const sub = Stream.listen(
3221
- * appStream,
3222
- * ["userLoggedIn", "checkoutStarted"],
3223
- * { ordered: true }
3224
- * ).reduce(
3225
- * (msg, state) => ({ count: state.count + 1 }),
3226
- * { count: 0 }
3227
- * );
3228
- * ```
3229
- */
3230
- listen: <S extends Record<string, unknown>, K extends keyof S & string>(stream: Stream<S>, events: K | ReadonlyArray<K>, options?: Stream.SequenceOptions<S>) => Stream.ListenerBuilder<S>;
3231
- };
3232
- declare namespace Stream {
3233
- type Message<S extends Record<string, unknown>> = { [K in keyof S & string]: WithKind<K> & WithValue<S[K]>; }[keyof S & string];
3234
- type Options = {
3235
- readonly name?: string;
3236
- readonly onError?: (error: unknown) => void;
3237
- };
3238
- type SequenceOptions<S extends Record<string, unknown>> = {
3239
- readonly ordered?: boolean;
3240
- readonly strict?: boolean;
3241
- readonly once?: boolean;
3242
- readonly reset?: (keyof S & string) | ReadonlyArray<keyof S & string>;
3243
- readonly optional?: (keyof S & string) | ReadonlyArray<keyof S & string>;
3244
- };
3245
- type Subscription<State> = {
3246
- readonly unsubscribe: () => void;
3247
- readonly getState: () => State;
3248
- };
3249
- type ForwardOptions<S extends Record<string, unknown>> = {
3250
- readonly from: Stream<S>;
3251
- readonly to: Stream<S> | ReadonlyArray<Stream<S>>;
3252
- readonly only?: ReadonlyArray<keyof S & string>;
3253
- };
3254
- type ListenerBuilder<S extends Record<string, unknown>> = {
3255
- readonly reduce: <State>(reducer: (msg: Message<S>, state: State) => State, initialState: State) => Subscription<State>;
3256
- readonly tap: (effect: (msg: Message<S>) => void) => () => void;
3257
- };
3258
- }
3259
- //#endregion
3260
3288
  //#region src/Core/Validation.d.ts
3261
3289
  /**
3262
3290
  * Validation represents a value that is either passed with a success value,
@@ -3649,7 +3677,7 @@ declare const Validation: {
3649
3677
  * return type using `Task.Result<E, A>` instead.
3650
3678
  *
3651
3679
  * An optional `AbortSignal` can be passed at the call site. Combinators like
3652
- * `retry`, `pollUntil`, and `timeout` thread it automatically to every inner
3680
+ * `retry`, `poll`, and `timeout` thread it automatically to every inner
3653
3681
  * operation. Existing tasks that ignore the signal continue to work unchanged.
3654
3682
  *
3655
3683
  * Calling a Task returns a `Deferred<A>` — a one-shot async value that supports
@@ -3781,14 +3809,19 @@ declare const Task: {
3781
3809
  tap: <A>(f: (a: A) => void) => (data: Task<A>) => Task<A>;
3782
3810
  /**
3783
3811
  * Runs multiple Tasks in parallel and collects their results.
3812
+ * An optional `concurrency` option limits the number of tasks executing at any given time.
3784
3813
  *
3785
3814
  * @example
3786
3815
  * ```ts
3787
3816
  * Task.all([loadConfig, detectLocale, loadTheme])();
3788
3817
  * // Deferred<[Config, string, Theme]>
3818
+ *
3819
+ * Task.all([loadConfig, detectLocale, loadTheme], { concurrency: 2 })();
3789
3820
  * ```
3790
3821
  */
3791
- all: <T extends readonly Task<unknown>[]>(tasks: T) => Task<{ [K in keyof T]: T[K] extends Task<infer A> ? A : never; }>;
3822
+ all: <T extends readonly Task<unknown>[]>(tasks: T, options?: {
3823
+ concurrency?: number;
3824
+ }) => Task<{ [K in keyof T]: T[K] extends Task<infer A> ? A : never; }>;
3792
3825
  /**
3793
3826
  * Delays the execution of a Task by the specified duration.
3794
3827
  * Useful for debouncing or rate limiting.
@@ -3819,23 +3852,23 @@ declare const Task: {
3819
3852
  delay?: Duration;
3820
3853
  }) => <A>(task: Task<A>) => Task<readonly A[]>;
3821
3854
  /**
3822
- * Runs a Task repeatedly until the result satisfies a predicate, returning that result.
3823
- * An optional delay duration can be inserted between runs.
3824
- * An optional `maxAttempts` cap stops the loop after N calls — the last value is returned
3855
+ * Polls a Task repeatedly until the result satisfies a predicate, returning that result.
3856
+ * An optional delay duration can be inserted between polling runs.
3857
+ * An optional `attempts` cap stops the loop after N calls — the last value is returned
3825
3858
  * regardless of whether the predicate was satisfied.
3826
3859
  *
3827
3860
  * @example
3828
3861
  * ```ts
3829
3862
  * pipe(
3830
3863
  * checkStatus,
3831
- * Task.repeatUntil({ when: (s) => s === "ready", delay: Duration.milliseconds(500) })
3864
+ * Task.poll({ until: (s) => s === "ready", delay: Duration.milliseconds(500) })
3832
3865
  * )(); // polls every 500ms until status is "ready"
3833
3866
  * ```
3834
3867
  */
3835
- repeatUntil: <A>(options: {
3836
- when: (a: A) => boolean;
3868
+ poll: <A>(options: {
3869
+ until: (a: A) => boolean;
3837
3870
  delay?: Duration;
3838
- maxAttempts?: number;
3871
+ attempts?: number;
3839
3872
  }) => (task: Task<A>) => Task<A>;
3840
3873
  /**
3841
3874
  * Resolves with the value of the first Task to complete. All Tasks start
@@ -4055,13 +4088,17 @@ declare const Task: {
4055
4088
  bindTo: <K extends string>(key: K) => <E, A>(data: Task.Result<E, A>) => Task.Result<E, { [P in K]: A; }>;
4056
4089
  bind: <K extends string, E, A, B>(key: K, f: (a: A) => Task.Result<E, B>) => (data: Task.Result<E, A>) => Task.Result<E, A & { [P in K]: B; }>;
4057
4090
  struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Task.Result<E, R[K]>; }) => Task.Result<E, R>;
4058
- retry: (policy: RetryPolicy) => <E, A>(task: Task.Result<E, A>) => Task.Result<E, A>;
4091
+ retry: (policy: RetryPolicy, options?: {
4092
+ when?: (error: unknown) => boolean;
4093
+ }) => <E, A>(task: Task.Result<E, A>) => Task.Result<E, A>;
4059
4094
  memoize: <E, A>(task: Task.Result<E, A>) => Task.Result<E, A>;
4060
4095
  timeout: <E2>(options: {
4061
4096
  duration: Duration;
4062
4097
  onTimeout: () => E2;
4063
4098
  }) => <E1 = never, A = unknown>(task: Task.Result<E1, A>) => Task.Result<E1 | E2, A>;
4064
4099
  allSettled: <E, A>(tasks: ReadonlyArray<Task.Result<E, A>>) => Task<ReadonlyArray<Result<E, A>>>;
4100
+ ensure: <A, E2>(predicate: (a: A) => boolean, onFail: (a: A) => E2) => <E1 = never>(task: Task.Result<E1, A>) => Task.Result<E1 | E2, A>;
4101
+ bimap: <E1, E2, A, B>(onErr: (e: E1) => E2, onOk: (a: A) => B) => (task: Task.Result<E1, A>) => Task.Result<E2, B>;
4065
4102
  };
4066
4103
  Validation: {
4067
4104
  make: {
@@ -4380,4 +4417,4 @@ declare const These: {
4380
4417
  swap: <A, B>(data: These<A, B>) => These<B, A>;
4381
4418
  };
4382
4419
  //#endregion
4383
- export { Logged as A, Pair as C, Maybe as D, Op as E, Lazy as M, Equality as N, None as O, Combinable as P, Predicate as S, Optional as T, NotAsked as _, Task as a, Refinement as b, Validation as c, Err$1 as d, Ok$1 as f, Loading as g, Failure as h, TheseSecond as i, Lens as j, Some as k, Stream as l, Resource as m, TheseBoth as n, Failed as o, Result as p, TheseFirst as r, Passed as s, These as t, State$1 as u, RemoteData as v, Ordering as w, Reader as x, Success as y };
4420
+ export { Lens as A, Ordering as C, None as D, Maybe as E, EventBus as M, Equality as N, Some as O, Combinable as P, Pair as S, Op as T, RemoteData as _, Task as a, Reader as b, Validation as c, Ok$1 as d, Result as f, NotAsked as g, Loading as h, TheseSecond as i, Lazy as j, Logged as k, State$1 as l, Failure as m, TheseBoth as n, Failed as o, Resource as p, TheseFirst as r, Passed as s, These as t, Err$1 as u, Success as v, Optional as w, Predicate as x, Refinement as y };