@playfast/reform 1.1.1 → 1.2.1

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.
Files changed (106) hide show
  1. package/README.md +85 -55
  2. package/package.json +17 -17
  3. package/src/boundary/boundary.test.ts +82 -33
  4. package/src/boundary/boundary.ts +141 -32
  5. package/src/calc/asyncCalc.invalidate.test.ts +733 -32
  6. package/src/calc/asyncCalc.test.ts +397 -225
  7. package/src/calc/asyncCalc.ts +115 -100
  8. package/src/calc/asyncCalcTypes.ts +147 -0
  9. package/src/calc/calc.test.ts +13 -16
  10. package/src/calc/calc.ts +44 -18
  11. package/src/calc/calcFamily.test.ts +90 -32
  12. package/src/calc/calcFamily.ts +56 -25
  13. package/src/calc/compose.ts +1 -14
  14. package/src/channel/channel.ts +25 -6
  15. package/src/channel/{procedureRegistry.ts → procedures.ts} +41 -23
  16. package/src/compose/composition.test.ts +19 -0
  17. package/src/compose/composition.ts +168 -81
  18. package/src/compose/compositionTypes.ts +249 -0
  19. package/src/compose/props.ts +13 -6
  20. package/src/compose/provide.ts +187 -46
  21. package/src/compose/slot.ts +156 -19
  22. package/src/compose/structure.test.ts +6 -3
  23. package/src/compose/structure.ts +106 -13
  24. package/src/compose/ui.test.ts +19 -3
  25. package/src/compose/ui.ts +147 -54
  26. package/src/compose/ui.typecheck.ts +40 -4
  27. package/src/definition/definition.ts +22 -9
  28. package/src/event/event.fromSource.test.ts +172 -0
  29. package/src/event/event.test.ts +10 -0
  30. package/src/event/event.ts +102 -18
  31. package/src/feature/feature.mount.test.ts +123 -56
  32. package/src/feature/feature.test.ts +67 -63
  33. package/src/feature/feature.ts +222 -262
  34. package/src/feature/feature.typecheck.ts +224 -91
  35. package/src/feature/featureBinding.ts +130 -20
  36. package/src/feature/featureClass.ts +162 -0
  37. package/src/feature/featureConfig.ts +192 -0
  38. package/src/feature/featureFactory.ts +163 -0
  39. package/src/feature/featureModule.ts +136 -0
  40. package/src/feature/featureModule.typecheck.ts +63 -0
  41. package/src/feature/featureNativeTree.ts +152 -0
  42. package/src/feature/featureRequirement.ts +82 -0
  43. package/src/feature/featureVariants.ts +234 -0
  44. package/src/feature/mountFeature.ts +54 -0
  45. package/src/graph/closure.ts +222 -0
  46. package/src/graph/services.ts +95 -0
  47. package/src/graph/summary.ts +134 -0
  48. package/src/index.ts +171 -245
  49. package/src/internal/bucketCache.ts +39 -0
  50. package/src/internal/capture.ts +9 -4
  51. package/src/internal/env.ts +1 -3
  52. package/src/internal/errors.ts +21 -10
  53. package/src/internal/queryDriver.ts +61 -25
  54. package/src/internal/queryDriverHydrate.ts +45 -0
  55. package/src/internal/queryDriverStore.ts +8 -5
  56. package/src/internal/queryDriverTypes.ts +11 -11
  57. package/src/internal/reuse.test.ts +10 -3
  58. package/src/internal/reuse.ts +5 -2
  59. package/src/internal/scheduler.ts +4 -1
  60. package/src/internal/sources.ts +25 -11
  61. package/src/internal/store.test.ts +27 -6
  62. package/src/internal/track.ts +3 -2
  63. package/src/internal.ts +222 -0
  64. package/src/namespace/namespace.ts +46 -25
  65. package/src/procedure/procedure.ts +38 -11
  66. package/src/reducer/reducer.ts +78 -34
  67. package/src/remote/pendingQueue.ts +145 -0
  68. package/src/remote/remoteState.test.ts +536 -354
  69. package/src/remote/remoteState.ts +145 -106
  70. package/src/remote/remoteState.typecheck.ts +47 -23
  71. package/src/remote/remoteStateMake.ts +97 -0
  72. package/src/remote/remoteStateSend.ts +95 -37
  73. package/src/remote/remoteStateTypes.ts +155 -0
  74. package/src/runtime/appRuntime.activation.test.ts +104 -0
  75. package/src/runtime/appRuntime.test.ts +187 -111
  76. package/src/runtime/appRuntime.ts +36 -130
  77. package/src/runtime/capturedAppRuntime.ts +274 -0
  78. package/src/runtime/eventBudget.test.ts +39 -12
  79. package/src/runtime/eventBudget.ts +9 -8
  80. package/src/runtime/featureMount.ts +94 -0
  81. package/src/runtime/hardening.test.ts +22 -13
  82. package/src/runtime/instrumentation.test.ts +213 -194
  83. package/src/runtime/instrumentation.ts +6 -11
  84. package/src/runtime/loop.test.ts +84 -7
  85. package/src/runtime/loop.ts +69 -40
  86. package/src/runtime/runtimeHandle.ts +124 -0
  87. package/src/scene/featureScene.test.ts +4 -2
  88. package/src/scene/scene.ts +234 -64
  89. package/src/scene/seedScene.test.ts +69 -86
  90. package/src/state/state.nominal.typecheck.ts +68 -0
  91. package/src/state/state.test.ts +17 -0
  92. package/src/state/state.ts +79 -26
  93. package/src/state/stateFamily.test.ts +39 -8
  94. package/src/state/stateFamily.ts +55 -22
  95. package/src/state/stateGroup.ts +53 -17
  96. package/src/state/token.ts +40 -10
  97. package/src/synced/syncedStore.ts +46 -23
  98. package/src/testkit/flight.testkit.ts +84 -0
  99. package/src/wire/tree.test.ts +8 -4
  100. package/src/wire/triggers.test.ts +6 -2
  101. package/src/wire/triggers.ts +14 -10
  102. package/src/calc/asyncCalcDefinitions.ts +0 -48
  103. package/src/internal/ctx.ts +0 -9
  104. package/src/remote/remoteStateDefinition.ts +0 -135
  105. package/src/remote/remoteStateLayers.ts +0 -118
  106. package/src/remote/remoteStateLiveTypes.ts +0 -59
@@ -0,0 +1,134 @@
1
+ import type { UiContract } from '../compose/ui'
2
+
3
+ export const FeatureGraphValidTypeId: unique symbol = Symbol.for('reform/FeatureGraphValid')
4
+ export type FeatureGraphValidTypeId = typeof FeatureGraphValidTypeId
5
+
6
+ export const FeatureModuleGraphValidTypeId: unique symbol = Symbol.for(
7
+ 'reform/FeatureModuleGraphValid',
8
+ )
9
+ export type FeatureModuleGraphValidTypeId = typeof FeatureModuleGraphValidTypeId
10
+
11
+ export const FeatureChildSummaryTypeId: unique symbol = Symbol.for('reform/FeatureChildSummary')
12
+ export type FeatureChildSummaryTypeId = typeof FeatureChildSummaryTypeId
13
+
14
+ export const FeatureGraphSummaryTypeId: unique symbol = Symbol.for('reform/FeatureGraphSummary')
15
+ export type FeatureGraphSummaryTypeId = typeof FeatureGraphSummaryTypeId
16
+
17
+ export const SlotBindingSummaryTypeId: unique symbol = Symbol.for('reform/SlotBindingSummary')
18
+ export type SlotBindingSummaryTypeId = typeof SlotBindingSummaryTypeId
19
+
20
+ export interface SlotBindingSummary {
21
+ readonly [SlotBindingSummaryTypeId]: SlotBindingSummaryTypeId
22
+ }
23
+
24
+ /**
25
+ * The constant-size proof published after a Feature's current module has passed
26
+ * graph validation. Type-only facts use empty-or-singleton tuples so the runtime
27
+ * summary stays compact while direct indexed access recovers their exact types.
28
+ */
29
+ export interface FeatureGraphSummary<
30
+ out FeatureIdentity,
31
+ out MountProps,
32
+ out CompositionProps,
33
+ out C extends UiContract,
34
+ out S extends ReadonlyArray<unknown>,
35
+ out N extends string,
36
+ out CompositionIdentity,
37
+ out OpenServices,
38
+ out SupportOpenServices,
39
+ out UsesInput extends boolean,
40
+ out Input,
41
+ > extends SlotBindingSummary {
42
+ readonly [FeatureGraphSummaryTypeId]: {
43
+ readonly featureIdentity: readonly [] | readonly [FeatureIdentity]
44
+ readonly mountProps: readonly [] | readonly [MountProps]
45
+ readonly compositionProps: readonly [] | readonly [CompositionProps]
46
+ readonly contract: readonly [] | readonly [C]
47
+ readonly states: readonly [] | readonly [S]
48
+ readonly name: N
49
+ readonly compositionIdentity: readonly [] | readonly [CompositionIdentity]
50
+ readonly openServices: readonly [] | readonly [OpenServices]
51
+ readonly supportOpenServices: readonly [] | readonly [SupportOpenServices]
52
+ readonly usesInput: readonly [] | readonly [UsesInput]
53
+ readonly input: readonly [] | readonly [Input]
54
+ readonly validated: FeatureModuleGraphValidTypeId
55
+ }
56
+ readonly [FeatureChildSummaryTypeId]: {
57
+ readonly featureIdentity: readonly [] | readonly [FeatureIdentity]
58
+ readonly compositionIdentity: readonly [] | readonly [CompositionIdentity]
59
+ }
60
+ }
61
+
62
+ export type FeatureChildSummary<
63
+ FeatureIdentity,
64
+ MountProps,
65
+ CompositionProps,
66
+ C extends UiContract,
67
+ S extends ReadonlyArray<unknown>,
68
+ N extends string,
69
+ CompositionIdentity,
70
+ OpenServices,
71
+ SupportOpenServices,
72
+ UsesInput extends boolean,
73
+ Input,
74
+ > = FeatureGraphSummary<
75
+ FeatureIdentity,
76
+ MountProps,
77
+ CompositionProps,
78
+ C,
79
+ S,
80
+ N,
81
+ CompositionIdentity,
82
+ OpenServices,
83
+ SupportOpenServices,
84
+ UsesInput,
85
+ Input
86
+ >
87
+
88
+ export type AnyFeatureGraphSummary = FeatureGraphSummary<
89
+ unknown,
90
+ unknown,
91
+ unknown,
92
+ UiContract,
93
+ ReadonlyArray<unknown>,
94
+ string,
95
+ unknown,
96
+ unknown,
97
+ unknown,
98
+ boolean,
99
+ unknown
100
+ >
101
+
102
+ export type FeatureSummaryIdentity<Summary extends AnyFeatureGraphSummary> =
103
+ Summary[FeatureGraphSummaryTypeId]['featureIdentity'][number]
104
+ export type FeatureSummaryMountProps<Summary extends AnyFeatureGraphSummary> =
105
+ Summary[FeatureGraphSummaryTypeId]['mountProps'][number]
106
+ export type FeatureSummaryCompositionProps<Summary extends AnyFeatureGraphSummary> =
107
+ Summary[FeatureGraphSummaryTypeId]['compositionProps'][number]
108
+ export type FeatureSummaryContract<Summary extends AnyFeatureGraphSummary> =
109
+ Summary[FeatureGraphSummaryTypeId]['contract'][number]
110
+ export type FeatureSummaryStates<Summary extends AnyFeatureGraphSummary> =
111
+ Summary[FeatureGraphSummaryTypeId]['states'][number]
112
+ export type FeatureSummaryName<Summary extends AnyFeatureGraphSummary> =
113
+ Summary[FeatureGraphSummaryTypeId]['name']
114
+ export type FeatureSummaryCompositionIdentity<Summary extends AnyFeatureGraphSummary> =
115
+ Summary[FeatureGraphSummaryTypeId]['compositionIdentity'][number]
116
+ export type FeatureSummaryOpenServices<Summary extends AnyFeatureGraphSummary> =
117
+ Summary[FeatureGraphSummaryTypeId]['openServices'][number]
118
+ export type FeatureSummarySupportOpenServices<Summary extends AnyFeatureGraphSummary> =
119
+ Summary[FeatureGraphSummaryTypeId]['supportOpenServices'][number]
120
+ export type FeatureSummaryUsesInput<Summary extends AnyFeatureGraphSummary> =
121
+ Summary[FeatureGraphSummaryTypeId]['usesInput'][number]
122
+ export type FeatureSummaryInput<Summary extends AnyFeatureGraphSummary> =
123
+ Summary[FeatureGraphSummaryTypeId]['input'][number]
124
+
125
+ export const CompositionChildSummaryTypeId: unique symbol = Symbol.for(
126
+ 'reform/CompositionChildSummary',
127
+ )
128
+ export type CompositionChildSummaryTypeId = typeof CompositionChildSummaryTypeId
129
+
130
+ export interface CompositionChildSummary<out CompositionIdentity> extends SlotBindingSummary {
131
+ readonly [CompositionChildSummaryTypeId]: {
132
+ readonly compositionIdentity: CompositionIdentity
133
+ }
134
+ }
package/src/index.ts CHANGED
@@ -1,255 +1,181 @@
1
- export * as State from "./state/state";
2
- export * as StateGroup from "./state/stateGroup";
3
- export * as StateFamily from "./state/stateFamily";
4
- export { StateToken } from "./state/token";
5
- export type { AnySource, Source } from "./state/token";
6
-
7
- export * as Event from "./event/event";
8
- // TS2742: plain type export so declaration emit can name EventOf
9
- export type { EventOf } from "./event/event";
10
- export * as EventGroup from "./event/eventGroup";
1
+ export * as State from './state/state'
2
+ export type { StateClass, StateStore, StateValue } from './state/state'
3
+ export * as StateGroup from './state/stateGroup'
4
+ export type { SeedsOf } from './state/stateGroup'
5
+ export * as StateFamily from './state/stateFamily'
6
+ export type {
7
+ FamilyKey,
8
+ FamilyValue,
9
+ StateFamilyClass,
10
+ StateFamilyStore,
11
+ } from './state/stateFamily'
11
12
 
12
- export * as Reducer from "./reducer/reducer";
13
- export * as Calc from "./calc/calc";
14
- export * as CalcFamily from "./calc/calcFamily";
15
- export * as AsyncCalc from "./calc/asyncCalc";
16
- export { composeCalcs } from "./calc/compose";
13
+ export * as Event from './event/event'
14
+ // TS2742: direct type exports allow declaration emit to name event-derived types.
17
15
  export type {
18
- InputsObject,
19
- InputStores,
20
- InvalidateBy,
21
- } from "./internal/sources";
22
- export {
23
- AsyncData,
24
- type AsyncError,
25
- type AsyncIdle,
26
- type AsyncLoading,
27
- type AsyncSuccess,
28
- } from "./calc/asyncData";
29
- export { isLoading, type QueryState, toAsyncData } from "./calc/queryState";
30
- export {
31
- noopQueryStore,
32
- QueryStore,
33
- type QueryStoreApi,
34
- resolveQueryStore,
35
- } from "./internal/queryStore";
36
- export {
37
- noopQueryEvents,
38
- QueryEvents,
39
- type QueryEventsApi,
40
- resolveQueryEvents,
41
- } from "./internal/queryEvents";
42
- export * as RemoteState from "./remote/remoteState";
43
- // TS2742: plain type exports so declaration emit can name pending/failed types
16
+ EventClass,
17
+ EventOf,
18
+ EventPayload,
19
+ SourceChange,
20
+ SourceEventConfig,
21
+ SourceEventConfigExternalApi,
22
+ } from './event/event'
23
+ export * as EventGroup from './event/eventGroup'
24
+
25
+ export * as Reducer from './reducer/reducer'
26
+ export * as Calc from './calc/calc'
27
+ export type { CalcClass, CalcStore } from './calc/calc'
28
+ export * as CalcFamily from './calc/calcFamily'
29
+ export type { CalcFamilyClass, CalcFamilyStore } from './calc/calcFamily'
30
+ export * as AsyncCalc from './calc/asyncCalc'
31
+ export type { AsyncCalcClass, AsyncCalcStore } from './calc/asyncCalc'
32
+ export { composeCalcs } from './calc/compose'
33
+ export type { InputsObject, InputStores, InvalidateBy } from './internal/sources'
34
+ export {
35
+ AsyncData,
36
+ type AsyncError,
37
+ type AsyncIdle,
38
+ type AsyncLoading,
39
+ type AsyncSuccess,
40
+ } from './calc/asyncData'
41
+ export { isLoading, type QueryState, toAsyncData } from './calc/queryState'
42
+
43
+ export * as RemoteState from './remote/remoteState'
44
+ // TS2742: direct exports keep pending and failed state types nameable.
44
45
  export type {
45
- FailedIntent,
46
- PendingIntent,
47
- RemoteStateClass,
48
- RemoteStateSettled,
49
- } from "./remote/remoteState";
50
- export * as SyncedStore from "./synced/syncedStore";
51
- // TS2742: plain type export for SyncedSource nameability
52
- export type { SyncedSource, SyncedStoreClass } from "./synced/syncedStore";
53
- export * as Boundary from "./boundary/boundary";
54
- // TS2742: plain type exports for Boundary* nameability
46
+ FailedIntent,
47
+ PendingIntent,
48
+ RemoteStateClass,
49
+ RemoteStatePendingStore,
50
+ RemoteStateSettled,
51
+ RemoteStateTruthStore,
52
+ RemoteStateVisibleStore,
53
+ } from './remote/remoteState'
54
+ export * as SyncedStore from './synced/syncedStore'
55
+ // TS2742: adapters need a directly nameable synchronized source type.
56
+ export type { SyncedSource, SyncedStoreClass, SyncedStoreIdentifier } from './synced/syncedStore'
57
+ export * as Boundary from './boundary/boundary'
58
+ // TS2742: direct exports keep boundary state types nameable.
55
59
  export type {
56
- BoundaryErrored,
57
- BoundaryPending,
58
- BoundaryReady,
59
- BoundaryState,
60
- } from "./boundary/boundary";
61
- export * as Procedure from "./procedure/procedure";
62
- export * as Channel from "./channel/channel";
63
- export * as Namespace from "./namespace/namespace";
64
- export type { FeatureNamespace } from "./namespace/namespace";
60
+ BoundaryErrored,
61
+ BoundaryPending,
62
+ BoundaryReady,
63
+ BoundaryState,
64
+ BoundaryStore,
65
+ } from './boundary/boundary'
65
66
 
66
- export * as Composition from "./compose/composition";
67
- export type {
68
- CompositionClass,
69
- CompositionService,
70
- Frame,
71
- RenderEnv,
72
- } from "./compose/composition";
73
- export {
74
- absent,
75
- each,
76
- type EachFill,
77
- isStructure,
78
- mount,
79
- one,
80
- type OneFill,
81
- type AbsentFill,
82
- type SlotFill,
83
- type Structure,
84
- structureEquals,
85
- type StructureSlots,
86
- StructureTypeId,
87
- when,
88
- } from "./compose/structure";
89
- export { Props } from "./compose/props";
90
- export {
91
- isSlot,
92
- type Node,
93
- slot,
94
- type SlotClass,
95
- type SlotInstance,
96
- type SlotProps,
97
- SlotTypeId,
98
- } from "./compose/slot";
99
- export { type SlotRenderer } from "./compose/host";
100
- export * as Ui from "./compose/ui";
101
- export {
102
- type DerivedContract,
103
- isUi,
104
- type MadeView,
105
- ui,
106
- type UiClass,
107
- type UiContract,
108
- type UiManifest,
109
- UiTypeId,
110
- UiViewContract,
111
- type ViewImpl,
112
- type WireSchemas,
113
- type WiredUi,
114
- type WiredUiManifest,
115
- } from "./compose/ui";
116
- export { provide } from "./compose/provide";
117
- export type { Trigger } from "./ui/trigger";
67
+ export * as Procedure from './procedure/procedure'
68
+ export type { ProcedureClass, ProcedureConfig } from './procedure/procedure'
69
+ export * as Channel from './channel/channel'
70
+ export type { ChannelClass, ChannelPolicy } from './channel/channel'
71
+ export * as Namespace from './namespace/namespace'
72
+ export type { FeatureNamespace } from './namespace/namespace'
118
73
 
119
- export * as Wire from "./wire/tree";
120
- export type { WireNode, WirePatch, WireProp, WireTree } from "./wire/tree";
74
+ export * as Composition from './compose/composition'
75
+ export { liveScoped } from './compose/composition'
76
+ export type {
77
+ CompositionActivation,
78
+ CompositionClass,
79
+ CompositionId,
80
+ CompositionService,
81
+ Frame,
82
+ RenderEnv,
83
+ ScopedCompositionLiveConfig,
84
+ } from './compose/composition'
85
+ export {
86
+ absent,
87
+ type AbsentFill,
88
+ each,
89
+ type EachFill,
90
+ isStructure,
91
+ mount,
92
+ one,
93
+ type OneFill,
94
+ type SlotFill,
95
+ type Structure,
96
+ structureEquals,
97
+ type StructureSlots,
98
+ when,
99
+ } from './compose/structure'
100
+ export { Props } from './compose/props'
101
+ export {
102
+ type CompositionOfSlotTarget,
103
+ type ContractOfSlotTarget,
104
+ type FeatureSlotTarget,
105
+ isSlot,
106
+ type Node,
107
+ type PropsOfSlotTarget,
108
+ slot,
109
+ type SlotClass,
110
+ type SlotComposition,
111
+ type SlotContract,
112
+ type SlotInstance,
113
+ type SlotProps,
114
+ type SlotService,
115
+ type SlotTarget,
116
+ type TargetOfSlot,
117
+ } from './compose/slot'
118
+ export * as Ui from './compose/ui'
119
+ export {
120
+ type CallableView,
121
+ type DerivedContract,
122
+ isUi,
123
+ type MadeView,
124
+ ui,
125
+ type UiClass,
126
+ type UiContract,
127
+ type UiService,
128
+ UiViewContract,
129
+ type ViewImpl,
130
+ } from './compose/ui'
131
+ export { provide, provideExisting, provideMergeExact } from './compose/provide'
132
+ export type { Trigger } from './ui/trigger'
121
133
 
122
- export * as Triggers from "./wire/triggers";
123
- export {
124
- TriggerRegistry,
125
- type TriggerHandle,
126
- type TriggerRegistryApi,
127
- UnknownTrigger,
128
- } from "./wire/triggers";
134
+ export * as Feature from './feature/feature'
135
+ export {
136
+ type EagerFeatureClass,
137
+ type FailedProps,
138
+ type FeatureClass,
139
+ featureModule,
140
+ type FeatureModule,
141
+ type FeatureModuleInput,
142
+ isFeature,
143
+ isFeatureBinding,
144
+ lazyImport,
145
+ type LazyFeatureClass,
146
+ type Placeholders,
147
+ } from './feature/feature'
129
148
 
130
- export * as Feature from "./feature/feature";
131
149
  export {
132
- type EngineServices,
133
- type FailedProps,
134
- type FeatureBinding,
135
- FeatureBindingTypeId,
136
- type FeatureClass,
137
- type FeatureRequirement,
138
- type FeatureManifest,
139
- featureModule,
140
- featureModuleFromInput,
141
- FeatureInput,
142
- type FeatureModule,
143
- type EagerFeatureClass,
144
- isFeature,
145
- isFeatureBinding,
146
- lazyImport,
147
- type LazyFeatureClass,
148
- type LoadedModule,
149
- mountFeature,
150
- type Placeholders,
151
- type ProvidedBy,
152
- type RequireCarrier,
153
- } from "./feature/feature";
154
- export { type SlotChild } from "./compose/slot";
150
+ type CapturedScene,
151
+ featureScene,
152
+ type FeatureSceneConfig,
153
+ isScene,
154
+ type MountedServices,
155
+ profiledScene,
156
+ type Scene,
157
+ scene,
158
+ sceneInstrumentation,
159
+ seedScene,
160
+ } from './scene/scene'
155
161
 
156
- export {
157
- isScene,
158
- type MountedServices,
159
- profiledScene,
160
- type Scene,
161
- type FeatureSceneConfig,
162
- featureScene,
163
- scene,
164
- sceneInstrumentation,
165
- seedScene,
166
- } from "./scene/scene";
167
- export type { SeedsOf } from "./state/stateGroup";
168
-
169
- export {
170
- Bus,
171
- busLayer,
172
- type Envelope,
173
- type Priority,
174
- publish,
175
- type Tagged,
176
- } from "./runtime/bus";
177
- export {
178
- type AppRuntime,
179
- type FeatureMountHandlers,
180
- makeAppRuntime,
181
- type RuntimeHandle,
182
- } from "./runtime/appRuntime";
183
- export {
184
- Engine,
185
- type ReducerEntry,
186
- Reducers,
187
- reducersLayer,
188
- } from "./runtime/loop";
189
- export {
190
- CurrentEventBudget,
191
- defaultEventBudget,
192
- type EventBudget,
193
- type ReformOptions,
194
- resolveEventBudget,
195
- } from "./runtime/eventBudget";
196
- export {
197
- CurrentInstrumentation,
198
- type Instrumentation,
199
- noopInstrumentation,
200
- resolveInstrumentation,
201
- type SpanEnd,
202
- } from "./runtime/instrumentation";
203
- export {
204
- Queries,
205
- queriesLayer,
206
- type QueryHandle,
207
- type QueryRegistry,
208
- } from "./runtime/queries";
209
- export {
210
- type ChannelClass,
211
- type ChannelPolicy,
212
- type ChannelRuntime,
213
- Channels,
214
- channelsLayer,
215
- type ProcedureEntry,
216
- Procedures,
217
- proceduresLayer,
218
- } from "./channel/channel";
219
- export {
220
- CurrentTracker,
221
- type Subscribable,
222
- type Tracker,
223
- } from "./internal/track";
224
- export {
225
- CaptureSink,
226
- type CaptureSinkApi,
227
- type UiCapture,
228
- } from "./internal/capture";
229
- export {
230
- AsyncReducer,
231
- AsyncSceneLayer,
232
- DuplicateRegistration,
233
- EventLoopOverflow,
234
- FeatureLoadFailed,
235
- forceSync,
236
- InvalidProvideTarget,
237
- UnknownGroupState,
238
- } from "./internal/errors";
239
- export {
240
- defaultScheduler,
241
- makeScheduler,
242
- Notifications,
243
- notificationsLayer,
244
- resolveScheduler,
245
- type Scheduler,
246
- } from "./internal/scheduler";
247
- export { makeStore, type Store } from "./internal/store";
248
- export type { FamilyStore } from "./state/stateFamily";
249
- export {
250
- type Kind,
251
- type Manifest,
252
- yieldableClass,
253
- } from "./definition/definition";
254
- export { readTracked } from "./internal/track";
255
- export { sameKey, wireSources, type WiredSources } from "./internal/sources";
162
+ export { type Priority, publish } from './runtime/bus'
163
+ export {
164
+ type AppRuntime,
165
+ type FeatureMountHandlers,
166
+ makeAppRuntime,
167
+ type RuntimeFeatureAvailability,
168
+ type RuntimeHandle,
169
+ } from './runtime/appRuntime'
170
+ export { Engine } from './runtime/loop'
171
+ export type { EventBudget, ReformOptions } from './runtime/eventBudget'
172
+ export {
173
+ AsyncReducer,
174
+ AsyncSceneLayer,
175
+ DuplicateRegistration,
176
+ EventLoopOverflow,
177
+ FeatureLoadFailed,
178
+ forceSync,
179
+ InvalidProvideTarget,
180
+ UnknownGroupState,
181
+ } from './internal/errors'
@@ -0,0 +1,39 @@
1
+ import { Option } from 'effect'
2
+
3
+ /**
4
+ * A read-through snapshot cache over a tag-indexed `Map<string, Set<T>>`.
5
+ *
6
+ * The registries keep mutable `Set` buckets so register/unregister stay O(1),
7
+ * but the dispatch loop must iterate a *snapshot*: an entry registered while a
8
+ * frame is folding must not join the fold already in flight (`Set` iteration is
9
+ * live, an array copy is not). Copying per event would pay that snapshot on
10
+ * every dispatch, so the copy is cached and dropped only when the bucket
11
+ * actually changes — registration is rare, dispatch is not.
12
+ *
13
+ * A tag with no bucket returns a shared empty array and is never cached, so
14
+ * events nothing handles allocate nothing and cannot grow the cache.
15
+ */
16
+ export interface BucketCache<T> {
17
+ readonly read: (tag: string) => ReadonlyArray<T>
18
+ readonly invalidate: (tag: string) => void
19
+ }
20
+
21
+ export const makeBucketCache = <T>(source: Map<string, Set<T>>): BucketCache<T> => {
22
+ const empty: ReadonlyArray<T> = []
23
+ const cache = new Map<string, ReadonlyArray<T>>()
24
+ const build = (tag: string): ReadonlyArray<T> =>
25
+ Option.match(Option.fromNullable(source.get(tag)), {
26
+ onNone: (): ReadonlyArray<T> => empty,
27
+ onSome: (bucket) => {
28
+ const current: ReadonlyArray<T> = Array.from(bucket)
29
+ cache.set(tag, current)
30
+ return current
31
+ },
32
+ })
33
+ return {
34
+ read: (tag) => Option.getOrElse(Option.fromNullable(cache.get(tag)), () => build(tag)),
35
+ invalidate: (tag) => {
36
+ cache.delete(tag)
37
+ },
38
+ }
39
+ }
@@ -1,7 +1,7 @@
1
1
  import { Context } from 'effect'
2
2
  import type { Trigger } from '../ui/trigger'
3
3
 
4
- export interface UiCapture {
4
+ export interface CapturedRender {
5
5
  readonly name: string
6
6
  readonly props: unknown
7
7
  readonly events: Record<string, Trigger<unknown>>
@@ -9,11 +9,16 @@ export interface UiCapture {
9
9
  readonly key?: string
10
10
  }
11
11
 
12
+ export type UiCapture = CapturedRender
13
+
12
14
  export interface CaptureSinkApi {
13
- record(capture: UiCapture): void
15
+ record(capture: CapturedRender): void
14
16
  }
15
17
 
16
- const CaptureSinkBase: Context.TagClass<CaptureSink, 'reform/internal/CaptureSink', CaptureSinkApi> =
17
- Context.Tag('reform/internal/CaptureSink')<CaptureSink, CaptureSinkApi>()
18
+ const CaptureSinkBase: Context.TagClass<
19
+ CaptureSink,
20
+ 'reform/internal/CaptureSink',
21
+ CaptureSinkApi
22
+ > = Context.Tag('reform/internal/CaptureSink')<CaptureSink, CaptureSinkApi>()
18
23
 
19
24
  export class CaptureSink extends CaptureSinkBase {}
@@ -1,6 +1,4 @@
1
- declare const process:
2
- | { readonly env: { readonly NODE_ENV: string | undefined } }
3
- | undefined
1
+ declare const process: { readonly env: { readonly NODE_ENV: string | undefined } } | undefined
4
2
 
5
3
  export const isDev: boolean =
6
4
  typeof process === 'undefined' ||