@playfast/reform 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boundary/boundary.d.ts +64 -0
- package/dist/boundary/boundary.d.ts.map +1 -0
- package/dist/boundary/boundary.js +102 -0
- package/dist/boundary/boundary.js.map +1 -0
- package/dist/calc/asyncCalc.d.ts +21 -0
- package/dist/calc/asyncCalc.d.ts.map +1 -0
- package/dist/calc/asyncCalc.js +90 -0
- package/dist/calc/asyncCalc.js.map +1 -0
- package/dist/calc/asyncCalcTypes.d.ts +78 -0
- package/dist/calc/asyncCalcTypes.d.ts.map +1 -0
- package/dist/calc/asyncCalcTypes.js +2 -0
- package/dist/calc/asyncCalcTypes.js.map +1 -0
- package/dist/calc/asyncData.d.ts +29 -0
- package/dist/calc/asyncData.d.ts.map +1 -0
- package/dist/calc/asyncData.js +21 -0
- package/dist/calc/asyncData.js.map +1 -0
- package/dist/calc/calc.d.ts +39 -0
- package/dist/calc/calc.d.ts.map +1 -0
- package/dist/calc/calc.js +48 -0
- package/dist/calc/calc.js.map +1 -0
- package/dist/calc/calcFamily.d.ts +40 -0
- package/dist/calc/calcFamily.d.ts.map +1 -0
- package/dist/calc/calcFamily.js +113 -0
- package/dist/calc/calcFamily.js.map +1 -0
- package/dist/calc/compose.d.ts +5 -0
- package/dist/calc/compose.d.ts.map +1 -0
- package/dist/calc/compose.js +5 -0
- package/dist/calc/compose.js.map +1 -0
- package/dist/calc/queryState.d.ts +12 -0
- package/dist/calc/queryState.d.ts.map +1 -0
- package/dist/calc/queryState.js +17 -0
- package/dist/calc/queryState.js.map +1 -0
- package/dist/channel/channel.d.ts +51 -0
- package/dist/channel/channel.d.ts.map +1 -0
- package/dist/channel/channel.js +86 -0
- package/dist/channel/channel.js.map +1 -0
- package/dist/channel/procedures.d.ts +24 -0
- package/dist/channel/procedures.d.ts.map +1 -0
- package/dist/channel/procedures.js +82 -0
- package/dist/channel/procedures.js.map +1 -0
- package/dist/compose/composition.d.ts +12 -0
- package/dist/compose/composition.d.ts.map +1 -0
- package/dist/compose/composition.js +56 -0
- package/dist/compose/composition.js.map +1 -0
- package/dist/compose/compositionTypes.d.ts +127 -0
- package/dist/compose/compositionTypes.d.ts.map +1 -0
- package/dist/compose/compositionTypes.js +2 -0
- package/dist/compose/compositionTypes.js.map +1 -0
- package/dist/compose/host.d.ts +6 -0
- package/dist/compose/host.d.ts.map +1 -0
- package/dist/compose/host.js +2 -0
- package/dist/compose/host.js.map +1 -0
- package/dist/compose/props.d.ts +10 -0
- package/dist/compose/props.d.ts.map +1 -0
- package/dist/compose/props.js +6 -0
- package/dist/compose/props.js.map +1 -0
- package/dist/compose/provide.d.ts +18 -0
- package/dist/compose/provide.d.ts.map +1 -0
- package/dist/compose/provide.js +49 -0
- package/dist/compose/provide.js.map +1 -0
- package/dist/compose/slot.d.ts +70 -0
- package/dist/compose/slot.d.ts.map +1 -0
- package/dist/compose/slot.js +26 -0
- package/dist/compose/slot.js.map +1 -0
- package/dist/compose/structure.d.ts +51 -0
- package/dist/compose/structure.d.ts.map +1 -0
- package/dist/compose/structure.js +92 -0
- package/dist/compose/structure.js.map +1 -0
- package/dist/compose/ui.d.ts +112 -0
- package/dist/compose/ui.d.ts.map +1 -0
- package/dist/compose/ui.js +47 -0
- package/dist/compose/ui.js.map +1 -0
- package/dist/definition/definition.d.ts +11 -0
- package/dist/definition/definition.d.ts.map +1 -0
- package/dist/definition/definition.js +35 -0
- package/dist/definition/definition.js.map +1 -0
- package/dist/event/event.d.ts +52 -0
- package/dist/event/event.d.ts.map +1 -0
- package/dist/event/event.js +67 -0
- package/dist/event/event.js.map +1 -0
- package/dist/event/eventGroup.d.ts +8 -0
- package/dist/event/eventGroup.d.ts.map +1 -0
- package/dist/event/eventGroup.js +3 -0
- package/dist/event/eventGroup.js.map +1 -0
- package/dist/feature/feature.d.ts +27 -0
- package/dist/feature/feature.d.ts.map +1 -0
- package/dist/feature/feature.js +20 -0
- package/dist/feature/feature.js.map +1 -0
- package/dist/feature/featureBinding.d.ts +85 -0
- package/dist/feature/featureBinding.d.ts.map +1 -0
- package/dist/feature/featureBinding.js +10 -0
- package/dist/feature/featureBinding.js.map +1 -0
- package/dist/feature/featureClass.d.ts +10 -0
- package/dist/feature/featureClass.d.ts.map +1 -0
- package/dist/feature/featureClass.js +2 -0
- package/dist/feature/featureClass.js.map +1 -0
- package/dist/feature/featureConfig.d.ts +86 -0
- package/dist/feature/featureConfig.d.ts.map +1 -0
- package/dist/feature/featureConfig.js +13 -0
- package/dist/feature/featureConfig.js.map +1 -0
- package/dist/feature/featureFactory.d.ts +15 -0
- package/dist/feature/featureFactory.d.ts.map +1 -0
- package/dist/feature/featureFactory.js +59 -0
- package/dist/feature/featureFactory.js.map +1 -0
- package/dist/feature/featureModule.d.ts +28 -0
- package/dist/feature/featureModule.d.ts.map +1 -0
- package/dist/feature/featureModule.js +33 -0
- package/dist/feature/featureModule.js.map +1 -0
- package/dist/feature/featureNativeTree.d.ts +26 -0
- package/dist/feature/featureNativeTree.d.ts.map +1 -0
- package/dist/feature/featureNativeTree.js +2 -0
- package/dist/feature/featureNativeTree.js.map +1 -0
- package/dist/feature/featureRequirement.d.ts +43 -0
- package/dist/feature/featureRequirement.d.ts.map +1 -0
- package/dist/feature/featureRequirement.js +6 -0
- package/dist/feature/featureRequirement.js.map +1 -0
- package/dist/feature/featureVariants.d.ts +9 -0
- package/dist/feature/featureVariants.d.ts.map +1 -0
- package/dist/feature/featureVariants.js +59 -0
- package/dist/feature/featureVariants.js.map +1 -0
- package/dist/feature/mountFeature.d.ts +10 -0
- package/dist/feature/mountFeature.d.ts.map +1 -0
- package/dist/feature/mountFeature.js +14 -0
- package/dist/feature/mountFeature.js.map +1 -0
- package/dist/graph/closure.d.ts +77 -0
- package/dist/graph/closure.d.ts.map +1 -0
- package/dist/graph/closure.js +4 -0
- package/dist/graph/closure.js.map +1 -0
- package/dist/graph/services.d.ts +30 -0
- package/dist/graph/services.d.ts.map +1 -0
- package/dist/graph/services.js +2 -0
- package/dist/graph/services.js.map +1 -0
- package/dist/graph/summary.d.ts +60 -0
- package/dist/graph/summary.d.ts.map +1 -0
- package/dist/graph/summary.js +7 -0
- package/dist/graph/summary.js.map +1 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/bucketCache.d.ts +19 -0
- package/dist/internal/bucketCache.d.ts.map +1 -0
- package/dist/internal/bucketCache.js +20 -0
- package/dist/internal/bucketCache.js.map +1 -0
- package/dist/internal/capture.d.ts +17 -0
- package/dist/internal/capture.d.ts.map +1 -0
- package/dist/internal/capture.js +5 -0
- package/dist/internal/capture.js.map +1 -0
- package/dist/internal/env.d.ts +2 -0
- package/dist/internal/env.d.ts.map +1 -0
- package/dist/internal/env.js +5 -0
- package/dist/internal/env.js.map +1 -0
- package/dist/internal/errors.d.ts +48 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +69 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/inspect.d.ts +5 -0
- package/dist/internal/inspect.d.ts.map +1 -0
- package/dist/internal/inspect.js +20 -0
- package/dist/internal/inspect.js.map +1 -0
- package/dist/internal/queryDriver.d.ts +7 -0
- package/dist/internal/queryDriver.d.ts.map +1 -0
- package/dist/internal/queryDriver.js +198 -0
- package/dist/internal/queryDriver.js.map +1 -0
- package/dist/internal/queryDriverHydrate.d.ts +17 -0
- package/dist/internal/queryDriverHydrate.d.ts.map +1 -0
- package/dist/internal/queryDriverHydrate.js +19 -0
- package/dist/internal/queryDriverHydrate.js.map +1 -0
- package/dist/internal/queryDriverStore.d.ts +54 -0
- package/dist/internal/queryDriverStore.d.ts.map +1 -0
- package/dist/internal/queryDriverStore.js +77 -0
- package/dist/internal/queryDriverStore.js.map +1 -0
- package/dist/internal/queryDriverTypes.d.ts +41 -0
- package/dist/internal/queryDriverTypes.d.ts.map +1 -0
- package/dist/internal/queryDriverTypes.js +9 -0
- package/dist/internal/queryDriverTypes.js.map +1 -0
- package/dist/internal/queryEvents.d.ts +12 -0
- package/dist/internal/queryEvents.d.ts.map +1 -0
- package/dist/internal/queryEvents.js +11 -0
- package/dist/internal/queryEvents.js.map +1 -0
- package/dist/internal/queryStore.d.ts +13 -0
- package/dist/internal/queryStore.d.ts.map +1 -0
- package/dist/internal/queryStore.js +11 -0
- package/dist/internal/queryStore.js.map +1 -0
- package/dist/internal/reuse.d.ts +2 -0
- package/dist/internal/reuse.d.ts.map +1 -0
- package/dist/internal/reuse.js +55 -0
- package/dist/internal/reuse.js.map +1 -0
- package/dist/internal/scheduler.d.ts +13 -0
- package/dist/internal/scheduler.d.ts.map +1 -0
- package/dist/internal/scheduler.js +38 -0
- package/dist/internal/scheduler.js.map +1 -0
- package/dist/internal/seeds.d.ts +3 -0
- package/dist/internal/seeds.d.ts.map +1 -0
- package/dist/internal/seeds.js +3 -0
- package/dist/internal/seeds.js.map +1 -0
- package/dist/internal/sources.d.ts +20 -0
- package/dist/internal/sources.d.ts.map +1 -0
- package/dist/internal/sources.js +39 -0
- package/dist/internal/sources.js.map +1 -0
- package/dist/internal/stateRegistry.d.ts +2 -0
- package/dist/internal/stateRegistry.d.ts.map +1 -0
- package/dist/internal/stateRegistry.js +15 -0
- package/dist/internal/stateRegistry.js.map +1 -0
- package/dist/internal/store.d.ts +15 -0
- package/dist/internal/store.d.ts.map +1 -0
- package/dist/internal/store.js +61 -0
- package/dist/internal/store.js.map +1 -0
- package/dist/internal/track.d.ts +15 -0
- package/dist/internal/track.d.ts.map +1 -0
- package/dist/internal/track.js +11 -0
- package/dist/internal/track.js.map +1 -0
- package/dist/internal/variance.d.ts +4 -0
- package/dist/internal/variance.d.ts.map +1 -0
- package/dist/internal/variance.js +2 -0
- package/dist/internal/variance.js.map +1 -0
- package/dist/internal.d.ts +42 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +58 -0
- package/dist/internal.js.map +1 -0
- package/dist/namespace/namespace.d.ts +24 -0
- package/dist/namespace/namespace.d.ts.map +1 -0
- package/dist/namespace/namespace.js +20 -0
- package/dist/namespace/namespace.js.map +1 -0
- package/dist/procedure/procedure.d.ts +32 -0
- package/dist/procedure/procedure.d.ts.map +1 -0
- package/dist/procedure/procedure.js +34 -0
- package/dist/procedure/procedure.js.map +1 -0
- package/dist/reducer/reducer.d.ts +35 -0
- package/dist/reducer/reducer.d.ts.map +1 -0
- package/dist/reducer/reducer.js +73 -0
- package/dist/reducer/reducer.js.map +1 -0
- package/dist/remote/pendingQueue.d.ts +20 -0
- package/dist/remote/pendingQueue.d.ts.map +1 -0
- package/dist/remote/pendingQueue.js +113 -0
- package/dist/remote/pendingQueue.js.map +1 -0
- package/dist/remote/remoteState.d.ts +13 -0
- package/dist/remote/remoteState.d.ts.map +1 -0
- package/dist/remote/remoteState.js +176 -0
- package/dist/remote/remoteState.js.map +1 -0
- package/dist/remote/remoteStateMake.d.ts +8 -0
- package/dist/remote/remoteStateMake.d.ts.map +1 -0
- package/dist/remote/remoteStateMake.js +46 -0
- package/dist/remote/remoteStateMake.js.map +1 -0
- package/dist/remote/remoteStateSend.d.ts +41 -0
- package/dist/remote/remoteStateSend.d.ts.map +1 -0
- package/dist/remote/remoteStateSend.js +67 -0
- package/dist/remote/remoteStateSend.js.map +1 -0
- package/dist/remote/remoteStateTypes.d.ts +103 -0
- package/dist/remote/remoteStateTypes.d.ts.map +1 -0
- package/dist/remote/remoteStateTypes.js +4 -0
- package/dist/remote/remoteStateTypes.js.map +1 -0
- package/dist/runtime/appRuntime.d.ts +10 -0
- package/dist/runtime/appRuntime.d.ts.map +1 -0
- package/dist/runtime/appRuntime.js +6 -0
- package/dist/runtime/appRuntime.js.map +1 -0
- package/dist/runtime/bus.d.ts +17 -0
- package/dist/runtime/bus.d.ts.map +1 -0
- package/dist/runtime/bus.js +12 -0
- package/dist/runtime/bus.js.map +1 -0
- package/dist/runtime/capturedAppRuntime.d.ts +7 -0
- package/dist/runtime/capturedAppRuntime.d.ts.map +1 -0
- package/dist/runtime/capturedAppRuntime.js +151 -0
- package/dist/runtime/capturedAppRuntime.js.map +1 -0
- package/dist/runtime/eventBudget.d.ts +32 -0
- package/dist/runtime/eventBudget.d.ts.map +1 -0
- package/dist/runtime/eventBudget.js +67 -0
- package/dist/runtime/eventBudget.js.map +1 -0
- package/dist/runtime/featureMount.d.ts +16 -0
- package/dist/runtime/featureMount.d.ts.map +1 -0
- package/dist/runtime/featureMount.js +54 -0
- package/dist/runtime/featureMount.js.map +1 -0
- package/dist/runtime/instrumentation.d.ts +18 -0
- package/dist/runtime/instrumentation.d.ts.map +1 -0
- package/dist/runtime/instrumentation.js +16 -0
- package/dist/runtime/instrumentation.js.map +1 -0
- package/dist/runtime/loop.d.ts +32 -0
- package/dist/runtime/loop.d.ts.map +1 -0
- package/dist/runtime/loop.js +128 -0
- package/dist/runtime/loop.js.map +1 -0
- package/dist/runtime/queries.d.ts +20 -0
- package/dist/runtime/queries.d.ts.map +1 -0
- package/dist/runtime/queries.js +21 -0
- package/dist/runtime/queries.js.map +1 -0
- package/dist/runtime/runtimeHandle.d.ts +56 -0
- package/dist/runtime/runtimeHandle.d.ts.map +1 -0
- package/dist/runtime/runtimeHandle.js +2 -0
- package/dist/runtime/runtimeHandle.js.map +1 -0
- package/dist/scene/scene.d.ts +55 -0
- package/dist/scene/scene.d.ts.map +1 -0
- package/dist/scene/scene.js +74 -0
- package/dist/scene/scene.js.map +1 -0
- package/dist/state/state.d.ts +54 -0
- package/dist/state/state.d.ts.map +1 -0
- package/dist/state/state.js +41 -0
- package/dist/state/state.js.map +1 -0
- package/dist/state/stateFamily.d.ts +59 -0
- package/dist/state/stateFamily.d.ts.map +1 -0
- package/dist/state/stateFamily.js +91 -0
- package/dist/state/stateFamily.js.map +1 -0
- package/dist/state/stateGroup.d.ts +36 -0
- package/dist/state/stateGroup.d.ts.map +1 -0
- package/dist/state/stateGroup.js +33 -0
- package/dist/state/stateGroup.js.map +1 -0
- package/dist/state/token.d.ts +35 -0
- package/dist/state/token.d.ts.map +1 -0
- package/dist/state/token.js +18 -0
- package/dist/state/token.js.map +1 -0
- package/dist/synced/syncedStore.d.ts +44 -0
- package/dist/synced/syncedStore.d.ts.map +1 -0
- package/dist/synced/syncedStore.js +32 -0
- package/dist/synced/syncedStore.js.map +1 -0
- package/dist/testkit/flight.testkit.d.ts +18 -0
- package/dist/testkit/flight.testkit.d.ts.map +1 -0
- package/dist/testkit/flight.testkit.js +45 -0
- package/dist/testkit/flight.testkit.js.map +1 -0
- package/dist/ui/node.d.ts +3 -0
- package/dist/ui/node.d.ts.map +1 -0
- package/dist/ui/node.js +2 -0
- package/dist/ui/node.js.map +1 -0
- package/dist/ui/trigger.d.ts +2 -0
- package/dist/ui/trigger.d.ts.map +1 -0
- package/dist/ui/trigger.js +2 -0
- package/dist/ui/trigger.js.map +1 -0
- package/dist/wire/tree.d.ts +32 -0
- package/dist/wire/tree.d.ts.map +1 -0
- package/dist/wire/tree.js +59 -0
- package/dist/wire/tree.js.map +1 -0
- package/dist/wire/triggers.d.ts +25 -0
- package/dist/wire/triggers.d.ts.map +1 -0
- package/dist/wire/triggers.js +31 -0
- package/dist/wire/triggers.js.map +1 -0
- package/package.json +17 -5
- package/src/boundary/boundary.test.ts +26 -23
- package/src/calc/asyncCalc.invalidate.test.ts +258 -55
- package/src/calc/asyncCalc.test.ts +225 -85
- package/src/calc/asyncCalc.ts +27 -141
- package/src/calc/asyncCalcTypes.test.ts +64 -0
- package/src/calc/asyncCalcTypes.ts +139 -0
- package/src/calc/calc.test.ts +10 -11
- package/src/calc/calcFamily.test.ts +12 -12
- package/src/channel/channel.ts +8 -106
- package/src/channel/procedures.ts +108 -0
- package/src/compose/composition.ts +49 -246
- package/src/compose/compositionTypes.ts +249 -0
- package/src/event/event.fromSource.test.ts +12 -12
- package/src/feature/feature.ts +50 -1210
- package/src/feature/feature.typecheck.ts +2 -61
- package/src/feature/featureBinding.ts +158 -0
- package/src/feature/featureClass.ts +162 -0
- package/src/feature/featureConfig.ts +192 -0
- package/src/feature/featureFactory.ts +163 -0
- package/src/feature/featureModule.ts +136 -0
- package/src/feature/featureModule.typecheck.ts +63 -0
- package/src/feature/featureNativeTree.ts +152 -0
- package/src/feature/featureRequirement.ts +82 -0
- package/src/feature/featureVariants.ts +234 -0
- package/src/feature/mountFeature.ts +54 -0
- package/src/graph/closure.ts +45 -226
- package/src/graph/services.ts +95 -0
- package/src/graph/summary.ts +134 -0
- package/src/internal/queryDriver.ts +20 -89
- package/src/internal/queryDriverHydrate.ts +45 -0
- package/src/internal/queryDriverTypes.ts +8 -10
- package/src/internal/store.test.ts +27 -6
- package/src/remote/pendingQueue.ts +145 -0
- package/src/remote/remoteState.test.ts +28 -22
- package/src/remote/remoteState.ts +63 -489
- package/src/remote/remoteStateMake.ts +97 -0
- package/src/remote/remoteStateSend.ts +122 -0
- package/src/remote/remoteStateTypes.ts +155 -0
- package/src/runtime/appRuntime.activation.test.ts +9 -5
- package/src/runtime/appRuntime.test.ts +40 -16
- package/src/runtime/appRuntime.ts +17 -472
- package/src/runtime/capturedAppRuntime.ts +274 -0
- package/src/runtime/eventBudget.test.ts +38 -8
- package/src/runtime/featureMount.ts +94 -0
- package/src/runtime/hardening.test.ts +18 -4
- package/src/runtime/instrumentation.test.ts +49 -12
- package/src/runtime/loop.test.ts +51 -10
- package/src/runtime/runtimeHandle.ts +124 -0
- package/src/state/stateFamily.test.ts +25 -8
- package/src/testkit/flight.testkit.ts +9 -0
package/src/calc/asyncCalc.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Context, Effect, Layer, Match, Option, Schema } from 'effect'
|
|
2
|
-
import
|
|
3
|
-
import { type Manifest, yieldableClass } from '../definition/definition'
|
|
2
|
+
import { yieldableClass } from '../definition/definition'
|
|
4
3
|
import { type AnyEvent } from '../event/event'
|
|
5
|
-
import { type
|
|
6
|
-
import type { AnySchema } from '../internal/variance'
|
|
4
|
+
import { type InputStores } from '../internal/sources'
|
|
7
5
|
import {
|
|
8
6
|
bumpRevision,
|
|
9
7
|
type GatedOf,
|
|
@@ -19,145 +17,33 @@ import * as Reducer from '../reducer/reducer'
|
|
|
19
17
|
import { Reducers } from '../runtime/loop'
|
|
20
18
|
import { Queries } from '../runtime/queries'
|
|
21
19
|
import * as State from '../state/state'
|
|
22
|
-
import { type AnySource, type
|
|
20
|
+
import { type AnySource, type SourceCapture } from '../state/token'
|
|
23
21
|
import { type AsyncData, narrowStore } from './asyncData'
|
|
22
|
+
import type {
|
|
23
|
+
AsyncCalcClass,
|
|
24
|
+
AsyncCalcConfig,
|
|
25
|
+
AsyncCalcLive,
|
|
26
|
+
AsyncCalcLiveView,
|
|
27
|
+
AsyncCalcLiveWithInvalidateOn,
|
|
28
|
+
AsyncCalcMakeConfigExternalApi,
|
|
29
|
+
AsyncCalcManifest,
|
|
30
|
+
AsyncCalcStore,
|
|
31
|
+
DefinedAsyncCalcClass,
|
|
32
|
+
} from './asyncCalcTypes'
|
|
33
|
+
|
|
34
|
+
export { AsyncCalcStoreTypeId } from './asyncCalcTypes'
|
|
35
|
+
export type {
|
|
36
|
+
AsyncCalcClass,
|
|
37
|
+
AsyncCalcConfig,
|
|
38
|
+
AsyncCalcLive,
|
|
39
|
+
AsyncCalcLiveView,
|
|
40
|
+
AsyncCalcLiveWithInvalidateOn,
|
|
41
|
+
AsyncCalcManifest,
|
|
42
|
+
AsyncCalcSchemaReflection,
|
|
43
|
+
AsyncCalcStore,
|
|
44
|
+
DefinedAsyncCalcClass,
|
|
45
|
+
} from './asyncCalcTypes'
|
|
24
46
|
|
|
25
|
-
export interface AsyncCalcSchemaReflection {
|
|
26
|
-
readonly ast: Schema.Schema<unknown, unknown, unknown>['ast']
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface AsyncCalcManifest<N extends string, A = unknown, E = never> extends Manifest {
|
|
30
|
-
readonly kind: 'AsyncCalc'
|
|
31
|
-
readonly name: N
|
|
32
|
-
readonly output: AnySchema<A>
|
|
33
|
-
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
34
|
-
readonly error?: AnySchema<E>
|
|
35
|
-
readonly gated: boolean
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const AsyncCalcStoreTypeId: unique symbol = Symbol.for('reform/AsyncCalcStore')
|
|
39
|
-
export type AsyncCalcStoreTypeId = typeof AsyncCalcStoreTypeId
|
|
40
|
-
|
|
41
|
-
interface AsyncCalcStoreCompatibilityExternalApi<
|
|
42
|
-
N extends string,
|
|
43
|
-
in out A,
|
|
44
|
-
in out E,
|
|
45
|
-
in out Gated extends boolean,
|
|
46
|
-
> extends Store<AsyncData<A, E, Gated>> {
|
|
47
|
-
readonly [AsyncCalcStoreTypeId]?: N
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export type AsyncCalcStore<
|
|
51
|
-
N extends string,
|
|
52
|
-
A,
|
|
53
|
-
E,
|
|
54
|
-
Gated extends boolean,
|
|
55
|
-
> = AsyncCalcStoreCompatibilityExternalApi<N, A, E, Gated>
|
|
56
|
-
|
|
57
|
-
export interface AsyncCalcClass<
|
|
58
|
-
N extends string,
|
|
59
|
-
Inputs extends ReadonlyArray<AnySource>,
|
|
60
|
-
A,
|
|
61
|
-
E,
|
|
62
|
-
Gated extends boolean,
|
|
63
|
-
>
|
|
64
|
-
extends
|
|
65
|
-
EffectType<AsyncData<A, E, Gated>, never, AsyncCalcStore<N, A, E, Gated>>,
|
|
66
|
-
Source<N, AsyncData<A, E, Gated>, AsyncCalcStore<N, A, E, Gated>> {
|
|
67
|
-
new (): {}
|
|
68
|
-
readonly manifest: AsyncCalcManifest<N, A, E>
|
|
69
|
-
readonly store: Context.Tag<AsyncCalcStore<N, A, E, Gated>, Store<AsyncData<A, E, Gated>>>
|
|
70
|
-
readonly name: N
|
|
71
|
-
readonly inputs: Inputs
|
|
72
|
-
readonly gated: Gated
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface DefinedAsyncCalcClass<
|
|
76
|
-
N extends string,
|
|
77
|
-
Inputs extends ReadonlyArray<AnySource>,
|
|
78
|
-
A,
|
|
79
|
-
E,
|
|
80
|
-
Gated extends boolean,
|
|
81
|
-
> extends AsyncCalcClass<N, Inputs, A, E, Gated> {
|
|
82
|
-
readonly codec: QueryCodec<A>
|
|
83
|
-
readonly capture: <Result>(visit: SourceCapture<Result>) => Result
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
type ConfigSchema<ValueOrSchema> = [ValueOrSchema] extends [Schema.Schema.AnyNoContext]
|
|
87
|
-
? ValueOrSchema
|
|
88
|
-
: AnySchema<ValueOrSchema>
|
|
89
|
-
|
|
90
|
-
type ConfigErrorSchema<ValueOrSchema> = [ValueOrSchema] extends [undefined]
|
|
91
|
-
? ValueOrSchema
|
|
92
|
-
: ConfigSchema<ValueOrSchema>
|
|
93
|
-
|
|
94
|
-
export interface AsyncCalcConfig<
|
|
95
|
-
Inputs extends ReadonlyArray<AnySource>,
|
|
96
|
-
OutputSchema,
|
|
97
|
-
ErrorSchema,
|
|
98
|
-
AlwaysOn extends boolean,
|
|
99
|
-
> {
|
|
100
|
-
readonly inputs: Inputs
|
|
101
|
-
readonly output: ConfigSchema<OutputSchema>
|
|
102
|
-
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
103
|
-
readonly error?: ConfigErrorSchema<ErrorSchema>
|
|
104
|
-
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
105
|
-
readonly alwaysOn?: AlwaysOn
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
interface AsyncCalcMakeConfigExternalApi<
|
|
109
|
-
Inputs extends ReadonlyArray<AnySource>,
|
|
110
|
-
OutputSchema extends Schema.Schema.AnyNoContext,
|
|
111
|
-
ErrorSchema extends Schema.Schema.AnyNoContext | undefined,
|
|
112
|
-
AlwaysOn extends boolean,
|
|
113
|
-
> {
|
|
114
|
-
readonly inputs: Inputs
|
|
115
|
-
readonly output: OutputSchema
|
|
116
|
-
readonly error?: ErrorSchema
|
|
117
|
-
readonly alwaysOn?: AlwaysOn
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export type AsyncCalcLive<
|
|
121
|
-
Inputs extends ReadonlyArray<AnySource>,
|
|
122
|
-
A,
|
|
123
|
-
E,
|
|
124
|
-
Gated extends boolean,
|
|
125
|
-
R,
|
|
126
|
-
> = {
|
|
127
|
-
readonly query: (inputs: InputsObject<Inputs>) => Effect.Effect<A, E, R>
|
|
128
|
-
readonly invalidateBy?: InvalidateBy<Inputs>
|
|
129
|
-
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
130
|
-
readonly coalesce?: 'switch' | 'trailing'
|
|
131
|
-
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
132
|
-
readonly reuse?: boolean
|
|
133
|
-
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
134
|
-
readonly persist?:
|
|
135
|
-
| boolean
|
|
136
|
-
| { readonly key?: string | ((inputs: InputsObject<Inputs>) => string) }
|
|
137
|
-
} & (Gated extends true
|
|
138
|
-
? { readonly disabled?: (inputs: InputsObject<Inputs>) => boolean }
|
|
139
|
-
: { readonly disabled?: never })
|
|
140
|
-
|
|
141
|
-
export type AsyncCalcLiveWithInvalidateOn<
|
|
142
|
-
Inputs extends ReadonlyArray<AnySource>,
|
|
143
|
-
A,
|
|
144
|
-
E,
|
|
145
|
-
Gated extends boolean,
|
|
146
|
-
R,
|
|
147
|
-
> = AsyncCalcLive<Inputs, A, E, Gated, R> & {
|
|
148
|
-
readonly invalidateOn?: ReadonlyArray<AnyEvent>
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface AsyncCalcLiveView<Inputs extends ReadonlyArray<AnySource>, A, E, R> {
|
|
152
|
-
readonly query: (inputs: InputsObject<Inputs>) => Effect.Effect<A, E, R>
|
|
153
|
-
readonly invalidateBy?: InvalidateBy<Inputs>
|
|
154
|
-
readonly disabled?: (inputs: InputsObject<Inputs>) => boolean
|
|
155
|
-
readonly coalesce?: 'switch' | 'trailing'
|
|
156
|
-
readonly reuse?: boolean
|
|
157
|
-
readonly persist?:
|
|
158
|
-
| boolean
|
|
159
|
-
| { readonly key?: string | ((inputs: InputsObject<Inputs>) => string) }
|
|
160
|
-
}
|
|
161
47
|
|
|
162
48
|
export function make<
|
|
163
49
|
const N extends string,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { expect, it } from '@effect/vitest'
|
|
2
|
+
import type { Effect } from 'effect'
|
|
3
|
+
import { Schema as S } from 'effect'
|
|
4
|
+
import { AsyncCalc, Namespace, State, StateGroup } from '../index'
|
|
5
|
+
import type { AsyncData } from './asyncData'
|
|
6
|
+
|
|
7
|
+
// Pins the config -> value-type contract: a named schema in `output`/`error` must survive
|
|
8
|
+
// inference. The package publishes source, so consumers compile these signatures under their
|
|
9
|
+
// own tsconfig — keep `output`/`error` bare inference sites rather than wrapped in anything
|
|
10
|
+
// deferred. `Namespace.make` is the exposed path here because `AsyncCalc.make` can fall back
|
|
11
|
+
// to its second overload, which would mask a regression in `AsyncCalcConfig` itself.
|
|
12
|
+
type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true
|
|
13
|
+
: false
|
|
14
|
+
const expectTypeEquality = <_Proof extends true>(): void => {}
|
|
15
|
+
|
|
16
|
+
const ns = Namespace.make('apps')
|
|
17
|
+
|
|
18
|
+
it('infers output and error schema types from named schemas', () => {
|
|
19
|
+
const Result = S.Struct({ id: S.String, count: S.Number })
|
|
20
|
+
|
|
21
|
+
class Count extends State.make('count', S.Number) {}
|
|
22
|
+
class Inputs extends StateGroup.make(Count) {}
|
|
23
|
+
class MyApps extends ns.AsyncCalc('MyApps', {
|
|
24
|
+
inputs: [StateGroup.select(Inputs, 'count')],
|
|
25
|
+
output: Result,
|
|
26
|
+
error: S.String,
|
|
27
|
+
alwaysOn: true,
|
|
28
|
+
}) {}
|
|
29
|
+
|
|
30
|
+
type Data = Effect.Effect.Success<typeof MyApps>
|
|
31
|
+
expectTypeEquality<
|
|
32
|
+
Equals<Data, AsyncData<{ readonly id: string; readonly count: number }, string, false>>
|
|
33
|
+
>()
|
|
34
|
+
|
|
35
|
+
// `MyApps.name` is the JS class binding's own name, which shadows the prefixed one.
|
|
36
|
+
expect(MyApps.manifest.name).toBe('apps.MyApps')
|
|
37
|
+
expect(MyApps.gated).toBe(false)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('defaults the error type to never when `error` is omitted', () => {
|
|
41
|
+
class Loaded extends ns.AsyncCalc('Loaded', {
|
|
42
|
+
inputs: [],
|
|
43
|
+
output: S.Number,
|
|
44
|
+
}) {}
|
|
45
|
+
|
|
46
|
+
type Data = Effect.Effect.Success<typeof Loaded>
|
|
47
|
+
expectTypeEquality<Equals<Data, AsyncData<number, never, true>>>()
|
|
48
|
+
|
|
49
|
+
expect(Loaded.gated).toBe(true)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('keeps `AsyncCalc.make` inference intact through its overloads', () => {
|
|
53
|
+
class Doubled extends AsyncCalc.make('Doubled', {
|
|
54
|
+
inputs: [],
|
|
55
|
+
output: S.Number,
|
|
56
|
+
error: S.String,
|
|
57
|
+
alwaysOn: true,
|
|
58
|
+
}) {}
|
|
59
|
+
|
|
60
|
+
type Data = Effect.Effect.Success<typeof Doubled>
|
|
61
|
+
expectTypeEquality<Equals<Data, AsyncData<number, string, false>>>()
|
|
62
|
+
|
|
63
|
+
expect(Doubled.gated).toBe(false)
|
|
64
|
+
})
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { Context, Effect, Schema } from 'effect'
|
|
2
|
+
import type { Effect as EffectType } from 'effect/Effect'
|
|
3
|
+
import type { Manifest } from '../definition/definition'
|
|
4
|
+
import type { AnyEvent } from '../event/event'
|
|
5
|
+
import type { InputsObject, InvalidateBy } from '../internal/sources'
|
|
6
|
+
import type { QueryCodec } from '../internal/queryDriver'
|
|
7
|
+
import type { Store } from '../internal/store'
|
|
8
|
+
import type { AnySchema } from '../internal/variance'
|
|
9
|
+
import type { AnySource, Source, SourceCapture } from '../state/token'
|
|
10
|
+
import type { AsyncData } from './asyncData'
|
|
11
|
+
|
|
12
|
+
export interface AsyncCalcSchemaReflection {
|
|
13
|
+
readonly ast: Schema.Schema<unknown, unknown, unknown>['ast']
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AsyncCalcManifest<N extends string, A = unknown, E = never> extends Manifest {
|
|
17
|
+
readonly kind: 'AsyncCalc'
|
|
18
|
+
readonly name: N
|
|
19
|
+
readonly output: AnySchema<A>
|
|
20
|
+
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
21
|
+
readonly error?: AnySchema<E>
|
|
22
|
+
readonly gated: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const AsyncCalcStoreTypeId: unique symbol = Symbol.for('reform/AsyncCalcStore')
|
|
26
|
+
export type AsyncCalcStoreTypeId = typeof AsyncCalcStoreTypeId
|
|
27
|
+
|
|
28
|
+
interface AsyncCalcStoreCompatibilityExternalApi<
|
|
29
|
+
N extends string,
|
|
30
|
+
in out A,
|
|
31
|
+
in out E,
|
|
32
|
+
in out Gated extends boolean,
|
|
33
|
+
> extends Store<AsyncData<A, E, Gated>> {
|
|
34
|
+
readonly [AsyncCalcStoreTypeId]?: N
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type AsyncCalcStore<
|
|
38
|
+
N extends string,
|
|
39
|
+
A,
|
|
40
|
+
E,
|
|
41
|
+
Gated extends boolean,
|
|
42
|
+
> = AsyncCalcStoreCompatibilityExternalApi<N, A, E, Gated>
|
|
43
|
+
|
|
44
|
+
export interface AsyncCalcClass<
|
|
45
|
+
N extends string,
|
|
46
|
+
Inputs extends ReadonlyArray<AnySource>,
|
|
47
|
+
A,
|
|
48
|
+
E,
|
|
49
|
+
Gated extends boolean,
|
|
50
|
+
>
|
|
51
|
+
extends
|
|
52
|
+
EffectType<AsyncData<A, E, Gated>, never, AsyncCalcStore<N, A, E, Gated>>,
|
|
53
|
+
Source<N, AsyncData<A, E, Gated>, AsyncCalcStore<N, A, E, Gated>> {
|
|
54
|
+
new (): {}
|
|
55
|
+
readonly manifest: AsyncCalcManifest<N, A, E>
|
|
56
|
+
readonly store: Context.Tag<AsyncCalcStore<N, A, E, Gated>, Store<AsyncData<A, E, Gated>>>
|
|
57
|
+
readonly name: N
|
|
58
|
+
readonly inputs: Inputs
|
|
59
|
+
readonly gated: Gated
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface DefinedAsyncCalcClass<
|
|
63
|
+
N extends string,
|
|
64
|
+
Inputs extends ReadonlyArray<AnySource>,
|
|
65
|
+
A,
|
|
66
|
+
E,
|
|
67
|
+
Gated extends boolean,
|
|
68
|
+
> extends AsyncCalcClass<N, Inputs, A, E, Gated> {
|
|
69
|
+
readonly codec: QueryCodec<A>
|
|
70
|
+
readonly capture: <Result>(visit: SourceCapture<Result>) => Result
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface AsyncCalcConfig<
|
|
74
|
+
Inputs extends ReadonlyArray<AnySource>,
|
|
75
|
+
OutputSchema,
|
|
76
|
+
ErrorSchema,
|
|
77
|
+
AlwaysOn extends boolean,
|
|
78
|
+
> {
|
|
79
|
+
readonly inputs: Inputs
|
|
80
|
+
readonly output: OutputSchema
|
|
81
|
+
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
82
|
+
readonly error?: ErrorSchema
|
|
83
|
+
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
84
|
+
readonly alwaysOn?: AlwaysOn
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface AsyncCalcMakeConfigExternalApi<
|
|
88
|
+
Inputs extends ReadonlyArray<AnySource>,
|
|
89
|
+
OutputSchema extends Schema.Schema.AnyNoContext,
|
|
90
|
+
ErrorSchema extends Schema.Schema.AnyNoContext | undefined,
|
|
91
|
+
AlwaysOn extends boolean,
|
|
92
|
+
> {
|
|
93
|
+
readonly inputs: Inputs
|
|
94
|
+
readonly output: OutputSchema
|
|
95
|
+
readonly error?: ErrorSchema
|
|
96
|
+
readonly alwaysOn?: AlwaysOn
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export type AsyncCalcLive<
|
|
100
|
+
Inputs extends ReadonlyArray<AnySource>,
|
|
101
|
+
A,
|
|
102
|
+
E,
|
|
103
|
+
Gated extends boolean,
|
|
104
|
+
R,
|
|
105
|
+
> = {
|
|
106
|
+
readonly query: (inputs: InputsObject<Inputs>) => Effect.Effect<A, E, R>
|
|
107
|
+
readonly invalidateBy?: InvalidateBy<Inputs>
|
|
108
|
+
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
109
|
+
readonly coalesce?: 'switch' | 'trailing'
|
|
110
|
+
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
111
|
+
readonly reuse?: boolean
|
|
112
|
+
// oxlint-disable-next-line reform-rules/no-optional-fields -- caller-omitted option built at the asyncCalc/remoteState construction site; Option<T> would change that call shape
|
|
113
|
+
readonly persist?:
|
|
114
|
+
| boolean
|
|
115
|
+
| { readonly key?: string | ((inputs: InputsObject<Inputs>) => string) }
|
|
116
|
+
} & (Gated extends true
|
|
117
|
+
? { readonly disabled?: (inputs: InputsObject<Inputs>) => boolean }
|
|
118
|
+
: { readonly disabled?: never })
|
|
119
|
+
|
|
120
|
+
export type AsyncCalcLiveWithInvalidateOn<
|
|
121
|
+
Inputs extends ReadonlyArray<AnySource>,
|
|
122
|
+
A,
|
|
123
|
+
E,
|
|
124
|
+
Gated extends boolean,
|
|
125
|
+
R,
|
|
126
|
+
> = AsyncCalcLive<Inputs, A, E, Gated, R> & {
|
|
127
|
+
readonly invalidateOn?: ReadonlyArray<AnyEvent>
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface AsyncCalcLiveView<Inputs extends ReadonlyArray<AnySource>, A, E, R> {
|
|
131
|
+
readonly query: (inputs: InputsObject<Inputs>) => Effect.Effect<A, E, R>
|
|
132
|
+
readonly invalidateBy?: InvalidateBy<Inputs>
|
|
133
|
+
readonly disabled?: (inputs: InputsObject<Inputs>) => boolean
|
|
134
|
+
readonly coalesce?: 'switch' | 'trailing'
|
|
135
|
+
readonly reuse?: boolean
|
|
136
|
+
readonly persist?:
|
|
137
|
+
| boolean
|
|
138
|
+
| { readonly key?: string | ((inputs: InputsObject<Inputs>) => string) }
|
|
139
|
+
}
|
package/src/calc/calc.test.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { expect, it } from '@effect/vitest'
|
|
2
|
-
import {
|
|
2
|
+
import { Effect, Layer, Schema as S } from 'effect'
|
|
3
3
|
import { Calc, State, StateGroup } from '../index'
|
|
4
|
-
|
|
5
|
-
const tick = Effect.sleep(Duration.millis(1))
|
|
4
|
+
import { flush } from '../testkit/flight.testkit'
|
|
6
5
|
|
|
7
6
|
it.live('a source change that does not move the output notifies no subscriber', () => {
|
|
8
7
|
class Count extends State.make('count', S.Number) {}
|
|
@@ -30,12 +29,12 @@ it.live('a source change that does not move the output notifies no subscriber',
|
|
|
30
29
|
expect(derived.get()).toBe(true)
|
|
31
30
|
|
|
32
31
|
source.set(2)
|
|
33
|
-
yield*
|
|
32
|
+
yield* flush()
|
|
34
33
|
expect(notifications.n).toBe(0)
|
|
35
34
|
expect(derived.get()).toBe(true)
|
|
36
35
|
|
|
37
36
|
source.set(-1)
|
|
38
|
-
yield*
|
|
37
|
+
yield* flush()
|
|
39
38
|
expect(notifications.n).toBe(1)
|
|
40
39
|
expect(derived.get()).toBe(false)
|
|
41
40
|
}).pipe(Effect.provide(TestLayer))
|
|
@@ -89,7 +88,7 @@ it.live('a calc can depend on another calc as an input source', () => {
|
|
|
89
88
|
const derived = yield* PlusDoubled.store
|
|
90
89
|
expect(derived.get()).toBe(15)
|
|
91
90
|
source.set(3)
|
|
92
|
-
yield*
|
|
91
|
+
yield* flush()
|
|
93
92
|
expect(derived.get()).toBe(9)
|
|
94
93
|
}).pipe(Effect.provide(TestLayer))
|
|
95
94
|
})
|
|
@@ -125,7 +124,7 @@ it.live('a diamond dependency resolves in one flush with a single leaf notificat
|
|
|
125
124
|
expect(c.get()).toBe(11)
|
|
126
125
|
|
|
127
126
|
source.set(5)
|
|
128
|
-
yield*
|
|
127
|
+
yield* flush()
|
|
129
128
|
expect(c.get()).toBe(21)
|
|
130
129
|
expect(wakes.n).toBe(1)
|
|
131
130
|
}).pipe(Effect.provide(TestLayer))
|
|
@@ -158,12 +157,12 @@ it.live('invalidateBy: a calc recomputes only when the projected key moves', ()
|
|
|
158
157
|
expect(sum.get()).toBe(2)
|
|
159
158
|
|
|
160
159
|
sb.set(100)
|
|
161
|
-
yield*
|
|
160
|
+
yield* flush()
|
|
162
161
|
expect(runs.n).toBe(base)
|
|
163
162
|
expect(sum.get()).toBe(2)
|
|
164
163
|
|
|
165
164
|
sa.set(5)
|
|
166
|
-
yield*
|
|
165
|
+
yield* flush()
|
|
167
166
|
expect(sum.get()).toBe(105)
|
|
168
167
|
}).pipe(Effect.provide(TestLayer))
|
|
169
168
|
})
|
|
@@ -222,7 +221,7 @@ it.live('reuse: an unchanged subtree keeps its identity across recompute', () =>
|
|
|
222
221
|
const before = derived.get()
|
|
223
222
|
|
|
224
223
|
b.set(2)
|
|
225
|
-
yield*
|
|
224
|
+
yield* flush()
|
|
226
225
|
const after = derived.get()
|
|
227
226
|
expect(after).not.toBe(before)
|
|
228
227
|
expect(after.left).toBe(before.left)
|
|
@@ -254,7 +253,7 @@ it.live('reuse: a value-equal recompute keeps the previous reference and wakes n
|
|
|
254
253
|
const before = derived.get()
|
|
255
254
|
|
|
256
255
|
source.set(2)
|
|
257
|
-
yield*
|
|
256
|
+
yield* flush()
|
|
258
257
|
expect(derived.get()).toBe(before)
|
|
259
258
|
expect(notifications.n).toBe(0)
|
|
260
259
|
}).pipe(Effect.provide(TestLayer))
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { expect, it } from '@effect/vitest'
|
|
2
|
-
import { Context,
|
|
2
|
+
import { Context, Effect, Exit, Layer, Schema as S, Scope } from 'effect'
|
|
3
3
|
import { CalcFamily, State, StateGroup } from '../index'
|
|
4
|
+
import { flush } from '../testkit/flight.testkit'
|
|
4
5
|
|
|
5
|
-
const tick = Effect.sleep(Duration.millis(1))
|
|
6
6
|
|
|
7
7
|
const Board = S.Record({ key: S.String, value: S.Number })
|
|
8
8
|
|
|
@@ -33,7 +33,7 @@ it.live('a member derives from the shared inputs and recomputes when they change
|
|
|
33
33
|
expect(yield* CalcFamily.read(Slice, 'b')).toBe(10)
|
|
34
34
|
|
|
35
35
|
feed.set({ a: 2, b: 10 })
|
|
36
|
-
yield*
|
|
36
|
+
yield* flush()
|
|
37
37
|
expect(yield* CalcFamily.read(Slice, 'a')).toBe(2)
|
|
38
38
|
}).pipe(Effect.provide(TestLayer))
|
|
39
39
|
})
|
|
@@ -55,11 +55,11 @@ it.live('a member only notifies when its own slice of the projection moves', ()
|
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
feed.set({ a: 2, b: 10 })
|
|
58
|
-
yield*
|
|
58
|
+
yield* flush()
|
|
59
59
|
expect(wakes).toEqual({ a: 1, b: 0 })
|
|
60
60
|
|
|
61
61
|
feed.set({ a: 2, b: 11 })
|
|
62
|
-
yield*
|
|
62
|
+
yield* flush()
|
|
63
63
|
expect(wakes).toEqual({ a: 1, b: 1 })
|
|
64
64
|
}).pipe(Effect.provide(TestLayer))
|
|
65
65
|
})
|
|
@@ -107,13 +107,13 @@ it.live('reuse preserves each member output when equal and replaces it when chan
|
|
|
107
107
|
|
|
108
108
|
expect(Object.is(initialA.nested, initialB.nested)).toBe(false)
|
|
109
109
|
revision.set(1)
|
|
110
|
-
yield*
|
|
110
|
+
yield* flush()
|
|
111
111
|
expect(Object.is(family.at('a').get().nested, initialA.nested)).toBe(true)
|
|
112
112
|
expect(Object.is(family.at('b').get().nested, initialB.nested)).toBe(true)
|
|
113
113
|
expect(wakes).toEqual({ a: 0, b: 0 })
|
|
114
114
|
|
|
115
115
|
feed.set({ a: 2, b: 1 })
|
|
116
|
-
yield*
|
|
116
|
+
yield* flush()
|
|
117
117
|
expect(family.at('a').get().nested).toEqual([{ value: 2 }])
|
|
118
118
|
expect(Object.is(family.at('a').get().nested, initialA.nested)).toBe(false)
|
|
119
119
|
expect(Object.is(family.at('b').get().nested, initialB.nested)).toBe(true)
|
|
@@ -165,7 +165,7 @@ it.live('invalidateBy: shared-input churn outside the key recomputes no member',
|
|
|
165
165
|
expect(runs.get('a')).toBe(1)
|
|
166
166
|
|
|
167
167
|
noise.set(99)
|
|
168
|
-
yield*
|
|
168
|
+
yield* flush()
|
|
169
169
|
expect(yield* CalcFamily.read(Slice, 'a')).toBe(1)
|
|
170
170
|
expect(runs.get('a')).toBe(1)
|
|
171
171
|
}).pipe(Effect.provide(TestLayer))
|
|
@@ -184,7 +184,7 @@ it.live('forget releases the member and its upstream subscription', () => {
|
|
|
184
184
|
expect(family.size()).toBe(0)
|
|
185
185
|
const before = runs.get('a') ?? 0
|
|
186
186
|
feed.set({ a: 2 })
|
|
187
|
-
yield*
|
|
187
|
+
yield* flush()
|
|
188
188
|
expect(runs.get('a') ?? 0).toBe(before)
|
|
189
189
|
|
|
190
190
|
expect(family.at('a').get()).toBe(2)
|
|
@@ -217,11 +217,11 @@ it.live('evictWhenUnused: an idle member is dropped on the next microtask and un
|
|
|
217
217
|
expect(family.size()).toBe(1)
|
|
218
218
|
|
|
219
219
|
off()
|
|
220
|
-
yield*
|
|
220
|
+
yield* flush()
|
|
221
221
|
expect(family.size()).toBe(0)
|
|
222
222
|
const before = runs.get('a') ?? 0
|
|
223
223
|
feed.set({ a: 2 })
|
|
224
|
-
yield*
|
|
224
|
+
yield* flush()
|
|
225
225
|
expect(runs.get('a') ?? 0).toBe(before)
|
|
226
226
|
}).pipe(Effect.provide(TestLayer))
|
|
227
227
|
})
|
|
@@ -245,7 +245,7 @@ it.live('the layer finalizer clears every member (no live subscriptions leak)',
|
|
|
245
245
|
expect(family.size()).toBe(0)
|
|
246
246
|
const before = [runs.get('a') ?? 0, runs.get('b') ?? 0]
|
|
247
247
|
feed.set({ a: 9, b: 9 })
|
|
248
|
-
yield*
|
|
248
|
+
yield* flush()
|
|
249
249
|
expect([runs.get('a') ?? 0, runs.get('b') ?? 0]).toEqual(before)
|
|
250
250
|
}),
|
|
251
251
|
)
|
package/src/channel/channel.ts
CHANGED
|
@@ -12,9 +12,16 @@ import {
|
|
|
12
12
|
Stream,
|
|
13
13
|
} from 'effect'
|
|
14
14
|
import { type Manifest, definitionClass } from '../definition/definition'
|
|
15
|
-
import { makeBucketCache } from '../internal/bucketCache'
|
|
16
15
|
import type { Tagged } from '../runtime/bus'
|
|
17
16
|
import { resolveInstrumentation } from '../runtime/instrumentation'
|
|
17
|
+
import { type ProcedureEntry, Procedures } from './procedures'
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
type ProcedureEntry,
|
|
21
|
+
type ProcedureRegistry,
|
|
22
|
+
Procedures,
|
|
23
|
+
proceduresLayer,
|
|
24
|
+
} from './procedures'
|
|
18
25
|
|
|
19
26
|
export type ChannelPolicy =
|
|
20
27
|
| { readonly _tag: 'merge' }
|
|
@@ -44,111 +51,6 @@ export interface ChannelConfig {
|
|
|
44
51
|
readonly policy: ChannelPolicy
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
export interface ProcedureEntry {
|
|
48
|
-
readonly name: string
|
|
49
|
-
readonly channelName: string
|
|
50
|
-
readonly handles: ReadonlySet<string>
|
|
51
|
-
readonly run: (event: Tagged) => Effect.Effect<unknown, unknown, never>
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface ProcedureRegistry {
|
|
55
|
-
readonly entries: Array<ProcedureEntry>
|
|
56
|
-
readonly byName: Map<string, Set<ProcedureEntry>>
|
|
57
|
-
readonly byTag: Map<string, Set<ProcedureEntry>>
|
|
58
|
-
readonly channelsByTag: Map<string, Set<string>>
|
|
59
|
-
readonly channelsFor: (tag: string) => ReadonlyArray<string>
|
|
60
|
-
readonly byChannelTag: Map<string, Map<string, Set<ProcedureEntry>>>
|
|
61
|
-
readonly register: (entry: ProcedureEntry) => void
|
|
62
|
-
readonly unregister: (entry: ProcedureEntry) => void
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const ProceduresBase: Context.TagClass<Procedures, 'reform/Procedures', ProcedureRegistry> =
|
|
66
|
-
Context.Tag('reform/Procedures')<Procedures, ProcedureRegistry>()
|
|
67
|
-
export class Procedures extends ProceduresBase {}
|
|
68
|
-
|
|
69
|
-
const getOrCreate = <K, V>(map: Map<K, V>, key: K, make: () => V): V => {
|
|
70
|
-
const existing = map.get(key)
|
|
71
|
-
if (existing !== undefined) {
|
|
72
|
-
return existing
|
|
73
|
-
}
|
|
74
|
-
const created = make()
|
|
75
|
-
map.set(key, created)
|
|
76
|
-
return created
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const dropFrom = <K, T>(map: Map<K, Set<T>>, key: K, target: T): void => {
|
|
80
|
-
const bucket = map.get(key)
|
|
81
|
-
if (bucket === undefined) {
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
bucket.delete(target)
|
|
85
|
-
if (bucket.size === 0) {
|
|
86
|
-
map.delete(key)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const makeProcedureRegistry = (): ProcedureRegistry => {
|
|
91
|
-
const entries = new Set<ProcedureEntry>()
|
|
92
|
-
const byName = new Map<string, Set<ProcedureEntry>>()
|
|
93
|
-
const byTag = new Map<string, Set<ProcedureEntry>>()
|
|
94
|
-
const channelsByTag = new Map<string, Set<string>>()
|
|
95
|
-
const channelsFor = makeBucketCache(channelsByTag)
|
|
96
|
-
const byChannelTag = new Map<string, Map<string, Set<ProcedureEntry>>>()
|
|
97
|
-
const snapshot: { value: Option.Option<Array<ProcedureEntry>> } = {
|
|
98
|
-
value: Option.some([]),
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
get entries() {
|
|
102
|
-
return Option.getOrElse(snapshot.value, () => {
|
|
103
|
-
const current = Array.from(entries)
|
|
104
|
-
snapshot.value = Option.some(current)
|
|
105
|
-
return current
|
|
106
|
-
})
|
|
107
|
-
},
|
|
108
|
-
byName,
|
|
109
|
-
byTag,
|
|
110
|
-
channelsByTag,
|
|
111
|
-
channelsFor: channelsFor.read,
|
|
112
|
-
byChannelTag,
|
|
113
|
-
register: (entry) => {
|
|
114
|
-
entries.add(entry)
|
|
115
|
-
snapshot.value = Option.none()
|
|
116
|
-
getOrCreate(byName, entry.name, () => new Set()).add(entry)
|
|
117
|
-
entry.handles.forEach((tag) => {
|
|
118
|
-
getOrCreate(byTag, tag, () => new Set()).add(entry)
|
|
119
|
-
getOrCreate(channelsByTag, tag, () => new Set()).add(entry.channelName)
|
|
120
|
-
channelsFor.invalidate(tag)
|
|
121
|
-
const channelMap = getOrCreate(byChannelTag, entry.channelName, () => new Map())
|
|
122
|
-
getOrCreate(channelMap, tag, () => new Set()).add(entry)
|
|
123
|
-
})
|
|
124
|
-
},
|
|
125
|
-
unregister: (entry) => {
|
|
126
|
-
entries.delete(entry)
|
|
127
|
-
snapshot.value = Option.none()
|
|
128
|
-
dropFrom(byName, entry.name, entry)
|
|
129
|
-
entry.handles.forEach((tag) => {
|
|
130
|
-
dropFrom(byTag, tag, entry)
|
|
131
|
-
const channelMap = byChannelTag.get(entry.channelName)
|
|
132
|
-
if (channelMap !== undefined) {
|
|
133
|
-
dropFrom(channelMap, tag, entry)
|
|
134
|
-
if (channelMap.get(tag) === undefined) {
|
|
135
|
-
dropFrom(channelsByTag, tag, entry.channelName)
|
|
136
|
-
channelsFor.invalidate(tag)
|
|
137
|
-
}
|
|
138
|
-
if (channelMap.size === 0) {
|
|
139
|
-
byChannelTag.delete(entry.channelName)
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
},
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export const proceduresLayer: Layer.Layer<Procedures> = Layer.sync(
|
|
148
|
-
Procedures,
|
|
149
|
-
makeProcedureRegistry,
|
|
150
|
-
)
|
|
151
|
-
|
|
152
54
|
export interface ChannelRuntime {
|
|
153
55
|
readonly name: string
|
|
154
56
|
readonly policy: ChannelPolicy
|