@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,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
+ }