@typed/fx 2.0.0-beta.1 → 2.0.0-beta.10
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/LICENSE +21 -0
- package/README.md +35 -21
- package/dist/Fx/Fx.d.ts +371 -19
- package/dist/Fx/Fx.d.ts.map +1 -1
- package/dist/Fx/Fx.js +37 -6
- package/dist/Fx/TypeId.d.ts +52 -6
- package/dist/Fx/TypeId.d.ts.map +1 -1
- package/dist/Fx/TypeId.js +41 -4
- package/dist/Fx/combinators/additive.d.ts +162 -11
- package/dist/Fx/combinators/additive.d.ts.map +1 -1
- package/dist/Fx/combinators/additive.js +162 -11
- package/dist/Fx/combinators/catch.d.ts +202 -29
- package/dist/Fx/combinators/catch.d.ts.map +1 -1
- package/dist/Fx/combinators/catch.js +193 -23
- package/dist/Fx/combinators/causes.d.ts +25 -2
- package/dist/Fx/combinators/causes.d.ts.map +1 -1
- package/dist/Fx/combinators/causes.js +25 -2
- package/dist/Fx/combinators/changesWithEffect.d.ts +21 -1
- package/dist/Fx/combinators/changesWithEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/changesWithEffect.js +21 -1
- package/dist/Fx/combinators/compact.d.ts +18 -1
- package/dist/Fx/combinators/compact.d.ts.map +1 -1
- package/dist/Fx/combinators/compact.js +18 -1
- package/dist/Fx/combinators/concatMap.d.ts +86 -0
- package/dist/Fx/combinators/concatMap.d.ts.map +1 -0
- package/dist/Fx/combinators/concatMap.js +86 -0
- package/dist/Fx/combinators/continueWith.d.ts +113 -5
- package/dist/Fx/combinators/continueWith.d.ts.map +1 -1
- package/dist/Fx/combinators/continueWith.js +113 -5
- package/dist/Fx/combinators/debounce.d.ts +34 -0
- package/dist/Fx/combinators/debounce.d.ts.map +1 -0
- package/dist/Fx/combinators/debounce.js +35 -0
- package/dist/Fx/combinators/delay.d.ts +36 -0
- package/dist/Fx/combinators/delay.d.ts.map +1 -0
- package/dist/Fx/combinators/delay.js +33 -0
- package/dist/Fx/combinators/dropUntil.d.ts +44 -2
- package/dist/Fx/combinators/dropUntil.d.ts.map +1 -1
- package/dist/Fx/combinators/dropUntil.js +44 -2
- package/dist/Fx/combinators/during.d.ts +38 -0
- package/dist/Fx/combinators/during.d.ts.map +1 -0
- package/dist/Fx/combinators/during.js +85 -0
- package/dist/Fx/combinators/ensuring.d.ts +34 -4
- package/dist/Fx/combinators/ensuring.d.ts.map +1 -1
- package/dist/Fx/combinators/ensuring.js +34 -4
- package/dist/Fx/combinators/exhaustLatestMap.d.ts +41 -5
- package/dist/Fx/combinators/exhaustLatestMap.d.ts.map +1 -1
- package/dist/Fx/combinators/exhaustLatestMap.js +41 -5
- package/dist/Fx/combinators/exhaustLatestMapEffect.d.ts +40 -4
- package/dist/Fx/combinators/exhaustLatestMapEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/exhaustLatestMapEffect.js +40 -4
- package/dist/Fx/combinators/exhaustMap.d.ts +38 -1
- package/dist/Fx/combinators/exhaustMap.d.ts.map +1 -1
- package/dist/Fx/combinators/exhaustMap.js +38 -1
- package/dist/Fx/combinators/exhaustMapEffect.d.ts +33 -1
- package/dist/Fx/combinators/exhaustMapEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/exhaustMapEffect.js +33 -1
- package/dist/Fx/combinators/exit.d.ts +23 -2
- package/dist/Fx/combinators/exit.d.ts.map +1 -1
- package/dist/Fx/combinators/exit.js +23 -2
- package/dist/Fx/combinators/filter.d.ts +17 -1
- package/dist/Fx/combinators/filter.d.ts.map +1 -1
- package/dist/Fx/combinators/filter.js +17 -1
- package/dist/Fx/combinators/filterEffect.d.ts +22 -1
- package/dist/Fx/combinators/filterEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/filterEffect.js +22 -1
- package/dist/Fx/combinators/filterMap.d.ts +20 -1
- package/dist/Fx/combinators/filterMap.d.ts.map +1 -1
- package/dist/Fx/combinators/filterMap.js +20 -1
- package/dist/Fx/combinators/filterMapEffect.d.ts +21 -1
- package/dist/Fx/combinators/filterMapEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/filterMapEffect.js +21 -1
- package/dist/Fx/combinators/filterMapLoop.d.ts +20 -1
- package/dist/Fx/combinators/filterMapLoop.d.ts.map +1 -1
- package/dist/Fx/combinators/filterMapLoop.js +20 -1
- package/dist/Fx/combinators/filterMapLoopCause.d.ts +21 -1
- package/dist/Fx/combinators/filterMapLoopCause.d.ts.map +1 -1
- package/dist/Fx/combinators/filterMapLoopCause.js +21 -1
- package/dist/Fx/combinators/filterMapLoopCauseEffect.d.ts +21 -1
- package/dist/Fx/combinators/filterMapLoopCauseEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/filterMapLoopCauseEffect.js +21 -1
- package/dist/Fx/combinators/filterMapLoopEffect.d.ts +21 -1
- package/dist/Fx/combinators/filterMapLoopEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/filterMapLoopEffect.js +21 -1
- package/dist/Fx/combinators/flatMap.d.ts +50 -5
- package/dist/Fx/combinators/flatMap.d.ts.map +1 -1
- package/dist/Fx/combinators/flatMap.js +36 -3
- package/dist/Fx/combinators/flatMapConcurrently.d.ts +51 -4
- package/dist/Fx/combinators/flatMapConcurrently.d.ts.map +1 -1
- package/dist/Fx/combinators/flatMapConcurrently.js +48 -2
- package/dist/Fx/combinators/flatMapConcurrentlyEffect.d.ts +48 -4
- package/dist/Fx/combinators/flatMapConcurrentlyEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/flatMapConcurrentlyEffect.js +40 -2
- package/dist/Fx/combinators/flatMapEffect.d.ts +46 -4
- package/dist/Fx/combinators/flatMapEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/flatMapEffect.js +32 -2
- package/dist/Fx/combinators/flip.d.ts +34 -2
- package/dist/Fx/combinators/flip.d.ts.map +1 -1
- package/dist/Fx/combinators/flip.js +34 -2
- package/dist/Fx/combinators/gen.d.ts +29 -10
- package/dist/Fx/combinators/gen.d.ts.map +1 -1
- package/dist/Fx/combinators/gen.js +28 -4
- package/dist/Fx/combinators/genScoped.d.ts +33 -10
- package/dist/Fx/combinators/genScoped.d.ts.map +1 -1
- package/dist/Fx/combinators/genScoped.js +31 -3
- package/dist/Fx/combinators/grouped.d.ts +89 -0
- package/dist/Fx/combinators/grouped.d.ts.map +1 -0
- package/dist/Fx/combinators/grouped.js +146 -0
- package/dist/Fx/combinators/index.d.ts +35 -0
- package/dist/Fx/combinators/index.d.ts.map +1 -1
- package/dist/Fx/combinators/index.js +35 -0
- package/dist/Fx/combinators/keyed.d.ts +123 -9
- package/dist/Fx/combinators/keyed.d.ts.map +1 -1
- package/dist/Fx/combinators/keyed.js +69 -11
- package/dist/Fx/combinators/loop.d.ts +17 -1
- package/dist/Fx/combinators/loop.d.ts.map +1 -1
- package/dist/Fx/combinators/loop.js +17 -1
- package/dist/Fx/combinators/loopCause.d.ts +18 -1
- package/dist/Fx/combinators/loopCause.d.ts.map +1 -1
- package/dist/Fx/combinators/loopCause.js +18 -1
- package/dist/Fx/combinators/loopCauseEffect.d.ts +19 -1
- package/dist/Fx/combinators/loopCauseEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/loopCauseEffect.js +19 -1
- package/dist/Fx/combinators/loopEffect.d.ts +24 -1
- package/dist/Fx/combinators/loopEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/loopEffect.js +24 -1
- package/dist/Fx/combinators/map.d.ts +46 -1
- package/dist/Fx/combinators/map.d.ts.map +1 -1
- package/dist/Fx/combinators/map.js +43 -1
- package/dist/Fx/combinators/mapBoth.d.ts +20 -1
- package/dist/Fx/combinators/mapBoth.d.ts.map +1 -1
- package/dist/Fx/combinators/mapBoth.js +20 -1
- package/dist/Fx/combinators/mapEffect.d.ts +25 -1
- package/dist/Fx/combinators/mapEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/mapEffect.js +25 -1
- package/dist/Fx/combinators/mapError.d.ts +21 -5
- package/dist/Fx/combinators/mapError.d.ts.map +1 -1
- package/dist/Fx/combinators/mapError.js +21 -5
- package/dist/Fx/combinators/mergeAll.d.ts +35 -1
- package/dist/Fx/combinators/mergeAll.d.ts.map +1 -1
- package/dist/Fx/combinators/mergeAll.js +35 -1
- package/dist/Fx/combinators/mergeOrdered.d.ts +36 -4
- package/dist/Fx/combinators/mergeOrdered.d.ts.map +1 -1
- package/dist/Fx/combinators/mergeOrdered.js +68 -14
- package/dist/Fx/combinators/onError.d.ts +34 -4
- package/dist/Fx/combinators/onError.d.ts.map +1 -1
- package/dist/Fx/combinators/onError.js +34 -4
- package/dist/Fx/combinators/onExit.d.ts +29 -3
- package/dist/Fx/combinators/onExit.d.ts.map +1 -1
- package/dist/Fx/combinators/onExit.js +29 -3
- package/dist/Fx/combinators/onInterrupt.d.ts +49 -4
- package/dist/Fx/combinators/onInterrupt.d.ts.map +1 -1
- package/dist/Fx/combinators/onInterrupt.js +49 -4
- package/dist/Fx/combinators/pairwise.d.ts +28 -0
- package/dist/Fx/combinators/pairwise.d.ts.map +1 -0
- package/dist/Fx/combinators/pairwise.js +31 -0
- package/dist/Fx/combinators/provide.d.ts +141 -20
- package/dist/Fx/combinators/provide.d.ts.map +1 -1
- package/dist/Fx/combinators/provide.js +137 -16
- package/dist/Fx/combinators/race.d.ts +92 -0
- package/dist/Fx/combinators/race.d.ts.map +1 -0
- package/dist/Fx/combinators/race.js +149 -0
- package/dist/Fx/combinators/repeat.d.ts +41 -0
- package/dist/Fx/combinators/repeat.d.ts.map +1 -0
- package/dist/Fx/combinators/repeat.js +57 -0
- package/dist/Fx/combinators/result.d.ts +23 -1
- package/dist/Fx/combinators/result.d.ts.map +1 -1
- package/dist/Fx/combinators/result.js +27 -13
- package/dist/Fx/combinators/retry.d.ts +53 -0
- package/dist/Fx/combinators/retry.d.ts.map +1 -0
- package/dist/Fx/combinators/retry.js +71 -0
- package/dist/Fx/combinators/sample.d.ts +31 -0
- package/dist/Fx/combinators/sample.d.ts.map +1 -0
- package/dist/Fx/combinators/sample.js +42 -0
- package/dist/Fx/combinators/scan.d.ts +41 -2
- package/dist/Fx/combinators/scan.d.ts.map +1 -1
- package/dist/Fx/combinators/scan.js +43 -4
- package/dist/Fx/combinators/since.d.ts +30 -0
- package/dist/Fx/combinators/since.d.ts.map +1 -0
- package/dist/Fx/combinators/since.js +39 -0
- package/dist/Fx/combinators/skip.d.ts +33 -2
- package/dist/Fx/combinators/skip.d.ts.map +1 -1
- package/dist/Fx/combinators/skip.js +33 -2
- package/dist/Fx/combinators/skipRepeats.d.ts +17 -1
- package/dist/Fx/combinators/skipRepeats.d.ts.map +1 -1
- package/dist/Fx/combinators/skipRepeats.js +17 -1
- package/dist/Fx/combinators/skipRepeatsWith.d.ts +18 -1
- package/dist/Fx/combinators/skipRepeatsWith.d.ts.map +1 -1
- package/dist/Fx/combinators/skipRepeatsWith.js +18 -1
- package/dist/Fx/combinators/skipWhile.d.ts +72 -4
- package/dist/Fx/combinators/skipWhile.d.ts.map +1 -1
- package/dist/Fx/combinators/skipWhile.js +72 -4
- package/dist/Fx/combinators/slice.d.ts +85 -3
- package/dist/Fx/combinators/slice.d.ts.map +1 -1
- package/dist/Fx/combinators/slice.js +35 -2
- package/dist/Fx/combinators/switchMap.d.ts +39 -1
- package/dist/Fx/combinators/switchMap.d.ts.map +1 -1
- package/dist/Fx/combinators/switchMap.js +43 -5
- package/dist/Fx/combinators/switchMapEffect.d.ts +38 -1
- package/dist/Fx/combinators/switchMapEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/switchMapEffect.js +38 -1
- package/dist/Fx/combinators/take.d.ts +34 -2
- package/dist/Fx/combinators/take.d.ts.map +1 -1
- package/dist/Fx/combinators/take.js +34 -2
- package/dist/Fx/combinators/takeUntil.d.ts +49 -3
- package/dist/Fx/combinators/takeUntil.d.ts.map +1 -1
- package/dist/Fx/combinators/takeUntil.js +49 -3
- package/dist/Fx/combinators/takeWhile.d.ts +33 -2
- package/dist/Fx/combinators/takeWhile.d.ts.map +1 -1
- package/dist/Fx/combinators/takeWhile.js +33 -2
- package/dist/Fx/combinators/tapEffect.d.ts +17 -1
- package/dist/Fx/combinators/tapEffect.d.ts.map +1 -1
- package/dist/Fx/combinators/tapEffect.js +17 -1
- package/dist/Fx/combinators/throttle.d.ts +79 -0
- package/dist/Fx/combinators/throttle.d.ts.map +1 -0
- package/dist/Fx/combinators/throttle.js +99 -0
- package/dist/Fx/combinators/timeout.d.ts +76 -0
- package/dist/Fx/combinators/timeout.d.ts.map +1 -0
- package/dist/Fx/combinators/timeout.js +110 -0
- package/dist/Fx/combinators/tuple.d.ts +32 -2
- package/dist/Fx/combinators/tuple.d.ts.map +1 -1
- package/dist/Fx/combinators/tuple.js +36 -5
- package/dist/Fx/combinators/until.d.ts +27 -0
- package/dist/Fx/combinators/until.d.ts.map +1 -0
- package/dist/Fx/combinators/until.js +56 -0
- package/dist/Fx/combinators/unwrap.d.ts +31 -2
- package/dist/Fx/combinators/unwrap.d.ts.map +1 -1
- package/dist/Fx/combinators/unwrap.js +30 -1
- package/dist/Fx/combinators/unwrapScoped.d.ts +34 -1
- package/dist/Fx/combinators/unwrapScoped.d.ts.map +1 -1
- package/dist/Fx/combinators/unwrapScoped.js +34 -1
- package/dist/Fx/combinators/when.d.ts +37 -2
- package/dist/Fx/combinators/when.d.ts.map +1 -1
- package/dist/Fx/combinators/when.js +38 -3
- package/dist/Fx/combinators/withLatestFrom.d.ts +58 -0
- package/dist/Fx/combinators/withLatestFrom.d.ts.map +1 -0
- package/dist/Fx/combinators/withLatestFrom.js +68 -0
- package/dist/Fx/combinators/withSpan.d.ts +35 -1
- package/dist/Fx/combinators/withSpan.d.ts.map +1 -1
- package/dist/Fx/combinators/withSpan.js +34 -3
- package/dist/Fx/combinators/zip.d.ts +64 -4
- package/dist/Fx/combinators/zip.d.ts.map +1 -1
- package/dist/Fx/combinators/zip.js +64 -4
- package/dist/Fx/constructors/at.d.ts +21 -1
- package/dist/Fx/constructors/at.d.ts.map +1 -1
- package/dist/Fx/constructors/at.js +21 -1
- package/dist/Fx/constructors/die.d.ts +22 -1
- package/dist/Fx/constructors/die.d.ts.map +1 -1
- package/dist/Fx/constructors/die.js +22 -1
- package/dist/Fx/constructors/empty.d.ts +19 -1
- package/dist/Fx/constructors/empty.d.ts.map +1 -1
- package/dist/Fx/constructors/empty.js +19 -1
- package/dist/Fx/constructors/fail.d.ts +22 -1
- package/dist/Fx/constructors/fail.d.ts.map +1 -1
- package/dist/Fx/constructors/fail.js +22 -1
- package/dist/Fx/constructors/failCause.d.ts +23 -1
- package/dist/Fx/constructors/failCause.d.ts.map +1 -1
- package/dist/Fx/constructors/failCause.js +23 -1
- package/dist/Fx/constructors/fn.d.ts +116 -16
- package/dist/Fx/constructors/fn.d.ts.map +1 -1
- package/dist/Fx/constructors/fn.js +36 -0
- package/dist/Fx/constructors/fromEffect.d.ts +45 -3
- package/dist/Fx/constructors/fromEffect.d.ts.map +1 -1
- package/dist/Fx/constructors/fromEffect.js +45 -3
- package/dist/Fx/constructors/fromFailures.d.ts +25 -1
- package/dist/Fx/constructors/fromFailures.d.ts.map +1 -1
- package/dist/Fx/constructors/fromFailures.js +25 -1
- package/dist/Fx/constructors/fromIterable.d.ts +23 -1
- package/dist/Fx/constructors/fromIterable.d.ts.map +1 -1
- package/dist/Fx/constructors/fromIterable.js +23 -1
- package/dist/Fx/constructors/fromSchedule.d.ts +26 -1
- package/dist/Fx/constructors/fromSchedule.d.ts.map +1 -1
- package/dist/Fx/constructors/fromSchedule.js +28 -3
- package/dist/Fx/constructors/index.d.ts +2 -1
- package/dist/Fx/constructors/index.d.ts.map +1 -1
- package/dist/Fx/constructors/index.js +2 -1
- package/dist/Fx/constructors/interrupt.d.ts +22 -2
- package/dist/Fx/constructors/interrupt.d.ts.map +1 -1
- package/dist/Fx/constructors/interrupt.js +22 -2
- package/dist/Fx/constructors/make.d.ts +151 -4
- package/dist/Fx/constructors/make.d.ts.map +1 -1
- package/dist/Fx/constructors/make.js +60 -7
- package/dist/Fx/constructors/periodic.d.ts +30 -1
- package/dist/Fx/constructors/periodic.d.ts.map +1 -1
- package/dist/Fx/constructors/periodic.js +30 -1
- package/dist/Fx/constructors/succeed.d.ts +79 -7
- package/dist/Fx/constructors/succeed.d.ts.map +1 -1
- package/dist/Fx/constructors/succeed.js +79 -7
- package/dist/Fx/constructors/suspend.d.ts +28 -0
- package/dist/Fx/constructors/suspend.d.ts.map +1 -1
- package/dist/Fx/constructors/suspend.js +28 -0
- package/dist/Fx/constructors/sync.d.ts +32 -0
- package/dist/Fx/constructors/sync.d.ts.map +1 -0
- package/dist/Fx/constructors/sync.js +32 -0
- package/dist/Fx/internal/DeferredRef.d.ts +259 -7
- package/dist/Fx/internal/DeferredRef.d.ts.map +1 -1
- package/dist/Fx/internal/DeferredRef.js +260 -9
- package/dist/Fx/internal/UnionToTuple.d.ts +22 -0
- package/dist/Fx/internal/UnionToTuple.d.ts.map +1 -1
- package/dist/Fx/internal/diff.d.ts +586 -0
- package/dist/Fx/internal/diff.d.ts.map +1 -1
- package/dist/Fx/internal/diff.js +120 -9
- package/dist/Fx/internal/effectableEvaluateKey.d.ts +30 -0
- package/dist/Fx/internal/effectableEvaluateKey.d.ts.map +1 -0
- package/dist/Fx/internal/effectableEvaluateKey.js +29 -0
- package/dist/Fx/internal/effectableWithOverride.d.ts +55 -0
- package/dist/Fx/internal/effectableWithOverride.d.ts.map +1 -0
- package/dist/Fx/internal/effectableWithOverride.js +46 -0
- package/dist/Fx/internal/equivalence.d.ts +29 -0
- package/dist/Fx/internal/equivalence.d.ts.map +1 -1
- package/dist/Fx/internal/equivalence.js +29 -0
- package/dist/Fx/internal/multicast.d.ts +145 -2
- package/dist/Fx/internal/multicast.d.ts.map +1 -1
- package/dist/Fx/internal/multicast.js +146 -4
- package/dist/Fx/internal/ring-buffer.d.ts +149 -0
- package/dist/Fx/internal/ring-buffer.d.ts.map +1 -1
- package/dist/Fx/internal/ring-buffer.js +155 -0
- package/dist/Fx/internal/scope.d.ts +184 -0
- package/dist/Fx/internal/scope.d.ts.map +1 -1
- package/dist/Fx/internal/scope.js +150 -0
- package/dist/Fx/internal/yieldable.d.ts +117 -2
- package/dist/Fx/internal/yieldable.d.ts.map +1 -1
- package/dist/Fx/internal/yieldable.js +86 -3
- package/dist/Fx/run/collect.d.ts +93 -4
- package/dist/Fx/run/collect.d.ts.map +1 -1
- package/dist/Fx/run/collect.js +94 -5
- package/dist/Fx/run/first.d.ts +23 -1
- package/dist/Fx/run/first.d.ts.map +1 -1
- package/dist/Fx/run/first.js +23 -1
- package/dist/Fx/run/fork.d.ts +52 -2
- package/dist/Fx/run/fork.d.ts.map +1 -1
- package/dist/Fx/run/fork.js +52 -2
- package/dist/Fx/run/observe.d.ts +112 -4
- package/dist/Fx/run/observe.d.ts.map +1 -1
- package/dist/Fx/run/observe.js +137 -16
- package/dist/Fx/run/runPromise.d.ts +45 -2
- package/dist/Fx/run/runPromise.d.ts.map +1 -1
- package/dist/Fx/run/runPromise.js +45 -2
- package/dist/Fx/stream.d.ts +92 -0
- package/dist/Fx/stream.d.ts.map +1 -1
- package/dist/Fx/stream.js +60 -1
- package/dist/Push/Push.d.ts +1229 -104
- package/dist/Push/Push.d.ts.map +1 -1
- package/dist/Push/Push.js +1024 -95
- package/dist/RefArray.d.ts +2 -0
- package/dist/RefArray.d.ts.map +1 -0
- package/dist/RefArray.js +1 -0
- package/dist/RefBigDecimal.d.ts +2 -0
- package/dist/RefBigDecimal.d.ts.map +1 -0
- package/dist/RefBigDecimal.js +1 -0
- package/dist/RefBigInt.d.ts +2 -0
- package/dist/RefBigInt.d.ts.map +1 -0
- package/dist/RefBigInt.js +1 -0
- package/dist/RefBoolean.d.ts +2 -0
- package/dist/RefBoolean.d.ts.map +1 -0
- package/dist/RefBoolean.js +1 -0
- package/dist/RefCause.d.ts +2 -0
- package/dist/RefCause.d.ts.map +1 -0
- package/dist/RefCause.js +1 -0
- package/dist/RefChunk.d.ts +2 -0
- package/dist/RefChunk.d.ts.map +1 -0
- package/dist/RefChunk.js +1 -0
- package/dist/RefDateTime.d.ts +2 -0
- package/dist/RefDateTime.d.ts.map +1 -0
- package/dist/RefDateTime.js +1 -0
- package/dist/RefDuration.d.ts +2 -0
- package/dist/RefDuration.d.ts.map +1 -0
- package/dist/RefDuration.js +1 -0
- package/dist/RefGraph.d.ts +2 -0
- package/dist/RefGraph.d.ts.map +1 -0
- package/dist/RefGraph.js +1 -0
- package/dist/RefHashMap.d.ts +2 -0
- package/dist/RefHashMap.d.ts.map +1 -0
- package/dist/RefHashMap.js +1 -0
- package/dist/RefHashRing.d.ts +2 -0
- package/dist/RefHashRing.d.ts.map +1 -0
- package/dist/RefHashRing.js +1 -0
- package/dist/RefHashSet.d.ts +2 -0
- package/dist/RefHashSet.d.ts.map +1 -0
- package/dist/RefHashSet.js +1 -0
- package/dist/RefIterable.d.ts +2 -0
- package/dist/RefIterable.d.ts.map +1 -0
- package/dist/RefIterable.js +1 -0
- package/dist/RefOption.d.ts +2 -0
- package/dist/RefOption.d.ts.map +1 -0
- package/dist/RefOption.js +1 -0
- package/dist/RefRecord.d.ts +2 -0
- package/dist/RefRecord.d.ts.map +1 -0
- package/dist/RefRecord.js +1 -0
- package/dist/RefResult.d.ts +2 -0
- package/dist/RefResult.d.ts.map +1 -0
- package/dist/RefResult.js +1 -0
- package/dist/RefString.d.ts +2 -0
- package/dist/RefString.d.ts.map +1 -0
- package/dist/RefString.js +1 -0
- package/dist/RefStruct.d.ts +2 -0
- package/dist/RefStruct.d.ts.map +1 -0
- package/dist/RefStruct.js +1 -0
- package/dist/RefSubject/Hydration.d.ts +504 -0
- package/dist/RefSubject/Hydration.d.ts.map +1 -0
- package/dist/RefSubject/Hydration.js +300 -0
- package/dist/RefSubject/RefArray.d.ts +382 -35
- package/dist/RefSubject/RefArray.d.ts.map +1 -1
- package/dist/RefSubject/RefArray.js +374 -40
- package/dist/RefSubject/RefBigDecimal.d.ts +241 -21
- package/dist/RefSubject/RefBigDecimal.d.ts.map +1 -1
- package/dist/RefSubject/RefBigDecimal.js +229 -20
- package/dist/RefSubject/RefBigInt.d.ts +181 -16
- package/dist/RefSubject/RefBigInt.d.ts.map +1 -1
- package/dist/RefSubject/RefBigInt.js +169 -15
- package/dist/RefSubject/RefBoolean.d.ts +181 -16
- package/dist/RefSubject/RefBoolean.d.ts.map +1 -1
- package/dist/RefSubject/RefBoolean.js +169 -15
- package/dist/RefSubject/RefCause.d.ts +133 -12
- package/dist/RefSubject/RefCause.d.ts.map +1 -1
- package/dist/RefSubject/RefCause.js +121 -11
- package/dist/RefSubject/RefChunk.d.ts +481 -76
- package/dist/RefSubject/RefChunk.d.ts.map +1 -1
- package/dist/RefSubject/RefChunk.js +471 -75
- package/dist/RefSubject/RefDateTime.d.ts +133 -12
- package/dist/RefSubject/RefDateTime.d.ts.map +1 -1
- package/dist/RefSubject/RefDateTime.js +122 -12
- package/dist/RefSubject/RefDuration.d.ts +169 -15
- package/dist/RefSubject/RefDuration.d.ts.map +1 -1
- package/dist/RefSubject/RefDuration.js +157 -14
- package/dist/RefSubject/RefGraph.d.ts +349 -35
- package/dist/RefSubject/RefGraph.d.ts.map +1 -1
- package/dist/RefSubject/RefGraph.js +334 -32
- package/dist/RefSubject/RefHashMap.d.ts +323 -28
- package/dist/RefSubject/RefHashMap.d.ts.map +1 -1
- package/dist/RefSubject/RefHashMap.js +317 -29
- package/dist/RefSubject/RefHashRing.d.ts +159 -15
- package/dist/RefSubject/RefHashRing.d.ts.map +1 -1
- package/dist/RefSubject/RefHashRing.js +145 -12
- package/dist/RefSubject/RefHashSet.d.ts +251 -22
- package/dist/RefSubject/RefHashSet.d.ts.map +1 -1
- package/dist/RefSubject/RefHashSet.js +238 -20
- package/dist/RefSubject/RefIterable.d.ts +358 -32
- package/dist/RefSubject/RefIterable.d.ts.map +1 -1
- package/dist/RefSubject/RefIterable.js +350 -30
- package/dist/RefSubject/RefOption.d.ts +157 -14
- package/dist/RefSubject/RefOption.d.ts.map +1 -1
- package/dist/RefSubject/RefOption.js +145 -13
- package/dist/RefSubject/RefRecord.d.ts +402 -64
- package/dist/RefSubject/RefRecord.d.ts.map +1 -1
- package/dist/RefSubject/RefRecord.js +364 -39
- package/dist/RefSubject/RefResult.d.ts +167 -35
- package/dist/RefSubject/RefResult.d.ts.map +1 -1
- package/dist/RefSubject/RefResult.js +133 -12
- package/dist/RefSubject/RefString.d.ts +205 -18
- package/dist/RefSubject/RefString.d.ts.map +1 -1
- package/dist/RefSubject/RefString.js +193 -17
- package/dist/RefSubject/RefStruct.d.ts +169 -14
- package/dist/RefSubject/RefStruct.d.ts.map +1 -1
- package/dist/RefSubject/RefStruct.js +157 -13
- package/dist/RefSubject/RefSubject.d.ts +1197 -45
- package/dist/RefSubject/RefSubject.d.ts.map +1 -1
- package/dist/RefSubject/RefSubject.js +935 -88
- package/dist/RefSubject/RefTrie.d.ts +323 -37
- package/dist/RefSubject/RefTrie.d.ts.map +1 -1
- package/dist/RefSubject/RefTrie.js +311 -31
- package/dist/RefSubject/RefTuple.d.ts +127 -11
- package/dist/RefSubject/RefTuple.d.ts.map +1 -1
- package/dist/RefSubject/RefTuple.js +114 -9
- package/dist/RefSubject/index.d.ts +1 -0
- package/dist/RefSubject/index.d.ts.map +1 -1
- package/dist/RefSubject/index.js +1 -0
- package/dist/RefSubject.d.ts +2 -1
- package/dist/RefSubject.d.ts.map +1 -1
- package/dist/RefSubject.js +2 -1
- package/dist/RefTrie.d.ts +2 -0
- package/dist/RefTrie.d.ts.map +1 -0
- package/dist/RefTrie.js +1 -0
- package/dist/RefTuple.d.ts +2 -0
- package/dist/RefTuple.d.ts.map +1 -0
- package/dist/RefTuple.js +1 -0
- package/dist/Sink/Sink.d.ts +396 -23
- package/dist/Sink/Sink.d.ts.map +1 -1
- package/dist/Sink/Sink.js +55 -7
- package/dist/Sink/combinators.d.ts +740 -11
- package/dist/Sink/combinators.d.ts.map +1 -1
- package/dist/Sink/combinators.js +716 -14
- package/dist/Subject/Subject.d.ts +1022 -27
- package/dist/Subject/Subject.d.ts.map +1 -1
- package/dist/Subject/Subject.js +909 -43
- package/dist/Versioned/Versioned.d.ts +447 -27
- package/dist/Versioned/Versioned.d.ts.map +1 -1
- package/dist/Versioned/Versioned.js +282 -48
- package/dist/index.d.ts +22 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -3
- package/package.json +126 -16
- package/dist/Fx/constructors/fromYieldable.d.ts +0 -12
- package/dist/Fx/constructors/fromYieldable.d.ts.map +0 -1
- package/dist/Fx/constructors/fromYieldable.js +0 -12
- package/src/Fx/Fx.ts +0 -164
- package/src/Fx/TypeId.ts +0 -25
- package/src/Fx/combinators/additive.ts +0 -142
- package/src/Fx/combinators/catch.ts +0 -421
- package/src/Fx/combinators/causes.ts +0 -23
- package/src/Fx/combinators/changesWithEffect.ts +0 -66
- package/src/Fx/combinators/compact.ts +0 -15
- package/src/Fx/combinators/continueWith.ts +0 -78
- package/src/Fx/combinators/dropUntil.ts +0 -47
- package/src/Fx/combinators/ensuring.ts +0 -23
- package/src/Fx/combinators/exhaustLatestMap.ts +0 -74
- package/src/Fx/combinators/exhaustLatestMapEffect.ts +0 -25
- package/src/Fx/combinators/exhaustMap.ts +0 -36
- package/src/Fx/combinators/exhaustMapEffect.ts +0 -23
- package/src/Fx/combinators/exit.ts +0 -15
- package/src/Fx/combinators/filter.ts +0 -22
- package/src/Fx/combinators/filterEffect.ts +0 -31
- package/src/Fx/combinators/filterMap.ts +0 -23
- package/src/Fx/combinators/filterMapEffect.ts +0 -32
- package/src/Fx/combinators/filterMapLoop.ts +0 -35
- package/src/Fx/combinators/filterMapLoopCause.ts +0 -36
- package/src/Fx/combinators/filterMapLoopCauseEffect.ts +0 -46
- package/src/Fx/combinators/filterMapLoopEffect.ts +0 -36
- package/src/Fx/combinators/flatMap.ts +0 -51
- package/src/Fx/combinators/flatMapConcurrently.ts +0 -39
- package/src/Fx/combinators/flatMapConcurrentlyEffect.ts +0 -26
- package/src/Fx/combinators/flatMapEffect.ts +0 -42
- package/src/Fx/combinators/flip.ts +0 -14
- package/src/Fx/combinators/gen.ts +0 -24
- package/src/Fx/combinators/genScoped.ts +0 -24
- package/src/Fx/combinators/index.ts +0 -61
- package/src/Fx/combinators/keyed.ts +0 -369
- package/src/Fx/combinators/loop.ts +0 -27
- package/src/Fx/combinators/loopCause.ts +0 -34
- package/src/Fx/combinators/loopCauseEffect.ts +0 -36
- package/src/Fx/combinators/loopEffect.ts +0 -34
- package/src/Fx/combinators/map.ts +0 -22
- package/src/Fx/combinators/mapBoth.ts +0 -40
- package/src/Fx/combinators/mapEffect.ts +0 -32
- package/src/Fx/combinators/mapError.ts +0 -28
- package/src/Fx/combinators/mergeAll.ts +0 -22
- package/src/Fx/combinators/mergeOrdered.ts +0 -123
- package/src/Fx/combinators/onError.ts +0 -40
- package/src/Fx/combinators/onExit.ts +0 -82
- package/src/Fx/combinators/onInterrupt.ts +0 -87
- package/src/Fx/combinators/provide.ts +0 -124
- package/src/Fx/combinators/result.ts +0 -39
- package/src/Fx/combinators/scan.ts +0 -82
- package/src/Fx/combinators/skip.ts +0 -41
- package/src/Fx/combinators/skipRepeats.ts +0 -15
- package/src/Fx/combinators/skipRepeatsWith.ts +0 -40
- package/src/Fx/combinators/skipWhile.ts +0 -100
- package/src/Fx/combinators/slice.ts +0 -55
- package/src/Fx/combinators/switchMap.ts +0 -55
- package/src/Fx/combinators/switchMapEffect.ts +0 -25
- package/src/Fx/combinators/take.ts +0 -38
- package/src/Fx/combinators/takeUntil.ts +0 -88
- package/src/Fx/combinators/takeWhile.ts +0 -47
- package/src/Fx/combinators/tapEffect.ts +0 -39
- package/src/Fx/combinators/tuple.ts +0 -79
- package/src/Fx/combinators/unwrap.ts +0 -21
- package/src/Fx/combinators/unwrapScoped.ts +0 -26
- package/src/Fx/combinators/when.ts +0 -64
- package/src/Fx/combinators/withSpan.ts +0 -24
- package/src/Fx/combinators/zip.ts +0 -175
- package/src/Fx/constructors/at.ts +0 -23
- package/src/Fx/constructors/die.ts +0 -17
- package/src/Fx/constructors/empty.ts +0 -10
- package/src/Fx/constructors/fail.ts +0 -14
- package/src/Fx/constructors/failCause.ts +0 -14
- package/src/Fx/constructors/fn.ts +0 -245
- package/src/Fx/constructors/fromEffect.ts +0 -24
- package/src/Fx/constructors/fromFailures.ts +0 -19
- package/src/Fx/constructors/fromIterable.ts +0 -15
- package/src/Fx/constructors/fromSchedule.ts +0 -18
- package/src/Fx/constructors/fromYieldable.ts +0 -17
- package/src/Fx/constructors/index.ts +0 -15
- package/src/Fx/constructors/interrupt.ts +0 -13
- package/src/Fx/constructors/make.ts +0 -103
- package/src/Fx/constructors/periodic.ts +0 -15
- package/src/Fx/constructors/succeed.ts +0 -37
- package/src/Fx/constructors/suspend.ts +0 -6
- package/src/Fx/index.ts +0 -6
- package/src/Fx/internal/DeferredRef.ts +0 -87
- package/src/Fx/internal/UnionToTuple.ts +0 -12
- package/src/Fx/internal/diff.ts +0 -191
- package/src/Fx/internal/equivalence.ts +0 -12
- package/src/Fx/internal/multicast.ts +0 -51
- package/src/Fx/internal/ring-buffer.ts +0 -60
- package/src/Fx/internal/scope.ts +0 -58
- package/src/Fx/internal/yieldable.ts +0 -31
- package/src/Fx/run/collect.ts +0 -79
- package/src/Fx/run/first.ts +0 -20
- package/src/Fx/run/fork.ts +0 -40
- package/src/Fx/run/index.ts +0 -5
- package/src/Fx/run/observe.ts +0 -114
- package/src/Fx/run/runPromise.ts +0 -32
- package/src/Fx/stream.ts +0 -42
- package/src/Fx.additive-combinators.test.ts +0 -126
- package/src/Fx.catch-additive.test.ts +0 -206
- package/src/Fx.catch.test.ts +0 -60
- package/src/Fx.dropUntil.test.ts +0 -61
- package/src/Fx.fn.test.ts +0 -51
- package/src/Fx.lifecycle.test.ts +0 -79
- package/src/Fx.mapError-mapBoth.test.ts +0 -101
- package/src/Fx.provide-combinators.test.ts +0 -94
- package/src/Fx.result-changesWithEffect.test.ts +0 -112
- package/src/Fx.scan.test.ts +0 -73
- package/src/Fx.takeWhile-skipWhile.test.ts +0 -84
- package/src/Fx.test.ts +0 -71
- package/src/Fx.ts +0 -1
- package/src/Fx.zip-merge-additive.test.ts +0 -171
- package/src/Fx.zip.test.ts +0 -133
- package/src/Push/Push.ts +0 -1072
- package/src/Push/index.ts +0 -1
- package/src/Push.additive.test.ts +0 -256
- package/src/Push.test.ts +0 -26
- package/src/Push.ts +0 -1
- package/src/RefSubject/RefArray.ts +0 -512
- package/src/RefSubject/RefBigDecimal.test.ts +0 -56
- package/src/RefSubject/RefBigDecimal.ts +0 -295
- package/src/RefSubject/RefBigInt.test.ts +0 -56
- package/src/RefSubject/RefBigInt.ts +0 -189
- package/src/RefSubject/RefBoolean.test.ts +0 -57
- package/src/RefSubject/RefBoolean.ts +0 -185
- package/src/RefSubject/RefCause.test.ts +0 -53
- package/src/RefSubject/RefCause.ts +0 -146
- package/src/RefSubject/RefChunk.ts +0 -510
- package/src/RefSubject/RefDateTime.test.ts +0 -43
- package/src/RefSubject/RefDateTime.ts +0 -264
- package/src/RefSubject/RefDuration.test.ts +0 -49
- package/src/RefSubject/RefDuration.ts +0 -188
- package/src/RefSubject/RefGraph.ts +0 -650
- package/src/RefSubject/RefHashMap.ts +0 -465
- package/src/RefSubject/RefHashRing.ts +0 -262
- package/src/RefSubject/RefHashSet.ts +0 -308
- package/src/RefSubject/RefIterable.ts +0 -445
- package/src/RefSubject/RefOption.test.ts +0 -67
- package/src/RefSubject/RefOption.ts +0 -193
- package/src/RefSubject/RefRecord.ts +0 -612
- package/src/RefSubject/RefResult.test.ts +0 -63
- package/src/RefSubject/RefResult.ts +0 -209
- package/src/RefSubject/RefString.test.ts +0 -61
- package/src/RefSubject/RefString.ts +0 -256
- package/src/RefSubject/RefStruct.test.ts +0 -60
- package/src/RefSubject/RefStruct.ts +0 -253
- package/src/RefSubject/RefSubject.ts +0 -2646
- package/src/RefSubject/RefTrie.ts +0 -356
- package/src/RefSubject/RefTuple.test.ts +0 -60
- package/src/RefSubject/RefTuple.ts +0 -231
- package/src/RefSubject/index.ts +0 -21
- package/src/RefSubject.additive-parity.test.ts +0 -101
- package/src/RefSubject.test.ts +0 -65
- package/src/RefSubject.ts +0 -1
- package/src/Sink/Sink.ts +0 -159
- package/src/Sink/combinators.ts +0 -1115
- package/src/Sink/index.ts +0 -2
- package/src/Sink.combinators.test.ts +0 -88
- package/src/Sink.reduce-collect-head-last.test.ts +0 -107
- package/src/Sink.ts +0 -1
- package/src/Subject/Subject.ts +0 -441
- package/src/Subject/index.ts +0 -1
- package/src/Subject.test.ts +0 -47
- package/src/Subject.ts +0 -1
- package/src/Versioned/Versioned.ts +0 -597
- package/src/Versioned/index.ts +0 -1
- package/src/Versioned.filterMap.test.ts +0 -91
- package/src/Versioned.test.ts +0 -23
- package/src/Versioned.ts +0 -1
- package/src/index.ts +0 -7
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/** @effect-diagnostics missingEffectContext:skip-file */
|
|
3
3
|
import * as Array from "effect/Array";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Effectable from "effect/Effectable";
|
|
5
6
|
import * as Semaphore from "effect/Semaphore";
|
|
6
7
|
import { equals } from "effect/Equal";
|
|
7
8
|
import * as Exit from "effect/Exit";
|
|
@@ -13,17 +14,18 @@ import { sum } from "effect/Number";
|
|
|
13
14
|
import * as Option from "effect/Option";
|
|
14
15
|
import { pipeArguments } from "effect/Pipeable";
|
|
15
16
|
import * as Scope from "effect/Scope";
|
|
16
|
-
import * as
|
|
17
|
+
import * as Context from "effect/Context";
|
|
17
18
|
import * as Stream from "effect/Stream";
|
|
18
19
|
import { compact as fxCompact } from "../Fx/combinators/compact.js";
|
|
19
20
|
import { continueWith } from "../Fx/combinators/continueWith.js";
|
|
20
21
|
import { filterMapEffect as fxFilterMapEffect } from "../Fx/combinators/filterMapEffect.js";
|
|
21
22
|
import { mapEffect as fxMapEffect } from "../Fx/combinators/mapEffect.js";
|
|
23
|
+
import { mergeAll as fxMergeAll } from "../Fx/combinators/mergeAll.js";
|
|
24
|
+
import { scanEffect as fxScanEffect } from "../Fx/combinators/scan.js";
|
|
22
25
|
import { skipRepeats } from "../Fx/combinators/skipRepeats.js";
|
|
23
26
|
import { slice as fxSlice } from "../Fx/combinators/slice.js";
|
|
24
27
|
import { unwrap } from "../Fx/combinators/unwrap.js";
|
|
25
28
|
import { fromEffect as fxFromEffect } from "../Fx/constructors/fromEffect.js";
|
|
26
|
-
import { fromYieldable } from "../Fx/constructors/fromYieldable.js";
|
|
27
29
|
import * as DeferredRef from "../Fx/internal/DeferredRef.js";
|
|
28
30
|
import { getExitEquivalence } from "../Fx/internal/equivalence.js";
|
|
29
31
|
import { YieldableFx } from "../Fx/internal/yieldable.js";
|
|
@@ -31,13 +33,92 @@ import { FxTypeId, isFx } from "../Fx/TypeId.js";
|
|
|
31
33
|
import * as Sink from "../Sink/Sink.js";
|
|
32
34
|
import * as Subject from "../Subject/Subject.js";
|
|
33
35
|
import * as Versioned from "../Versioned/Versioned.js";
|
|
36
|
+
import { hasProperty } from "effect/Predicate";
|
|
37
|
+
/**
|
|
38
|
+
* Runtime symbol identifying writable RefSubject values.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* ## Why
|
|
42
|
+
*
|
|
43
|
+
* Provides stable runtime identity for RefSubject values without relying on classes or a renderer.
|
|
44
|
+
*
|
|
45
|
+
* ## Ownership and lifetime
|
|
46
|
+
*
|
|
47
|
+
* This declaration performs no acquisition and retains no resources. Implementations preserve
|
|
48
|
+
* source errors, services, and lifetime.
|
|
49
|
+
*
|
|
50
|
+
* @since 1.18.0
|
|
51
|
+
* @category Type identity
|
|
52
|
+
*/
|
|
34
53
|
export const RefSubjectTypeId = Symbol.for("@typed/fx/RefSubject");
|
|
54
|
+
/**
|
|
55
|
+
* Runtime symbol identifying read-only Computed values.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* ## Why
|
|
59
|
+
*
|
|
60
|
+
* Provides stable runtime identity for Computed values without relying on classes or a renderer.
|
|
61
|
+
*
|
|
62
|
+
* ## Ownership and lifetime
|
|
63
|
+
*
|
|
64
|
+
* This declaration performs no acquisition and retains no resources. Implementations preserve
|
|
65
|
+
* source errors, services, and lifetime.
|
|
66
|
+
*
|
|
67
|
+
* @since 1.18.0
|
|
68
|
+
* @category Type identity
|
|
69
|
+
*/
|
|
35
70
|
export const ComputedTypeId = Symbol.for("@typed/fx/Computed");
|
|
71
|
+
/**
|
|
72
|
+
* Runtime symbol identifying conditionally available Filtered values.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* ## Why
|
|
76
|
+
*
|
|
77
|
+
* Provides stable runtime identity for Filtered values without relying on classes or a renderer.
|
|
78
|
+
*
|
|
79
|
+
* ## Ownership and lifetime
|
|
80
|
+
*
|
|
81
|
+
* This declaration performs no acquisition and retains no resources. Implementations preserve
|
|
82
|
+
* source errors, services, and lifetime.
|
|
83
|
+
*
|
|
84
|
+
* @since 1.18.0
|
|
85
|
+
* @category Type identity
|
|
86
|
+
*/
|
|
36
87
|
export const FilteredTypeId = Symbol.for("@typed/fx/Filtered");
|
|
37
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Selects whether a computed Fx observes only its current value or also follows later pushes.
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* ## Why
|
|
93
|
+
*
|
|
94
|
+
* `"multiple"` (the default) emits the current value and then follows distinct source pushes.
|
|
95
|
+
* `"one"` emits only the current value. Hydration temporarily uses `"one"` when it must resolve a
|
|
96
|
+
* single server value without leaving a live observation running.
|
|
97
|
+
*
|
|
98
|
+
* ## Ownership and lifetime
|
|
99
|
+
*
|
|
100
|
+
* This is an Effect Context reference with a default value, not mutable global state. Supplying a
|
|
101
|
+
* value changes computed observation only in the provided Effect context; the observing Scope
|
|
102
|
+
* still owns any subscription created by `"multiple"`.
|
|
103
|
+
*
|
|
104
|
+
* @since 1.18.0
|
|
105
|
+
* @category Observation policy
|
|
106
|
+
*/
|
|
107
|
+
export const CurrentComputedBehavior = Context.Reference("@typed/fx/CurrentComputedBehavior", {
|
|
38
108
|
defaultValue: () => "multiple",
|
|
39
109
|
});
|
|
40
|
-
const checkIsMultiple = (ctx) =>
|
|
110
|
+
const checkIsMultiple = (ctx) => Context.getUnsafe(ctx, CurrentComputedBehavior) === "multiple";
|
|
111
|
+
function holdInContext(fx) {
|
|
112
|
+
const contexts = new WeakMap();
|
|
113
|
+
return unwrap(Effect.map(Effect.context(), (context) => {
|
|
114
|
+
let shared = contexts.get(context);
|
|
115
|
+
if (!shared) {
|
|
116
|
+
shared = Subject.hold(fx);
|
|
117
|
+
contexts.set(context, shared);
|
|
118
|
+
}
|
|
119
|
+
return shared;
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
41
122
|
class ComputedImpl extends Versioned.VersionedTransform {
|
|
42
123
|
[ComputedTypeId] = ComputedTypeId;
|
|
43
124
|
_computed;
|
|
@@ -47,20 +128,145 @@ class ComputedImpl extends Versioned.VersionedTransform {
|
|
|
47
128
|
super(input, (fx) => fxMapEffect(fx, f), Effect.flatMap(f));
|
|
48
129
|
this.input = input;
|
|
49
130
|
this.f = f;
|
|
50
|
-
this._computed =
|
|
131
|
+
this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
|
|
51
132
|
if (checkIsMultiple(ctx)) {
|
|
52
|
-
return
|
|
133
|
+
return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxMapEffect(f));
|
|
53
134
|
}
|
|
54
|
-
return fxFromEffect(Effect.flatMap(input
|
|
135
|
+
return fxFromEffect(Effect.flatMap(input, f));
|
|
55
136
|
})));
|
|
56
137
|
}
|
|
57
138
|
run(sink) {
|
|
58
139
|
return this._computed.run(sink);
|
|
59
140
|
}
|
|
60
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Builds a read-only Computed projection from a Versioned source.
|
|
144
|
+
*
|
|
145
|
+
* @remarks
|
|
146
|
+
* ## Why
|
|
147
|
+
*
|
|
148
|
+
* Applies the same Effectful projection to current reads and pushed versions, preserving all three
|
|
149
|
+
* Versioned channels without granting writes to the source.
|
|
150
|
+
*
|
|
151
|
+
* ## Ownership and lifetime
|
|
152
|
+
*
|
|
153
|
+
* Current reads cache the transformed input by source version within each Effect Context. The
|
|
154
|
+
* pushed channel uses `Subject.hold`: observers with the same Context object share one upstream
|
|
155
|
+
* session and its retained projection; distinct Context objects have separate sessions. The last
|
|
156
|
+
* observer ends its session and clears its held value. The observing Scope owns cleanup.
|
|
157
|
+
*
|
|
158
|
+
* @since 1.18.0
|
|
159
|
+
* @category Derived queries
|
|
160
|
+
*/
|
|
61
161
|
export function makeComputed(input, f) {
|
|
62
162
|
return new ComputedImpl(input, f);
|
|
63
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Stateful scan over a `RefSubject` / `Computed`, producing a `Computed` of the accumulated state.
|
|
166
|
+
*
|
|
167
|
+
* Fx subscriptions follow `Fx.scan` semantics (emit `initial`, then fold each source value).
|
|
168
|
+
* Effect sampling accumulates across source versions via a private state ref (do not mix heavy
|
|
169
|
+
* subscribe + sample on the same scan if you need a single shared accumulator).
|
|
170
|
+
*
|
|
171
|
+
* @remarks
|
|
172
|
+
* ## Why
|
|
173
|
+
*
|
|
174
|
+
* Stateful scan over a `RefSubject` / `Computed`, producing a `Computed` of the accumulated state.
|
|
175
|
+
* Fx subscriptions follow `Fx.scan` semantics (emit `initial`, then fold each source value).
|
|
176
|
+
* Effect sampling accumulates across source versions via a private state ref (do not mix heavy
|
|
177
|
+
* subscribe + sample on the same scan if you need a single shared accumulator). The result remains
|
|
178
|
+
* a lazy view rather than a duplicated mutable value.
|
|
179
|
+
*
|
|
180
|
+
* ## Ownership and lifetime
|
|
181
|
+
*
|
|
182
|
+
* Each Effect Context object gets a private current-read accumulator, advanced after a successful
|
|
183
|
+
* fold for a new source version. The pushed channel runs `Fx.scanEffect` from `initial` inside
|
|
184
|
+
* `Subject.hold`: observers using the same Context share that active scan and retained result.
|
|
185
|
+
* The last observer ends its session and clears its held value. The observing Scope owns
|
|
186
|
+
* subscription cleanup. Read accumulators are weakly held by Context and need no finalizer.
|
|
187
|
+
*
|
|
188
|
+
* @since 1.0.0
|
|
189
|
+
* @category Accumulation
|
|
190
|
+
*/
|
|
191
|
+
export const scan = dual(3, function scan(versioned, initial, f) {
|
|
192
|
+
return new ComputedScanImpl(versioned, initial, (s, a) => Effect.succeed(f(s, a)));
|
|
193
|
+
});
|
|
194
|
+
/**
|
|
195
|
+
* Effectful stateful scan over a `RefSubject` / `Computed`, producing a `Computed` of the accumulated state.
|
|
196
|
+
*
|
|
197
|
+
* @remarks
|
|
198
|
+
* ## Why
|
|
199
|
+
*
|
|
200
|
+
* Effectful stateful scan over a `RefSubject` / `Computed`, producing a `Computed` of the
|
|
201
|
+
* accumulated state. The result remains a lazy view rather than a duplicated mutable value.
|
|
202
|
+
*
|
|
203
|
+
* ## Ownership and lifetime
|
|
204
|
+
*
|
|
205
|
+
* Each Effect Context object gets a private current-read accumulator. It advances only after `f`
|
|
206
|
+
* succeeds, so a typed failure leaves the previous state intact. The pushed channel runs
|
|
207
|
+
* `Fx.scanEffect` from `initial` inside `Subject.hold`: observers using the same Context share
|
|
208
|
+
* that active scan and retained result; each fold requires `R3`. The last observer ends its
|
|
209
|
+
* session and clears its held value. The observing Scope owns cleanup. Read accumulators are
|
|
210
|
+
* weakly held by Context and need no finalizer.
|
|
211
|
+
*
|
|
212
|
+
* @since 1.0.0
|
|
213
|
+
* @category Accumulation
|
|
214
|
+
*/
|
|
215
|
+
export const scanEffect = dual(3, function scanEffect(versioned, initial, f) {
|
|
216
|
+
return new ComputedScanImpl(versioned, initial, f);
|
|
217
|
+
});
|
|
218
|
+
class ComputedScanImpl extends Versioned.VersionedTransform {
|
|
219
|
+
[ComputedTypeId] = ComputedTypeId;
|
|
220
|
+
_computed;
|
|
221
|
+
input;
|
|
222
|
+
initial;
|
|
223
|
+
f;
|
|
224
|
+
constructor(input, initial, f) {
|
|
225
|
+
const states = new WeakMap();
|
|
226
|
+
super(input, (fx) => fxScanEffect(fx, initial, f), (effect) => Effect.contextWith((context) => {
|
|
227
|
+
let state = states.get(context);
|
|
228
|
+
if (!state) {
|
|
229
|
+
state = MutableRef.make(initial);
|
|
230
|
+
states.set(context, state);
|
|
231
|
+
}
|
|
232
|
+
const current = state;
|
|
233
|
+
return Effect.flatMap(effect, (a) => Effect.flatMap(f(MutableRef.get(current), a), (next) => Effect.sync(() => {
|
|
234
|
+
MutableRef.set(current, next);
|
|
235
|
+
return next;
|
|
236
|
+
})));
|
|
237
|
+
}));
|
|
238
|
+
this.input = input;
|
|
239
|
+
this.initial = initial;
|
|
240
|
+
this.f = f;
|
|
241
|
+
this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
|
|
242
|
+
if (checkIsMultiple(ctx)) {
|
|
243
|
+
return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxScanEffect(initial, f));
|
|
244
|
+
}
|
|
245
|
+
return fxFromEffect(Effect.flatMap(input, (a) => f(initial, a)));
|
|
246
|
+
})));
|
|
247
|
+
}
|
|
248
|
+
run(sink) {
|
|
249
|
+
return this._computed.run(sink);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Builds a Filtered view from the three channels of a Versioned source.
|
|
254
|
+
*
|
|
255
|
+
* @remarks
|
|
256
|
+
* ## Why
|
|
257
|
+
*
|
|
258
|
+
* Applies `f` to current reads and later pushes while preserving absence as Filtered semantics:
|
|
259
|
+
* Effect reads fail with `NoSuchElementError`, whereas the Fx channel simply omits absent values.
|
|
260
|
+
*
|
|
261
|
+
* ## Ownership and lifetime
|
|
262
|
+
*
|
|
263
|
+
* Sampled results and pushed sessions are isolated by Effect Context identity. Within one Context,
|
|
264
|
+
* current reads cache by source version and observers share the active held projection. Its
|
|
265
|
+
* Effect read fails with NoSuchElement while absent; the observing Scope owns its subscription.
|
|
266
|
+
*
|
|
267
|
+
* @since 1.18.0
|
|
268
|
+
* @category Optional queries
|
|
269
|
+
*/
|
|
64
270
|
export function makeFiltered(input, f) {
|
|
65
271
|
return new FilteredImpl(input, f);
|
|
66
272
|
}
|
|
@@ -70,14 +276,14 @@ class FilteredImpl extends Versioned.VersionedTransform {
|
|
|
70
276
|
input;
|
|
71
277
|
f;
|
|
72
278
|
constructor(input, f) {
|
|
73
|
-
super(input, (fx) => fxFilterMapEffect(fx, f), (effect) => Effect.flatMap(Effect.flatMap(effect, f),
|
|
279
|
+
super(input, (fx) => fxFilterMapEffect(fx, f), (effect) => Effect.flatMap(Effect.flatMap(effect, f), Effect.fromOption));
|
|
74
280
|
this.input = input;
|
|
75
281
|
this.f = f;
|
|
76
|
-
this._computed =
|
|
282
|
+
this._computed = holdInContext(unwrap(Effect.map(Effect.context(), (ctx) => {
|
|
77
283
|
if (checkIsMultiple(ctx)) {
|
|
78
|
-
return
|
|
284
|
+
return fxFromEffect(input).pipe(continueWith(() => input), skipRepeats, fxFilterMapEffect(f));
|
|
79
285
|
}
|
|
80
|
-
return fxCompact(fxFromEffect(Effect.flatMap(input
|
|
286
|
+
return fxCompact(fxFromEffect(Effect.flatMap(input, f)));
|
|
81
287
|
})));
|
|
82
288
|
}
|
|
83
289
|
run(sink) {
|
|
@@ -87,6 +293,7 @@ class FilteredImpl extends Versioned.VersionedTransform {
|
|
|
87
293
|
return new ComputedImpl(this.input, this.f);
|
|
88
294
|
}
|
|
89
295
|
}
|
|
296
|
+
let nextTransactionOrder = 0;
|
|
90
297
|
class RefSubjectCore {
|
|
91
298
|
initial;
|
|
92
299
|
subject;
|
|
@@ -94,6 +301,7 @@ class RefSubjectCore {
|
|
|
94
301
|
scope;
|
|
95
302
|
deferredRef;
|
|
96
303
|
semaphore;
|
|
304
|
+
transactionOrder = nextTransactionOrder++;
|
|
97
305
|
constructor(initial, subject, services, scope, deferredRef, semaphore) {
|
|
98
306
|
this.initial = initial;
|
|
99
307
|
this.subject = subject;
|
|
@@ -104,10 +312,116 @@ class RefSubjectCore {
|
|
|
104
312
|
}
|
|
105
313
|
_fiber = undefined;
|
|
106
314
|
}
|
|
107
|
-
function
|
|
315
|
+
function combineTransactionCores(accesses) {
|
|
316
|
+
return [...new Set(accesses.flatMap((access) => access.cores))].sort((left, right) => left.transactionOrder - right.transactionOrder);
|
|
317
|
+
}
|
|
318
|
+
function getTupleTransactionAccess(refs) {
|
|
319
|
+
const accessEffects = refs.map(getTransactionAccess);
|
|
320
|
+
if (!accessEffects.every((access) => access !== undefined)) {
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
return Effect.map(Effect.all(accessEffects, UNBOUNDED), (accessOptions) => Option.map(Option.all(accessOptions), (accesses) => ({
|
|
324
|
+
cores: combineTransactionCores(accesses),
|
|
325
|
+
getSetDelete: (recordCommit) => {
|
|
326
|
+
const transactions = accesses.map((access) => access.getSetDelete(recordCommit));
|
|
327
|
+
return {
|
|
328
|
+
get: Effect.all(transactions.map((transaction) => transaction.get), UNBOUNDED),
|
|
329
|
+
set: (value) => Effect.all(transactions.map((transaction, index) => transaction.set(value[index])), UNBOUNDED),
|
|
330
|
+
delete: Effect.map(Effect.all(transactions.map((transaction) => transaction.delete), UNBOUNDED), Option.all),
|
|
331
|
+
};
|
|
332
|
+
},
|
|
333
|
+
})));
|
|
334
|
+
}
|
|
335
|
+
function getStructTransactionAccess(refs) {
|
|
336
|
+
const keys = Object.keys(refs);
|
|
337
|
+
const accessEffects = keys.map((key) => getTransactionAccess(refs[key]));
|
|
338
|
+
if (!accessEffects.every((access) => access !== undefined)) {
|
|
339
|
+
return undefined;
|
|
340
|
+
}
|
|
341
|
+
return Effect.map(Effect.all(accessEffects, UNBOUNDED), (accessOptions) => Option.map(Option.all(accessOptions), (accesses) => ({
|
|
342
|
+
cores: combineTransactionCores(accesses),
|
|
343
|
+
getSetDelete: (recordCommit) => {
|
|
344
|
+
const transactions = accesses.map((access) => access.getSetDelete(recordCommit));
|
|
345
|
+
return {
|
|
346
|
+
get: Effect.map(Effect.all(transactions.map((transaction) => transaction.get), UNBOUNDED), (values) => Object.fromEntries(keys.map((key, index) => [key, values[index]]))),
|
|
347
|
+
set: (value) => Effect.all(transactions.map((transaction, index) => transaction.set(value[keys[index]])), UNBOUNDED),
|
|
348
|
+
delete: Effect.map(Effect.all(transactions.map((transaction) => transaction.delete), UNBOUNDED), (values) => Option.all(Object.fromEntries(keys.map((key, index) => [key, values[index]])))),
|
|
349
|
+
};
|
|
350
|
+
},
|
|
351
|
+
})));
|
|
352
|
+
}
|
|
353
|
+
function getTransactionAccess(ref) {
|
|
354
|
+
if (ref instanceof RefSubjectImpl) {
|
|
355
|
+
return Effect.succeed(Option.some({
|
|
356
|
+
cores: [ref.core],
|
|
357
|
+
getSetDelete: (recordCommit) => getSetDelete(ref.core, (exit) => recordCommit([ref.core, exit, ref.core.deferredRef.version])),
|
|
358
|
+
}));
|
|
359
|
+
}
|
|
360
|
+
if (ref instanceof RefSubjectSimpleTransform)
|
|
361
|
+
return getTransactionAccess(ref.ref);
|
|
362
|
+
if (ref instanceof RefSubjectTransform) {
|
|
363
|
+
const accessEffect = getTransactionAccess(ref.ref);
|
|
364
|
+
if (!accessEffect)
|
|
365
|
+
return undefined;
|
|
366
|
+
return Effect.map(accessEffect, Option.map((access) => ({
|
|
367
|
+
cores: access.cores,
|
|
368
|
+
getSetDelete: (recordCommit) => {
|
|
369
|
+
const transaction = access.getSetDelete(recordCommit);
|
|
370
|
+
return {
|
|
371
|
+
get: Effect.map(transaction.get, ref.toB),
|
|
372
|
+
set: (value) => Effect.map(transaction.set(ref.toA(value)), ref.toB),
|
|
373
|
+
delete: Effect.map(transaction.delete, Option.map(ref.toB)),
|
|
374
|
+
};
|
|
375
|
+
},
|
|
376
|
+
})));
|
|
377
|
+
}
|
|
378
|
+
if (ref instanceof RefSubjectTuple)
|
|
379
|
+
return getTupleTransactionAccess(ref.refs);
|
|
380
|
+
if (ref instanceof RefSubjectStruct)
|
|
381
|
+
return getStructTransactionAccess(ref.refs);
|
|
382
|
+
if (typeof ref === "function") {
|
|
383
|
+
const service = ref.service;
|
|
384
|
+
if (Effect.isEffect(service)) {
|
|
385
|
+
return Effect.flatMap(service, (providedRef) => {
|
|
386
|
+
const accessEffect = getTransactionAccess(providedRef);
|
|
387
|
+
return accessEffect ?? Effect.succeed(Option.none());
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return undefined;
|
|
392
|
+
}
|
|
393
|
+
function withTransactionLocks(cores, effect) {
|
|
394
|
+
let locked = effect;
|
|
395
|
+
for (let index = cores.length - 1; index >= 0; index--) {
|
|
396
|
+
locked = cores[index].semaphore.withPermits(1)(locked);
|
|
397
|
+
}
|
|
398
|
+
return locked;
|
|
399
|
+
}
|
|
400
|
+
function runTransaction(access, run) {
|
|
401
|
+
return Effect.uninterruptibleMask((restore) => {
|
|
402
|
+
const commits = [];
|
|
403
|
+
const transaction = restore(withTransactionLocks(access.cores, Effect.suspend(() => run(access.getSetDelete((commit) => {
|
|
404
|
+
commits.push(commit);
|
|
405
|
+
})))));
|
|
406
|
+
return Effect.flatMap(Effect.exit(transaction), (exit) => Effect.andThen(Effect.forEach(commits, ([core, commit, version]) => sendCurrentEvent(core, commit, version), {
|
|
407
|
+
discard: true,
|
|
408
|
+
}), exit));
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
function sendCurrentEvent(core, commit, version) {
|
|
412
|
+
return Effect.suspend(() => {
|
|
413
|
+
const current = MutableRef.get(core.deferredRef.current);
|
|
414
|
+
return core.deferredRef.version === version &&
|
|
415
|
+
Option.isSome(current) &&
|
|
416
|
+
core.deferredRef.eq(current.value, commit)
|
|
417
|
+
? sendEvent(core, commit)
|
|
418
|
+
: Effect.void;
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
function getSetDelete(ref, recordCommit) {
|
|
108
422
|
return {
|
|
109
423
|
get: getOrInitializeCore(ref, false),
|
|
110
|
-
set: (a) =>
|
|
424
|
+
set: (a) => bufferSuccessCore(ref, a, recordCommit),
|
|
111
425
|
delete: deleteCore(ref),
|
|
112
426
|
};
|
|
113
427
|
}
|
|
@@ -117,7 +431,6 @@ class RefSubjectImpl extends YieldableFx {
|
|
|
117
431
|
version;
|
|
118
432
|
interrupt;
|
|
119
433
|
subscriberCount;
|
|
120
|
-
getSetDelete;
|
|
121
434
|
core;
|
|
122
435
|
constructor(core) {
|
|
123
436
|
super();
|
|
@@ -125,25 +438,25 @@ class RefSubjectImpl extends YieldableFx {
|
|
|
125
438
|
this.version = Effect.sync(() => core.deferredRef.version);
|
|
126
439
|
this.interrupt = Effect.provide(interruptCore(core), core.services);
|
|
127
440
|
this.subscriberCount = Effect.provide(core.subject.subscriberCount, core.services);
|
|
128
|
-
this.getSetDelete = getSetDelete(core);
|
|
129
441
|
this.updates = this.updates.bind(this);
|
|
130
442
|
this.onSuccess = this.onSuccess.bind(this);
|
|
131
443
|
this.onFailure = this.onFailure.bind(this);
|
|
132
444
|
}
|
|
133
445
|
run(sink) {
|
|
446
|
+
const subscribe = Effect.provide(this.core.subject.run(sink), this.core.services);
|
|
134
447
|
return Effect.matchCauseEffect(getOrInitializeCore(this.core, true), {
|
|
135
|
-
onFailure: (
|
|
136
|
-
onSuccess: () =>
|
|
448
|
+
onFailure: () => subscribe,
|
|
449
|
+
onSuccess: () => subscribe,
|
|
137
450
|
});
|
|
138
451
|
}
|
|
139
452
|
updates(run) {
|
|
140
|
-
return this.core
|
|
453
|
+
return updateCore(this.core, (recordCommit) => run(getSetDelete(this.core, recordCommit)));
|
|
141
454
|
}
|
|
142
455
|
onSuccess(value) {
|
|
143
|
-
return
|
|
456
|
+
return updateCore(this.core, (recordCommit) => bufferSuccessCore(this.core, value, recordCommit));
|
|
144
457
|
}
|
|
145
458
|
onFailure(cause) {
|
|
146
|
-
return
|
|
459
|
+
return updateCore(this.core, (recordCommit) => bufferFailureCore(this.core, cause, recordCommit));
|
|
147
460
|
}
|
|
148
461
|
toEffect() {
|
|
149
462
|
return getOrInitializeCore(this.core, true);
|
|
@@ -152,6 +465,31 @@ class RefSubjectImpl extends YieldableFx {
|
|
|
152
465
|
/**
|
|
153
466
|
* Creates a new `RefSubject` from a value, `Effect`, or `Fx`.
|
|
154
467
|
*
|
|
468
|
+
* @remarks
|
|
469
|
+
* ## Why
|
|
470
|
+
*
|
|
471
|
+
* `RefSubject` keeps current state and pushed changes independent of any UI
|
|
472
|
+
* renderer. Domain transitions can therefore be constructed, composed, and
|
|
473
|
+
* tested with Effect alone; rendering is one optional consumer of the state.
|
|
474
|
+
* Plain values, Effect programs, pull-based Effect `Stream`s, and push-based
|
|
475
|
+
* `Fx` sources all enter through the same state boundary.
|
|
476
|
+
*
|
|
477
|
+
* ## Ownership and lifetime
|
|
478
|
+
*
|
|
479
|
+
* Creation requires an Effect `Scope`. That scope owns source acquisition,
|
|
480
|
+
* subscriptions, and finalization. The returned `RefSubject` exposes the
|
|
481
|
+
* source error type when read or observed, while construction itself cannot
|
|
482
|
+
* fail. Closing the scope interrupts a live source and releases its resources.
|
|
483
|
+
*
|
|
484
|
+
* ## Initialization
|
|
485
|
+
*
|
|
486
|
+
* Calling `make` is lazy because it returns an Effect: nothing is allocated and no source runs
|
|
487
|
+
* until that creation Effect is executed. After creation, a plain value is immediately available.
|
|
488
|
+
* An Effect input runs once on the first current read or observation. Fx and Stream inputs instead
|
|
489
|
+
* start one shared source run when the creation Effect executes; reads wait for their first value
|
|
490
|
+
* or failure and later emissions replace the retained current state. Equality and buffering
|
|
491
|
+
* behavior can be customized with `RefSubjectOptions`.
|
|
492
|
+
*
|
|
155
493
|
* @example
|
|
156
494
|
* ```ts
|
|
157
495
|
* import { Effect } from "effect"
|
|
@@ -185,7 +523,7 @@ class RefSubjectImpl extends YieldableFx {
|
|
|
185
523
|
* ```
|
|
186
524
|
*
|
|
187
525
|
* @since 1.0.0
|
|
188
|
-
* @category
|
|
526
|
+
* @category Constructors
|
|
189
527
|
*/
|
|
190
528
|
export function make(effect, options) {
|
|
191
529
|
if (isFx(effect)) {
|
|
@@ -204,6 +542,19 @@ export function make(effect, options) {
|
|
|
204
542
|
/**
|
|
205
543
|
* Creates a `RefSubject` from an `Effect`.
|
|
206
544
|
*
|
|
545
|
+
* @remarks
|
|
546
|
+
* ## Why
|
|
547
|
+
*
|
|
548
|
+
* Makes effect acquisition explicit while normalizing it into current RefSubject state and
|
|
549
|
+
* subsequent pushed versions.
|
|
550
|
+
*
|
|
551
|
+
* ## Ownership and lifetime
|
|
552
|
+
*
|
|
553
|
+
* The creation Effect requires Scope and the source's services, which it captures for the private
|
|
554
|
+
* initializer Scope. The source Effect itself stays deferred until the first current read or
|
|
555
|
+
* observation and runs at most once. Source failures remain visible on reads and observations;
|
|
556
|
+
* closing the creation Scope interrupts an initializer that is still running.
|
|
557
|
+
*
|
|
207
558
|
* @example
|
|
208
559
|
* ```ts
|
|
209
560
|
* import { Effect } from "effect"
|
|
@@ -220,7 +571,7 @@ export function make(effect, options) {
|
|
|
220
571
|
* ```
|
|
221
572
|
*
|
|
222
573
|
* @since 1.0.0
|
|
223
|
-
* @category
|
|
574
|
+
* @category Source adapters
|
|
224
575
|
*/
|
|
225
576
|
export function fromEffect(effect, options) {
|
|
226
577
|
return Effect.map(makeCore(effect, options), (core) => new RefSubjectImpl(core));
|
|
@@ -228,6 +579,17 @@ export function fromEffect(effect, options) {
|
|
|
228
579
|
/**
|
|
229
580
|
* Creates a `RefSubject` from an `Fx`, tracking the latest emitted value.
|
|
230
581
|
*
|
|
582
|
+
* @remarks
|
|
583
|
+
* ## Why
|
|
584
|
+
*
|
|
585
|
+
* Makes fx acquisition explicit while normalizing it into current RefSubject state and subsequent
|
|
586
|
+
* pushed versions.
|
|
587
|
+
*
|
|
588
|
+
* ## Ownership and lifetime
|
|
589
|
+
*
|
|
590
|
+
* The creation Effect requires Scope. It owns initializer acquisition, live source subscriptions,
|
|
591
|
+
* and cleanup; source failures and services stay on reads and pushes.
|
|
592
|
+
*
|
|
231
593
|
* @example
|
|
232
594
|
* ```ts
|
|
233
595
|
* import { Effect } from "effect"
|
|
@@ -248,27 +610,59 @@ export function fromEffect(effect, options) {
|
|
|
248
610
|
* ```
|
|
249
611
|
*
|
|
250
612
|
* @since 1.0.0
|
|
251
|
-
* @category
|
|
613
|
+
* @category Source adapters
|
|
252
614
|
*/
|
|
253
615
|
export function fromFx(fx, options) {
|
|
254
616
|
return Effect.gen(function* () {
|
|
255
617
|
const core = yield* makeDeferredCore(options);
|
|
256
618
|
const ref = new RefSubjectImpl(core);
|
|
257
|
-
yield* Effect.forkIn(fx.run(Sink.make((cause) =>
|
|
619
|
+
yield* Effect.forkIn(fx.run(Sink.make((cause) => updateCore(core, (recordCommit) => bufferFailureCore(core, cause, recordCommit)), (value) => updateCore(core, (recordCommit) => bufferSuccessCore(core, value, recordCommit)))), core.scope, { startImmediately: true });
|
|
258
620
|
return ref;
|
|
259
621
|
});
|
|
260
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* Creates a RefSubject that tracks the latest value emitted by an Effect Stream.
|
|
625
|
+
*
|
|
626
|
+
* @remarks
|
|
627
|
+
* ## Why
|
|
628
|
+
*
|
|
629
|
+
* Bridges a pull-based Stream into renderer-independent state: each emitted value enters the
|
|
630
|
+
* RefSubject's serialized commit path, while a stream failure becomes the ref's current and pushed
|
|
631
|
+
* failure.
|
|
632
|
+
*
|
|
633
|
+
* ## Ownership and lifetime
|
|
634
|
+
*
|
|
635
|
+
* Construction forks stream consumption immediately into the RefSubject's private Scope and cannot
|
|
636
|
+
* fail. `R` is required while constructing that fiber; closing the outer Scope interrupts it.
|
|
637
|
+
* Before the first value or failure, a current read waits for initialization. Later reads and pushes
|
|
638
|
+
* expose `E`.
|
|
639
|
+
*
|
|
640
|
+
* @since 1.18.0
|
|
641
|
+
* @category Source adapters
|
|
642
|
+
*/
|
|
261
643
|
export function fromStream(stream, options) {
|
|
262
644
|
return Effect.gen(function* () {
|
|
263
645
|
const core = yield* makeDeferredCore(options);
|
|
264
646
|
const ref = new RefSubjectImpl(core);
|
|
265
|
-
yield* Effect.forkIn(stream.pipe(redirectCause(core), Stream.runForEach((value) =>
|
|
647
|
+
yield* Effect.forkIn(stream.pipe(redirectCause(core), Stream.runForEach((value) => updateCore(core, (recordCommit) => bufferSuccessCore(core, value, recordCommit)))), core.scope, { startImmediately: true });
|
|
266
648
|
return ref;
|
|
267
649
|
});
|
|
268
650
|
}
|
|
269
651
|
/**
|
|
270
652
|
* Creates a `RefSubject` from an `Option` value.
|
|
271
653
|
*
|
|
654
|
+
* @remarks
|
|
655
|
+
* ## Why
|
|
656
|
+
*
|
|
657
|
+
* Stores the Option itself in writable state. `None` is an ordinary current value and does not add
|
|
658
|
+
* `NoSuchElementError`; callers opt into absence semantics with `compact`, or a fallback with
|
|
659
|
+
* `getOrElse`.
|
|
660
|
+
*
|
|
661
|
+
* ## Ownership and lifetime
|
|
662
|
+
*
|
|
663
|
+
* Construction requires Scope because it delegates to `make`, but the supplied Option needs no
|
|
664
|
+
* services and cannot fail. The returned RefSubject owns and publishes subsequent Option writes.
|
|
665
|
+
*
|
|
272
666
|
* @example
|
|
273
667
|
* ```ts
|
|
274
668
|
* import { Effect, Option } from "effect"
|
|
@@ -282,7 +676,7 @@ export function fromStream(stream, options) {
|
|
|
282
676
|
* ```
|
|
283
677
|
*
|
|
284
678
|
* @since 1.0.0
|
|
285
|
-
* @category
|
|
679
|
+
* @category Source adapters
|
|
286
680
|
*/
|
|
287
681
|
export function fromOption(option, options) {
|
|
288
682
|
return make(option, options);
|
|
@@ -307,23 +701,41 @@ export function fromOption(option, options) {
|
|
|
307
701
|
* ```
|
|
308
702
|
*
|
|
309
703
|
* @since 1.0.0
|
|
310
|
-
* @category
|
|
704
|
+
* @category Source adapters
|
|
311
705
|
*/
|
|
312
706
|
function optionFromNullable(value) {
|
|
313
707
|
return value === null || value === undefined
|
|
314
708
|
? Option.none()
|
|
315
709
|
: Option.some(value);
|
|
316
710
|
}
|
|
711
|
+
/**
|
|
712
|
+
* Creates Option-valued RefSubject state from a nullable input.
|
|
713
|
+
*
|
|
714
|
+
* @remarks
|
|
715
|
+
* ## Why
|
|
716
|
+
*
|
|
717
|
+
* Converts `null` and `undefined` to `Option.none` and every other value to `Option.some`, then
|
|
718
|
+
* stores that Option in a writable RefSubject. It does not create Filtered state or add
|
|
719
|
+
* `NoSuchElementError`.
|
|
720
|
+
*
|
|
721
|
+
* ## Ownership and lifetime
|
|
722
|
+
*
|
|
723
|
+
* Construction requires Scope because it delegates to `make`; it needs no services and cannot
|
|
724
|
+
* fail. The returned RefSubject owns and publishes subsequent Option writes.
|
|
725
|
+
*
|
|
726
|
+
* @since 1.18.0
|
|
727
|
+
* @category Source adapters
|
|
728
|
+
*/
|
|
317
729
|
export function fromNullable(value, options) {
|
|
318
730
|
return make(optionFromNullable(value), options);
|
|
319
731
|
}
|
|
320
732
|
function redirectCause(core) {
|
|
321
|
-
return Stream.catchCause((cause) => Stream.unwrap(Effect.as(
|
|
733
|
+
return Stream.catchCause((cause) => Stream.unwrap(Effect.as(updateCore(core, (recordCommit) => bufferFailureCore(core, cause, recordCommit)), Stream.empty)));
|
|
322
734
|
}
|
|
323
735
|
function makeCore(initial, options, deferredRef) {
|
|
324
736
|
return Effect.gen(function* () {
|
|
325
|
-
const services = yield* Effect.
|
|
326
|
-
const scope = yield* Scope.fork(
|
|
737
|
+
const services = yield* Effect.context();
|
|
738
|
+
const scope = yield* Scope.fork(Context.get(services, Scope.Scope));
|
|
327
739
|
const id = yield* Effect.withFiber((fiber) => Effect.succeed(fiber.id));
|
|
328
740
|
const subject = new Subject.HoldSubjectImpl();
|
|
329
741
|
const core = new RefSubjectCore(initial, subject, services, scope, deferredRef ??
|
|
@@ -335,7 +747,7 @@ function makeCore(initial, options, deferredRef) {
|
|
|
335
747
|
function makeDeferredCore(options) {
|
|
336
748
|
return Effect.gen(function* () {
|
|
337
749
|
const deferredRef = yield* DeferredRef.make(getExitEquivalence(options?.eq ?? equals));
|
|
338
|
-
return yield* makeCore(deferredRef
|
|
750
|
+
return yield* makeCore(deferredRef, options, deferredRef);
|
|
339
751
|
});
|
|
340
752
|
}
|
|
341
753
|
function getOrInitializeCore(core, lockInitialize) {
|
|
@@ -344,30 +756,51 @@ function getOrInitializeCore(core, lockInitialize) {
|
|
|
344
756
|
return initializeCoreAndTap(core, lockInitialize);
|
|
345
757
|
}
|
|
346
758
|
else {
|
|
347
|
-
return core.deferredRef
|
|
759
|
+
return core.deferredRef;
|
|
348
760
|
}
|
|
349
761
|
});
|
|
350
762
|
}
|
|
351
763
|
function initializeCoreEffect(core, lock) {
|
|
764
|
+
let completed = false;
|
|
352
765
|
const initialize = Effect.onExit(Effect.provide(core.initial, core.services), (exit) => Effect.sync(() => {
|
|
766
|
+
completed = true;
|
|
353
767
|
core._fiber = undefined;
|
|
354
768
|
core.deferredRef.done(exit);
|
|
355
769
|
}));
|
|
356
|
-
|
|
770
|
+
const isSourceBacked = core.initial === core.deferredRef;
|
|
771
|
+
return Effect.flatMap(Effect.forkIn(lock && !isSourceBacked ? core.semaphore.withPermits(1)(initialize) : initialize, core.scope,
|
|
772
|
+
// Acquire the initializer's permit before a competing update can hold it while awaiting us.
|
|
773
|
+
{ startImmediately: true }), (fiber) => Effect.sync(() => {
|
|
774
|
+
// A synchronous initializer has already cleared its ownership in onExit.
|
|
775
|
+
if (!completed)
|
|
776
|
+
core._fiber = fiber;
|
|
777
|
+
return fiber;
|
|
778
|
+
}));
|
|
357
779
|
}
|
|
358
780
|
function initializeCoreAndTap(core, lock) {
|
|
359
|
-
return Effect.flatMapEager(initializeCoreEffect(core, lock), () =>
|
|
781
|
+
return Effect.flatMapEager(initializeCoreEffect(core, lock), () =>
|
|
782
|
+
// Kind of weird hack, but this second clause will happen for HydrationRefs that are already hydrated
|
|
783
|
+
core.deferredRef.current === core.subject.lastValue
|
|
784
|
+
? tapEventCore(core, core.deferredRef)
|
|
785
|
+
: core.deferredRef);
|
|
786
|
+
}
|
|
787
|
+
function updateCore(core, run) {
|
|
788
|
+
return Effect.uninterruptibleMask((restore) => {
|
|
789
|
+
const commits = [];
|
|
790
|
+
const transaction = restore(core.semaphore.withPermits(1)(Effect.suspend(() => run((commit) => {
|
|
791
|
+
commits.push(commit);
|
|
792
|
+
}))));
|
|
793
|
+
return Effect.flatMap(Effect.exit(transaction), (exit) => Effect.andThen(Effect.forEach(commits, (commit) => sendEvent(core, commit), { discard: true }), exit));
|
|
794
|
+
});
|
|
360
795
|
}
|
|
361
796
|
function setCore(core, a) {
|
|
362
797
|
return Effect.suspend(() => {
|
|
363
798
|
const exit = Exit.succeed(a);
|
|
364
799
|
if (core.deferredRef.done(exit)) {
|
|
365
|
-
|
|
366
|
-
return Effect.as(sendEvent(core, exit), a);
|
|
800
|
+
return Effect.succeed(Option.some(exit));
|
|
367
801
|
}
|
|
368
802
|
else {
|
|
369
|
-
|
|
370
|
-
return Effect.succeed(a);
|
|
803
|
+
return Effect.succeed(Option.none());
|
|
371
804
|
}
|
|
372
805
|
});
|
|
373
806
|
}
|
|
@@ -375,13 +808,26 @@ function onFailureCore(core, cause) {
|
|
|
375
808
|
const exit = Exit.failCause(cause);
|
|
376
809
|
return Effect.suspend(() => {
|
|
377
810
|
if (core.deferredRef.done(exit)) {
|
|
378
|
-
return
|
|
811
|
+
return Effect.succeed(Option.some(exit));
|
|
379
812
|
}
|
|
380
813
|
else {
|
|
381
|
-
return Effect.
|
|
814
|
+
return Effect.succeed(Option.none());
|
|
382
815
|
}
|
|
383
816
|
});
|
|
384
817
|
}
|
|
818
|
+
function bufferSuccessCore(core, value, recordCommit) {
|
|
819
|
+
return Effect.map(setCore(core, value), (commit) => {
|
|
820
|
+
if (Option.isSome(commit))
|
|
821
|
+
recordCommit(commit.value);
|
|
822
|
+
return value;
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
function bufferFailureCore(core, cause, recordCommit) {
|
|
826
|
+
return Effect.asVoid(Effect.map(onFailureCore(core, cause), (commit) => {
|
|
827
|
+
if (Option.isSome(commit))
|
|
828
|
+
recordCommit(commit.value);
|
|
829
|
+
}));
|
|
830
|
+
}
|
|
385
831
|
function interruptCore(core) {
|
|
386
832
|
return Effect.withFiber((fiber) => {
|
|
387
833
|
core.deferredRef.reset();
|
|
@@ -415,6 +861,17 @@ function sendEvent(core, exit) {
|
|
|
415
861
|
/**
|
|
416
862
|
* Sets the value of a `RefSubject`.
|
|
417
863
|
*
|
|
864
|
+
* @remarks
|
|
865
|
+
* ## Why
|
|
866
|
+
*
|
|
867
|
+
* Sets the value of a `RefSubject`. The transition is serialized at the RefSubject rather than
|
|
868
|
+
* coordinated by callers or UI components.
|
|
869
|
+
*
|
|
870
|
+
* ## Ownership and lifetime
|
|
871
|
+
*
|
|
872
|
+
* Running set performs one serialized subject transition and resolves with its committed value. It
|
|
873
|
+
* acquires no resource; failures and services remain those of the source ref.
|
|
874
|
+
*
|
|
418
875
|
* @example
|
|
419
876
|
* ```ts
|
|
420
877
|
* import { Effect } from "effect"
|
|
@@ -436,7 +893,7 @@ function sendEvent(core, exit) {
|
|
|
436
893
|
* ```
|
|
437
894
|
*
|
|
438
895
|
* @since 1.0.0
|
|
439
|
-
* @category
|
|
896
|
+
* @category State updates
|
|
440
897
|
*/
|
|
441
898
|
export const set = dual(2, function set(ref, a) {
|
|
442
899
|
return ref.updates((ref) => ref.set(a));
|
|
@@ -444,6 +901,17 @@ export const set = dual(2, function set(ref, a) {
|
|
|
444
901
|
/**
|
|
445
902
|
* Resets a `RefSubject` to its initial value, returning the previous value if it existed.
|
|
446
903
|
*
|
|
904
|
+
* @remarks
|
|
905
|
+
* ## Why
|
|
906
|
+
*
|
|
907
|
+
* Resets a `RefSubject` to its initial value, returning the previous value if it existed. The
|
|
908
|
+
* transition is serialized at the RefSubject rather than coordinated by callers or UI components.
|
|
909
|
+
*
|
|
910
|
+
* ## Ownership and lifetime
|
|
911
|
+
*
|
|
912
|
+
* Running reset performs one serialized subject transition and resolves with its committed value.
|
|
913
|
+
* It acquires no resource; failures and services remain those of the source ref.
|
|
914
|
+
*
|
|
447
915
|
* @example
|
|
448
916
|
* ```ts
|
|
449
917
|
* import { Effect, Option } from "effect"
|
|
@@ -467,7 +935,7 @@ export const set = dual(2, function set(ref, a) {
|
|
|
467
935
|
* ```
|
|
468
936
|
*
|
|
469
937
|
* @since 1.0.0
|
|
470
|
-
* @category
|
|
938
|
+
* @category State updates
|
|
471
939
|
*/
|
|
472
940
|
export function reset(ref) {
|
|
473
941
|
return ref.updates((ref) => ref.delete);
|
|
@@ -497,12 +965,23 @@ export {
|
|
|
497
965
|
* ```
|
|
498
966
|
*
|
|
499
967
|
* @since 1.20.0
|
|
500
|
-
* @category
|
|
968
|
+
* @category State updates
|
|
501
969
|
*/
|
|
502
970
|
reset as delete, };
|
|
503
971
|
/**
|
|
504
972
|
* Updates a `RefSubject` using an `Effect`ful function.
|
|
505
973
|
*
|
|
974
|
+
* @remarks
|
|
975
|
+
* ## Why
|
|
976
|
+
*
|
|
977
|
+
* Updates a `RefSubject` using an `Effect`ful function. The transition is serialized at the
|
|
978
|
+
* RefSubject rather than coordinated by callers or UI components.
|
|
979
|
+
*
|
|
980
|
+
* ## Ownership and lifetime
|
|
981
|
+
*
|
|
982
|
+
* Running update effect performs one serialized subject transition and resolves with its committed
|
|
983
|
+
* value. It acquires no resource; failures and services remain those of the source ref.
|
|
984
|
+
*
|
|
506
985
|
* @example
|
|
507
986
|
* ```ts
|
|
508
987
|
* import { Effect } from "effect"
|
|
@@ -522,7 +1001,7 @@ reset as delete, };
|
|
|
522
1001
|
* ```
|
|
523
1002
|
*
|
|
524
1003
|
* @since 1.0.0
|
|
525
|
-
* @category
|
|
1004
|
+
* @category State updates
|
|
526
1005
|
*/
|
|
527
1006
|
export const updateEffect = dual(2, function updateEffect(ref, f) {
|
|
528
1007
|
return ref.updates((ref) => Effect.flatMap(Effect.flatMap(ref.get, f), ref.set));
|
|
@@ -530,6 +1009,26 @@ export const updateEffect = dual(2, function updateEffect(ref, f) {
|
|
|
530
1009
|
/**
|
|
531
1010
|
* Updates a `RefSubject` using a pure function.
|
|
532
1011
|
*
|
|
1012
|
+
* @remarks
|
|
1013
|
+
* ## Why
|
|
1014
|
+
*
|
|
1015
|
+
* `update` expresses a state transition where the state lives, without moving
|
|
1016
|
+
* transition logic into a component or renderer. The same function can run in
|
|
1017
|
+
* application code, tests, workers, event handlers, or a Typed template.
|
|
1018
|
+
*
|
|
1019
|
+
* ## Ownership and lifetime
|
|
1020
|
+
*
|
|
1021
|
+
* The update runs inside the RefSubject's existing synchronized update
|
|
1022
|
+
* boundary: it reads the committed value, derives the next value, commits it,
|
|
1023
|
+
* and publishes that change. It acquires no independent resource and retains
|
|
1024
|
+
* the subject's existing error and service channels.
|
|
1025
|
+
*
|
|
1026
|
+
* ## Concurrency and failure
|
|
1027
|
+
*
|
|
1028
|
+
* Concurrent updates are serialized by the subject core so each function sees
|
|
1029
|
+
* a committed value. A pure updater adds no error channel; failures already
|
|
1030
|
+
* associated with reading or writing the RefSubject remain explicit in `E`.
|
|
1031
|
+
*
|
|
533
1032
|
* @example
|
|
534
1033
|
* ```ts
|
|
535
1034
|
* import { Effect } from "effect"
|
|
@@ -551,7 +1050,7 @@ export const updateEffect = dual(2, function updateEffect(ref, f) {
|
|
|
551
1050
|
* ```
|
|
552
1051
|
*
|
|
553
1052
|
* @since 1.0.0
|
|
554
|
-
* @category
|
|
1053
|
+
* @category State updates
|
|
555
1054
|
*/
|
|
556
1055
|
export const update = dual(2, function update(ref, f) {
|
|
557
1056
|
return updateEffect(ref, (value) => Effect.succeed(f(value)));
|
|
@@ -559,6 +1058,18 @@ export const update = dual(2, function update(ref, f) {
|
|
|
559
1058
|
/**
|
|
560
1059
|
* Modifies a `RefSubject` using an `Effect`ful function that returns both a result and a new value.
|
|
561
1060
|
*
|
|
1061
|
+
* @remarks
|
|
1062
|
+
* ## Why
|
|
1063
|
+
*
|
|
1064
|
+
* Modifies a `RefSubject` using an `Effect`ful function that returns both a result and a new
|
|
1065
|
+
* value. The transition is serialized at the RefSubject rather than coordinated by callers or UI
|
|
1066
|
+
* components.
|
|
1067
|
+
*
|
|
1068
|
+
* ## Ownership and lifetime
|
|
1069
|
+
*
|
|
1070
|
+
* Running modify effect performs one serialized subject transition and resolves with its committed
|
|
1071
|
+
* value. It acquires no resource; failures and services remain those of the source ref.
|
|
1072
|
+
*
|
|
562
1073
|
* @example
|
|
563
1074
|
* ```ts
|
|
564
1075
|
* import { Effect } from "effect"
|
|
@@ -579,14 +1090,25 @@ export const update = dual(2, function update(ref, f) {
|
|
|
579
1090
|
* ```
|
|
580
1091
|
*
|
|
581
1092
|
* @since 1.0.0
|
|
582
|
-
* @category
|
|
1093
|
+
* @category Transactions
|
|
583
1094
|
*/
|
|
584
1095
|
export const modifyEffect = dual(2, function modifyEffect(ref, f) {
|
|
585
|
-
return ref.updates((ref) => Effect.flatMap(ref.get, (value) => Effect.flatMap(f(value), ([b, a]) => Effect.
|
|
1096
|
+
return ref.updates((ref) => Effect.flatMap(ref.get, (value) => Effect.flatMap(f(value), ([b, a]) => Effect.as(ref.set(a), b))));
|
|
586
1097
|
});
|
|
587
1098
|
/**
|
|
588
1099
|
* Modifies a `RefSubject` using a pure function that returns both a result and a new value.
|
|
589
1100
|
*
|
|
1101
|
+
* @remarks
|
|
1102
|
+
* ## Why
|
|
1103
|
+
*
|
|
1104
|
+
* Modifies a `RefSubject` using a pure function that returns both a result and a new value. The
|
|
1105
|
+
* transition is serialized at the RefSubject rather than coordinated by callers or UI components.
|
|
1106
|
+
*
|
|
1107
|
+
* ## Ownership and lifetime
|
|
1108
|
+
*
|
|
1109
|
+
* Running modify performs one serialized subject transition and resolves with its committed value.
|
|
1110
|
+
* It acquires no resource; failures and services remain those of the source ref.
|
|
1111
|
+
*
|
|
590
1112
|
* @example
|
|
591
1113
|
* ```ts
|
|
592
1114
|
* import { Effect } from "effect"
|
|
@@ -605,7 +1127,7 @@ export const modifyEffect = dual(2, function modifyEffect(ref, f) {
|
|
|
605
1127
|
* ```
|
|
606
1128
|
*
|
|
607
1129
|
* @since 1.0.0
|
|
608
|
-
* @category
|
|
1130
|
+
* @category Transactions
|
|
609
1131
|
*/
|
|
610
1132
|
export const modify = dual(2, function modify(ref, f) {
|
|
611
1133
|
return modifyEffect(ref, (value) => Effect.succeed(f(value)));
|
|
@@ -613,6 +1135,16 @@ export const modify = dual(2, function modify(ref, f) {
|
|
|
613
1135
|
/**
|
|
614
1136
|
* Checks if a value is a `RefSubject`.
|
|
615
1137
|
*
|
|
1138
|
+
* @remarks
|
|
1139
|
+
* ## Why
|
|
1140
|
+
*
|
|
1141
|
+
* Checks if a value is a `RefSubject`.
|
|
1142
|
+
*
|
|
1143
|
+
* ## Ownership and lifetime
|
|
1144
|
+
*
|
|
1145
|
+
* The derived ref owns no independent state or subscription. It follows the source lifetime and
|
|
1146
|
+
* routes writes through the source's synchronized update boundary.
|
|
1147
|
+
*
|
|
616
1148
|
* @example
|
|
617
1149
|
* ```ts
|
|
618
1150
|
* import { Effect } from "effect"
|
|
@@ -630,14 +1162,45 @@ export const modify = dual(2, function modify(ref, f) {
|
|
|
630
1162
|
* ```
|
|
631
1163
|
*
|
|
632
1164
|
* @since 1.0.0
|
|
633
|
-
* @category guards
|
|
1165
|
+
* @category Type guards
|
|
634
1166
|
*/
|
|
635
1167
|
export function isRefSubject(value) {
|
|
636
|
-
return value
|
|
1168
|
+
return hasProperty(value, RefSubjectTypeId) && value[RefSubjectTypeId] === RefSubjectTypeId;
|
|
637
1169
|
}
|
|
638
1170
|
const isRefSubjectDataFirst = (args) => isRefSubject(args[0]);
|
|
639
1171
|
/**
|
|
1172
|
+
* Tests whether a value carries the public Computed TypeId.
|
|
1173
|
+
*
|
|
1174
|
+
* @remarks
|
|
1175
|
+
* ## Why
|
|
1176
|
+
*
|
|
1177
|
+
* Uses the TypeId contract rather than a concrete implementation class, so custom Computed values
|
|
1178
|
+
* and service facades participate in the same runtime guard.
|
|
1179
|
+
*
|
|
1180
|
+
* ## Ownership and lifetime
|
|
1181
|
+
*
|
|
1182
|
+
* This synchronous predicate performs no Effect, subscription, or acquisition.
|
|
1183
|
+
*
|
|
1184
|
+
* @since 1.18.0
|
|
1185
|
+
* @category Type guards
|
|
1186
|
+
*/
|
|
1187
|
+
export function isComputed(value) {
|
|
1188
|
+
return hasProperty(value, ComputedTypeId) && value[ComputedTypeId] === ComputedTypeId;
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Runs an effect that can modify a `RefSubject` transactionally, with optional interrupt handling.
|
|
1192
|
+
*
|
|
1193
|
+
* @remarks
|
|
1194
|
+
* ## Why
|
|
1195
|
+
*
|
|
640
1196
|
* Runs an effect that can modify a `RefSubject` transactionally, with optional interrupt handling.
|
|
1197
|
+
* The transition is serialized at the RefSubject rather than coordinated by callers or UI
|
|
1198
|
+
* components.
|
|
1199
|
+
*
|
|
1200
|
+
* ## Ownership and lifetime
|
|
1201
|
+
*
|
|
1202
|
+
* Running run updates performs one serialized subject transition and resolves with its committed
|
|
1203
|
+
* value. It acquires no resource; failures and services remain those of the source ref.
|
|
641
1204
|
*
|
|
642
1205
|
* @example
|
|
643
1206
|
* ```ts
|
|
@@ -668,7 +1231,7 @@ const isRefSubjectDataFirst = (args) => isRefSubject(args[0]);
|
|
|
668
1231
|
* ```
|
|
669
1232
|
*
|
|
670
1233
|
* @since 1.0.0
|
|
671
|
-
* @category
|
|
1234
|
+
* @category Transactions
|
|
672
1235
|
*/
|
|
673
1236
|
export const runUpdates = dual(isRefSubjectDataFirst, function runUpdates(ref, f, options) {
|
|
674
1237
|
if (options === undefined) {
|
|
@@ -684,6 +1247,17 @@ export const runUpdates = dual(isRefSubjectDataFirst, function runUpdates(ref, f
|
|
|
684
1247
|
/**
|
|
685
1248
|
* Increments a numeric `RefSubject` by 1.
|
|
686
1249
|
*
|
|
1250
|
+
* @remarks
|
|
1251
|
+
* ## Why
|
|
1252
|
+
*
|
|
1253
|
+
* Increments a numeric `RefSubject` by 1. The transition is serialized at the RefSubject rather
|
|
1254
|
+
* than coordinated by callers or UI components.
|
|
1255
|
+
*
|
|
1256
|
+
* ## Ownership and lifetime
|
|
1257
|
+
*
|
|
1258
|
+
* Running increment performs one serialized subject transition and resolves with its committed
|
|
1259
|
+
* value. It acquires no resource; failures and services remain those of the source ref.
|
|
1260
|
+
*
|
|
687
1261
|
* @example
|
|
688
1262
|
* ```ts
|
|
689
1263
|
* import { Effect } from "effect"
|
|
@@ -703,7 +1277,7 @@ export const runUpdates = dual(isRefSubjectDataFirst, function runUpdates(ref, f
|
|
|
703
1277
|
* ```
|
|
704
1278
|
*
|
|
705
1279
|
* @since 1.0.0
|
|
706
|
-
* @category
|
|
1280
|
+
* @category State updates
|
|
707
1281
|
*/
|
|
708
1282
|
export function increment(ref) {
|
|
709
1283
|
return update(ref, (value) => value + 1);
|
|
@@ -711,6 +1285,17 @@ export function increment(ref) {
|
|
|
711
1285
|
/**
|
|
712
1286
|
* Decrements a numeric `RefSubject` by 1.
|
|
713
1287
|
*
|
|
1288
|
+
* @remarks
|
|
1289
|
+
* ## Why
|
|
1290
|
+
*
|
|
1291
|
+
* Decrements a numeric `RefSubject` by 1. The transition is serialized at the RefSubject rather
|
|
1292
|
+
* than coordinated by callers or UI components.
|
|
1293
|
+
*
|
|
1294
|
+
* ## Ownership and lifetime
|
|
1295
|
+
*
|
|
1296
|
+
* Running decrement performs one serialized subject transition and resolves with its committed
|
|
1297
|
+
* value. It acquires no resource; failures and services remain those of the source ref.
|
|
1298
|
+
*
|
|
714
1299
|
* @example
|
|
715
1300
|
* ```ts
|
|
716
1301
|
* import { Effect } from "effect"
|
|
@@ -730,7 +1315,7 @@ export function increment(ref) {
|
|
|
730
1315
|
* ```
|
|
731
1316
|
*
|
|
732
1317
|
* @since 1.0.0
|
|
733
|
-
* @category
|
|
1318
|
+
* @category State updates
|
|
734
1319
|
*/
|
|
735
1320
|
export function decrement(ref) {
|
|
736
1321
|
return update(ref, (value) => value - 1);
|
|
@@ -740,12 +1325,42 @@ const Variance = {
|
|
|
740
1325
|
_E: identity,
|
|
741
1326
|
_R: identity,
|
|
742
1327
|
};
|
|
1328
|
+
/**
|
|
1329
|
+
* Creates a Context-backed RefSubject service facade and Layer constructors.
|
|
1330
|
+
*
|
|
1331
|
+
* @remarks
|
|
1332
|
+
* ## Why
|
|
1333
|
+
*
|
|
1334
|
+
* The returned class is simultaneously a service tag, a current-value Effect, an Fx source, and a
|
|
1335
|
+
* writable RefSubject facade. This lets consumers read, observe, and update renderer-independent
|
|
1336
|
+
* state without manually retrieving the underlying service from Context.
|
|
1337
|
+
*
|
|
1338
|
+
* ## Ownership and lifetime
|
|
1339
|
+
*
|
|
1340
|
+
* Calling `Service` is pure. `layer` installs an existing scoped RefSubject; `make` constructs one
|
|
1341
|
+
* and installs it in a Layer. The Layer Scope owns the subject and its initializer subscription.
|
|
1342
|
+
* Reads and pushes expose the declared `E` channel; construction requirements remain on the Layer,
|
|
1343
|
+
* while consumers require only the generated `Self` service.
|
|
1344
|
+
*
|
|
1345
|
+
* @since 1.18.0
|
|
1346
|
+
* @category Services
|
|
1347
|
+
*/
|
|
743
1348
|
export function Service() {
|
|
744
1349
|
return (id) => {
|
|
745
|
-
const service =
|
|
1350
|
+
const service = Context.Service(id);
|
|
746
1351
|
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
747
1352
|
return class RefSubjectService {
|
|
748
1353
|
/// Service
|
|
1354
|
+
static {
|
|
1355
|
+
// @effect-diagnostics-next-line floatingEffect:off
|
|
1356
|
+
Object.assign(this, service);
|
|
1357
|
+
Object.setPrototypeOf(this, Object.getPrototypeOf(service));
|
|
1358
|
+
// @effect-diagnostics-next-line floatingEffect:off
|
|
1359
|
+
Object.assign(this, Effectable.Prototype({
|
|
1360
|
+
label: "RefSubject.Service",
|
|
1361
|
+
evaluate: () => Effect.flatMap(service, identity),
|
|
1362
|
+
}));
|
|
1363
|
+
}
|
|
749
1364
|
static id = id;
|
|
750
1365
|
static service = service;
|
|
751
1366
|
static layer = (make) => Layer.effect(service, make);
|
|
@@ -755,21 +1370,21 @@ export function Service() {
|
|
|
755
1370
|
};
|
|
756
1371
|
// Fx
|
|
757
1372
|
static [FxTypeId] = Variance;
|
|
758
|
-
static run = (sink) => Effect.flatMap(service
|
|
1373
|
+
static run = (sink) => Effect.flatMap(service, (ref) => ref.run(sink));
|
|
759
1374
|
// Sink
|
|
760
|
-
static onSuccess = (value) => Effect.flatMap(service
|
|
761
|
-
static onFailure = (cause) => Effect.flatMap(service
|
|
1375
|
+
static onSuccess = (value) => Effect.flatMap(service, (ref) => ref.onSuccess(value));
|
|
1376
|
+
static onFailure = (cause) => Effect.flatMap(service, (ref) => ref.onFailure(cause));
|
|
762
1377
|
/// Computed
|
|
763
1378
|
static [ComputedTypeId] = ComputedTypeId;
|
|
764
|
-
static version = Effect.flatMap(service
|
|
1379
|
+
static version = Effect.flatMap(service, (ref) => ref.version);
|
|
765
1380
|
// Subject
|
|
766
|
-
static subscriberCount = Effect.flatMap(service
|
|
767
|
-
static interrupt = Effect.flatMap(service
|
|
1381
|
+
static subscriberCount = Effect.flatMap(service, (ref) => ref.subscriberCount);
|
|
1382
|
+
static interrupt = Effect.flatMap(service, (ref) => ref.interrupt);
|
|
768
1383
|
// RefSubject
|
|
769
1384
|
static [RefSubjectTypeId] = RefSubjectTypeId;
|
|
770
|
-
static updates = (f) => Effect.flatMap(service
|
|
1385
|
+
static updates = (f) => Effect.flatMap(service, (ref) => ref.updates(f));
|
|
771
1386
|
// Yieldable
|
|
772
|
-
static
|
|
1387
|
+
static override = Effect.flatten(service);
|
|
773
1388
|
static [Symbol.iterator] = function* () {
|
|
774
1389
|
const ref = yield* service;
|
|
775
1390
|
return yield* ref;
|
|
@@ -793,6 +1408,19 @@ function getDefaultBounds(options) {
|
|
|
793
1408
|
* Extract all values from an object using a Proxy.
|
|
794
1409
|
* Allows accessing nested properties of a `Computed` or `Filtered` object/array as individual computed values.
|
|
795
1410
|
*
|
|
1411
|
+
* @remarks
|
|
1412
|
+
* ## Why
|
|
1413
|
+
*
|
|
1414
|
+
* Lazily creates one property projection per accessed key and memoizes that projection on the
|
|
1415
|
+
* JavaScript Proxy. A Computed or RefSubject source produces Computed properties; only a Filtered
|
|
1416
|
+
* source produces Filtered properties and preserves conditional absence.
|
|
1417
|
+
*
|
|
1418
|
+
* ## Ownership and lifetime
|
|
1419
|
+
*
|
|
1420
|
+
* The Proxy caches derived view objects, not property values. Computed property reads expose only
|
|
1421
|
+
* the source's `E`; Filtered property reads can additionally fail with `NoSuchElementError` while
|
|
1422
|
+
* their source is absent. Each observed property follows the source and uses the observing Scope.
|
|
1423
|
+
*
|
|
796
1424
|
* @example
|
|
797
1425
|
* ```ts
|
|
798
1426
|
* import { Effect } from "effect"
|
|
@@ -821,7 +1449,7 @@ function getDefaultBounds(options) {
|
|
|
821
1449
|
* ```
|
|
822
1450
|
*
|
|
823
1451
|
* @since 2.0.0
|
|
824
|
-
* @category
|
|
1452
|
+
* @category Derived queries
|
|
825
1453
|
*/
|
|
826
1454
|
export const proxy = (source) => {
|
|
827
1455
|
const target = {};
|
|
@@ -836,6 +1464,20 @@ export const proxy = (source) => {
|
|
|
836
1464
|
/**
|
|
837
1465
|
* Transforms a `RefSubject`, `Computed`, or `Filtered` using an `Effect`ful function.
|
|
838
1466
|
*
|
|
1467
|
+
* @remarks
|
|
1468
|
+
* ## Why
|
|
1469
|
+
*
|
|
1470
|
+
* Applies one Effectful derivation to current reads and pushed versions. RefSubject and Computed
|
|
1471
|
+
* inputs return Computed and add only `E2`; a Filtered input returns Filtered and preserves its
|
|
1472
|
+
* conditional absence in addition to `E2`.
|
|
1473
|
+
*
|
|
1474
|
+
* ## Ownership and lifetime
|
|
1475
|
+
*
|
|
1476
|
+
* No callback runs until the result is read or observed. Computed results cannot become absent and
|
|
1477
|
+
* do not add `NoSuchElementError`; only the Filtered overload can fail a current read for absence.
|
|
1478
|
+
* Callback services and failures remain `R2` and `E2`, and the observing Scope owns subscription
|
|
1479
|
+
* cleanup.
|
|
1480
|
+
*
|
|
839
1481
|
* @example
|
|
840
1482
|
* ```ts
|
|
841
1483
|
* import { Effect } from "effect"
|
|
@@ -862,7 +1504,7 @@ export const proxy = (source) => {
|
|
|
862
1504
|
* ```
|
|
863
1505
|
*
|
|
864
1506
|
* @since 1.0.0
|
|
865
|
-
* @category
|
|
1507
|
+
* @category Derived queries
|
|
866
1508
|
*/
|
|
867
1509
|
export const mapEffect = dual(2, function mapEffect(versioned, f) {
|
|
868
1510
|
return FilteredTypeId in versioned
|
|
@@ -872,6 +1514,25 @@ export const mapEffect = dual(2, function mapEffect(versioned, f) {
|
|
|
872
1514
|
/**
|
|
873
1515
|
* Transforms a `RefSubject`, `Computed`, or `Filtered` using a pure function.
|
|
874
1516
|
*
|
|
1517
|
+
* @remarks
|
|
1518
|
+
* ## Why
|
|
1519
|
+
*
|
|
1520
|
+
* `map` creates derived state instead of copying source state into a component.
|
|
1521
|
+
* Reads and pushed updates remain connected to the original `Versioned` value,
|
|
1522
|
+
* so a projection can be tested without rendering and consumed by any renderer.
|
|
1523
|
+
*
|
|
1524
|
+
* ## Ownership and lifetime
|
|
1525
|
+
*
|
|
1526
|
+
* The returned `Computed` or `Filtered` view does not take ownership of the
|
|
1527
|
+
* source. It follows the source lifetime and preserves its error and service
|
|
1528
|
+
* channels. The pure mapping function adds neither resources nor failures.
|
|
1529
|
+
*
|
|
1530
|
+
* ## Re-computation
|
|
1531
|
+
*
|
|
1532
|
+
* The mapping function runs for the current value and subsequent committed
|
|
1533
|
+
* source versions. Updates still occur on the writable source; the derived view
|
|
1534
|
+
* is read-only unless a more specific bidirectional combinator is used.
|
|
1535
|
+
*
|
|
875
1536
|
* @example
|
|
876
1537
|
* ```ts
|
|
877
1538
|
* import { Effect } from "effect"
|
|
@@ -896,7 +1557,7 @@ export const mapEffect = dual(2, function mapEffect(versioned, f) {
|
|
|
896
1557
|
* ```
|
|
897
1558
|
*
|
|
898
1559
|
* @since 1.0.0
|
|
899
|
-
* @category
|
|
1560
|
+
* @category Derived queries
|
|
900
1561
|
*/
|
|
901
1562
|
export const map = dual(2, function map(versioned, f) {
|
|
902
1563
|
return mapEffect(versioned, (a) => Effect.succeed(f(a)));
|
|
@@ -904,6 +1565,18 @@ export const map = dual(2, function map(versioned, f) {
|
|
|
904
1565
|
/**
|
|
905
1566
|
* Filters and transforms a `RefSubject`, `Computed`, or `Filtered` using an `Effect`ful function that returns an `Option`.
|
|
906
1567
|
*
|
|
1568
|
+
* @remarks
|
|
1569
|
+
* ## Why
|
|
1570
|
+
*
|
|
1571
|
+
* Filters and transforms a `RefSubject`, `Computed`, or `Filtered` using an `Effect`ful function
|
|
1572
|
+
* that returns an `Option`. Current reads and pushed versions use the same derivation, preventing
|
|
1573
|
+
* snapshot and subscription behavior from diverging.
|
|
1574
|
+
*
|
|
1575
|
+
* ## Ownership and lifetime
|
|
1576
|
+
*
|
|
1577
|
+
* The filter map effect view retains no independent value. Its Effect read fails with NoSuchElement
|
|
1578
|
+
* while absent; the observing Scope owns and finalizes its Fx subscription.
|
|
1579
|
+
*
|
|
907
1580
|
* @example
|
|
908
1581
|
* ```ts
|
|
909
1582
|
* import { Effect, Option } from "effect"
|
|
@@ -923,7 +1596,7 @@ export const map = dual(2, function map(versioned, f) {
|
|
|
923
1596
|
* ```
|
|
924
1597
|
*
|
|
925
1598
|
* @since 1.0.0
|
|
926
|
-
* @category
|
|
1599
|
+
* @category Optional queries
|
|
927
1600
|
*/
|
|
928
1601
|
export const filterMapEffect = dual(2, function filterMapEffect(versioned, f) {
|
|
929
1602
|
return new FilteredImpl(versioned, f);
|
|
@@ -931,6 +1604,18 @@ export const filterMapEffect = dual(2, function filterMapEffect(versioned, f) {
|
|
|
931
1604
|
/**
|
|
932
1605
|
* Filters and transforms a `RefSubject`, `Computed`, or `Filtered` using a pure function that returns an `Option`.
|
|
933
1606
|
*
|
|
1607
|
+
* @remarks
|
|
1608
|
+
* ## Why
|
|
1609
|
+
*
|
|
1610
|
+
* Filters and transforms a `RefSubject`, `Computed`, or `Filtered` using a pure function that
|
|
1611
|
+
* returns an `Option`. Current reads and pushed versions use the same derivation, preventing
|
|
1612
|
+
* snapshot and subscription behavior from diverging.
|
|
1613
|
+
*
|
|
1614
|
+
* ## Ownership and lifetime
|
|
1615
|
+
*
|
|
1616
|
+
* The filter map view retains no independent value. Its Effect read fails with NoSuchElement
|
|
1617
|
+
* while absent; the observing Scope owns and finalizes its Fx subscription.
|
|
1618
|
+
*
|
|
934
1619
|
* @example
|
|
935
1620
|
* ```ts
|
|
936
1621
|
* import { Effect, Option } from "effect"
|
|
@@ -950,7 +1635,7 @@ export const filterMapEffect = dual(2, function filterMapEffect(versioned, f) {
|
|
|
950
1635
|
* ```
|
|
951
1636
|
*
|
|
952
1637
|
* @since 1.0.0
|
|
953
|
-
* @category
|
|
1638
|
+
* @category Optional queries
|
|
954
1639
|
*/
|
|
955
1640
|
export const filterMap = dual(2, function filterMap(versioned, f) {
|
|
956
1641
|
return new FilteredImpl(versioned, (a) => Effect.succeed(f(a)));
|
|
@@ -958,6 +1643,18 @@ export const filterMap = dual(2, function filterMap(versioned, f) {
|
|
|
958
1643
|
/**
|
|
959
1644
|
* Converts a `Computed` or `Filtered` of `Option<A>` into a `Filtered<A>`, filtering out `None` values.
|
|
960
1645
|
*
|
|
1646
|
+
* @remarks
|
|
1647
|
+
* ## Why
|
|
1648
|
+
*
|
|
1649
|
+
* Converts a `Computed` or `Filtered` of `Option<A>` into a `Filtered<A>`, filtering out `None`
|
|
1650
|
+
* values. Current reads and pushed versions use the same derivation, preventing snapshot and
|
|
1651
|
+
* subscription behavior from diverging.
|
|
1652
|
+
*
|
|
1653
|
+
* ## Ownership and lifetime
|
|
1654
|
+
*
|
|
1655
|
+
* The compact view retains no independent value. Its Effect read fails with NoSuchElement
|
|
1656
|
+
* while absent; the observing Scope owns and finalizes its Fx subscription.
|
|
1657
|
+
*
|
|
961
1658
|
* @example
|
|
962
1659
|
* ```ts
|
|
963
1660
|
* import { Effect, Option } from "effect"
|
|
@@ -979,7 +1676,7 @@ export const filterMap = dual(2, function filterMap(versioned, f) {
|
|
|
979
1676
|
* ```
|
|
980
1677
|
*
|
|
981
1678
|
* @since 1.0.0
|
|
982
|
-
* @category
|
|
1679
|
+
* @category Optional queries
|
|
983
1680
|
*/
|
|
984
1681
|
export const compact = function compact(versioned) {
|
|
985
1682
|
return new FilteredImpl(versioned, Effect.succeed);
|
|
@@ -988,6 +1685,20 @@ export const compact = function compact(versioned) {
|
|
|
988
1685
|
* Returns a `Computed` that yields the value inside the `Option`, or the fallback when `None`.
|
|
989
1686
|
* Works with `Computed<Option<A>>` (e.g. from `fromOption` / `fromNullable`) and with `Filtered<A>`.
|
|
990
1687
|
*
|
|
1688
|
+
* @remarks
|
|
1689
|
+
* ## Why
|
|
1690
|
+
*
|
|
1691
|
+
* Returns a `Computed` that yields the value inside the `Option`, or the fallback when `None`.
|
|
1692
|
+
* Works with `Computed<Option<A>>` (e.g. from `fromOption` / `fromNullable`) and with
|
|
1693
|
+
* `Filtered<A>`. Current reads and pushed versions use the same derivation, preventing snapshot
|
|
1694
|
+
* and subscription behavior from diverging.
|
|
1695
|
+
*
|
|
1696
|
+
* ## Ownership and lifetime
|
|
1697
|
+
*
|
|
1698
|
+
* The returned Computed never fails for absence: `None` or an absent Filtered value invokes
|
|
1699
|
+
* `fallback`. It preserves only the input's declared `E` and `R`; the pure fallback adds no failure,
|
|
1700
|
+
* service, subscription, or retained value.
|
|
1701
|
+
*
|
|
991
1702
|
* @example
|
|
992
1703
|
* ```ts
|
|
993
1704
|
* import { Effect, Option } from "effect"
|
|
@@ -1005,7 +1716,7 @@ export const compact = function compact(versioned) {
|
|
|
1005
1716
|
* ```
|
|
1006
1717
|
*
|
|
1007
1718
|
* @since 1.0.0
|
|
1008
|
-
* @category
|
|
1719
|
+
* @category Optional queries
|
|
1009
1720
|
*/
|
|
1010
1721
|
export const getOrElse = dual(2, function getOrElse(ref, fallback) {
|
|
1011
1722
|
const computed = FilteredTypeId in ref ? ref.asComputed() : ref;
|
|
@@ -1035,7 +1746,7 @@ class RefSubjectSimpleTransform extends YieldableFx {
|
|
|
1035
1746
|
return this._fx.run(sink);
|
|
1036
1747
|
}
|
|
1037
1748
|
toEffect() {
|
|
1038
|
-
return this.transformEffect(this.ref
|
|
1749
|
+
return this.transformEffect(this.ref);
|
|
1039
1750
|
}
|
|
1040
1751
|
updates(run) {
|
|
1041
1752
|
return this.ref.updates(run);
|
|
@@ -1047,6 +1758,25 @@ class RefSubjectSimpleTransform extends YieldableFx {
|
|
|
1047
1758
|
return this.ref.onSuccess(value);
|
|
1048
1759
|
}
|
|
1049
1760
|
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Limits which pushed versions a RefSubject view observes without changing its state.
|
|
1763
|
+
*
|
|
1764
|
+
* @remarks
|
|
1765
|
+
* ## Why
|
|
1766
|
+
*
|
|
1767
|
+
* Applies `skip` and `take` only to the Fx observation channel. Current reads still sample the
|
|
1768
|
+
* underlying RefSubject directly, and writes still use its original serialized update boundary.
|
|
1769
|
+
*
|
|
1770
|
+
* ## Ownership and lifetime
|
|
1771
|
+
*
|
|
1772
|
+
* Creating the view starts nothing and retains no value. Each observation uses its Scope and ends
|
|
1773
|
+
* after `take` selected pushes; ending that observation does not interrupt or delete the source.
|
|
1774
|
+
* Version, interruption, subscriber count, reads, failures, services, and writes delegate to the
|
|
1775
|
+
* source RefSubject.
|
|
1776
|
+
*
|
|
1777
|
+
* @since 1.18.0
|
|
1778
|
+
* @category Observation policy
|
|
1779
|
+
*/
|
|
1050
1780
|
export const slice = dual(3, function slice(ref, skip, take) {
|
|
1051
1781
|
return new RefSubjectSimpleTransform(ref, (_) => fxSlice(_, { skip, take }), identity);
|
|
1052
1782
|
});
|
|
@@ -1074,7 +1804,7 @@ class RefSubjectTransform extends YieldableFx {
|
|
|
1074
1804
|
return this._fx.run(sink);
|
|
1075
1805
|
}
|
|
1076
1806
|
toEffect() {
|
|
1077
|
-
return Effect.map(this.ref
|
|
1807
|
+
return Effect.map(this.ref, this.toB);
|
|
1078
1808
|
}
|
|
1079
1809
|
updates(run) {
|
|
1080
1810
|
return this.ref.updates((innerRef) => {
|
|
@@ -1096,6 +1826,17 @@ class RefSubjectTransform extends YieldableFx {
|
|
|
1096
1826
|
/**
|
|
1097
1827
|
* Transforms a `RefSubject` invariantly using bidirectional mapping functions.
|
|
1098
1828
|
*
|
|
1829
|
+
* @remarks
|
|
1830
|
+
* ## Why
|
|
1831
|
+
*
|
|
1832
|
+
* Creates a bidirectional lens over state: reads map outward and writes map back to the original
|
|
1833
|
+
* RefSubject without allocating a second store.
|
|
1834
|
+
*
|
|
1835
|
+
* ## Ownership and lifetime
|
|
1836
|
+
*
|
|
1837
|
+
* The derived ref owns no independent state or subscription. It follows the source lifetime and
|
|
1838
|
+
* routes writes through the source's synchronized update boundary.
|
|
1839
|
+
*
|
|
1099
1840
|
* @example
|
|
1100
1841
|
* ```ts
|
|
1101
1842
|
* import { Effect } from "effect"
|
|
@@ -1124,7 +1865,7 @@ class RefSubjectTransform extends YieldableFx {
|
|
|
1124
1865
|
* ```
|
|
1125
1866
|
*
|
|
1126
1867
|
* @since 1.0.0
|
|
1127
|
-
* @category
|
|
1868
|
+
* @category Writable views
|
|
1128
1869
|
*/
|
|
1129
1870
|
export const transform = dual(3, function transform(ref, toB, toA) {
|
|
1130
1871
|
return new RefSubjectTransform(ref, toB, toA);
|
|
@@ -1156,6 +1897,17 @@ function getRefKind(refs) {
|
|
|
1156
1897
|
/**
|
|
1157
1898
|
* Combines multiple `RefSubject`, `Computed`, or `Filtered` instances into a single struct.
|
|
1158
1899
|
*
|
|
1900
|
+
* @remarks
|
|
1901
|
+
* ## Why
|
|
1902
|
+
*
|
|
1903
|
+
* Combines several refs into one state value while preserving whether the result is writable,
|
|
1904
|
+
* computed, or filtered from its inputs.
|
|
1905
|
+
*
|
|
1906
|
+
* ## Ownership and lifetime
|
|
1907
|
+
*
|
|
1908
|
+
* This declaration performs no acquisition and retains no resources. Implementations preserve
|
|
1909
|
+
* source errors, services, and lifetime.
|
|
1910
|
+
*
|
|
1159
1911
|
* @example
|
|
1160
1912
|
* ```ts
|
|
1161
1913
|
* import { Effect } from "effect"
|
|
@@ -1186,7 +1938,7 @@ function getRefKind(refs) {
|
|
|
1186
1938
|
* ```
|
|
1187
1939
|
*
|
|
1188
1940
|
* @since 1.0.0
|
|
1189
|
-
* @category
|
|
1941
|
+
* @category State composition
|
|
1190
1942
|
*/
|
|
1191
1943
|
export function struct(refs) {
|
|
1192
1944
|
const kind = getRefKind(Object.values(refs));
|
|
@@ -1202,6 +1954,17 @@ export function struct(refs) {
|
|
|
1202
1954
|
/**
|
|
1203
1955
|
* Combines multiple `RefSubject`, `Computed`, or `Filtered` instances into a single tuple.
|
|
1204
1956
|
*
|
|
1957
|
+
* @remarks
|
|
1958
|
+
* ## Why
|
|
1959
|
+
*
|
|
1960
|
+
* Combines several refs into one state value while preserving whether the result is writable,
|
|
1961
|
+
* computed, or filtered from its inputs.
|
|
1962
|
+
*
|
|
1963
|
+
* ## Ownership and lifetime
|
|
1964
|
+
*
|
|
1965
|
+
* This declaration performs no acquisition and retains no resources. Implementations preserve
|
|
1966
|
+
* source errors, services, and lifetime.
|
|
1967
|
+
*
|
|
1205
1968
|
* @example
|
|
1206
1969
|
* ```ts
|
|
1207
1970
|
* import { Effect } from "effect"
|
|
@@ -1228,7 +1991,7 @@ export function struct(refs) {
|
|
|
1228
1991
|
* ```
|
|
1229
1992
|
*
|
|
1230
1993
|
* @since 1.0.0
|
|
1231
|
-
* @category
|
|
1994
|
+
* @category State composition
|
|
1232
1995
|
*/
|
|
1233
1996
|
export function tuple(refs) {
|
|
1234
1997
|
const kind = getRefKind(refs);
|
|
@@ -1245,6 +2008,38 @@ function makeTupleRef(refs) {
|
|
|
1245
2008
|
return new RefSubjectTuple(refs);
|
|
1246
2009
|
}
|
|
1247
2010
|
const UNBOUNDED = { concurrency: "unbounded" };
|
|
2011
|
+
const sampleRefSubject = (ref) =>
|
|
2012
|
+
// @effect-diagnostics-next-line unnecessaryEffectGen:off
|
|
2013
|
+
Effect.gen(function* () {
|
|
2014
|
+
return yield* ref;
|
|
2015
|
+
});
|
|
2016
|
+
function versionedInContext(make) {
|
|
2017
|
+
// Automatic composites share both pushed sessions and in-flight reads only within one Context.
|
|
2018
|
+
const contexts = new WeakMap();
|
|
2019
|
+
const current = Effect.map(Effect.context(), (context) => {
|
|
2020
|
+
let versioned = contexts.get(context);
|
|
2021
|
+
if (!versioned) {
|
|
2022
|
+
versioned = make();
|
|
2023
|
+
contexts.set(context, versioned);
|
|
2024
|
+
}
|
|
2025
|
+
return versioned;
|
|
2026
|
+
});
|
|
2027
|
+
return new (class extends YieldableFx {
|
|
2028
|
+
version = Effect.flatMap(current, (versioned) => versioned.version);
|
|
2029
|
+
interrupt = Effect.flatMap(current, (versioned) => versioned.interrupt);
|
|
2030
|
+
run(sink) {
|
|
2031
|
+
return Effect.flatMap(current, (versioned) => versioned.run(sink));
|
|
2032
|
+
}
|
|
2033
|
+
toEffect() {
|
|
2034
|
+
return Effect.flatMap(current, identity);
|
|
2035
|
+
}
|
|
2036
|
+
})();
|
|
2037
|
+
}
|
|
2038
|
+
function makeCompositeVersioned(refs, current) {
|
|
2039
|
+
const version = Effect.map(Effect.all(refs.map((ref) => ref.version), UNBOUNDED), (versions) => versions.reduce(sum, 0));
|
|
2040
|
+
const changes = skipRepeats(fxMapEffect(fxMergeAll(...refs), () => current));
|
|
2041
|
+
return versionedInContext(() => Versioned.hold(Versioned.make(version, changes, current)));
|
|
2042
|
+
}
|
|
1248
2043
|
class RefSubjectTuple extends YieldableFx {
|
|
1249
2044
|
[ComputedTypeId] = ComputedTypeId;
|
|
1250
2045
|
[RefSubjectTypeId] = RefSubjectTypeId;
|
|
@@ -1257,12 +2052,14 @@ class RefSubjectTuple extends YieldableFx {
|
|
|
1257
2052
|
constructor(refs) {
|
|
1258
2053
|
super();
|
|
1259
2054
|
this.refs = refs;
|
|
1260
|
-
this.versioned =
|
|
2055
|
+
this.versioned = (refs.length > 0 && getTupleTransactionAccess(refs)
|
|
2056
|
+
? makeCompositeVersioned(refs, Effect.all(refs.map(sampleRefSubject), UNBOUNDED))
|
|
2057
|
+
: versionedInContext(() => Versioned.hold(Versioned.tuple(refs))));
|
|
1261
2058
|
this.version = this.versioned.version;
|
|
1262
2059
|
this.interrupt = Effect.all(refs.map((r) => r.interrupt), UNBOUNDED);
|
|
1263
2060
|
this.subscriberCount = Effect.map(Effect.all(refs.map((r) => r.subscriberCount), UNBOUNDED), Array.reduce(0, sum));
|
|
1264
2061
|
this.getSetDelete = {
|
|
1265
|
-
get: this.versioned
|
|
2062
|
+
get: this.versioned,
|
|
1266
2063
|
set: (a) => Effect.all(refs.map((r, i) => set(r, a[i])), UNBOUNDED),
|
|
1267
2064
|
delete: Effect.map(Effect.all(refs.map((r) => reset(r)), UNBOUNDED), Option.all),
|
|
1268
2065
|
};
|
|
@@ -1274,10 +2071,15 @@ class RefSubjectTuple extends YieldableFx {
|
|
|
1274
2071
|
return this.versioned.run(sink);
|
|
1275
2072
|
}
|
|
1276
2073
|
toEffect() {
|
|
1277
|
-
return this.versioned
|
|
2074
|
+
return this.versioned;
|
|
1278
2075
|
}
|
|
1279
2076
|
updates(run) {
|
|
1280
|
-
|
|
2077
|
+
const accessEffect = getTransactionAccess(this);
|
|
2078
|
+
return accessEffect
|
|
2079
|
+
? Effect.flatMap(accessEffect, (transactionAccess) => Option.isSome(transactionAccess)
|
|
2080
|
+
? runTransaction(transactionAccess.value, run)
|
|
2081
|
+
: Effect.suspend(() => run(this.getSetDelete)))
|
|
2082
|
+
: Effect.suspend(() => run(this.getSetDelete));
|
|
1281
2083
|
}
|
|
1282
2084
|
onFailure(cause) {
|
|
1283
2085
|
return Effect.all(this.refs.map((ref) => ref.onFailure(cause)));
|
|
@@ -1287,10 +2089,10 @@ class RefSubjectTuple extends YieldableFx {
|
|
|
1287
2089
|
}
|
|
1288
2090
|
}
|
|
1289
2091
|
function makeTupleComputed(refs) {
|
|
1290
|
-
return new ComputedImpl(Versioned.tuple(refs), Effect.succeed);
|
|
2092
|
+
return new ComputedImpl(versionedInContext(() => Versioned.tuple(refs)), Effect.succeed);
|
|
1291
2093
|
}
|
|
1292
2094
|
function makeTupleFiltered(refs) {
|
|
1293
|
-
return new FilteredImpl(Versioned.tuple(refs), Effect.succeedSome);
|
|
2095
|
+
return new FilteredImpl(versionedInContext(() => Versioned.tuple(refs)), Effect.succeedSome);
|
|
1294
2096
|
}
|
|
1295
2097
|
function makeStructRef(refs) {
|
|
1296
2098
|
return new RefSubjectStruct(refs);
|
|
@@ -1307,12 +2109,16 @@ class RefSubjectStruct extends YieldableFx {
|
|
|
1307
2109
|
constructor(refs) {
|
|
1308
2110
|
super();
|
|
1309
2111
|
this.refs = refs;
|
|
1310
|
-
|
|
2112
|
+
const keys = Object.keys(refs);
|
|
2113
|
+
const current = Effect.map(Effect.all(keys.map((key) => sampleRefSubject(refs[key])), UNBOUNDED), (values) => Object.fromEntries(keys.map((key, index) => [key, values[index]])));
|
|
2114
|
+
this.versioned = (keys.length > 0 && getStructTransactionAccess(refs)
|
|
2115
|
+
? makeCompositeVersioned(Object.values(refs), current)
|
|
2116
|
+
: versionedInContext(() => Versioned.hold(Versioned.struct(refs))));
|
|
1311
2117
|
this.version = this.versioned.version;
|
|
1312
2118
|
this.interrupt = Effect.all(Object.values(refs).map((r) => r.interrupt), UNBOUNDED);
|
|
1313
2119
|
this.subscriberCount = Effect.map(Effect.all(Object.values(refs).map((r) => r.subscriberCount), UNBOUNDED), Array.reduce(0, sum));
|
|
1314
2120
|
this.getSetDelete = {
|
|
1315
|
-
get: this.versioned
|
|
2121
|
+
get: this.versioned,
|
|
1316
2122
|
set: (a) => Effect.all(Object.keys(refs).map((k) => set(refs[k], a[k])), UNBOUNDED),
|
|
1317
2123
|
delete: Effect.map(Effect.all(Object.values(refs).map((r) => reset(r)), UNBOUNDED), Option.all),
|
|
1318
2124
|
};
|
|
@@ -1324,10 +2130,15 @@ class RefSubjectStruct extends YieldableFx {
|
|
|
1324
2130
|
return this.versioned.run(sink);
|
|
1325
2131
|
}
|
|
1326
2132
|
toEffect() {
|
|
1327
|
-
return this.versioned
|
|
2133
|
+
return this.versioned;
|
|
1328
2134
|
}
|
|
1329
2135
|
updates(run) {
|
|
1330
|
-
|
|
2136
|
+
const accessEffect = getTransactionAccess(this);
|
|
2137
|
+
return accessEffect
|
|
2138
|
+
? Effect.flatMap(accessEffect, (transactionAccess) => Option.isSome(transactionAccess)
|
|
2139
|
+
? runTransaction(transactionAccess.value, run)
|
|
2140
|
+
: Effect.suspend(() => run(this.getSetDelete)))
|
|
2141
|
+
: Effect.suspend(() => run(this.getSetDelete));
|
|
1331
2142
|
}
|
|
1332
2143
|
onFailure(cause) {
|
|
1333
2144
|
return Effect.all(Object.values(this.refs).map((ref) => ref.onFailure(cause)));
|
|
@@ -1337,11 +2148,29 @@ class RefSubjectStruct extends YieldableFx {
|
|
|
1337
2148
|
}
|
|
1338
2149
|
}
|
|
1339
2150
|
function makeStructComputed(refs) {
|
|
1340
|
-
return new ComputedImpl(Versioned.struct(refs), Effect.succeed);
|
|
2151
|
+
return new ComputedImpl(versionedInContext(() => Versioned.struct(refs)), Effect.succeed);
|
|
1341
2152
|
}
|
|
1342
2153
|
function makeStructFiltered(refs) {
|
|
1343
|
-
return new FilteredImpl(Versioned.struct(refs), Effect.succeedSome);
|
|
2154
|
+
return new FilteredImpl(versionedInContext(() => Versioned.struct(refs)), Effect.succeedSome);
|
|
1344
2155
|
}
|
|
2156
|
+
/**
|
|
2157
|
+
* Lifts an Effect-provided Computed into a Computed facade.
|
|
2158
|
+
*
|
|
2159
|
+
* @remarks
|
|
2160
|
+
* ## Why
|
|
2161
|
+
*
|
|
2162
|
+
* Defers service lookup until each version read, current read, interruption, or Fx observation, so
|
|
2163
|
+
* callers can compose a Context-provided Computed without manually flat-mapping the service Effect.
|
|
2164
|
+
*
|
|
2165
|
+
* ## Ownership and lifetime
|
|
2166
|
+
*
|
|
2167
|
+
* The facade caches neither the resolved Computed nor its value. Each operation runs the supplied
|
|
2168
|
+
* Effect, then delegates to the resolved Computed. Service requirements combine as `R | R2`, source
|
|
2169
|
+
* failures remain `E`, and the observing Scope owns the delegated subscription.
|
|
2170
|
+
*
|
|
2171
|
+
* @since 1.18.0
|
|
2172
|
+
* @category Services
|
|
2173
|
+
*/
|
|
1345
2174
|
export function computedFromService(effect) {
|
|
1346
2175
|
return new ComputedFromService(effect);
|
|
1347
2176
|
}
|
|
@@ -1360,9 +2189,26 @@ class ComputedFromService extends YieldableFx {
|
|
|
1360
2189
|
return Effect.flatMap(this.effect, (c) => c.run(sink));
|
|
1361
2190
|
}
|
|
1362
2191
|
toEffect() {
|
|
1363
|
-
return Effect.flatMap(this.effect, (c) => c
|
|
2192
|
+
return Effect.flatMap(this.effect, (c) => c);
|
|
1364
2193
|
}
|
|
1365
2194
|
}
|
|
2195
|
+
/**
|
|
2196
|
+
* Defers retrieval of a Filtered value from Effect Context while preserving Filtered behavior.
|
|
2197
|
+
*
|
|
2198
|
+
* @remarks
|
|
2199
|
+
* ## Why
|
|
2200
|
+
*
|
|
2201
|
+
* Lets a service-provided Filtered participate directly in Effect reads and Fx observation without
|
|
2202
|
+
* manually flat-mapping the service tag at every use.
|
|
2203
|
+
*
|
|
2204
|
+
* ## Ownership and lifetime
|
|
2205
|
+
*
|
|
2206
|
+
* The filtered from service view retains no independent value. Its Effect read fails with NoSuchElement
|
|
2207
|
+
* while absent; the observing Scope owns and finalizes its Fx subscription.
|
|
2208
|
+
*
|
|
2209
|
+
* @since 1.18.0
|
|
2210
|
+
* @category Services
|
|
2211
|
+
*/
|
|
1366
2212
|
export function filteredFromService(effect) {
|
|
1367
2213
|
return new FilteredFromService(effect);
|
|
1368
2214
|
}
|
|
@@ -1381,9 +2227,10 @@ class FilteredFromService extends YieldableFx {
|
|
|
1381
2227
|
return Effect.flatMap(this.effect, (c) => c.run(sink));
|
|
1382
2228
|
}
|
|
1383
2229
|
toEffect() {
|
|
1384
|
-
return Effect.flatMap(this.effect, (c) => c
|
|
2230
|
+
return Effect.flatMap(this.effect, (c) => c);
|
|
1385
2231
|
}
|
|
1386
2232
|
asComputed() {
|
|
1387
2233
|
return computedFromService(Effect.map(this.effect, (c) => c.asComputed()));
|
|
1388
2234
|
}
|
|
1389
2235
|
}
|
|
2236
|
+
export * from "./Hydration.js";
|