@playfast/reform 1.2.0 → 1.3.0

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