@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.
- package/README.md +85 -55
- package/package.json +17 -17
- package/src/boundary/boundary.test.ts +82 -33
- package/src/boundary/boundary.ts +141 -32
- package/src/calc/asyncCalc.invalidate.test.ts +733 -32
- package/src/calc/asyncCalc.test.ts +397 -225
- package/src/calc/asyncCalc.ts +115 -100
- package/src/calc/asyncCalcTypes.ts +147 -0
- package/src/calc/calc.test.ts +13 -16
- package/src/calc/calc.ts +44 -18
- package/src/calc/calcFamily.test.ts +90 -32
- package/src/calc/calcFamily.ts +56 -25
- package/src/calc/compose.ts +1 -14
- package/src/channel/channel.ts +25 -6
- package/src/channel/{procedureRegistry.ts → procedures.ts} +41 -23
- package/src/compose/composition.test.ts +19 -0
- package/src/compose/composition.ts +168 -81
- package/src/compose/compositionTypes.ts +249 -0
- package/src/compose/props.ts +13 -6
- package/src/compose/provide.ts +187 -46
- package/src/compose/slot.ts +156 -19
- package/src/compose/structure.test.ts +6 -3
- package/src/compose/structure.ts +106 -13
- package/src/compose/ui.test.ts +19 -3
- package/src/compose/ui.ts +147 -54
- package/src/compose/ui.typecheck.ts +40 -4
- package/src/definition/definition.ts +22 -9
- package/src/event/event.fromSource.test.ts +172 -0
- package/src/event/event.test.ts +10 -0
- package/src/event/event.ts +102 -18
- package/src/feature/feature.mount.test.ts +123 -56
- package/src/feature/feature.test.ts +67 -63
- package/src/feature/feature.ts +222 -262
- package/src/feature/feature.typecheck.ts +224 -91
- package/src/feature/featureBinding.ts +130 -20
- 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 +222 -0
- package/src/graph/services.ts +95 -0
- package/src/graph/summary.ts +134 -0
- package/src/index.ts +171 -245
- package/src/internal/bucketCache.ts +39 -0
- package/src/internal/capture.ts +9 -4
- package/src/internal/env.ts +1 -3
- package/src/internal/errors.ts +21 -10
- package/src/internal/queryDriver.ts +61 -25
- package/src/internal/queryDriverHydrate.ts +45 -0
- package/src/internal/queryDriverStore.ts +8 -5
- package/src/internal/queryDriverTypes.ts +11 -11
- package/src/internal/reuse.test.ts +10 -3
- package/src/internal/reuse.ts +5 -2
- package/src/internal/scheduler.ts +4 -1
- package/src/internal/sources.ts +25 -11
- package/src/internal/store.test.ts +27 -6
- package/src/internal/track.ts +3 -2
- package/src/internal.ts +222 -0
- package/src/namespace/namespace.ts +46 -25
- package/src/procedure/procedure.ts +38 -11
- package/src/reducer/reducer.ts +78 -34
- package/src/remote/pendingQueue.ts +145 -0
- package/src/remote/remoteState.test.ts +536 -354
- package/src/remote/remoteState.ts +145 -106
- package/src/remote/remoteState.typecheck.ts +47 -23
- package/src/remote/remoteStateMake.ts +97 -0
- package/src/remote/remoteStateSend.ts +95 -37
- package/src/remote/remoteStateTypes.ts +155 -0
- package/src/runtime/appRuntime.activation.test.ts +104 -0
- package/src/runtime/appRuntime.test.ts +187 -111
- package/src/runtime/appRuntime.ts +36 -130
- package/src/runtime/capturedAppRuntime.ts +274 -0
- package/src/runtime/eventBudget.test.ts +39 -12
- package/src/runtime/eventBudget.ts +9 -8
- package/src/runtime/featureMount.ts +94 -0
- package/src/runtime/hardening.test.ts +22 -13
- package/src/runtime/instrumentation.test.ts +213 -194
- package/src/runtime/instrumentation.ts +6 -11
- package/src/runtime/loop.test.ts +84 -7
- package/src/runtime/loop.ts +69 -40
- package/src/runtime/runtimeHandle.ts +124 -0
- package/src/scene/featureScene.test.ts +4 -2
- package/src/scene/scene.ts +234 -64
- package/src/scene/seedScene.test.ts +69 -86
- package/src/state/state.nominal.typecheck.ts +68 -0
- package/src/state/state.test.ts +17 -0
- package/src/state/state.ts +79 -26
- package/src/state/stateFamily.test.ts +39 -8
- package/src/state/stateFamily.ts +55 -22
- package/src/state/stateGroup.ts +53 -17
- package/src/state/token.ts +40 -10
- package/src/synced/syncedStore.ts +46 -23
- package/src/testkit/flight.testkit.ts +84 -0
- package/src/wire/tree.test.ts +8 -4
- package/src/wire/triggers.test.ts +6 -2
- package/src/wire/triggers.ts +14 -10
- package/src/calc/asyncCalcDefinitions.ts +0 -48
- package/src/internal/ctx.ts +0 -9
- package/src/remote/remoteStateDefinition.ts +0 -135
- package/src/remote/remoteStateLayers.ts +0 -118
- package/src/remote/remoteStateLiveTypes.ts +0 -59
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { Equal, MutableRef, Option } from 'effect'
|
|
2
|
+
import { inspectable } from '../internal/inspect'
|
|
3
|
+
import type { Scheduler } from '../internal/scheduler'
|
|
4
|
+
import type { Store } from '../internal/store'
|
|
5
|
+
import type { PendingIntent } from './remoteStateTypes'
|
|
6
|
+
|
|
7
|
+
export interface PendingNode<I> {
|
|
8
|
+
readonly entry: MutableRef.MutableRef<PendingIntent<I>>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Duplicate opIds retain every node so indexed updates preserve the old map semantics.
|
|
12
|
+
export interface PendingOpEntry<I> {
|
|
13
|
+
readonly nodes: Set<PendingNode<I>>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface PendingQueue<I> {
|
|
17
|
+
readonly store: Store<ReadonlyArray<PendingIntent<I>>>
|
|
18
|
+
readonly revision: () => number
|
|
19
|
+
readonly fold: <B>(initial: B, combine: (accumulator: B, entry: PendingIntent<I>) => B) => B
|
|
20
|
+
readonly append: (entry: PendingIntent<I>) => void
|
|
21
|
+
readonly ack: (opId: string) => void
|
|
22
|
+
readonly settle: (opId: string) => void
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const makePendingQueue = <I>(scheduler: Scheduler): PendingQueue<I> => {
|
|
26
|
+
// Set insertion order preserves dispatch/apply order while allowing O(1) updates.
|
|
27
|
+
const ordered = new Set<PendingNode<I>>()
|
|
28
|
+
const byOpId = new Map<string, PendingOpEntry<I>>()
|
|
29
|
+
const listeners = new Set<() => void>()
|
|
30
|
+
const revision = MutableRef.make(0)
|
|
31
|
+
const initial: ReadonlyArray<PendingIntent<I>> = []
|
|
32
|
+
const snapshot = MutableRef.make<Option.Option<ReadonlyArray<PendingIntent<I>>>>(
|
|
33
|
+
Option.some(initial),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const materialize = (): ReadonlyArray<PendingIntent<I>> => {
|
|
37
|
+
const cached = MutableRef.get(snapshot)
|
|
38
|
+
if (Option.isSome(cached)) {
|
|
39
|
+
return cached.value
|
|
40
|
+
}
|
|
41
|
+
const current = Array.from(ordered, (node) => MutableRef.get(node.entry))
|
|
42
|
+
MutableRef.set(snapshot, Option.some(current))
|
|
43
|
+
return current
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const announce = (next: Option.Option<ReadonlyArray<PendingIntent<I>>>): void => {
|
|
47
|
+
MutableRef.set(snapshot, next)
|
|
48
|
+
MutableRef.update(revision, (current) => current + 1)
|
|
49
|
+
scheduler.schedule(listeners)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const link = (entry: PendingIntent<I>): void => {
|
|
53
|
+
const node: PendingNode<I> = {
|
|
54
|
+
entry: MutableRef.make(entry),
|
|
55
|
+
}
|
|
56
|
+
ordered.add(node)
|
|
57
|
+
const indexed = byOpId.get(entry.opId)
|
|
58
|
+
if (indexed === undefined) {
|
|
59
|
+
byOpId.set(entry.opId, { nodes: new Set([node]) })
|
|
60
|
+
} else {
|
|
61
|
+
indexed.nodes.add(node)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const clear = (): void => {
|
|
66
|
+
ordered.clear()
|
|
67
|
+
byOpId.clear()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const fold = <B>(initialValue: B, combine: (accumulator: B, entry: PendingIntent<I>) => B): B => {
|
|
71
|
+
const folded = MutableRef.make(initialValue)
|
|
72
|
+
ordered.forEach((node) => {
|
|
73
|
+
MutableRef.update(folded, (accumulator) => combine(accumulator, MutableRef.get(node.entry)))
|
|
74
|
+
})
|
|
75
|
+
return MutableRef.get(folded)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const append = (entry: PendingIntent<I>): void => {
|
|
79
|
+
link(entry)
|
|
80
|
+
announce(Option.none())
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const ack = (opId: string): void => {
|
|
84
|
+
const indexed = byOpId.get(opId)
|
|
85
|
+
if (indexed === undefined) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
const stillSending = MutableRef.make(false)
|
|
89
|
+
indexed.nodes.forEach((node) => {
|
|
90
|
+
if (MutableRef.get(node.entry).status === 'sending') {
|
|
91
|
+
MutableRef.set(stillSending, true)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
if (!MutableRef.get(stillSending)) {
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
// Rebuild every duplicate once one is sending, matching the former array map.
|
|
98
|
+
indexed.nodes.forEach((node) => {
|
|
99
|
+
MutableRef.update(node.entry, (entry) => ({ ...entry, status: 'confirmed' as const }))
|
|
100
|
+
})
|
|
101
|
+
announce(Option.none())
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const settle = (opId: string): void => {
|
|
105
|
+
const indexed = byOpId.get(opId)
|
|
106
|
+
if (indexed === undefined) {
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
indexed.nodes.forEach((node) => {
|
|
110
|
+
ordered.delete(node)
|
|
111
|
+
})
|
|
112
|
+
byOpId.delete(opId)
|
|
113
|
+
announce(Option.none())
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const store: Store<ReadonlyArray<PendingIntent<I>>> = {
|
|
117
|
+
get: materialize,
|
|
118
|
+
getSnapshot: materialize,
|
|
119
|
+
getVersion: () => MutableRef.get(revision),
|
|
120
|
+
set: (next) => {
|
|
121
|
+
if (Equal.equals(materialize(), next)) {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
clear()
|
|
125
|
+
next.forEach(link)
|
|
126
|
+
announce(Option.some(next))
|
|
127
|
+
},
|
|
128
|
+
subscribe: (listener) => {
|
|
129
|
+
listeners.add(listener)
|
|
130
|
+
return () => {
|
|
131
|
+
listeners.delete(listener)
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
...inspectable(() => ({ _id: 'reform/Store', value: materialize() })),
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
store,
|
|
139
|
+
revision: () => MutableRef.get(revision),
|
|
140
|
+
fold,
|
|
141
|
+
append,
|
|
142
|
+
ack,
|
|
143
|
+
settle,
|
|
144
|
+
}
|
|
145
|
+
}
|