@nlozgachev/pipelined 0.65.0 → 0.67.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 +70 -57
- package/dist/{Core-BHN87zoB.mjs → Core-BCN6WRzp.mjs} +1038 -616
- package/dist/{Core-BDXRLmMa.cjs → Core-CfAL_21H.cjs} +1043 -621
- package/dist/{InternalTypes-DzDey5Do.d.ts → InternalTypes-C0F5jyVQ.d.ts} +1 -1
- package/dist/{InternalTypes-B1Lh9uw_.d.cts → InternalTypes-DxSlzrpu.d.cts} +1 -1
- package/dist/composition.d.cts +2 -2
- package/dist/composition.d.ts +2 -2
- package/dist/core.cjs +2 -2
- package/dist/core.d.cts +3 -3
- package/dist/core.d.ts +3 -3
- package/dist/core.mjs +2 -2
- package/dist/data.cjs +1040 -535
- package/dist/data.d.cts +497 -310
- package/dist/data.d.ts +497 -310
- package/dist/data.mjs +1040 -535
- package/dist/{index-Bs8En5LJ.d.cts → index-CTe9CCHY.d.cts} +3 -0
- package/dist/{index-Bs8En5LJ.d.ts → index-CTe9CCHY.d.ts} +3 -0
- package/dist/{index-B07Wr815.d.ts → index-CdzHrj62.d.ts} +792 -444
- package/dist/{index-DCK_VPog.d.cts → index-NYjtX7XS.d.cts} +792 -444
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +2 -2
- package/dist/types.cjs +5 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.mjs +5 -1
- package/package.json +20 -19
package/README.md
CHANGED
|
@@ -19,8 +19,8 @@ propagation, unhandled async rejections, race conditions, and verbose nested spr
|
|
|
19
19
|
|
|
20
20
|
`pipelined` provides discriminated unions and pure combinators to model these conditions explicitly:
|
|
21
21
|
`Maybe` for absence, `Result` for typed failures, `Validation` for multi-error accumulation,
|
|
22
|
-
`Task.Result` for lazy infallible async, `Op` for declarative request concurrency, and `
|
|
23
|
-
typed event
|
|
22
|
+
`Task.Result` for lazy infallible async, `Op` for declarative request concurrency, and `EventBus`
|
|
23
|
+
for typed event dispatching and sequence funnels.
|
|
24
24
|
|
|
25
25
|
The library has zero external dependencies, <11 KB core gzipped (<17 KB total), and compiles to dual
|
|
26
26
|
ESM and CommonJS distributions.
|
|
@@ -205,6 +205,19 @@ if (Validation.is.failed(outcome)) {
|
|
|
205
205
|
console.log(outcome.errors);
|
|
206
206
|
// ["Username must be at least 3 characters", "Email must contain an @ symbol"]
|
|
207
207
|
}
|
|
208
|
+
|
|
209
|
+
// Or keep errors partitioned per field for UI forms:
|
|
210
|
+
const validateForm = Validation.keyed.make({
|
|
211
|
+
username: validateUsername,
|
|
212
|
+
email: validateEmail,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const formState = validateForm({ username: "a", email: "invalid" });
|
|
216
|
+
|
|
217
|
+
if (Validation.keyed.is.failed(formState)) {
|
|
218
|
+
const errors = Validation.keyed.getErrors(formState);
|
|
219
|
+
// Some({ username: ["Username must be at least 3 characters"], email: ["Email must contain an @ symbol"] })
|
|
220
|
+
}
|
|
208
221
|
```
|
|
209
222
|
|
|
210
223
|
### Eliminating impossible UI states
|
|
@@ -287,7 +300,7 @@ const fetchUser = Op.interpret(
|
|
|
287
300
|
Op.create(
|
|
288
301
|
(signal) => (id: string) =>
|
|
289
302
|
fetch(`/users/${id}`, { signal }).then((r) => r.json() as Promise<User>),
|
|
290
|
-
(e) => new ApiError(e),
|
|
303
|
+
{ onError: (e) => new ApiError(e) },
|
|
291
304
|
),
|
|
292
305
|
{
|
|
293
306
|
strategy: "restartable",
|
|
@@ -334,7 +347,7 @@ const searchOp = Op.create(
|
|
|
334
347
|
fetch(`/search?q=${query}`, { signal }).then((r) =>
|
|
335
348
|
r.json() as Promise<SearchResult[]>
|
|
336
349
|
),
|
|
337
|
-
(e) => new SearchError(e),
|
|
350
|
+
{ onError: (e) => new SearchError(e) },
|
|
338
351
|
);
|
|
339
352
|
|
|
340
353
|
const search = Op.interpret(searchOp, {
|
|
@@ -360,7 +373,7 @@ const submitOp = Op.create(
|
|
|
360
373
|
fetch("/orders", { method: "POST", body: data, signal }).then((r) =>
|
|
361
374
|
r.json()
|
|
362
375
|
),
|
|
363
|
-
(e) => new ApiError(e),
|
|
376
|
+
{ onError: (e) => new ApiError(e) },
|
|
364
377
|
);
|
|
365
378
|
|
|
366
379
|
const submit = Op.interpret(submitOp, {
|
|
@@ -382,14 +395,14 @@ form.addEventListener("submit", (e) => {
|
|
|
382
395
|
The system supports a variety of built-in strategies — `restartable`, `exclusive`, `debounced`,
|
|
383
396
|
`throttled`, `queue`, `buffered`, `concurrent`, `keyed`, and `once`.
|
|
384
397
|
|
|
385
|
-
###
|
|
398
|
+
### Typed event dispatching, sequence funnels, and queue safety
|
|
386
399
|
|
|
387
400
|
Decoupling event producers from stateful event consumers often leads to untyped event emitters or
|
|
388
|
-
recursive call stack crashes during event cascades. `
|
|
389
|
-
typed message schemas, multi-step sequence pattern matching, and causal FIFO queue dispatching:
|
|
401
|
+
recursive call stack crashes during event cascades. `EventBus` models in-memory event dispatching
|
|
402
|
+
with typed message schemas, multi-step sequence pattern matching, and causal FIFO queue dispatching:
|
|
390
403
|
|
|
391
404
|
```ts
|
|
392
|
-
import {
|
|
405
|
+
import { EventBus } from "@nlozgachev/pipelined/core";
|
|
393
406
|
|
|
394
407
|
type UserFlowMessages = {
|
|
395
408
|
sessionStarted: { sessionId: string };
|
|
@@ -398,11 +411,11 @@ type UserFlowMessages = {
|
|
|
398
411
|
flowCancelled: { reason: string };
|
|
399
412
|
};
|
|
400
413
|
|
|
401
|
-
const
|
|
414
|
+
const flowBus = EventBus.make<UserFlowMessages>();
|
|
402
415
|
|
|
403
416
|
// Pattern-match the complete multi-step funnel
|
|
404
|
-
const sub =
|
|
405
|
-
|
|
417
|
+
const sub = EventBus.listen(
|
|
418
|
+
flowBus,
|
|
406
419
|
["sessionStarted", "stepCompleted", "flowFinished"],
|
|
407
420
|
{ ordered: true, reset: "flowCancelled" },
|
|
408
421
|
).reduce(
|
|
@@ -415,18 +428,18 @@ const sub = Stream.listen(
|
|
|
415
428
|
{ completedFlows: 0 },
|
|
416
429
|
);
|
|
417
430
|
|
|
418
|
-
// Emit typed messages to the
|
|
419
|
-
|
|
431
|
+
// Emit typed messages to the event bus
|
|
432
|
+
EventBus.emit(flowBus, {
|
|
420
433
|
kind: "sessionStarted",
|
|
421
434
|
value: { sessionId: "sess-101" },
|
|
422
435
|
});
|
|
423
436
|
|
|
424
|
-
|
|
437
|
+
EventBus.emit(flowBus, {
|
|
425
438
|
kind: "stepCompleted",
|
|
426
439
|
value: { stepName: "onboarding" },
|
|
427
440
|
});
|
|
428
441
|
|
|
429
|
-
|
|
442
|
+
EventBus.emit(flowBus, {
|
|
430
443
|
kind: "flowFinished",
|
|
431
444
|
value: { totalTimeMs: 4200 },
|
|
432
445
|
});
|
|
@@ -434,7 +447,7 @@ Stream.emit(flowStream, {
|
|
|
434
447
|
sub.getState(); // { completedFlows: 1 }
|
|
435
448
|
```
|
|
436
449
|
|
|
437
|
-
`
|
|
450
|
+
`EventBus` executes cascading events iteratively using an internal queue with O(1) stack overhead,
|
|
438
451
|
completely preventing stack overflow crashes and out-of-order re-entrant execution.
|
|
439
452
|
|
|
440
453
|
### Deep immutable updates without spread boilerplate
|
|
@@ -504,44 +517,44 @@ if (Result.is.ok(email)) {
|
|
|
504
517
|
|
|
505
518
|
## Quick Reference
|
|
506
519
|
|
|
507
|
-
| Problem to Solve
|
|
508
|
-
|
|
|
509
|
-
| Optional values without `null` / `undefined` checks
|
|
510
|
-
| Synchronous typed errors without `try`/`catch`
|
|
511
|
-
| Multi-field form and batch validation error accumulation
|
|
512
|
-
| Lazy async workflows with automatic `AbortSignal`
|
|
513
|
-
| Infallible async return container for tasks
|
|
514
|
-
| Eliminating impossible UI loading/error/data states
|
|
515
|
-
| Managing request race conditions, retries, and locks
|
|
516
|
-
| In-memory event
|
|
517
|
-
| Deep nested immutable updates without spread boilerplate
|
|
518
|
-
| Implicit dependency injection without prop drilling
|
|
519
|
-
| Pure state transitions, tokenizers, and parsers
|
|
520
|
-
| Deterministic bracket cleanup (DB pools, file locks)
|
|
521
|
-
| Deferred computation memoized on first access
|
|
522
|
-
| Pure calculation audit trails and decision logging
|
|
523
|
-
| Inclusive-OR data modeling and two-way sync diffs
|
|
524
|
-
| Deep structural equality & React component memoization
|
|
525
|
-
| Multi-column table sorting with tiebreakers
|
|
526
|
-
| Composable boolean filter pipelines & authorization policies
|
|
527
|
-
| Runtime type narrowing & custom type guard composition
|
|
528
|
-
| Merging configurations & metric structures (Monoids)
|
|
529
|
-
| Strongly-typed immutable pair manipulation
|
|
530
|
-
| Point-free, bounds-safe array transformations
|
|
531
|
-
| Type-safe object manipulation & key migration
|
|
532
|
-
| Insertion-ordered maps with non-string keys
|
|
533
|
-
| Immutable sets & role/permission algebra
|
|
534
|
-
| String sanitization, numeric conversion & slug parsing
|
|
535
|
-
| Boundary clamping & division-by-zero protection
|
|
536
|
-
| Financial ledger arithmetic without float precision drift
|
|
537
|
-
| Safe JSON parsing & circular reference protection
|
|
538
|
-
| Nominal typing & security boundary gates
|
|
539
|
-
| Explicit, unit-safe time spans & timeout policies
|
|
540
|
-
| Left-to-right value pipeline execution
|
|
541
|
-
| Left-to-right and right-to-left function composition
|
|
542
|
-
| Currying, uncurrying, and argument flipping
|
|
543
|
-
| Multi-branch argument routing and combining
|
|
544
|
-
| Pure function memoization, predicates & pipeline side-effects
|
|
520
|
+
| Problem to Solve | Module | Import Path |
|
|
521
|
+
| ------------------------------------------------------------------ | ----------------------------- | ----------------------------------- |
|
|
522
|
+
| Optional values without `null` / `undefined` checks | `Maybe` | `@nlozgachev/pipelined/core` |
|
|
523
|
+
| Synchronous typed errors without `try`/`catch` | `Result` | `@nlozgachev/pipelined/core` |
|
|
524
|
+
| Multi-field form and batch validation error accumulation | `Validation` | `@nlozgachev/pipelined/core` |
|
|
525
|
+
| Lazy async workflows with automatic `AbortSignal` | `Task.Result`, `Task` | `@nlozgachev/pipelined/core` |
|
|
526
|
+
| Infallible async return container for tasks | `Deferred` | `@nlozgachev/pipelined/core` |
|
|
527
|
+
| Eliminating impossible UI loading/error/data states | `RemoteData` | `@nlozgachev/pipelined/core` |
|
|
528
|
+
| Managing request race conditions, retries, and locks | `Op` | `@nlozgachev/pipelined/core` |
|
|
529
|
+
| In-memory typed event dispatching, sequence funnels & queue safety | `EventBus` | `@nlozgachev/pipelined/core` |
|
|
530
|
+
| Deep nested immutable updates without spread boilerplate | `Lens`, `Optional` | `@nlozgachev/pipelined/core` |
|
|
531
|
+
| Implicit dependency injection without prop drilling | `Reader` | `@nlozgachev/pipelined/core` |
|
|
532
|
+
| Pure state transitions, tokenizers, and parsers | `State` | `@nlozgachev/pipelined/core` |
|
|
533
|
+
| Deterministic bracket cleanup (DB pools, file locks) | `Resource` | `@nlozgachev/pipelined/core` |
|
|
534
|
+
| Deferred computation memoized on first access | `Lazy` | `@nlozgachev/pipelined/core` |
|
|
535
|
+
| Pure calculation audit trails and decision logging | `Logged` | `@nlozgachev/pipelined/core` |
|
|
536
|
+
| Inclusive-OR data modeling and two-way sync diffs | `These` | `@nlozgachev/pipelined/core` |
|
|
537
|
+
| Deep structural equality & React component memoization | `Equality` | `@nlozgachev/pipelined/core` |
|
|
538
|
+
| Multi-column table sorting with tiebreakers | `Ordering` | `@nlozgachev/pipelined/core` |
|
|
539
|
+
| Composable boolean filter pipelines & authorization policies | `Predicate` | `@nlozgachev/pipelined/core` |
|
|
540
|
+
| Runtime type narrowing & custom type guard composition | `Refinement` | `@nlozgachev/pipelined/core` |
|
|
541
|
+
| Merging configurations & metric structures (Monoids) | `Combinable` | `@nlozgachev/pipelined/core` |
|
|
542
|
+
| Strongly-typed immutable pair manipulation | `Pair` | `@nlozgachev/pipelined/core` |
|
|
543
|
+
| Point-free, bounds-safe array transformations | `Arr`, `Arr.NonEmpty` | `@nlozgachev/pipelined/data` |
|
|
544
|
+
| Type-safe object manipulation & key migration | `Rec`, `Rec.NonEmpty` | `@nlozgachev/pipelined/data` |
|
|
545
|
+
| Insertion-ordered maps with non-string keys | `Dict`, `Dict.NonEmpty` | `@nlozgachev/pipelined/data` |
|
|
546
|
+
| Immutable sets & role/permission algebra | `Uniq` | `@nlozgachev/pipelined/data` |
|
|
547
|
+
| String sanitization, numeric conversion & slug parsing | `Str` | `@nlozgachev/pipelined/data` |
|
|
548
|
+
| Boundary clamping & division-by-zero protection | `Num` | `@nlozgachev/pipelined/data` |
|
|
549
|
+
| Financial ledger arithmetic without float precision drift | `BigNum` | `@nlozgachev/pipelined/data` |
|
|
550
|
+
| Safe JSON parsing & circular reference protection | `Json` | `@nlozgachev/pipelined/data` |
|
|
551
|
+
| Nominal typing & security boundary gates | `Brand` | `@nlozgachev/pipelined/types` |
|
|
552
|
+
| Explicit, unit-safe time spans & timeout policies | `Duration`, `RetryPolicy` | `@nlozgachev/pipelined/types` |
|
|
553
|
+
| Left-to-right value pipeline execution | `pipe` | `@nlozgachev/pipelined/composition` |
|
|
554
|
+
| Left-to-right and right-to-left function composition | `flow`, `compose` | `@nlozgachev/pipelined/composition` |
|
|
555
|
+
| Currying, uncurrying, and argument flipping | `curry`, `uncurry`, `flip` | `@nlozgachev/pipelined/composition` |
|
|
556
|
+
| Multi-branch argument routing and combining | `converge`, `juxt`, `on` | `@nlozgachev/pipelined/composition` |
|
|
557
|
+
| Pure function memoization, predicates & pipeline side-effects | `memoize`, `tap`, `not`, `fn` | `@nlozgachev/pipelined/composition` |
|
|
545
558
|
|
|
546
559
|
---
|
|
547
560
|
|
|
@@ -552,11 +565,11 @@ if (Result.is.ok(email)) {
|
|
|
552
565
|
- **`@nlozgachev/pipelined/core`**: Core context containers, async runtimes, optics, and logic
|
|
553
566
|
abstractions (<11 KB gzipped).
|
|
554
567
|
- **`@nlozgachev/pipelined/data`**: Curried, data-last utilities for collections, numbers, strings,
|
|
555
|
-
and JSON (<
|
|
568
|
+
and JSON (<10 KB gzipped).
|
|
556
569
|
- **`@nlozgachev/pipelined/composition`**: Pure higher-order function combinators (`pipe`, `flow`,
|
|
557
570
|
`compose`, `curry`, `uncurry`, `converge`, `juxt`, `memoize`, `tap`, `on`, `not`, `flip`, `fn`)
|
|
558
571
|
(<2 KB gzipped).
|
|
559
|
-
- **`@nlozgachev/pipelined/types`**: Type-level utilities (`Brand`, `Duration`, `RetryPolicy`) (<
|
|
572
|
+
- **`@nlozgachev/pipelined/types`**: Type-level utilities (`Brand`, `Duration`, `RetryPolicy`) (<450
|
|
560
573
|
B gzipped).
|
|
561
574
|
|
|
562
575
|
Every utility in the library is benchmarked against its native equivalent. While currying introduces
|