@playfast/reform 0.0.4 → 0.0.7
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 +72 -0
- package/dist/boundary/boundary.d.ts.map +1 -0
- package/dist/boundary/boundary.js +83 -0
- package/dist/boundary/boundary.js.map +1 -0
- package/dist/calc/asyncCalc.d.ts +91 -0
- package/dist/calc/asyncCalc.d.ts.map +1 -0
- package/dist/calc/asyncCalc.js +95 -0
- package/dist/calc/asyncCalc.js.map +1 -0
- package/{src/calc/asyncData.ts → dist/calc/asyncData.d.ts} +22 -53
- package/dist/calc/asyncData.d.ts.map +1 -0
- package/dist/calc/asyncData.js +34 -0
- package/dist/calc/asyncData.js.map +1 -0
- package/dist/calc/calc.d.ts +57 -0
- package/dist/calc/calc.d.ts.map +1 -0
- package/dist/calc/calc.js +58 -0
- package/dist/calc/calc.js.map +1 -0
- package/dist/calc/calcFamily.d.ts +57 -0
- package/dist/calc/calcFamily.d.ts.map +1 -0
- package/dist/calc/calcFamily.js +124 -0
- package/dist/calc/calcFamily.js.map +1 -0
- package/dist/calc/compose.d.ts +16 -0
- package/dist/calc/compose.d.ts.map +1 -0
- package/dist/calc/compose.js +7 -0
- package/dist/calc/compose.js.map +1 -0
- package/dist/channel/channel.d.ts +115 -0
- package/dist/channel/channel.d.ts.map +1 -0
- package/dist/channel/channel.js +138 -0
- package/dist/channel/channel.js.map +1 -0
- package/dist/compose/composition.d.ts +72 -0
- package/dist/compose/composition.d.ts.map +1 -0
- package/dist/compose/composition.js +46 -0
- package/dist/compose/composition.js.map +1 -0
- package/{src/compose/host.ts → dist/compose/host.d.ts} +8 -6
- package/dist/compose/host.d.ts.map +1 -0
- package/dist/compose/host.js +6 -0
- package/dist/compose/host.js.map +1 -0
- package/dist/compose/props.d.ts +13 -0
- package/dist/compose/props.d.ts.map +1 -0
- package/{src/compose/props.ts → dist/compose/props.js} +5 -3
- package/dist/compose/props.js.map +1 -0
- package/dist/compose/provide.d.ts +22 -0
- package/dist/compose/provide.d.ts.map +1 -0
- package/dist/compose/provide.js +28 -0
- package/dist/compose/provide.js.map +1 -0
- package/{src/compose/slot.ts → dist/compose/slot.d.ts} +19 -36
- package/dist/compose/slot.d.ts.map +1 -0
- package/dist/compose/slot.js +23 -0
- package/dist/compose/slot.js.map +1 -0
- package/dist/compose/ui.d.ts +135 -0
- package/dist/compose/ui.d.ts.map +1 -0
- package/dist/compose/ui.js +63 -0
- package/dist/compose/ui.js.map +1 -0
- package/dist/definition/definition.d.ts +33 -0
- package/dist/definition/definition.d.ts.map +1 -0
- package/dist/definition/definition.js +42 -0
- package/dist/definition/definition.js.map +1 -0
- package/dist/event/event.d.ts +33 -0
- package/dist/event/event.d.ts.map +1 -0
- package/dist/event/event.js +30 -0
- package/dist/event/event.js.map +1 -0
- package/dist/event/eventGroup.d.ts +9 -0
- package/dist/event/eventGroup.d.ts.map +1 -0
- package/dist/event/eventGroup.js +4 -0
- package/dist/event/eventGroup.js.map +1 -0
- package/{src/feature/feature.ts → dist/feature/feature.d.ts} +92 -178
- package/dist/feature/feature.d.ts.map +1 -0
- package/dist/feature/feature.js +98 -0
- package/dist/feature/feature.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/{src/internal/capture.ts → dist/internal/capture.d.ts} +11 -13
- package/dist/internal/capture.d.ts.map +1 -0
- package/dist/internal/capture.js +12 -0
- package/dist/internal/capture.js.map +1 -0
- package/{src/internal/ctx.ts → dist/internal/ctx.d.ts} +4 -8
- package/dist/internal/ctx.d.ts.map +1 -0
- package/dist/internal/ctx.js +2 -0
- package/dist/internal/ctx.js.map +1 -0
- package/dist/internal/errors.d.ts +89 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +102 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/inspect.d.ts +17 -0
- package/dist/internal/inspect.d.ts.map +1 -0
- package/dist/internal/inspect.js +32 -0
- package/dist/internal/inspect.js.map +1 -0
- package/dist/internal/queryDriver.d.ts +65 -0
- package/dist/internal/queryDriver.d.ts.map +1 -0
- package/dist/internal/queryDriver.js +134 -0
- package/dist/internal/queryDriver.js.map +1 -0
- package/dist/internal/reuse.d.ts +10 -0
- package/dist/internal/reuse.d.ts.map +1 -0
- package/dist/internal/reuse.js +68 -0
- package/dist/internal/reuse.js.map +1 -0
- package/dist/internal/scheduler.d.ts +47 -0
- package/dist/internal/scheduler.d.ts.map +1 -0
- package/dist/internal/scheduler.js +70 -0
- package/dist/internal/scheduler.js.map +1 -0
- package/{src/internal/seeds.ts → dist/internal/seeds.d.ts} +3 -6
- package/dist/internal/seeds.d.ts.map +1 -0
- package/dist/internal/seeds.js +17 -0
- package/dist/internal/seeds.js.map +1 -0
- package/dist/internal/sources.d.ts +39 -0
- package/dist/internal/sources.d.ts.map +1 -0
- package/dist/internal/sources.js +59 -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 +28 -0
- package/dist/internal/stateRegistry.js.map +1 -0
- package/dist/internal/store.d.ts +47 -0
- package/dist/internal/store.d.ts.map +1 -0
- package/dist/internal/store.js +73 -0
- package/dist/internal/store.js.map +1 -0
- package/{src/internal/track.ts → dist/internal/track.d.ts} +11 -15
- package/dist/internal/track.d.ts.map +1 -0
- package/dist/internal/track.js +19 -0
- package/dist/internal/track.js.map +1 -0
- package/dist/procedure/procedure.d.ts +40 -0
- package/dist/procedure/procedure.d.ts.map +1 -0
- package/dist/procedure/procedure.js +50 -0
- package/dist/procedure/procedure.js.map +1 -0
- package/dist/reducer/reducer.d.ts +44 -0
- package/dist/reducer/reducer.d.ts.map +1 -0
- package/dist/reducer/reducer.js +63 -0
- package/dist/reducer/reducer.js.map +1 -0
- package/dist/remote/remoteState.d.ts +119 -0
- package/dist/remote/remoteState.d.ts.map +1 -0
- package/dist/remote/remoteState.js +270 -0
- package/dist/remote/remoteState.js.map +1 -0
- package/dist/runtime/bus.d.ts +27 -0
- package/dist/runtime/bus.d.ts.map +1 -0
- package/{src/runtime/bus.ts → dist/runtime/bus.js} +8 -23
- package/dist/runtime/bus.js.map +1 -0
- package/dist/runtime/loop.d.ts +45 -0
- package/dist/runtime/loop.d.ts.map +1 -0
- package/dist/runtime/loop.js +117 -0
- package/dist/runtime/loop.js.map +1 -0
- package/dist/scene/scene.d.ts +44 -0
- package/dist/scene/scene.d.ts.map +1 -0
- package/dist/scene/scene.js +31 -0
- package/dist/scene/scene.js.map +1 -0
- package/dist/state/state.d.ts +37 -0
- package/dist/state/state.d.ts.map +1 -0
- package/dist/state/state.js +46 -0
- package/dist/state/state.js.map +1 -0
- package/dist/state/stateFamily.d.ts +79 -0
- package/dist/state/stateFamily.d.ts.map +1 -0
- package/dist/state/stateFamily.js +99 -0
- package/dist/state/stateFamily.js.map +1 -0
- package/dist/state/stateGroup.d.ts +50 -0
- package/dist/state/stateGroup.d.ts.map +1 -0
- package/dist/state/stateGroup.js +54 -0
- package/dist/state/stateGroup.js.map +1 -0
- package/{src/state/token.ts → dist/state/token.d.ts} +13 -21
- package/dist/state/token.d.ts.map +1 -0
- package/dist/state/token.js +20 -0
- package/dist/state/token.js.map +1 -0
- package/dist/synced/syncedStore.d.ts +51 -0
- package/dist/synced/syncedStore.d.ts.map +1 -0
- package/dist/synced/syncedStore.js +43 -0
- package/dist/synced/syncedStore.js.map +1 -0
- package/{src/ui/node.ts → dist/ui/node.d.ts} +3 -3
- 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/{src/ui/trigger.ts → dist/ui/trigger.d.ts} +2 -1
- 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 +66 -0
- package/dist/wire/tree.d.ts.map +1 -0
- package/dist/wire/tree.js +60 -0
- package/dist/wire/tree.js.map +1 -0
- package/dist/wire/triggers.d.ts +44 -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 +32 -11
- package/src/boundary/boundary.ts +0 -192
- package/src/calc/asyncCalc.ts +0 -267
- package/src/calc/calc.ts +0 -120
- package/src/calc/calcFamily.ts +0 -194
- package/src/calc/compose.ts +0 -69
- package/src/channel/channel.ts +0 -265
- package/src/compose/composition.ts +0 -112
- package/src/compose/provide.ts +0 -70
- package/src/compose/ui.ts +0 -97
- package/src/definition/definition.ts +0 -74
- package/src/event/event.ts +0 -65
- package/src/event/eventGroup.ts +0 -14
- package/src/index.ts +0 -140
- package/src/internal/errors.ts +0 -69
- package/src/internal/inspect.ts +0 -34
- package/src/internal/queryDriver.ts +0 -247
- package/src/internal/reuse.ts +0 -73
- package/src/internal/scheduler.ts +0 -91
- package/src/internal/sources.ts +0 -104
- package/src/internal/store.ts +0 -105
- package/src/procedure/procedure.ts +0 -89
- package/src/reducer/reducer.ts +0 -137
- package/src/remote/remoteState.ts +0 -571
- package/src/runtime/loop.ts +0 -169
- package/src/scene/scene.ts +0 -76
- package/src/state/state.ts +0 -91
- package/src/state/stateFamily.ts +0 -171
- package/src/state/stateGroup.ts +0 -78
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene.js","sourceRoot":"","sources":["../../src/scene/scene.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAG9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAgCxD;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,WAAyC,EACzC,MAGC,EACS,EAAE,CAAC,CAAC;IACd,IAAI,EAAE,OAAO;IACb,WAAW;IACX,OAAO,EAAE,MAAM,CAAC,OAAO;IACvB,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CAC5D,CAAC,CAAA;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAc,EACd,KAAwC,EAC9B,EAAE,CACZ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC;IAC7B,CAAC,CAAC,IAAI;IACN,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC,EAAE,CAAA;AAExF,wDAAwD;AACxD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAU,EAAc,EAAE,CAChD,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAK,CAAiC,CAAC,IAAI,KAAK,OAAO,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Schema } from 'effect';
|
|
2
|
+
import { type Manifest } from '../definition/definition';
|
|
3
|
+
import { type Store } from '../internal/store';
|
|
4
|
+
export interface StateOptions {
|
|
5
|
+
readonly title?: string;
|
|
6
|
+
readonly description?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface StateManifest<N extends string, A> extends Manifest {
|
|
9
|
+
readonly kind: 'State';
|
|
10
|
+
readonly name: N;
|
|
11
|
+
readonly schema: Schema.Schema<A, any>;
|
|
12
|
+
readonly title?: string;
|
|
13
|
+
readonly description?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface StateClass<out N extends string, in out A> extends Effect.Effect<A, never, Store<A>> {
|
|
16
|
+
new (): {};
|
|
17
|
+
readonly manifest: StateManifest<N, A>;
|
|
18
|
+
/** Internal DI tag holding the live store. The loop reads/writes through it. */
|
|
19
|
+
readonly store: Context.Tag<Store<A>, Store<A>>;
|
|
20
|
+
}
|
|
21
|
+
export type AnyState = StateClass<string, any>;
|
|
22
|
+
export type StateValue<S> = S extends StateClass<string, infer A> ? A : never;
|
|
23
|
+
export type StateName<S> = S extends StateClass<infer N, any> ? N : never;
|
|
24
|
+
/**
|
|
25
|
+
* Atomic reactive state. `State.make` is the *definition* (a reflectable
|
|
26
|
+
* manifest + an internal store tag); it carries no starting value — the seed is
|
|
27
|
+
* an implementation detail supplied at create-time by `State.live(state, seed)`.
|
|
28
|
+
* Composed into a `StateGroup` exactly as `@effect/rpc` composes rpcs.
|
|
29
|
+
*/
|
|
30
|
+
export declare const make: <const N extends string, A>(name: N, schema: Schema.Schema<A, any>, options?: StateOptions) => StateClass<N, A>;
|
|
31
|
+
/**
|
|
32
|
+
* Allocate a state's store, seeded with `initial` — `State.live(Feed, seed)`.
|
|
33
|
+
* The seed lives here (implementation), not on the definition, so the same
|
|
34
|
+
* definition can boot from different values in app vs. test wiring.
|
|
35
|
+
*/
|
|
36
|
+
export declare const live: <S extends AnyState>(state: S, initial: StateValue<S>) => Layer.Layer<Store<StateValue<S>>>;
|
|
37
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/state/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAY,KAAK,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAA;AACzE,OAAO,EAAE,KAAK,QAAQ,EAAkB,MAAM,0BAA0B,CAAA;AAIxE,OAAO,EAAa,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAGzD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,CAAE,SAAQ,QAAQ;IAClE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAE,SAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACnG,QAAQ,EAAE,CAAA;IACV,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACtC,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;CAChD;AAED,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAC9C,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAC7E,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,IAAI,GAAI,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAC5C,MAAM,CAAC,EACP,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,EAC7B,UAAS,YAAiB,KACzB,UAAU,CAAC,CAAC,EAAE,CAAC,CAajB,CAAA;AAwBD;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,SAAS,QAAQ,EACrC,OAAO,CAAC,EACR,SAAS,UAAU,CAAC,CAAC,CAAC,KACrB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAMhC,CAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Context, Effect, FiberRef, Layer, Option, Schema } from 'effect';
|
|
2
|
+
import { yieldableClass } from '../definition/definition';
|
|
3
|
+
import { resolveScheduler } from '../internal/scheduler';
|
|
4
|
+
import { CurrentSeedOverrides } from '../internal/seeds';
|
|
5
|
+
import { claimStateTag } from '../internal/stateRegistry';
|
|
6
|
+
import { makeStore } from '../internal/store';
|
|
7
|
+
import { readTracked } from '../internal/track';
|
|
8
|
+
/**
|
|
9
|
+
* Atomic reactive state. `State.make` is the *definition* (a reflectable
|
|
10
|
+
* manifest + an internal store tag); it carries no starting value — the seed is
|
|
11
|
+
* an implementation detail supplied at create-time by `State.live(state, seed)`.
|
|
12
|
+
* Composed into a `StateGroup` exactly as `@effect/rpc` composes rpcs.
|
|
13
|
+
*/
|
|
14
|
+
export const make = (name, schema, options = {}) => {
|
|
15
|
+
const identifier = `reform/state/${name}`;
|
|
16
|
+
claimStateTag(identifier);
|
|
17
|
+
const store = Context.GenericTag(identifier);
|
|
18
|
+
const manifest = {
|
|
19
|
+
kind: 'State',
|
|
20
|
+
name,
|
|
21
|
+
schema,
|
|
22
|
+
...(options.title !== undefined ? { title: options.title } : {}),
|
|
23
|
+
...(options.description !== undefined ? { description: options.description } : {}),
|
|
24
|
+
};
|
|
25
|
+
const read = Effect.flatMap(store, readTracked);
|
|
26
|
+
return yieldableClass(read, { manifest, store });
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the value a store should boot from: the ambient seed override when
|
|
30
|
+
* one is present (and valid) for this state's member name, else the authored
|
|
31
|
+
* `initial`. Reads `CurrentSeedOverrides` — empty outside the tooling seam
|
|
32
|
+
* (`Scene.seedScene`), so production wiring always boots from `initial`. An
|
|
33
|
+
* override is decoded against the state's schema; an invalid value silently
|
|
34
|
+
* falls back to `initial` — a half-typed override from the dev tool must never
|
|
35
|
+
* crash a preview.
|
|
36
|
+
*/
|
|
37
|
+
const resolveSeed = (state, initial) => Effect.map(FiberRef.get(CurrentSeedOverrides), (overrides) => state.manifest.name in overrides
|
|
38
|
+
? Option.getOrElse(Schema.decodeUnknownOption(state.manifest.schema)(overrides[state.manifest.name]), () => initial)
|
|
39
|
+
: initial);
|
|
40
|
+
/**
|
|
41
|
+
* Allocate a state's store, seeded with `initial` — `State.live(Feed, seed)`.
|
|
42
|
+
* The seed lives here (implementation), not on the definition, so the same
|
|
43
|
+
* definition can boot from different values in app vs. test wiring.
|
|
44
|
+
*/
|
|
45
|
+
export const live = (state, initial) => Layer.effect(state.store, Effect.zipWith(resolveScheduler, resolveSeed(state, initial), (scheduler, seed) => makeStore(seed, scheduler)));
|
|
46
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/state/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACzE,OAAO,EAAiB,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,SAAS,EAAc,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA0B/C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,IAAO,EACP,MAA6B,EAC7B,UAAwB,EAAE,EACR,EAAE;IACpB,MAAM,UAAU,GAAG,gBAAgB,IAAI,EAAE,CAAA;IACzC,aAAa,CAAC,UAAU,CAAC,CAAA;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAqB,UAAU,CAAC,CAAA;IAChE,MAAM,QAAQ,GAAwB;QACpC,IAAI,EAAE,OAAO;QACb,IAAI;QACJ,MAAM;QACN,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnF,CAAA;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;IAC/C,OAAO,cAAc,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;AAClD,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,GAAG,CAClB,KAAQ,EACR,OAAsB,EACQ,EAAE,CAChC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,CAC3D,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS;IAC9B,CAAC,CAAC,MAAM,CAAC,SAAS,CACd,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EACjF,GAAG,EAAE,CAAC,OAAO,CACd;IACH,CAAC,CAAC,OAAO,CACZ,CAAA;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,KAAQ,EACR,OAAsB,EACa,EAAE,CACrC,KAAK,CAAC,MAAM,CACV,KAAK,CAAC,KAAK,EACX,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAChF,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAC3B,CACF,CAAA"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Context, Effect, Layer, type Schema } from 'effect';
|
|
2
|
+
import { type Manifest } from '../definition/definition';
|
|
3
|
+
import { type Store } from '../internal/store';
|
|
4
|
+
/**
|
|
5
|
+
* A reducer fold returns this to evict the key it folded over, instead of a new
|
|
6
|
+
* value. The loop drops the entry's store from the family, so a normalized
|
|
7
|
+
* collection (chat messages, search hits, transient rows) does not grow without
|
|
8
|
+
* bound — the one fix for the otherwise-unbounded per-key `Map`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const Tombstone: unique symbol;
|
|
11
|
+
export type Tombstone = typeof Tombstone;
|
|
12
|
+
/** Per-key stores, created lazily so a write to one key wakes only its subscribers. */
|
|
13
|
+
export interface FamilyStore<K, V> {
|
|
14
|
+
at(key: K): Store<V>;
|
|
15
|
+
/**
|
|
16
|
+
* Drop a key's store so it stops occupying memory. A live subscriber keeps its
|
|
17
|
+
* own closure over the previous store, so eviction is for keys whose entity is
|
|
18
|
+
* gone (the component is unmounting) — re-`at`-ing the key allocates a fresh,
|
|
19
|
+
* reseeded store.
|
|
20
|
+
*/
|
|
21
|
+
forget(key: K): void;
|
|
22
|
+
/** Drop every key's store — a wholesale reset of the family. */
|
|
23
|
+
clear(): void;
|
|
24
|
+
/** Number of live keys — for tests/diagnostics. */
|
|
25
|
+
size(): number;
|
|
26
|
+
}
|
|
27
|
+
/** Options for a family's keyed store. */
|
|
28
|
+
export interface FamilyOptions {
|
|
29
|
+
/**
|
|
30
|
+
* Drop a key's store automatically once it has no live subscribers (checked on
|
|
31
|
+
* the next microtask, so a same-commit re-subscribe — e.g. a key that just moved
|
|
32
|
+
* position in a list — cancels the eviction). This bounds an otherwise-unbounded
|
|
33
|
+
* family without explicit `Tombstone`s, but it also DISCARDS the key's value —
|
|
34
|
+
* re-`at`-ing a dropped key reseeds from `initial`. Use only for keys whose value
|
|
35
|
+
* is disposable when nothing renders them (search hits, transient rows); for a
|
|
36
|
+
* source-of-truth entity that may be temporarily off-screen (a virtualized list),
|
|
37
|
+
* keep this off and reclaim with an explicit reducer `Tombstone`. Default: off.
|
|
38
|
+
*/
|
|
39
|
+
readonly evictWhenUnused?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface StateFamilyManifest<N extends string, K, V> extends Manifest {
|
|
42
|
+
readonly kind: 'StateFamily';
|
|
43
|
+
readonly name: N;
|
|
44
|
+
readonly key: Schema.Schema<K, any>;
|
|
45
|
+
readonly value: Schema.Schema<V, any>;
|
|
46
|
+
readonly title?: string;
|
|
47
|
+
readonly description?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface StateFamilyClass<out N extends string, in out K, in out V> {
|
|
50
|
+
/** Instance carries the key phantom so `Family['Key']` resolves in `keyOf` types. */
|
|
51
|
+
new (): {
|
|
52
|
+
readonly Key: K;
|
|
53
|
+
};
|
|
54
|
+
readonly manifest: StateFamilyManifest<N, K, V>;
|
|
55
|
+
readonly store: Context.Tag<FamilyStore<K, V>, FamilyStore<K, V>>;
|
|
56
|
+
}
|
|
57
|
+
export type AnyFamily = StateFamilyClass<string, any, any>;
|
|
58
|
+
export type FamilyKey<F> = F extends StateFamilyClass<any, infer K, any> ? K : never;
|
|
59
|
+
export type FamilyValue<F> = F extends StateFamilyClass<any, any, infer V> ? V : never;
|
|
60
|
+
/**
|
|
61
|
+
* Normalized keyed state: one logical State per key, backed by a single family
|
|
62
|
+
* store. Scales with the collection without re-rendering unrelated entries.
|
|
63
|
+
*/
|
|
64
|
+
export declare const make: <const N extends string, K, V>(name: N, key: Schema.Schema<K, any>, value: Schema.Schema<V, any>, options?: {
|
|
65
|
+
readonly title?: string;
|
|
66
|
+
readonly description?: string;
|
|
67
|
+
}) => StateFamilyClass<N, K, V>;
|
|
68
|
+
/**
|
|
69
|
+
* Read one entry by key — `StateFamily.read(ItemUi, id)`. Inside a render it
|
|
70
|
+
* subscribes that key's slice; elsewhere it just snapshots (D5).
|
|
71
|
+
*/
|
|
72
|
+
export declare const read: <N extends string, K, V>(family: StateFamilyClass<N, K, V>, key: K) => Effect.Effect<V, never, FamilyStore<K, V>>;
|
|
73
|
+
/**
|
|
74
|
+
* Allocate a family's keyed store — `StateFamily.live(ItemUi, seed)`. The seed
|
|
75
|
+
* is a plain value or a factory; a factory receives the key, so a new entry can
|
|
76
|
+
* derive its starting value from its own id (`(id) => ({ ...blank, id }))`).
|
|
77
|
+
*/
|
|
78
|
+
export declare const live: <N extends string, K, V>(family: StateFamilyClass<N, K, V>, initial: V | ((key: K) => V), options?: FamilyOptions) => Layer.Layer<FamilyStore<K, V>>;
|
|
79
|
+
//# sourceMappingURL=stateFamily.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateFamily.d.ts","sourceRoot":"","sources":["../../src/state/stateFamily.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from 'effect';
|
|
2
|
+
import { definitionClass } from '../definition/definition';
|
|
3
|
+
import { resolveScheduler } from '../internal/scheduler';
|
|
4
|
+
import { claimStateTag } from '../internal/stateRegistry';
|
|
5
|
+
import { makeStore } from '../internal/store';
|
|
6
|
+
import { readTracked } from '../internal/track';
|
|
7
|
+
/**
|
|
8
|
+
* A reducer fold returns this to evict the key it folded over, instead of a new
|
|
9
|
+
* value. The loop drops the entry's store from the family, so a normalized
|
|
10
|
+
* collection (chat messages, search hits, transient rows) does not grow without
|
|
11
|
+
* bound — the one fix for the otherwise-unbounded per-key `Map`.
|
|
12
|
+
*/
|
|
13
|
+
export const Tombstone = Symbol.for('reform/StateFamily/Tombstone');
|
|
14
|
+
const makeFamilyStore = (seed, scheduler, options = {}) => {
|
|
15
|
+
const entries = new Map();
|
|
16
|
+
const evictWhenUnused = options.evictWhenUnused === true;
|
|
17
|
+
// Live subscriber count per key — maintained only when eviction is on.
|
|
18
|
+
const subscribers = new Map();
|
|
19
|
+
// Wrap a store's `subscribe` to ref-count, evicting the key when it falls idle.
|
|
20
|
+
// `get`/`set`/`getVersion` are delegated unchanged, so the loop writes and the
|
|
21
|
+
// host reads see the same cell; only subscribe/unsubscribe are instrumented.
|
|
22
|
+
const refCounted = (key, store) => ({
|
|
23
|
+
...store,
|
|
24
|
+
subscribe: (listener) => {
|
|
25
|
+
subscribers.set(key, (subscribers.get(key) ?? 0) + 1);
|
|
26
|
+
const off = store.subscribe(listener);
|
|
27
|
+
const released = { done: false };
|
|
28
|
+
return () => {
|
|
29
|
+
if (released.done)
|
|
30
|
+
return;
|
|
31
|
+
released.done = true;
|
|
32
|
+
off();
|
|
33
|
+
const remaining = (subscribers.get(key) ?? 1) - 1;
|
|
34
|
+
if (remaining > 0) {
|
|
35
|
+
subscribers.set(key, remaining);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
subscribers.delete(key);
|
|
39
|
+
queueMicrotask(() => {
|
|
40
|
+
if ((subscribers.get(key) ?? 0) === 0)
|
|
41
|
+
entries.delete(key);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
at: (key) => {
|
|
48
|
+
const existing = entries.get(key);
|
|
49
|
+
if (existing !== undefined)
|
|
50
|
+
return existing;
|
|
51
|
+
const base = makeStore(seed(key), scheduler);
|
|
52
|
+
const created = evictWhenUnused ? refCounted(key, base) : base;
|
|
53
|
+
entries.set(key, created);
|
|
54
|
+
return created;
|
|
55
|
+
},
|
|
56
|
+
forget: (key) => {
|
|
57
|
+
entries.delete(key);
|
|
58
|
+
subscribers.delete(key);
|
|
59
|
+
},
|
|
60
|
+
clear: () => {
|
|
61
|
+
entries.clear();
|
|
62
|
+
subscribers.clear();
|
|
63
|
+
},
|
|
64
|
+
size: () => entries.size,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Normalized keyed state: one logical State per key, backed by a single family
|
|
69
|
+
* store. Scales with the collection without re-rendering unrelated entries.
|
|
70
|
+
*/
|
|
71
|
+
export const make = (name, key, value, options = {}) => {
|
|
72
|
+
const identifier = `reform/family/${name}`;
|
|
73
|
+
claimStateTag(identifier);
|
|
74
|
+
const store = Context.GenericTag(identifier);
|
|
75
|
+
const manifest = {
|
|
76
|
+
kind: 'StateFamily',
|
|
77
|
+
name,
|
|
78
|
+
key,
|
|
79
|
+
value,
|
|
80
|
+
...(options.title !== undefined ? { title: options.title } : {}),
|
|
81
|
+
...(options.description !== undefined ? { description: options.description } : {}),
|
|
82
|
+
};
|
|
83
|
+
return definitionClass({ manifest, store });
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Read one entry by key — `StateFamily.read(ItemUi, id)`. Inside a render it
|
|
87
|
+
* subscribes that key's slice; elsewhere it just snapshots (D5).
|
|
88
|
+
*/
|
|
89
|
+
export const read = (family, key) => Effect.flatMap(family.store, (fs) => readTracked(fs.at(key)));
|
|
90
|
+
/**
|
|
91
|
+
* Allocate a family's keyed store — `StateFamily.live(ItemUi, seed)`. The seed
|
|
92
|
+
* is a plain value or a factory; a factory receives the key, so a new entry can
|
|
93
|
+
* derive its starting value from its own id (`(id) => ({ ...blank, id }))`).
|
|
94
|
+
*/
|
|
95
|
+
export const live = (family, initial, options = {}) => {
|
|
96
|
+
const seed = typeof initial === 'function' ? initial : () => initial;
|
|
97
|
+
return Layer.effect(family.store, Effect.map(resolveScheduler, (scheduler) => makeFamilyStore(seed, scheduler, options)));
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=stateFamily.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateFamily.js","sourceRoot":"","sources":["../../src/state/stateFamily.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Layer } from 'effect';
|
|
2
|
+
import { type StoresOf } from '../internal/sources';
|
|
3
|
+
import { type AnyState, type StateClass, type StateName } from './state';
|
|
4
|
+
import { StateToken } from './token';
|
|
5
|
+
type ValueForName<Members extends ReadonlyArray<AnyState>, N extends string> = Extract<Members[number], StateClass<N, any>> extends StateClass<any, infer A> ? A : never;
|
|
6
|
+
export interface StateGroupClass<Members extends ReadonlyArray<AnyState>> {
|
|
7
|
+
new (): {};
|
|
8
|
+
readonly kind: 'StateGroup';
|
|
9
|
+
readonly members: Members;
|
|
10
|
+
/** Members indexed by name, so `select` is an O(1) lookup instead of a scan. */
|
|
11
|
+
readonly byName: ReadonlyMap<string, AnyState>;
|
|
12
|
+
}
|
|
13
|
+
export type AnyStateGroup = StateGroupClass<ReadonlyArray<AnyState>>;
|
|
14
|
+
/**
|
|
15
|
+
* Compile-time uniqueness guard for `StateGroup.make`. Member names key the tag,
|
|
16
|
+
* the seed record, `byName`, and `select` — duplicates are unaddressable, so a
|
|
17
|
+
* repeated name is replaced (positionally) by this marker tuple, which a real
|
|
18
|
+
* `StateClass` is not assignable to. The offending argument fails to typecheck
|
|
19
|
+
* with the colliding name spelled out in the message, rather than collapsing
|
|
20
|
+
* silently. Runtime `make` throws the same clash for seeds the root tsconfig
|
|
21
|
+
* never typechecks (test files live outside it).
|
|
22
|
+
*/
|
|
23
|
+
type DuplicateStateName<N extends string> = readonly ['reform: duplicate state name in group', N];
|
|
24
|
+
type NoDuplicateNames<Members extends ReadonlyArray<AnyState>, Seen extends string = never> = Members extends readonly [infer Head extends AnyState, ...infer Tail extends ReadonlyArray<AnyState>] ? readonly [
|
|
25
|
+
StateName<Head> extends Seen ? DuplicateStateName<StateName<Head>> : Head,
|
|
26
|
+
...NoDuplicateNames<Tail, Seen | StateName<Head>>
|
|
27
|
+
] : readonly [];
|
|
28
|
+
export type GroupSeeds<G extends AnyStateGroup> = G extends StateGroupClass<infer Members> ? {
|
|
29
|
+
readonly [N in StateName<Members[number]>]: ValueForName<Members, N>;
|
|
30
|
+
} : never;
|
|
31
|
+
/** Compose atomic States into a group provided (and addressed) as a unit. */
|
|
32
|
+
export declare const make: <const Members extends ReadonlyArray<AnyState>>(...members: Members & NoDuplicateNames<Members>) => StateGroupClass<Members>;
|
|
33
|
+
/**
|
|
34
|
+
* Address a member by its tag — `StateGroup.select(TodosStates, 'feed')` —
|
|
35
|
+
* yielding a `StateToken` for reads and calc inputs (still `yield*`-able).
|
|
36
|
+
*
|
|
37
|
+
* Data-first only (not `dual`): the member name's type depends on the group, and
|
|
38
|
+
* a group is not `Pipeable`, so a data-last form would be both more verbose and
|
|
39
|
+
* harder to type than the direct call. Effect reserves `dual` for operators on a
|
|
40
|
+
* `Pipeable` self with an independent value arg (e.g. `ref.pipe(Ref.set(v))`);
|
|
41
|
+
* this is not that shape.
|
|
42
|
+
*/
|
|
43
|
+
export declare const select: <Members extends ReadonlyArray<AnyState>, N extends StateName<Members[number]>>(group: StateGroupClass<Members>, name: N) => StateToken<N, ValueForName<Members, N>>;
|
|
44
|
+
/**
|
|
45
|
+
* Allocate every member's store as one merged layer, each seeded from `seeds`
|
|
46
|
+
* keyed by member name — `StateGroup.live(BoardStates, { board: { _tag: 'Idle' } })`.
|
|
47
|
+
*/
|
|
48
|
+
export declare const live: <Members extends ReadonlyArray<AnyState>>(group: StateGroupClass<Members>, seeds: GroupSeeds<StateGroupClass<Members>>) => Layer.Layer<StoresOf<Members>>;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=stateGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateGroup.d.ts","sourceRoot":"","sources":["../../src/state/stateGroup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAM9B,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,KAAK,QAAQ,EAAqB,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAA;AAC3F,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEpC,KAAK,YAAY,CAAC,OAAO,SAAS,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,MAAM,IACzE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,SAAS,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAE3F,MAAM,WAAW,eAAe,CAAC,OAAO,SAAS,aAAa,CAAC,QAAQ,CAAC;IACtE,QAAQ,EAAE,CAAA;IACV,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CAC/C;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAA;AAEpE;;;;;;;;GAQG;AACH,KAAK,kBAAkB,CAAC,CAAC,SAAS,MAAM,IAAI,SAAS,CAAC,uCAAuC,EAAE,CAAC,CAAC,CAAA;AAEjG,KAAK,gBAAgB,CACnB,OAAO,SAAS,aAAa,CAAC,QAAQ,CAAC,EACvC,IAAI,SAAS,MAAM,GAAG,KAAK,IACzB,OAAO,SAAS,SAAS,CAAC,MAAM,IAAI,SAAS,QAAQ,EAAE,GAAG,MAAM,IAAI,SAAS,aAAa,CAAC,QAAQ,CAAC,CAAC,GACrG,SAAS;IACP,SAAS,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,kBAAkB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI;IACzE,GAAG,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;CAClD,GACD,SAAS,EAAE,CAAA;AAMf,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,aAAa,IAC5C,CAAC,SAAS,eAAe,CAAC,MAAM,OAAO,CAAC,GACpC;IAAE,QAAQ,EAAE,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC;CAAE,GACxE,KAAK,CAAA;AAEX,6EAA6E;AAC7E,eAAO,MAAM,IAAI,GAAI,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,QAAQ,CAAC,EAChE,GAAG,SAAS,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,KAC9C,eAAe,CAAC,OAAO,CAWzB,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,MAAM,GAAI,OAAO,SAAS,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAClG,OAAO,eAAe,CAAC,OAAO,CAAC,EAC/B,MAAM,CAAC,KACN,UAAU,CAAC,CAAC,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAIxC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,GAAI,OAAO,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC1D,OAAO,eAAe,CAAC,OAAO,CAAC,EAC/B,OAAO,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,KAC1C,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAS/B,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Layer } from 'effect';
|
|
2
|
+
import { definitionClass } from '../definition/definition';
|
|
3
|
+
import { DuplicateRegistration, UnknownGroupState } from '../internal/errors';
|
|
4
|
+
// A group's members each carry a `store` tag, so the shared `StoresOf` (used for
|
|
5
|
+
// calc inputs too) distributes them into the union of distinct stores their
|
|
6
|
+
// `live` layer provides — no group-specific mapped type needed.
|
|
7
|
+
import {} from '../internal/sources';
|
|
8
|
+
import { live as stateLive } from './state';
|
|
9
|
+
import { StateToken } from './token';
|
|
10
|
+
/** Compose atomic States into a group provided (and addressed) as a unit. */
|
|
11
|
+
export const make = (...members) => {
|
|
12
|
+
// `byName` already de-dupes, so a smaller map than the member list means two
|
|
13
|
+
// members claimed one name — unaddressable, and a silent footgun on merge.
|
|
14
|
+
const names = members.map((m) => m.manifest.name);
|
|
15
|
+
const duplicate = names.find((name, i) => names.indexOf(name) !== i);
|
|
16
|
+
if (duplicate !== undefined)
|
|
17
|
+
throw new DuplicateRegistration({ kind: 'state in group', name: duplicate });
|
|
18
|
+
return definitionClass({
|
|
19
|
+
kind: 'StateGroup',
|
|
20
|
+
members,
|
|
21
|
+
byName: new Map(members.map((m) => [m.manifest.name, m])),
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Address a member by its tag — `StateGroup.select(TodosStates, 'feed')` —
|
|
26
|
+
* yielding a `StateToken` for reads and calc inputs (still `yield*`-able).
|
|
27
|
+
*
|
|
28
|
+
* Data-first only (not `dual`): the member name's type depends on the group, and
|
|
29
|
+
* a group is not `Pipeable`, so a data-last form would be both more verbose and
|
|
30
|
+
* harder to type than the direct call. Effect reserves `dual` for operators on a
|
|
31
|
+
* `Pipeable` self with an independent value arg (e.g. `ref.pipe(Ref.set(v))`);
|
|
32
|
+
* this is not that shape.
|
|
33
|
+
*/
|
|
34
|
+
export const select = (group, name) => {
|
|
35
|
+
const member = group.byName.get(name);
|
|
36
|
+
if (member === undefined)
|
|
37
|
+
throw new UnknownGroupState({ name });
|
|
38
|
+
return new StateToken(name, member.store);
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Allocate every member's store as one merged layer, each seeded from `seeds`
|
|
42
|
+
* keyed by member name — `StateGroup.live(BoardStates, { board: { _tag: 'Idle' } })`.
|
|
43
|
+
*/
|
|
44
|
+
export const live = (group, seeds) => {
|
|
45
|
+
// Index the typed seed record by the member's runtime name — a genuine
|
|
46
|
+
// reflection boundary (string key into a mapped type). Each member's store
|
|
47
|
+
// layer is then merged; the union of stores is exactly `StoresOf<Members>`,
|
|
48
|
+
// which `reduce`'s single-layer accumulator can't express, so restate it.
|
|
49
|
+
const seedRecord = seeds;
|
|
50
|
+
return group.members
|
|
51
|
+
.map((m) => stateLive(m, seedRecord[m.manifest.name]))
|
|
52
|
+
.reduce((a, b) => Layer.merge(a, b));
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=stateGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateGroup.js","sourceRoot":"","sources":["../../src/state/stateGroup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC7E,iFAAiF;AACjF,4EAA4E;AAC5E,gEAAgE;AAChE,OAAO,EAAiB,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAiB,IAAI,IAAI,SAAS,EAAmC,MAAM,SAAS,CAAA;AAC3F,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AA6CpC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,GAAG,OAA4C,EACrB,EAAE;IAC5B,6EAA6E;IAC7E,2EAA2E;IAC3E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IACpE,IAAI,SAAS,KAAK,SAAS;QAAE,MAAM,IAAI,qBAAqB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IACzG,OAAO,eAAe,CAA2B;QAC/C,IAAI,EAAE,YAAqB;QAC3B,OAAO;QACP,MAAM,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAU,CAAC,CAAC;KACnE,CAAC,CAAA;AACJ,CAAC,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,KAA+B,EAC/B,IAAO,EACkC,EAAE;IAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACrC,IAAI,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/D,OAAO,IAAI,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAA4C,CAAA;AACtF,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,KAA+B,EAC/B,KAA2C,EACX,EAAE;IAClC,uEAAuE;IACvE,2EAA2E;IAC3E,4EAA4E;IAC5E,0EAA0E;IAC1E,MAAM,UAAU,GAAG,KAAgC,CAAA;IACnD,OAAO,KAAK,CAAC,OAAO;SACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;SACrD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAmC,CAAA;AAC1E,CAAC,CAAA"}
|
|
@@ -1,24 +1,16 @@
|
|
|
1
|
-
import { Context, Effect, Effectable } from 'effect'
|
|
2
|
-
import type { Store } from '../internal/store'
|
|
3
|
-
import { readTracked } from '../internal/track'
|
|
4
|
-
|
|
1
|
+
import { Context, Effect, Effectable } from 'effect';
|
|
2
|
+
import type { Store } from '../internal/store';
|
|
5
3
|
/**
|
|
6
4
|
* A reference to one slice of state: yieldable to its current value (`yield*`
|
|
7
5
|
* reads + — under React — subscribes) and carrying the metadata calcs need
|
|
8
6
|
* (its `name` and backing store tag). Returned by `StateGroup.select(group, name)`.
|
|
9
7
|
*/
|
|
10
|
-
export class StateToken<out N extends string, in out A> extends Effectable.Class<A, never, Store<A>> {
|
|
11
|
-
|
|
12
|
-
readonly
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
super()
|
|
16
|
-
}
|
|
17
|
-
commit(): Effect.Effect<A, never, Store<A>> {
|
|
18
|
-
return Effect.flatMap(this.store, readTracked)
|
|
19
|
-
}
|
|
8
|
+
export declare class StateToken<out N extends string, in out A> extends Effectable.Class<A, never, Store<A>> {
|
|
9
|
+
readonly name: N;
|
|
10
|
+
readonly store: Context.Tag<Store<A>, Store<A>>;
|
|
11
|
+
constructor(name: N, store: Context.Tag<Store<A>, Store<A>>);
|
|
12
|
+
commit(): Effect.Effect<A, never, Store<A>>;
|
|
20
13
|
}
|
|
21
|
-
|
|
22
14
|
/**
|
|
23
15
|
* Anything a derived value can read and depend on: a named slice backed by a
|
|
24
16
|
* subscribable store tag. A `StateToken` (group member), a `Calc`, and an
|
|
@@ -29,10 +21,10 @@ export class StateToken<out N extends string, in out A> extends Effectable.Class
|
|
|
29
21
|
* satisfy the same shape so the three are interchangeable as calc inputs.
|
|
30
22
|
*/
|
|
31
23
|
export interface Source<out N extends string, in out A> {
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
readonly name: N;
|
|
25
|
+
readonly store: Context.Tag<Store<A>, Store<A>>;
|
|
34
26
|
}
|
|
35
|
-
|
|
36
|
-
export type
|
|
37
|
-
export type
|
|
38
|
-
|
|
27
|
+
export type AnySource = Source<string, any>;
|
|
28
|
+
export type SourceName<S> = S extends Source<infer N, any> ? N : never;
|
|
29
|
+
export type SourceValue<S> = S extends Source<any, infer A> ? A : never;
|
|
30
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/state/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAG9C;;;;GAIG;AACH,qBAAa,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;gBACnC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAK3D,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;CAG5C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IACpD,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;CAChD;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAC3C,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AACtE,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Context, Effect, Effectable } from 'effect';
|
|
2
|
+
import { readTracked } from '../internal/track';
|
|
3
|
+
/**
|
|
4
|
+
* A reference to one slice of state: yieldable to its current value (`yield*`
|
|
5
|
+
* reads + — under React — subscribes) and carrying the metadata calcs need
|
|
6
|
+
* (its `name` and backing store tag). Returned by `StateGroup.select(group, name)`.
|
|
7
|
+
*/
|
|
8
|
+
export class StateToken extends Effectable.Class {
|
|
9
|
+
name;
|
|
10
|
+
store;
|
|
11
|
+
constructor(name, store) {
|
|
12
|
+
super();
|
|
13
|
+
this.name = name;
|
|
14
|
+
this.store = store;
|
|
15
|
+
}
|
|
16
|
+
commit() {
|
|
17
|
+
return Effect.flatMap(this.store, readTracked);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/state/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C;;;;GAIG;AACH,MAAM,OAAO,UAA2C,SAAQ,UAAU,CAAC,KAAyB;IACzF,IAAI,CAAG;IACP,KAAK,CAAiC;IAC/C,YAAY,IAAO,EAAE,KAAsC;QACzD,KAAK,EAAE,CAAA;QACP,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;IACD,MAAM;QACJ,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;IAChD,CAAC;CACF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Context, Effect, Layer, type Schema, type Scope } from 'effect';
|
|
2
|
+
import { type Manifest } from '../definition/definition';
|
|
3
|
+
import { type Store } from '../internal/store';
|
|
4
|
+
import type { Source } from '../state/token';
|
|
5
|
+
import type { StateOptions } from '../state/state';
|
|
6
|
+
/**
|
|
7
|
+
* The contract an external reactive source implements. `snapshot` must return a
|
|
8
|
+
* stable reference until the value actually changes (the `makeDerivedStore`
|
|
9
|
+
* memoization contract `useSyncExternalStore` requires); `subscribe` returns an
|
|
10
|
+
* unsubscribe thunk, fired on every upstream change.
|
|
11
|
+
*/
|
|
12
|
+
export interface SyncedSource<A> {
|
|
13
|
+
readonly snapshot: () => A;
|
|
14
|
+
readonly subscribe: (onChange: () => void) => () => void;
|
|
15
|
+
}
|
|
16
|
+
export interface SyncedStoreManifest<N extends string, A> extends Manifest {
|
|
17
|
+
readonly kind: 'SyncedStore';
|
|
18
|
+
readonly name: N;
|
|
19
|
+
readonly schema: Schema.Schema<A, any>;
|
|
20
|
+
readonly title?: string;
|
|
21
|
+
readonly description?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface SyncedStoreClass<out N extends string, in out A> extends Effect.Effect<A, never, Store<A>>, Source<N, A> {
|
|
24
|
+
new (): {};
|
|
25
|
+
readonly manifest: SyncedStoreManifest<N, A>;
|
|
26
|
+
/** Internal DI tag holding the live store. `SyncedStore.live` allocates it. */
|
|
27
|
+
readonly store: Context.Tag<Store<A>, Store<A>>;
|
|
28
|
+
/** The name, so the class doubles as a `Source` input to a calc/composition. */
|
|
29
|
+
readonly name: N;
|
|
30
|
+
}
|
|
31
|
+
export type AnySyncedStore = SyncedStoreClass<string, any>;
|
|
32
|
+
export type SyncedValue<S> = S extends SyncedStoreClass<string, infer A> ? A : never;
|
|
33
|
+
/**
|
|
34
|
+
* Define an externally-synced slice: a reflectable manifest + an internal store
|
|
35
|
+
* tag, yieldable to its current value and usable as a calc/composition `Source`.
|
|
36
|
+
* Carries no source — that is supplied at wiring time by `SyncedStore.live`,
|
|
37
|
+
* exactly as `State.make` defers its seed to `State.live`.
|
|
38
|
+
*/
|
|
39
|
+
export declare const make: <const N extends string, A>(name: N, schema: Schema.Schema<A, any>, options?: StateOptions) => SyncedStoreClass<N, A>;
|
|
40
|
+
/**
|
|
41
|
+
* Allocate a synced store's backing cell and bind it to an external source.
|
|
42
|
+
* `acquire` yields the source within the layer's scope (so it can open a live
|
|
43
|
+
* query / subscription whose `R` — e.g. a `Db` driver — is captured here); the
|
|
44
|
+
* store mirrors `snapshot()` and re-notifies on every `subscribe` change through
|
|
45
|
+
* the runtime's coalescing scheduler. The upstream subscription is released with
|
|
46
|
+
* the layer's scope.
|
|
47
|
+
*/
|
|
48
|
+
export declare const live: <A, R>(def: {
|
|
49
|
+
readonly store: Context.Tag<Store<A>, Store<A>>;
|
|
50
|
+
}, acquire: Effect.Effect<SyncedSource<A>, never, R>) => Layer.Layer<Store<A>, never, Exclude<R, Scope.Scope>>;
|
|
51
|
+
//# sourceMappingURL=syncedStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syncedStore.d.ts","sourceRoot":"","sources":["../../src/synced/syncedStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EAAE,KAAK,QAAQ,EAAkB,MAAM,0BAA0B,CAAA;AAExE,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAEhE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAYlD;;;;;GAKG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CACzD;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,CAAE,SAAQ,QAAQ;IACxE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,gBAAgB,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAC9D,SAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EACvC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IACd,QAAQ,EAAE,CAAA;IACV,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC5C,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/C,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAC1D,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAEpF;;;;;GAKG;AACH,eAAO,MAAM,IAAI,GAAI,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAC5C,MAAM,CAAC,EACP,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,EAC7B,UAAS,YAAiB,KACzB,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAWvB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,EAAE,CAAC,EAIvB,KAAK;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;CAAE,EACxD,SAAS,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAChD,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAUpD,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from 'effect';
|
|
2
|
+
import { yieldableClass } from '../definition/definition';
|
|
3
|
+
import { resolveScheduler } from '../internal/scheduler';
|
|
4
|
+
import { makeDerivedStore } from '../internal/store';
|
|
5
|
+
import { readTracked } from '../internal/track';
|
|
6
|
+
/**
|
|
7
|
+
* Define an externally-synced slice: a reflectable manifest + an internal store
|
|
8
|
+
* tag, yieldable to its current value and usable as a calc/composition `Source`.
|
|
9
|
+
* Carries no source — that is supplied at wiring time by `SyncedStore.live`,
|
|
10
|
+
* exactly as `State.make` defers its seed to `State.live`.
|
|
11
|
+
*/
|
|
12
|
+
export const make = (name, schema, options = {}) => {
|
|
13
|
+
const store = Context.GenericTag(`reform/syncedStore/${name}`);
|
|
14
|
+
const manifest = {
|
|
15
|
+
kind: 'SyncedStore',
|
|
16
|
+
name,
|
|
17
|
+
schema,
|
|
18
|
+
...(options.title !== undefined ? { title: options.title } : {}),
|
|
19
|
+
...(options.description !== undefined ? { description: options.description } : {}),
|
|
20
|
+
};
|
|
21
|
+
const read = Effect.flatMap(store, readTracked);
|
|
22
|
+
return yieldableClass(read, { manifest, store, name });
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Allocate a synced store's backing cell and bind it to an external source.
|
|
26
|
+
* `acquire` yields the source within the layer's scope (so it can open a live
|
|
27
|
+
* query / subscription whose `R` — e.g. a `Db` driver — is captured here); the
|
|
28
|
+
* store mirrors `snapshot()` and re-notifies on every `subscribe` change through
|
|
29
|
+
* the runtime's coalescing scheduler. The upstream subscription is released with
|
|
30
|
+
* the layer's scope.
|
|
31
|
+
*/
|
|
32
|
+
export const live = (
|
|
33
|
+
// A minimal store-carrier — satisfied by a `SyncedStoreClass` and by any
|
|
34
|
+
// companion primitive (e.g. `@playfast/reform-db`'s `DbQuery`) that allocates
|
|
35
|
+
// its own `Store` tag, so the seam is reusable beyond `SyncedStore` itself.
|
|
36
|
+
def, acquire) => Layer.scoped(def.store, Effect.gen(function* () {
|
|
37
|
+
const scheduler = yield* resolveScheduler;
|
|
38
|
+
const source = yield* acquire;
|
|
39
|
+
const { store, unsubscribe } = makeDerivedStore(source.snapshot, source.subscribe, scheduler);
|
|
40
|
+
yield* Effect.addFinalizer(() => Effect.sync(unsubscribe));
|
|
41
|
+
return store;
|
|
42
|
+
}));
|
|
43
|
+
//# sourceMappingURL=syncedStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syncedStore.js","sourceRoot":"","sources":["../../src/synced/syncedStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAA2B,MAAM,QAAQ,CAAA;AACxE,OAAO,EAAiB,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAc,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA+C/C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,IAAO,EACP,MAA6B,EAC7B,UAAwB,EAAE,EACF,EAAE;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAqB,sBAAsB,IAAI,EAAE,CAAC,CAAA;IAClF,MAAM,QAAQ,GAA8B;QAC1C,IAAI,EAAE,aAAa;QACnB,IAAI;QACJ,MAAM;QACN,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnF,CAAA;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;IAC/C,OAAO,cAAc,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AACxD,CAAC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;AAClB,yEAAyE;AACzE,8EAA8E;AAC9E,4EAA4E;AAC5E,GAAwD,EACxD,OAAiD,EACM,EAAE,CACzD,KAAK,CAAC,MAAM,CACV,GAAG,CAAC,KAAK,EACT,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,gBAAgB,CAAA;IACzC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,CAAA;IAC7B,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;IAC7F,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAA;IAC1D,OAAO,KAAK,CAAA;AACd,CAAC,CAAC,CACH,CAAA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { ReactNode } from 'react'
|
|
2
|
-
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
3
2
|
/**
|
|
4
3
|
* What a view renders. Reform targets React, so a node is a `ReactNode` — this
|
|
5
4
|
* is a *type-only* dependency: core never imports the React runtime nor renders
|
|
6
5
|
* anything itself (that is `@reform/react`). Typing it precisely lets the `.ui`
|
|
7
6
|
* presentations author real JSX and lets slots be valid components.
|
|
8
7
|
*/
|
|
9
|
-
export type Node = ReactNode
|
|
8
|
+
export type Node = ReactNode;
|
|
9
|
+
//# sourceMappingURL=node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/ui/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC;;;;;GAKG;AACH,MAAM,MAAM,IAAI,GAAG,SAAS,CAAA"}
|
package/dist/ui/node.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/ui/node.ts"],"names":[],"mappings":""}
|