@barnum/barnum 0.0.0-main-ef6df91f → 0.0.0-main-e8b82cff

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/src/builtins.ts CHANGED
@@ -1,4 +1,12 @@
1
- import { type Action, type Option as OptionT, type Pipeable, type Result as ResultT, type TaggedUnion, type TypedAction, typedAction } from "./ast.js";
1
+ import {
2
+ type Action,
3
+ type Option as OptionT,
4
+ type Pipeable,
5
+ type Result as ResultT,
6
+ type TaggedUnion,
7
+ type TypedAction,
8
+ typedAction,
9
+ } from "./ast.js";
2
10
  import { chain } from "./chain.js";
3
11
 
4
12
  /**
@@ -51,9 +59,7 @@ export const drop: TypedAction<any, never> = typedAction({
51
59
  export function tag<
52
60
  TDef extends Record<string, unknown>,
53
61
  TKind extends keyof TDef & string,
54
- >(
55
- kind: TKind,
56
- ): TypedAction<TDef[TKind], TaggedUnion<TDef>> {
62
+ >(kind: TKind): TypedAction<TDef[TKind], TaggedUnion<TDef>> {
57
63
  return typedAction({
58
64
  kind: "Invoke",
59
65
  handler: { kind: "Builtin", builtin: { kind: "Tag", value: kind } },
@@ -112,10 +118,9 @@ export function extractField<
112
118
  // ExtractIndex — extract a single element from an array by index
113
119
  // ---------------------------------------------------------------------------
114
120
 
115
- export function extractIndex<
116
- TTuple extends unknown[],
117
- TIndex extends number,
118
- >(index: TIndex): TypedAction<TTuple, TTuple[TIndex]> {
121
+ export function extractIndex<TTuple extends unknown[], TIndex extends number>(
122
+ index: TIndex,
123
+ ): TypedAction<TTuple, TTuple[TIndex]> {
119
124
  return typedAction({
120
125
  kind: "Invoke",
121
126
  handler: {
@@ -151,7 +156,10 @@ export function dropResult<TInput, TOutput, TRefs extends string = never>(
151
156
  return typedAction({
152
157
  kind: "Chain",
153
158
  first: action as Action,
154
- rest: { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Drop" } } },
159
+ rest: {
160
+ kind: "Invoke",
161
+ handler: { kind: "Builtin", builtin: { kind: "Drop" } },
162
+ },
155
163
  });
156
164
  }
157
165
 
@@ -205,13 +213,19 @@ export function withResource<
205
213
 
206
214
  // Step 2: all(action, identity) → [TOut, TResource & TIn]
207
215
  // Keep merged object so dispose can access resource fields.
208
- const actionAndKeepMerged = typedAction<TResource & TIn, [TOut, TResource & TIn]>({
216
+ const actionAndKeepMerged = typedAction<
217
+ TResource & TIn,
218
+ [TOut, TResource & TIn]
219
+ >({
209
220
  kind: "All",
210
221
  actions: [action as Action, identity as Action],
211
222
  });
212
223
 
213
224
  // Step 3: all(extractIndex(0), chain(extractIndex(1), dispose)) → [TOut, unknown]
214
- const disposeAndKeepResult = typedAction<[TOut, TResource & TIn], [TOut, unknown]>({
225
+ const disposeAndKeepResult = typedAction<
226
+ [TOut, TResource & TIn],
227
+ [TOut, unknown]
228
+ >({
215
229
  kind: "All",
216
230
  actions: [
217
231
  extractIndex<[TOut, TResource & TIn], 0>(0) as Action,
@@ -257,7 +271,10 @@ export function augment<
257
271
  kind: "All",
258
272
  actions: [action as Action, identity as Action],
259
273
  },
260
- rest: { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Merge" } } },
274
+ rest: {
275
+ kind: "Invoke",
276
+ handler: { kind: "Builtin", builtin: { kind: "Merge" } },
277
+ },
261
278
  });
262
279
  }
263
280
 
@@ -277,9 +294,10 @@ export function augment<
277
294
  * Example:
278
295
  * pipe(tap(pipe(pick("worktreePath", "description"), implement)), createPR)
279
296
  */
280
- export function tap<TInput extends Record<string, unknown>, TRefs extends string = never>(
281
- action: Pipeable<TInput, any, TRefs>,
282
- ): TypedAction<TInput, TInput, TRefs> {
297
+ export function tap<
298
+ TInput extends Record<string, unknown>,
299
+ TRefs extends string = never,
300
+ >(action: Pipeable<TInput, any, TRefs>): TypedAction<TInput, TInput, TRefs> {
283
301
  // Build AST directly — internal plumbing (action → constant → augment)
284
302
  // can't go through typed chain/augment with invariant phantom fields.
285
303
  // tap: all(chain(action, constant({})), identity()) → merge
@@ -291,12 +309,24 @@ export function tap<TInput extends Record<string, unknown>, TRefs extends string
291
309
  {
292
310
  kind: "Chain",
293
311
  first: action as Action,
294
- rest: { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: {} } } },
312
+ rest: {
313
+ kind: "Invoke",
314
+ handler: {
315
+ kind: "Builtin",
316
+ builtin: { kind: "Constant", value: {} },
317
+ },
318
+ },
319
+ },
320
+ {
321
+ kind: "Invoke",
322
+ handler: { kind: "Builtin", builtin: { kind: "Identity" } },
295
323
  },
296
- { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Identity" } } },
297
324
  ],
298
325
  },
299
- rest: { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Merge" } } },
326
+ rest: {
327
+ kind: "Invoke",
328
+ handler: { kind: "Builtin", builtin: { kind: "Merge" } },
329
+ },
300
330
  });
301
331
  }
302
332
 
@@ -304,10 +334,7 @@ export function tap<TInput extends Record<string, unknown>, TRefs extends string
304
334
  // Range — produce an integer array [start, start+1, ..., end-1]
305
335
  // ---------------------------------------------------------------------------
306
336
 
307
- export function range(
308
- start: number,
309
- end: number,
310
- ): TypedAction<any, number[]> {
337
+ export function range(start: number, end: number): TypedAction<any, number[]> {
311
338
  const result: number[] = [];
312
339
  for (let i = start; i < end; i++) {
313
340
  result.push(i);
@@ -323,11 +350,29 @@ export function range(
323
350
  // ---------------------------------------------------------------------------
324
351
 
325
352
  // Shared AST fragments for Option desugaring
326
- const TAG_SOME: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Some" } } };
327
- const TAG_NONE: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Tag", value: "None" } } };
328
- const EXTRACT_VALUE: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "ExtractField", value: "value" } } };
329
- const DROP: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Drop" } } };
330
- const IDENTITY: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Identity" } } };
353
+ const TAG_SOME: Action = {
354
+ kind: "Invoke",
355
+ handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Some" } },
356
+ };
357
+ const TAG_NONE: Action = {
358
+ kind: "Invoke",
359
+ handler: { kind: "Builtin", builtin: { kind: "Tag", value: "None" } },
360
+ };
361
+ const EXTRACT_VALUE: Action = {
362
+ kind: "Invoke",
363
+ handler: {
364
+ kind: "Builtin",
365
+ builtin: { kind: "ExtractField", value: "value" },
366
+ },
367
+ };
368
+ const DROP: Action = {
369
+ kind: "Invoke",
370
+ handler: { kind: "Builtin", builtin: { kind: "Drop" } },
371
+ };
372
+ const IDENTITY: Action = {
373
+ kind: "Invoke",
374
+ handler: { kind: "Builtin", builtin: { kind: "Identity" } },
375
+ };
331
376
 
332
377
  /** Wrap branch cases with ExtractField("value") auto-unwrapping. */
333
378
  function optionBranch(someCaseBody: Action, noneCaseBody: Action): Action {
@@ -370,10 +415,12 @@ export const Option = {
370
415
  * Desugars to: `branch({ Some: pipe(action, tag("Some")), None: tag("None") })`
371
416
  */
372
417
  map<T, U>(action: Pipeable<T, U>): TypedAction<OptionT<T>, OptionT<U>> {
373
- return typedAction(optionBranch(
374
- { kind: "Chain", first: action as Action, rest: TAG_SOME },
375
- TAG_NONE,
376
- ));
418
+ return typedAction(
419
+ optionBranch(
420
+ { kind: "Chain", first: action as Action, rest: TAG_SOME },
421
+ TAG_NONE,
422
+ ),
423
+ );
377
424
  },
378
425
 
379
426
  /**
@@ -385,11 +432,10 @@ export const Option = {
385
432
  *
386
433
  * Desugars to: `branch({ Some: action, None: tag("None") })`
387
434
  */
388
- andThen<T, U>(action: Pipeable<T, OptionT<U>>): TypedAction<OptionT<T>, OptionT<U>> {
389
- return typedAction(optionBranch(
390
- action as Action,
391
- TAG_NONE,
392
- ));
435
+ andThen<T, U>(
436
+ action: Pipeable<T, OptionT<U>>,
437
+ ): TypedAction<OptionT<T>, OptionT<U>> {
438
+ return typedAction(optionBranch(action as Action, TAG_NONE));
393
439
  },
394
440
 
395
441
  /**
@@ -410,7 +456,11 @@ export const Option = {
410
456
  kind: "Branch",
411
457
  cases: {
412
458
  Some: { kind: "Chain", first: EXTRACT_VALUE, rest: IDENTITY },
413
- None: { kind: "Chain", first: EXTRACT_VALUE, rest: { kind: "Chain", first: DROP, rest: defaultAction as Action } },
459
+ None: {
460
+ kind: "Chain",
461
+ first: EXTRACT_VALUE,
462
+ rest: { kind: "Chain", first: DROP, rest: defaultAction as Action },
463
+ },
414
464
  },
415
465
  });
416
466
  },
@@ -421,10 +471,7 @@ export const Option = {
421
471
  * Desugars to: `branch({ Some: identity(), None: tag("None") })`
422
472
  */
423
473
  flatten<T>(): TypedAction<OptionT<OptionT<T>>, OptionT<T>> {
424
- return typedAction(optionBranch(
425
- IDENTITY,
426
- TAG_NONE,
427
- ));
474
+ return typedAction(optionBranch(IDENTITY, TAG_NONE));
428
475
  },
429
476
 
430
477
  /**
@@ -437,11 +484,10 @@ export const Option = {
437
484
  *
438
485
  * Desugars to: `branch({ Some: predicate, None: tag("None") })`
439
486
  */
440
- filter<T>(predicate: Pipeable<T, OptionT<T>>): TypedAction<OptionT<T>, OptionT<T>> {
441
- return typedAction(optionBranch(
442
- predicate as Action,
443
- TAG_NONE,
444
- ));
487
+ filter<T>(
488
+ predicate: Pipeable<T, OptionT<T>>,
489
+ ): TypedAction<OptionT<T>, OptionT<T>> {
490
+ return typedAction(optionBranch(predicate as Action, TAG_NONE));
445
491
  },
446
492
 
447
493
  /**
@@ -467,12 +513,20 @@ export const Option = {
467
513
  * Desugars to: `branch({ Some: pipe(drop(), constant(true)), None: pipe(drop(), constant(false)) })`
468
514
  */
469
515
  isSome<T>(): TypedAction<OptionT<T>, boolean> {
470
- const constTrue: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } } };
471
- const constFalse: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } } };
472
- return typedAction(optionBranch(
473
- { kind: "Chain", first: DROP, rest: constTrue },
474
- { kind: "Chain", first: DROP, rest: constFalse },
475
- ));
516
+ const constTrue: Action = {
517
+ kind: "Invoke",
518
+ handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
519
+ };
520
+ const constFalse: Action = {
521
+ kind: "Invoke",
522
+ handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
523
+ };
524
+ return typedAction(
525
+ optionBranch(
526
+ { kind: "Chain", first: DROP, rest: constTrue },
527
+ { kind: "Chain", first: DROP, rest: constFalse },
528
+ ),
529
+ );
476
530
  },
477
531
 
478
532
  /**
@@ -483,12 +537,20 @@ export const Option = {
483
537
  * Desugars to: `branch({ Some: pipe(drop(), constant(false)), None: pipe(drop(), constant(true)) })`
484
538
  */
485
539
  isNone<T>(): TypedAction<OptionT<T>, boolean> {
486
- const constTrue: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } } };
487
- const constFalse: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } } };
488
- return typedAction(optionBranch(
489
- { kind: "Chain", first: DROP, rest: constFalse },
490
- { kind: "Chain", first: DROP, rest: constTrue },
491
- ));
540
+ const constTrue: Action = {
541
+ kind: "Invoke",
542
+ handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
543
+ };
544
+ const constFalse: Action = {
545
+ kind: "Invoke",
546
+ handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
547
+ };
548
+ return typedAction(
549
+ optionBranch(
550
+ { kind: "Chain", first: DROP, rest: constFalse },
551
+ { kind: "Chain", first: DROP, rest: constTrue },
552
+ ),
553
+ );
492
554
  },
493
555
  } as const;
494
556
 
@@ -497,8 +559,14 @@ export const Option = {
497
559
  // ---------------------------------------------------------------------------
498
560
 
499
561
  // Shared AST fragments for Result desugaring
500
- const TAG_OK: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Ok" } } };
501
- const TAG_ERR: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Err" } } };
562
+ const TAG_OK: Action = {
563
+ kind: "Invoke",
564
+ handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Ok" } },
565
+ };
566
+ const TAG_ERR: Action = {
567
+ kind: "Invoke",
568
+ handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Err" } },
569
+ };
502
570
 
503
571
  /** Wrap branch cases with ExtractField("value") auto-unwrapping. */
504
572
  function resultBranch(okCaseBody: Action, errCaseBody: Action): Action {
@@ -538,10 +606,12 @@ export const Result = {
538
606
  map<TValue, TOut, TError>(
539
607
  action: Pipeable<TValue, TOut>,
540
608
  ): TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>> {
541
- return typedAction(resultBranch(
542
- { kind: "Chain", first: action as Action, rest: TAG_OK },
543
- TAG_ERR,
544
- ));
609
+ return typedAction(
610
+ resultBranch(
611
+ { kind: "Chain", first: action as Action, rest: TAG_OK },
612
+ TAG_ERR,
613
+ ),
614
+ );
545
615
  },
546
616
 
547
617
  /**
@@ -552,10 +622,13 @@ export const Result = {
552
622
  mapErr<TValue, TError, TErrorOut>(
553
623
  action: Pipeable<TError, TErrorOut>,
554
624
  ): TypedAction<ResultT<TValue, TError>, ResultT<TValue, TErrorOut>> {
555
- return typedAction(resultBranch(
556
- TAG_OK,
557
- { kind: "Chain", first: action as Action, rest: TAG_ERR },
558
- ));
625
+ return typedAction(
626
+ resultBranch(TAG_OK, {
627
+ kind: "Chain",
628
+ first: action as Action,
629
+ rest: TAG_ERR,
630
+ }),
631
+ );
559
632
  },
560
633
 
561
634
  /**
@@ -567,10 +640,7 @@ export const Result = {
567
640
  andThen<TValue, TOut, TError>(
568
641
  action: Pipeable<TValue, ResultT<TOut, TError>>,
569
642
  ): TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>> {
570
- return typedAction(resultBranch(
571
- action as Action,
572
- TAG_ERR,
573
- ));
643
+ return typedAction(resultBranch(action as Action, TAG_ERR));
574
644
  },
575
645
 
576
646
  /**
@@ -582,10 +652,7 @@ export const Result = {
582
652
  or<TValue, TError, TErrorOut>(
583
653
  fallback: Pipeable<TError, ResultT<TValue, TErrorOut>>,
584
654
  ): TypedAction<ResultT<TValue, TError>, ResultT<TValue, TErrorOut>> {
585
- return typedAction(resultBranch(
586
- TAG_OK,
587
- fallback as Action,
588
- ));
655
+ return typedAction(resultBranch(TAG_OK, fallback as Action));
589
656
  },
590
657
 
591
658
  /**
@@ -597,10 +664,12 @@ export const Result = {
597
664
  and<TValue, TOut, TError>(
598
665
  other: Pipeable<never, ResultT<TOut, TError>>,
599
666
  ): TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>> {
600
- return typedAction(resultBranch(
601
- { kind: "Chain", first: DROP, rest: other as Action },
602
- TAG_ERR,
603
- ));
667
+ return typedAction(
668
+ resultBranch(
669
+ { kind: "Chain", first: DROP, rest: other as Action },
670
+ TAG_ERR,
671
+ ),
672
+ );
604
673
  },
605
674
 
606
675
  /**
@@ -621,10 +690,7 @@ export const Result = {
621
690
  __phantom_out?: () => TValue;
622
691
  },
623
692
  ): TypedAction<ResultT<TValue, TError>, TValue> {
624
- return typedAction(resultBranch(
625
- IDENTITY,
626
- defaultAction as Action,
627
- ));
693
+ return typedAction(resultBranch(IDENTITY, defaultAction as Action));
628
694
  },
629
695
 
630
696
  /**
@@ -632,11 +698,11 @@ export const Result = {
632
698
  *
633
699
  * Desugars to: `branch({ Ok: identity(), Err: tag("Err") })`
634
700
  */
635
- flatten<TValue, TError>(): TypedAction<ResultT<ResultT<TValue, TError>, TError>, ResultT<TValue, TError>> {
636
- return typedAction(resultBranch(
637
- IDENTITY,
638
- TAG_ERR,
639
- ));
701
+ flatten<TValue, TError>(): TypedAction<
702
+ ResultT<ResultT<TValue, TError>, TError>,
703
+ ResultT<TValue, TError>
704
+ > {
705
+ return typedAction(resultBranch(IDENTITY, TAG_ERR));
640
706
  },
641
707
 
642
708
  /**
@@ -644,11 +710,13 @@ export const Result = {
644
710
  *
645
711
  * Desugars to: `branch({ Ok: tag("Some"), Err: pipe(drop(), tag("None")) })`
646
712
  */
647
- toOption<TValue, TError>(): TypedAction<ResultT<TValue, TError>, OptionT<TValue>> {
648
- return typedAction(resultBranch(
649
- TAG_SOME,
650
- { kind: "Chain", first: DROP, rest: TAG_NONE },
651
- ));
713
+ toOption<TValue, TError>(): TypedAction<
714
+ ResultT<TValue, TError>,
715
+ OptionT<TValue>
716
+ > {
717
+ return typedAction(
718
+ resultBranch(TAG_SOME, { kind: "Chain", first: DROP, rest: TAG_NONE }),
719
+ );
652
720
  },
653
721
 
654
722
  /**
@@ -656,53 +724,84 @@ export const Result = {
656
724
  *
657
725
  * Desugars to: `branch({ Ok: pipe(drop(), tag("None")), Err: tag("Some") })`
658
726
  */
659
- toOptionErr<TValue, TError>(): TypedAction<ResultT<TValue, TError>, OptionT<TError>> {
660
- return typedAction(resultBranch(
661
- { kind: "Chain", first: DROP, rest: TAG_NONE },
662
- TAG_SOME,
663
- ));
727
+ toOptionErr<TValue, TError>(): TypedAction<
728
+ ResultT<TValue, TError>,
729
+ OptionT<TError>
730
+ > {
731
+ return typedAction(
732
+ resultBranch({ kind: "Chain", first: DROP, rest: TAG_NONE }, TAG_SOME),
733
+ );
664
734
  },
665
735
 
666
736
  /**
667
737
  * Swap Result/Option nesting.
668
738
  * `Result<Option<TValue>, TError> → Option<Result<TValue, TError>>`
669
739
  */
670
- transpose<TValue, TError>(): TypedAction<ResultT<OptionT<TValue>, TError>, OptionT<ResultT<TValue, TError>>> {
671
- return typedAction(resultBranch(
672
- // Ok case: receives Option<TValue>, branch on Some/None
673
- {
674
- kind: "Branch",
675
- cases: {
676
- Some: { kind: "Chain", first: EXTRACT_VALUE, rest: { kind: "Chain", first: TAG_OK, rest: TAG_SOME } },
677
- None: { kind: "Chain", first: EXTRACT_VALUE, rest: { kind: "Chain", first: DROP, rest: TAG_NONE } },
740
+ transpose<TValue, TError>(): TypedAction<
741
+ ResultT<OptionT<TValue>, TError>,
742
+ OptionT<ResultT<TValue, TError>>
743
+ > {
744
+ return typedAction(
745
+ resultBranch(
746
+ // Ok case: receives Option<TValue>, branch on Some/None
747
+ {
748
+ kind: "Branch",
749
+ cases: {
750
+ Some: {
751
+ kind: "Chain",
752
+ first: EXTRACT_VALUE,
753
+ rest: { kind: "Chain", first: TAG_OK, rest: TAG_SOME },
754
+ },
755
+ None: {
756
+ kind: "Chain",
757
+ first: EXTRACT_VALUE,
758
+ rest: { kind: "Chain", first: DROP, rest: TAG_NONE },
759
+ },
760
+ },
678
761
  },
679
- },
680
- // Err case: receives TError, wrap as Result.err then Option.some
681
- { kind: "Chain", first: TAG_ERR, rest: TAG_SOME },
682
- ));
762
+ // Err case: receives TError, wrap as Result.err then Option.some
763
+ { kind: "Chain", first: TAG_ERR, rest: TAG_SOME },
764
+ ),
765
+ );
683
766
  },
684
767
 
685
768
  /**
686
769
  * Test if the value is Ok. `Result<TValue, TError> → boolean`
687
770
  */
688
771
  isOk<TValue, TError>(): TypedAction<ResultT<TValue, TError>, boolean> {
689
- const constTrue: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } } };
690
- const constFalse: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } } };
691
- return typedAction(resultBranch(
692
- { kind: "Chain", first: DROP, rest: constTrue },
693
- { kind: "Chain", first: DROP, rest: constFalse },
694
- ));
772
+ const constTrue: Action = {
773
+ kind: "Invoke",
774
+ handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
775
+ };
776
+ const constFalse: Action = {
777
+ kind: "Invoke",
778
+ handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
779
+ };
780
+ return typedAction(
781
+ resultBranch(
782
+ { kind: "Chain", first: DROP, rest: constTrue },
783
+ { kind: "Chain", first: DROP, rest: constFalse },
784
+ ),
785
+ );
695
786
  },
696
787
 
697
788
  /**
698
789
  * Test if the value is Err. `Result<TValue, TError> → boolean`
699
790
  */
700
791
  isErr<TValue, TError>(): TypedAction<ResultT<TValue, TError>, boolean> {
701
- const constTrue: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } } };
702
- const constFalse: Action = { kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } } };
703
- return typedAction(resultBranch(
704
- { kind: "Chain", first: DROP, rest: constFalse },
705
- { kind: "Chain", first: DROP, rest: constTrue },
706
- ));
792
+ const constTrue: Action = {
793
+ kind: "Invoke",
794
+ handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
795
+ };
796
+ const constFalse: Action = {
797
+ kind: "Invoke",
798
+ handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
799
+ };
800
+ return typedAction(
801
+ resultBranch(
802
+ { kind: "Chain", first: DROP, rest: constFalse },
803
+ { kind: "Chain", first: DROP, rest: constTrue },
804
+ ),
805
+ );
707
806
  },
708
807
  } as const;
package/src/chain.ts CHANGED
@@ -1,8 +1,17 @@
1
- import { type Action, type Pipeable, type TypedAction, typedAction } from "./ast.js";
1
+ import {
2
+ type Action,
3
+ type Pipeable,
4
+ type TypedAction,
5
+ typedAction,
6
+ } from "./ast.js";
2
7
 
3
8
  export function chain<T1, T2, T3, R1 extends string, R2 extends string>(
4
9
  first: Pipeable<T1, T2, R1>,
5
10
  rest: Pipeable<T2, T3, R2>,
6
11
  ): TypedAction<T1, T3, R1 | R2> {
7
- return typedAction({ kind: "Chain", first: first as Action, rest: rest as Action });
12
+ return typedAction({
13
+ kind: "Chain",
14
+ first: first as Action,
15
+ rest: rest as Action,
16
+ });
8
17
  }
package/src/effect-id.ts CHANGED
@@ -2,14 +2,29 @@
2
2
  // Shared effect ID counter for gensym'd effect identifiers
3
3
  // ---------------------------------------------------------------------------
4
4
 
5
- let nextEffectId = 0;
5
+ /** Branded ID for resume-style effect handlers. */
6
+ export type ResumeHandlerId = number & {
7
+ readonly __resumeHandlerBrand: unique symbol;
8
+ };
6
9
 
7
- /** Allocate a fresh, unique effect ID. */
8
- export function allocateEffectId(): number {
9
- return nextEffectId++;
10
+ /** Branded ID for restart-style effect handlers. */
11
+ export type RestartHandlerId = number & {
12
+ readonly __restartHandlerBrand: unique symbol;
13
+ };
14
+
15
+ let nextId = 0;
16
+
17
+ /** Allocate a fresh, unique resume handler ID. */
18
+ export function allocateResumeHandlerId(): ResumeHandlerId {
19
+ return nextId++ as ResumeHandlerId;
20
+ }
21
+
22
+ /** Allocate a fresh, unique restart handler ID. */
23
+ export function allocateRestartHandlerId(): RestartHandlerId {
24
+ return nextId++ as RestartHandlerId;
10
25
  }
11
26
 
12
- /** Reset the effect ID counter. For test isolation only. */
27
+ /** Reset the ID counter. For test isolation only. */
13
28
  export function resetEffectIdCounter(): void {
14
- nextEffectId = 0;
29
+ nextId = 0;
15
30
  }