@dreamboard-games/sdk 0.2.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 (369) hide show
  1. package/LICENSE.md +96 -0
  2. package/README.md +12 -0
  3. package/dist/HandView-ncJIVLhN.d.ts +193 -0
  4. package/dist/ResourceCounter-CTREyF73.d.ts +102 -0
  5. package/dist/ThemeProvider-fy0_QzgO.d.ts +99 -0
  6. package/dist/bundle-TIZcw8LB.d.ts +281 -0
  7. package/dist/cards-Sl3b40Mv.d.ts +13 -0
  8. package/dist/chunk-7YAHLYBR.js +481 -0
  9. package/dist/chunk-7YAHLYBR.js.map +1 -0
  10. package/dist/chunk-FDNZTDD6.js +8085 -0
  11. package/dist/chunk-FDNZTDD6.js.map +1 -0
  12. package/dist/chunk-GKKBPPSW.js +598 -0
  13. package/dist/chunk-GKKBPPSW.js.map +1 -0
  14. package/dist/chunk-I46YJSOD.js +1 -0
  15. package/dist/chunk-I46YJSOD.js.map +1 -0
  16. package/dist/chunk-KAELH4KC.js +104 -0
  17. package/dist/chunk-KAELH4KC.js.map +1 -0
  18. package/dist/chunk-PZ5AY32C.js +10 -0
  19. package/dist/chunk-PZ5AY32C.js.map +1 -0
  20. package/dist/chunk-T3ZKNUZ7.js +1 -0
  21. package/dist/chunk-T3ZKNUZ7.js.map +1 -0
  22. package/dist/chunk-T52J5RMF.js +1 -0
  23. package/dist/chunk-T52J5RMF.js.map +1 -0
  24. package/dist/chunk-TDSWKVZ4.js +5401 -0
  25. package/dist/chunk-TDSWKVZ4.js.map +1 -0
  26. package/dist/chunk-U5C6BONG.js +34 -0
  27. package/dist/chunk-U5C6BONG.js.map +1 -0
  28. package/dist/chunk-VDXOF4FW.js +69 -0
  29. package/dist/chunk-VDXOF4FW.js.map +1 -0
  30. package/dist/chunk-VFTAA4WO.js +115 -0
  31. package/dist/chunk-VFTAA4WO.js.map +1 -0
  32. package/dist/chunk-WN74KVNY.js +17 -0
  33. package/dist/chunk-WN74KVNY.js.map +1 -0
  34. package/dist/chunk-WYPQ3GG5.js +10990 -0
  35. package/dist/chunk-WYPQ3GG5.js.map +1 -0
  36. package/dist/components-D5ZRE2Hl.d.ts +1451 -0
  37. package/dist/generated/runtime/primitives.d.ts +12 -0
  38. package/dist/generated/runtime/primitives.js +180 -0
  39. package/dist/generated/runtime/primitives.js.map +1 -0
  40. package/dist/generated/runtime-api.d.ts +3 -0
  41. package/dist/generated/runtime-api.js +2 -0
  42. package/dist/generated/runtime-api.js.map +1 -0
  43. package/dist/generated/runtime.d.ts +14 -0
  44. package/dist/generated/runtime.js +18 -0
  45. package/dist/generated/runtime.js.map +1 -0
  46. package/dist/generated/workspace-contract.d.ts +14 -0
  47. package/dist/generated/workspace-contract.js +14 -0
  48. package/dist/generated/workspace-contract.js.map +1 -0
  49. package/dist/hex-board-view-D_07hO6O.d.ts +933 -0
  50. package/dist/hex-color-MhOyuY-o.d.ts +8 -0
  51. package/dist/index-BwqPQtBu.d.ts +1433 -0
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.js +12 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/infrastructure/reducer-bundle-abi.d.ts +1083 -0
  56. package/dist/infrastructure/reducer-bundle-abi.js +14 -0
  57. package/dist/infrastructure/reducer-bundle-abi.js.map +1 -0
  58. package/dist/infrastructure/workspace-codegen.d.ts +53 -0
  59. package/dist/infrastructure/workspace-codegen.js +44 -0
  60. package/dist/infrastructure/workspace-codegen.js.map +1 -0
  61. package/dist/manifest-contract-BNHVGFtU.d.ts +9 -0
  62. package/dist/package-set.d.ts +13 -0
  63. package/dist/package-set.js +12 -0
  64. package/dist/package-set.js.map +1 -0
  65. package/dist/primitive-props-DpKs-GCr.d.ts +11 -0
  66. package/dist/reducer.d.ts +3786 -0
  67. package/dist/reducer.js +8131 -0
  68. package/dist/reducer.js.map +1 -0
  69. package/dist/runtime/primitives.d.ts +226 -0
  70. package/dist/runtime/primitives.js +180 -0
  71. package/dist/runtime/primitives.js.map +1 -0
  72. package/dist/runtime/types/runtime-api.d.ts +1 -0
  73. package/dist/runtime/types/runtime-api.js +2 -0
  74. package/dist/runtime/types/runtime-api.js.map +1 -0
  75. package/dist/runtime/workspace-contract.d.ts +172 -0
  76. package/dist/runtime/workspace-contract.js +14 -0
  77. package/dist/runtime/workspace-contract.js.map +1 -0
  78. package/dist/runtime-api-3dshj6kK.d.ts +101 -0
  79. package/dist/runtime-api-DWxvTr-O.d.ts +379 -0
  80. package/dist/runtime.d.ts +58 -0
  81. package/dist/runtime.js +13 -0
  82. package/dist/runtime.js.map +1 -0
  83. package/dist/slots-1GPGihk8.d.ts +8 -0
  84. package/dist/testing.d.ts +149 -0
  85. package/dist/testing.js +513 -0
  86. package/dist/testing.js.map +1 -0
  87. package/dist/types.d.ts +496 -0
  88. package/dist/types.js +28 -0
  89. package/dist/types.js.map +1 -0
  90. package/dist/ui/components.d.ts +16 -0
  91. package/dist/ui/components.js +192 -0
  92. package/dist/ui/components.js.map +1 -0
  93. package/dist/ui/defaults.d.ts +19 -0
  94. package/dist/ui/defaults.js +104 -0
  95. package/dist/ui/defaults.js.map +1 -0
  96. package/dist/ui/plugin-styles.css +250 -0
  97. package/dist/ui/types/player-state.d.ts +365 -0
  98. package/dist/ui/types/player-state.js +1 -0
  99. package/dist/ui/types/player-state.js.map +1 -0
  100. package/dist/ui-contract-iQfTtUSL.d.ts +1161 -0
  101. package/dist/ui.d.ts +320 -0
  102. package/dist/ui.js +253 -0
  103. package/dist/ui.js.map +1 -0
  104. package/package.json +199 -0
  105. package/src/generated/reducer-contract/builders.ts +90 -0
  106. package/src/generated/reducer-contract/version.ts +9 -0
  107. package/src/generated/reducer-contract/wire.ts +100 -0
  108. package/src/generated/reducer-contract/zod.ts +101 -0
  109. package/src/generated/runtime/primitives.ts +2 -0
  110. package/src/generated/runtime-api.ts +5 -0
  111. package/src/generated/runtime.ts +35 -0
  112. package/src/generated/workspace-contract.ts +2 -0
  113. package/src/index.ts +7 -0
  114. package/src/infrastructure/reducer-bundle-abi.ts +8 -0
  115. package/src/infrastructure/reducer-contract/bundle.ts +37 -0
  116. package/src/infrastructure/workspace-codegen/hex-geometry.ts +69 -0
  117. package/src/infrastructure/workspace-codegen/index.ts +64 -0
  118. package/src/infrastructure/workspace-codegen/manifest-contract.ts +6632 -0
  119. package/src/infrastructure/workspace-codegen/manifest-validation.ts +795 -0
  120. package/src/infrastructure/workspace-codegen/ownership.ts +131 -0
  121. package/src/infrastructure/workspace-codegen/preset-card-sets.ts +169 -0
  122. package/src/infrastructure/workspace-codegen/seeds.ts +1705 -0
  123. package/src/infrastructure/workspace-codegen.ts +1 -0
  124. package/src/package-set.ts +19 -0
  125. package/src/reducer/authoring/contract.ts +157 -0
  126. package/src/reducer/authoring/effect.ts +224 -0
  127. package/src/reducer/authoring/game.ts +23 -0
  128. package/src/reducer/authoring/interaction.ts +98 -0
  129. package/src/reducer/authoring/phase.ts +300 -0
  130. package/src/reducer/authoring/types.ts +70 -0
  131. package/src/reducer/authoring/validation.ts +382 -0
  132. package/src/reducer/authoring/view-stage.ts +68 -0
  133. package/src/reducer/authoring.ts +29 -0
  134. package/src/reducer/bundle/ingress-bundle.ts +491 -0
  135. package/src/reducer/bundle/trusted/engine-instruction-resolver.ts +254 -0
  136. package/src/reducer/bundle/trusted/flow-instruction-resolver.ts +73 -0
  137. package/src/reducer/bundle/trusted/instruction-runner.ts +414 -0
  138. package/src/reducer/bundle/trusted/interaction-authorization.ts +137 -0
  139. package/src/reducer/bundle/trusted/interaction-collectors.ts +859 -0
  140. package/src/reducer/bundle/trusted/interaction-decision.ts +747 -0
  141. package/src/reducer/bundle/trusted/interaction-resolver.ts +95 -0
  142. package/src/reducer/bundle/trusted/interaction-types.ts +171 -0
  143. package/src/reducer/bundle/trusted/lifecycle-runner.ts +427 -0
  144. package/src/reducer/bundle/trusted/projection-builder.ts +356 -0
  145. package/src/reducer/bundle/trusted/projection-context.ts +39 -0
  146. package/src/reducer/bundle/trusted/rng-sampler.ts +150 -0
  147. package/src/reducer/bundle/trusted/runtime-registry.ts +120 -0
  148. package/src/reducer/bundle/trusted/runtime-scope.ts +336 -0
  149. package/src/reducer/bundle/trusted/simultaneous-player.ts +97 -0
  150. package/src/reducer/bundle/trusted/stage-resolver.ts +87 -0
  151. package/src/reducer/bundle/trusted/static-projection.ts +116 -0
  152. package/src/reducer/bundle/trusted/trusted-runtime-args.ts +97 -0
  153. package/src/reducer/bundle/trusted/trusted-runtime-result.ts +39 -0
  154. package/src/reducer/bundle/trusted/trusted-setup-profiles.ts +43 -0
  155. package/src/reducer/bundle/trusted/trusted-state-codec.ts +48 -0
  156. package/src/reducer/bundle/trusted-bundle.ts +97 -0
  157. package/src/reducer/bundle/types.ts +171 -0
  158. package/src/reducer/bundle.ts +2 -0
  159. package/src/reducer/client-param-schemas.ts +57 -0
  160. package/src/reducer/compose.ts +34 -0
  161. package/src/reducer/core/runtime-input.ts +30 -0
  162. package/src/reducer/core/runtime-instruction.ts +59 -0
  163. package/src/reducer/core/types.ts +62 -0
  164. package/src/reducer/definition-index.ts +277 -0
  165. package/src/reducer/derived.ts +106 -0
  166. package/src/reducer/effects.ts +92 -0
  167. package/src/reducer/engine/runtime-instruction-engine.ts +155 -0
  168. package/src/reducer/ingress/decode-runtime-input.ts +7 -0
  169. package/src/reducer/ingress/decode-session-state.ts +9 -0
  170. package/src/reducer/ingress/encode-session-state.ts +6 -0
  171. package/src/reducer/ingress/input-codec.ts +18 -0
  172. package/src/reducer/ingress/phase-schemas.ts +62 -0
  173. package/src/reducer/ingress/raw-types.ts +107 -0
  174. package/src/reducer/ingress/runtime-codec.ts +14 -0
  175. package/src/reducer/ingress/runtime-payload.ts +13 -0
  176. package/src/reducer/ingress/session-codec.ts +392 -0
  177. package/src/reducer/ingress/types.ts +6 -0
  178. package/src/reducer/inputs/boardInput.ts +217 -0
  179. package/src/reducer/inputs/boardTarget.ts +190 -0
  180. package/src/reducer/inputs/cardInput.ts +86 -0
  181. package/src/reducer/inputs/cardTarget.ts +101 -0
  182. package/src/reducer/inputs/choiceTarget.ts +104 -0
  183. package/src/reducer/inputs/defineInputs.ts +71 -0
  184. package/src/reducer/inputs/formInput.ts +809 -0
  185. package/src/reducer/inputs/many.ts +120 -0
  186. package/src/reducer/inputs/promptInput.ts +87 -0
  187. package/src/reducer/inputs/rngInput.ts +58 -0
  188. package/src/reducer/inputs/targetRule.ts +123 -0
  189. package/src/reducer/inputs.ts +41 -0
  190. package/src/reducer/model/definition.ts +1072 -0
  191. package/src/reducer/model/extract.ts +745 -0
  192. package/src/reducer/model/manifest.ts +570 -0
  193. package/src/reducer/model/queries.ts +641 -0
  194. package/src/reducer/model/runtime.ts +264 -0
  195. package/src/reducer/model/spec.ts +1386 -0
  196. package/src/reducer/model/table.ts +260 -0
  197. package/src/reducer/model.ts +7 -0
  198. package/src/reducer/ops.ts +1034 -0
  199. package/src/reducer/parse-utils.ts +28 -0
  200. package/src/reducer/per-player.ts +422 -0
  201. package/src/reducer/rng.ts +69 -0
  202. package/src/reducer/schema-helpers.ts +185 -0
  203. package/src/reducer/setup-bootstrap-helpers.ts +171 -0
  204. package/src/reducer/setup-bootstrap.ts +481 -0
  205. package/src/reducer/table-ops.ts +2671 -0
  206. package/src/reducer/table-queries.ts +372 -0
  207. package/src/reducer/transaction.ts +120 -0
  208. package/src/reducer.ts +314 -0
  209. package/src/runtime/primitives.ts +1 -0
  210. package/src/runtime/types/runtime-api.ts +1 -0
  211. package/src/runtime/workspace-contract.ts +32 -0
  212. package/src/runtime-internal/components/InteractionForm.tsx +1309 -0
  213. package/src/runtime-internal/components/PluginRuntime.tsx +103 -0
  214. package/src/runtime-internal/components/board/target-layer.ts +70 -0
  215. package/src/runtime-internal/context/ClientParamSchemaContext.tsx +44 -0
  216. package/src/runtime-internal/context/InteractionDraftContext.tsx +279 -0
  217. package/src/runtime-internal/context/PluginSessionContext.tsx +47 -0
  218. package/src/runtime-internal/context/PluginStateContext.tsx +262 -0
  219. package/src/runtime-internal/context/RuntimeContext.tsx +96 -0
  220. package/src/runtime-internal/defaults/components.tsx +409 -0
  221. package/src/runtime-internal/defaults/index.ts +11 -0
  222. package/src/runtime-internal/errors/ValidationError.ts +29 -0
  223. package/src/runtime-internal/hooks/useActivePlayers.ts +33 -0
  224. package/src/runtime-internal/hooks/useBoardInteractions.ts +665 -0
  225. package/src/runtime-internal/hooks/useGameSelector.ts +105 -0
  226. package/src/runtime-internal/hooks/useGameView.ts +9 -0
  227. package/src/runtime-internal/hooks/useInteractionByKey.ts +354 -0
  228. package/src/runtime-internal/hooks/useInteractionHandle.ts +438 -0
  229. package/src/runtime-internal/hooks/useIsMyTurn.ts +20 -0
  230. package/src/runtime-internal/hooks/useLobby.ts +76 -0
  231. package/src/runtime-internal/hooks/useMe.ts +48 -0
  232. package/src/runtime-internal/hooks/usePlayerInfo.ts +28 -0
  233. package/src/runtime-internal/hooks/usePlayerTurnOrder.ts +23 -0
  234. package/src/runtime-internal/hooks/usePluginRuntime.ts +147 -0
  235. package/src/runtime-internal/hooks/useSeatInbox.ts +61 -0
  236. package/src/runtime-internal/hooks/useSimultaneousPhase.ts +10 -0
  237. package/src/runtime-internal/index.ts +42 -0
  238. package/src/runtime-internal/internal.ts +43 -0
  239. package/src/runtime-internal/plugin-styles.css +250 -0
  240. package/src/runtime-internal/primitives/board.tsx +459 -0
  241. package/src/runtime-internal/primitives/dialog-lifecycle.ts +58 -0
  242. package/src/runtime-internal/primitives/dice.tsx +79 -0
  243. package/src/runtime-internal/primitives/game-ui-provider.tsx +35 -0
  244. package/src/runtime-internal/primitives/game.tsx +387 -0
  245. package/src/runtime-internal/primitives/hand-intent-adapter.ts +147 -0
  246. package/src/runtime-internal/primitives/hand-surface.tsx +594 -0
  247. package/src/runtime-internal/primitives/index.ts +196 -0
  248. package/src/runtime-internal/primitives/interaction-form-binding.tsx +56 -0
  249. package/src/runtime-internal/primitives/interaction-submit.ts +90 -0
  250. package/src/runtime-internal/primitives/interaction.tsx +987 -0
  251. package/src/runtime-internal/primitives/phase.tsx +43 -0
  252. package/src/runtime-internal/primitives/player-roster.tsx +302 -0
  253. package/src/runtime-internal/primitives/primitive-props.tsx +101 -0
  254. package/src/runtime-internal/primitives/prompt.tsx +255 -0
  255. package/src/runtime-internal/primitives/ui.tsx +60 -0
  256. package/src/runtime-internal/primitives/zone.tsx +791 -0
  257. package/src/runtime-internal/reducer.ts +30 -0
  258. package/src/runtime-internal/runtime/createPluginRuntimeAPI.ts +605 -0
  259. package/src/runtime-internal/types/plugin-state.ts +508 -0
  260. package/src/runtime-internal/types/reducer-state.ts +24 -0
  261. package/src/runtime-internal/types/runtime-api.ts +114 -0
  262. package/src/runtime-internal/ui-contract.ts +519 -0
  263. package/src/runtime-internal/utils/card-intent-adapter.ts +546 -0
  264. package/src/runtime-internal/utils/interaction-inputs.ts +492 -0
  265. package/src/runtime-internal/utils/interaction-labels.ts +23 -0
  266. package/src/runtime-internal/utils/interaction-router.ts +273 -0
  267. package/src/runtime-internal/utils/interaction-status.ts +74 -0
  268. package/src/runtime-internal/workspace-contract.ts +1170 -0
  269. package/src/runtime.ts +34 -0
  270. package/src/testing/create-expect-api.ts +352 -0
  271. package/src/testing/create-test-runtime.ts +381 -0
  272. package/src/testing/definitions.ts +127 -0
  273. package/src/testing/index.ts +3 -0
  274. package/src/testing.ts +1 -0
  275. package/src/type-stubs/manifest-contract.d.ts +42 -0
  276. package/src/type-stubs/manifest-contract.js +72 -0
  277. package/src/type-stubs/ui-contract.d.ts +5 -0
  278. package/src/type-stubs/ui-contract.js +1 -0
  279. package/src/types/authoring-card-properties.type-test.ts +266 -0
  280. package/src/types/authoring.ts +1282 -0
  281. package/src/types/cards.ts +19 -0
  282. package/src/types/contracts.ts +1550 -0
  283. package/src/types/generated-helpers.ts +35 -0
  284. package/src/types/index.ts +147 -0
  285. package/src/types/slots.ts +11 -0
  286. package/src/types.ts +1 -0
  287. package/src/ui/components/ActionButton.tsx +97 -0
  288. package/src/ui/components/ActionPanel.tsx +315 -0
  289. package/src/ui/components/Card.tsx +378 -0
  290. package/src/ui/components/CardDragSurface.tsx +1076 -0
  291. package/src/ui/components/ChromeSuppressionContext.tsx +70 -0
  292. package/src/ui/components/CostDisplay.tsx +145 -0
  293. package/src/ui/components/DiceRoller.tsx +581 -0
  294. package/src/ui/components/Drawer.tsx +180 -0
  295. package/src/ui/components/ErrorBoundary.tsx +275 -0
  296. package/src/ui/components/GameEndDisplay.tsx +398 -0
  297. package/src/ui/components/GameSkeleton.tsx +260 -0
  298. package/src/ui/components/Hand.tsx +468 -0
  299. package/src/ui/components/HandDock.tsx +299 -0
  300. package/src/ui/components/HandView.tsx +441 -0
  301. package/src/ui/components/MobileHandTray.tsx +381 -0
  302. package/src/ui/components/MoreActions.tsx +143 -0
  303. package/src/ui/components/PhaseIndicator.tsx +341 -0
  304. package/src/ui/components/PlayArea.tsx +146 -0
  305. package/src/ui/components/PrimaryActionButton.tsx +336 -0
  306. package/src/ui/components/PrimaryButton.tsx +45 -0
  307. package/src/ui/components/ResourceCounter.tsx +270 -0
  308. package/src/ui/components/StagingZone.tsx +134 -0
  309. package/src/ui/components/ThemedButton.tsx +113 -0
  310. package/src/ui/components/Toast.tsx +264 -0
  311. package/src/ui/components/board/HexGrid.tsx +1294 -0
  312. package/src/ui/components/board/NetworkGraph.tsx +476 -0
  313. package/src/ui/components/board/SlotSystem.tsx +388 -0
  314. package/src/ui/components/board/SquareGrid.tsx +1165 -0
  315. package/src/ui/components/board/TrackBoard.tsx +496 -0
  316. package/src/ui/components/board/ZoneMap.tsx +448 -0
  317. package/src/ui/components/board/hex-board-view.ts +123 -0
  318. package/src/ui/components/board/index.ts +142 -0
  319. package/src/ui/components/board/interaction-accessibility.ts +21 -0
  320. package/src/ui/components/board/target-layer.ts +66 -0
  321. package/src/ui/components/card-render-content.type-test.ts +27 -0
  322. package/src/ui/components/hand-layout-math.ts +163 -0
  323. package/src/ui/components/hand-pointer-engine.ts +413 -0
  324. package/src/ui/components/index.ts +245 -0
  325. package/src/ui/components.ts +1 -0
  326. package/src/ui/defaults/components.tsx +106 -0
  327. package/src/ui/defaults/index.ts +8 -0
  328. package/src/ui/defaults.ts +1 -0
  329. package/src/ui/errors/ValidationError.ts +29 -0
  330. package/src/ui/helpers/cards.ts +19 -0
  331. package/src/ui/helpers/track-board.ts +211 -0
  332. package/src/ui/hooks/useBoardTopology.ts +316 -0
  333. package/src/ui/hooks/useCards.ts +10 -0
  334. package/src/ui/hooks/useHandCardPointer.ts +381 -0
  335. package/src/ui/hooks/useHandLayout.ts +378 -0
  336. package/src/ui/hooks/useHandPresentation.ts +121 -0
  337. package/src/ui/hooks/useHexBoard.ts +74 -0
  338. package/src/ui/hooks/useHexGrid.ts +185 -0
  339. package/src/ui/hooks/useIsMobile.ts +35 -0
  340. package/src/ui/hooks/usePanZoom.ts +278 -0
  341. package/src/ui/hooks/useSquareBoard.ts +124 -0
  342. package/src/ui/hooks/useSquareGrid.ts +328 -0
  343. package/src/ui/index.ts +98 -0
  344. package/src/ui/internal/ui/alert.tsx +51 -0
  345. package/src/ui/internal/ui/button.tsx +58 -0
  346. package/src/ui/internal/ui/dialog.tsx +134 -0
  347. package/src/ui/internal/ui/input.tsx +21 -0
  348. package/src/ui/internal/ui/label.tsx +21 -0
  349. package/src/ui/internal/ui/select.tsx +129 -0
  350. package/src/ui/internal/ui/tooltip.tsx +54 -0
  351. package/src/ui/internal/ui/utils.ts +5 -0
  352. package/src/ui/plugin-styles.css +250 -0
  353. package/src/ui/primitives/dialog-lifecycle.ts +58 -0
  354. package/src/ui/primitives/dice.tsx +79 -0
  355. package/src/ui/primitives/primitive-props.tsx +101 -0
  356. package/src/ui/theme/ThemeProvider.tsx +252 -0
  357. package/src/ui/theme/board.ts +61 -0
  358. package/src/ui/theme/css-vars.ts +105 -0
  359. package/src/ui/theme/derive.ts +240 -0
  360. package/src/ui/theme/index.ts +61 -0
  361. package/src/ui/theme/presets/arcade.ts +261 -0
  362. package/src/ui/theme/presets/studio.ts +261 -0
  363. package/src/ui/theme/presets/tabletop.ts +266 -0
  364. package/src/ui/theme/tokens.ts +392 -0
  365. package/src/ui/types/hex-color.ts +20 -0
  366. package/src/ui/types/player-state.ts +463 -0
  367. package/src/ui/types/tiled-board.ts +785 -0
  368. package/src/ui/types/visual-state.ts +137 -0
  369. package/src/ui.ts +1 -0
@@ -0,0 +1,1386 @@
1
+ import type { z } from "zod";
2
+ import type {
3
+ AnySchema,
4
+ RuntimeTableRecord,
5
+ SchemaLike,
6
+ StringKeyOf,
7
+ } from "./table";
8
+ import type { ManifestContract } from "./manifest";
9
+ import type {
10
+ CardIdOfState,
11
+ CardTypeOfState,
12
+ PhaseNameOfState,
13
+ PhaseStepOfState,
14
+ PlayerIdOfState,
15
+ PlayerZoneIdOfManifest,
16
+ TableOfState,
17
+ SetupSelectionOfManifest,
18
+ } from "./extract";
19
+ import type {
20
+ AnyContinuationToken,
21
+ ContinuationToken,
22
+ ReducerAccept,
23
+ ReducerFx,
24
+ ReducerReject,
25
+ ReducerResult,
26
+ ReducerRuntimeStateForState,
27
+ } from "./runtime";
28
+ import type { RuntimeInstructionForState } from "../core/runtime-instruction";
29
+ import type { TableQueriesOfState } from "./queries";
30
+ import type { ReducerOps } from "../ops";
31
+ import type { ReducerTransaction } from "../transaction";
32
+ import type { DerivedResolver } from "../derived";
33
+
34
+ type StaticBoardsOfManifest<Manifest> = Manifest extends {
35
+ staticBoards?: infer StaticBoards;
36
+ }
37
+ ? NonNullable<StaticBoards>
38
+ : {
39
+ byId: Record<string, never>;
40
+ hex: Record<string, never>;
41
+ square: Record<string, never>;
42
+ };
43
+
44
+ type StaticBoardMapOfManifest<Manifest> =
45
+ StaticBoardsOfManifest<Manifest> extends {
46
+ byId: infer Boards;
47
+ }
48
+ ? Boards
49
+ : Record<string, never>;
50
+
51
+ type StaticHexBoardMapOfManifest<Manifest> =
52
+ StaticBoardsOfManifest<Manifest> extends {
53
+ hex: infer Boards;
54
+ }
55
+ ? Boards
56
+ : Record<string, never>;
57
+
58
+ type StaticSquareBoardMapOfManifest<Manifest> =
59
+ StaticBoardsOfManifest<Manifest> extends {
60
+ square: infer Boards;
61
+ }
62
+ ? Boards
63
+ : Record<string, never>;
64
+
65
+ export type StaticViewQueries<
66
+ Manifest extends ManifestContract<RuntimeTableRecord>,
67
+ > = {
68
+ board: {
69
+ get: <BoardId extends StringKeyOf<StaticBoardMapOfManifest<Manifest>>>(
70
+ boardId: BoardId,
71
+ ) => StaticBoardMapOfManifest<Manifest>[BoardId];
72
+ hex: <BoardId extends StringKeyOf<StaticHexBoardMapOfManifest<Manifest>>>(
73
+ boardId: BoardId,
74
+ ) => StaticHexBoardMapOfManifest<Manifest>[BoardId];
75
+ square: <
76
+ BoardId extends StringKeyOf<StaticSquareBoardMapOfManifest<Manifest>>,
77
+ >(
78
+ boardId: BoardId,
79
+ ) => StaticSquareBoardMapOfManifest<Manifest>[BoardId];
80
+ };
81
+ };
82
+
83
+ // --- Continuation Input Types ---
84
+
85
+ // Engine-level routing kind. Retained as a single-value alias for clarity at
86
+ // engine boundaries; every continuation is effect-sourced in the canonical
87
+ // SDK.
88
+ export type ContinuationSourceKind = "effect";
89
+
90
+ // Names of engine effects that can resume a typed continuation.
91
+ export type ResumableEffectKind =
92
+ | "rollDie"
93
+ | "shuffleSharedZone"
94
+ | "shufflePlayerZone";
95
+
96
+ // Internal tag shared between the continuation callable and the engine.
97
+ export type ContinuationKind = ResumableEffectKind;
98
+
99
+ // Per-effect response shapes. These are produced by the engine after an effect
100
+ // runs and delivered back to the continuation's reduce callback as input.response.
101
+ export type RollDieContinuationResponse = {
102
+ dieId: string;
103
+ value: number;
104
+ };
105
+
106
+ export type ShuffleSharedZoneContinuationResponse = {
107
+ zoneId: string;
108
+ orderedCardIds: readonly string[];
109
+ };
110
+
111
+ export type ShufflePlayerZoneContinuationResponse = {
112
+ zoneId: string;
113
+ playerId: string;
114
+ orderedCardIds: readonly string[];
115
+ };
116
+
117
+ export type EffectContinuationResponse<Kind extends ResumableEffectKind> =
118
+ Kind extends "rollDie"
119
+ ? RollDieContinuationResponse
120
+ : Kind extends "shuffleSharedZone"
121
+ ? ShuffleSharedZoneContinuationResponse
122
+ : Kind extends "shufflePlayerZone"
123
+ ? ShufflePlayerZoneContinuationResponse
124
+ : never;
125
+
126
+ export type EffectContinuationInput<
127
+ DataSchema extends AnySchema,
128
+ Kind extends ResumableEffectKind = ResumableEffectKind,
129
+ > = {
130
+ source: "effect";
131
+ effectKind: Kind;
132
+ data: z.infer<DataSchema>;
133
+ response: EffectContinuationResponse<Kind>;
134
+ };
135
+
136
+ export type ContinuationInput<DataSchema extends AnySchema> =
137
+ EffectContinuationInput<DataSchema, ResumableEffectKind>;
138
+
139
+ export type ContinuationInputForSource<
140
+ DataSchema extends AnySchema,
141
+ EffectType extends ResumableEffectKind = ResumableEffectKind,
142
+ > = EffectContinuationInput<DataSchema, EffectType>;
143
+
144
+ // --- Context Types ---
145
+
146
+ export type PhaseEnterContext = {
147
+ event: "initialize" | "transition";
148
+ };
149
+
150
+ type BivariantCallback<Args, Result> = {
151
+ bivarianceHack(args: Args): Result;
152
+ }["bivarianceHack"];
153
+
154
+ export type ActionContext<
155
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
156
+ Manifest extends ManifestContract<TableOfState<State>>,
157
+ > = {
158
+ currentPhase: PhaseNameOfState<State>;
159
+ manifest: Manifest;
160
+ playerOrder: PlayerIdOfState<State>[];
161
+ activePlayers: PlayerIdOfState<State>[];
162
+ runtime: Omit<ReducerRuntimeStateForState<State>, "rng">;
163
+ setup: SetupSelectionOfManifest<Manifest> | null;
164
+ };
165
+
166
+ export type ValidationIssue = {
167
+ errorCode: string;
168
+ message?: string;
169
+ };
170
+
171
+ export type RuntimeHelpers<
172
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
173
+ > = {
174
+ accept(
175
+ state: State,
176
+ instructions?: RuntimeInstructionForState<State>[],
177
+ ): ReducerAccept<State>;
178
+ reject: (errorCode: string, message?: string) => ReducerReject;
179
+ fx: ReducerFx<State>;
180
+ ops: ReducerOps<State>;
181
+ edit<DraftState extends State>(
182
+ state: DraftState,
183
+ ): ReducerTransaction<DraftState>;
184
+ q: TableQueriesOfState<State>;
185
+ derived: DerivedResolver;
186
+ };
187
+
188
+ export type RandomHelpers = {
189
+ subset<const Values extends readonly unknown[]>(options: {
190
+ from: Values;
191
+ count: number;
192
+ }): readonly Values[number][];
193
+ };
194
+
195
+ export type MutationRuntimeHelpers = {
196
+ random: RandomHelpers;
197
+ };
198
+
199
+ export type PhaseEnterArgs<
200
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
201
+ Manifest extends ManifestContract<TableOfState<State>>,
202
+ > = ActionContext<State, Manifest> &
203
+ RuntimeHelpers<State> &
204
+ MutationRuntimeHelpers &
205
+ PhaseEnterContext & {
206
+ state: State;
207
+ };
208
+
209
+ export type ActorSelectorArgs<
210
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
211
+ Manifest extends ManifestContract<TableOfState<State>>,
212
+ > = ActionContext<State, Manifest> &
213
+ RuntimeHelpers<State> & {
214
+ state: State;
215
+ };
216
+
217
+ export type ActorSelection<
218
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
219
+ > =
220
+ | PlayerIdOfState<State>
221
+ | readonly PlayerIdOfState<State>[]
222
+ | null
223
+ | undefined;
224
+
225
+ export type ActorSelector<
226
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
227
+ Manifest extends ManifestContract<TableOfState<State>>,
228
+ > = BivariantCallback<
229
+ ActorSelectorArgs<State, Manifest>,
230
+ ActorSelection<State>
231
+ >;
232
+
233
+ export type ContinuationReduceArgs<
234
+ DataSchema extends AnySchema,
235
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
236
+ Manifest extends ManifestContract<TableOfState<State>>,
237
+ EffectType extends ResumableEffectKind = ResumableEffectKind,
238
+ > = ActionContext<State, Manifest> &
239
+ RuntimeHelpers<State> &
240
+ MutationRuntimeHelpers & {
241
+ state: State;
242
+ input: ContinuationInputForSource<DataSchema, EffectType>;
243
+ };
244
+
245
+ export type ScopedPhaseState<
246
+ State extends {
247
+ table: RuntimeTableRecord;
248
+ flow: { currentPhase: string };
249
+ phase: object;
250
+ },
251
+ PhaseState extends object,
252
+ > = State & { phase: PhaseState };
253
+
254
+ // --- Continuation Callables ---
255
+
256
+ export type ContinuationCallable<
257
+ DataSchema extends AnySchema,
258
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
259
+ Manifest extends ManifestContract<TableOfState<State>>,
260
+ ContinuationId extends string = string,
261
+ EffectType extends ResumableEffectKind = ResumableEffectKind,
262
+ > = ((
263
+ data: z.infer<DataSchema>,
264
+ ) => ContinuationToken<
265
+ z.infer<DataSchema>,
266
+ ContinuationId,
267
+ EffectContinuationResponse<EffectType>
268
+ >) & {
269
+ id: ContinuationId;
270
+ source: "effect";
271
+ dataSchema: DataSchema;
272
+ responseSchema: AnySchema;
273
+ effectKind?: EffectType;
274
+ reduce: BivariantCallback<
275
+ ContinuationReduceArgs<DataSchema, State, Manifest, EffectType>,
276
+ ReducerResult<State>
277
+ >;
278
+ };
279
+
280
+ export type AnyContinuationCallable<
281
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
282
+ > = {
283
+ (data: never): AnyContinuationToken;
284
+ id: string;
285
+ source: "effect";
286
+ dataSchema: AnySchema;
287
+ responseSchema: AnySchema;
288
+ effectKind?: ResumableEffectKind;
289
+ // Heterogeneously-typed erasure: the concrete args shape is determined by
290
+ // `effectKind` and validated at runtime via `dataSchema` +
291
+ // `responseSchema`. Consumers must cast at the call site.
292
+ reduce: (args: unknown) => ReducerResult<State>;
293
+ };
294
+
295
+ export type EffectContinuationCallable<
296
+ DataSchema extends AnySchema,
297
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
298
+ Manifest extends ManifestContract<TableOfState<State>>,
299
+ ContinuationId extends string = string,
300
+ Kind extends ResumableEffectKind = ResumableEffectKind,
301
+ > = ContinuationCallable<DataSchema, State, Manifest, ContinuationId, Kind>;
302
+
303
+ // --- Effect definitions (the single authoring factory for engine cues) ---
304
+ //
305
+ // Effects are resumable engine-side cues (e.g. rolling a die, shuffling a
306
+ // shared zone). They are authored with `defineEffect({ type, id, context?,
307
+ // reduce? })` and dispatched at runtime via `fx.effect(effect, options)`.
308
+ // Addressed player requests are NOT effects — they are authored as
309
+ // prompt-kind interactions via `defineInteraction({ kind: "prompt", ... })`.
310
+
311
+ /**
312
+ * `rollDie` effect. Resolves a `rollDie` wire effect. `reduce` / `context`
313
+ * are both optional so authors can fire-and-forget a die roll without
314
+ * observing the result.
315
+ */
316
+ export type EffectRollDieDefinition<
317
+ Id extends string,
318
+ ContextSchema extends AnySchema,
319
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
320
+ Manifest extends ManifestContract<TableOfState<State>>,
321
+ > = {
322
+ readonly type: "rollDie";
323
+ readonly id: Id;
324
+ readonly contextSchema?: ContextSchema;
325
+ readonly __continuation?: EffectContinuationCallable<
326
+ ContextSchema,
327
+ State,
328
+ Manifest,
329
+ Id,
330
+ "rollDie"
331
+ >;
332
+ };
333
+
334
+ /**
335
+ * `shuffleSharedZone` effect. Resolves a `shuffleSharedZone` wire effect.
336
+ * `reduce` / `context` are both optional.
337
+ */
338
+ export type EffectShuffleDefinition<
339
+ Id extends string,
340
+ ContextSchema extends AnySchema,
341
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
342
+ Manifest extends ManifestContract<TableOfState<State>>,
343
+ > = {
344
+ readonly type: "shuffleSharedZone";
345
+ readonly id: Id;
346
+ readonly contextSchema?: ContextSchema;
347
+ readonly __continuation?: EffectContinuationCallable<
348
+ ContextSchema,
349
+ State,
350
+ Manifest,
351
+ Id,
352
+ "shuffleSharedZone"
353
+ >;
354
+ };
355
+
356
+ /**
357
+ * `shufflePlayerZone` effect. Resolves a `shufflePlayerZone` wire effect for
358
+ * a single player's perPlayer zone (e.g. deck-builder reshuffle of discard
359
+ * into deck). `reduce` / `context` are both optional.
360
+ */
361
+ export type EffectShufflePlayerZoneDefinition<
362
+ Id extends string,
363
+ ContextSchema extends AnySchema,
364
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
365
+ Manifest extends ManifestContract<TableOfState<State>>,
366
+ > = {
367
+ readonly type: "shufflePlayerZone";
368
+ readonly id: Id;
369
+ readonly contextSchema?: ContextSchema;
370
+ readonly __continuation?: EffectContinuationCallable<
371
+ ContextSchema,
372
+ State,
373
+ Manifest,
374
+ Id,
375
+ "shufflePlayerZone"
376
+ >;
377
+ };
378
+
379
+ /**
380
+ * Discriminated union of every `defineEffect` output.
381
+ */
382
+ export type EffectDefinition<
383
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
384
+ Manifest extends ManifestContract<TableOfState<State>>,
385
+ > =
386
+ | EffectRollDieDefinition<string, AnySchema, State, Manifest>
387
+ | EffectShuffleDefinition<string, AnySchema, State, Manifest>
388
+ | EffectShufflePlayerZoneDefinition<string, AnySchema, State, Manifest>;
389
+
390
+ export type EffectMap<
391
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
392
+ Manifest extends ManifestContract<TableOfState<State>>,
393
+ > = Record<string, EffectDefinition<State, Manifest>>;
394
+
395
+ export type EffectRegistryOfPhase<Phase> = Phase extends {
396
+ effects?: infer Effects extends Record<string, unknown>;
397
+ }
398
+ ? Effects
399
+ : Record<string, never>;
400
+
401
+ // --- Phase & View Definitions ---
402
+
403
+ export type SimultaneousSubmission<
404
+ Collectors extends Record<string, InputCollector>,
405
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
406
+ > = {
407
+ playerId: PlayerIdOfState<State>;
408
+ params: ParamsOf<Collectors>;
409
+ };
410
+
411
+ export type SimultaneousResolveArgs<
412
+ Collectors extends Record<string, InputCollector>,
413
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
414
+ Manifest extends ManifestContract<TableOfState<State>>,
415
+ > = ActionContext<State, Manifest> &
416
+ RuntimeHelpers<State> &
417
+ MutationRuntimeHelpers & {
418
+ state: State;
419
+ submissions: Record<
420
+ PlayerIdOfState<State>,
421
+ SimultaneousSubmission<Collectors, State>
422
+ >;
423
+ submittedPlayerIds: PlayerIdOfState<State>[];
424
+ waitingPlayerIds: PlayerIdOfState<State>[];
425
+ };
426
+
427
+ export type SimultaneousSubmitSpec<
428
+ Collectors extends Record<string, InputCollector> = Record<
429
+ string,
430
+ InputCollector
431
+ >,
432
+ State extends {
433
+ table: RuntimeTableRecord;
434
+ flow: { currentPhase: string };
435
+ } = {
436
+ table: RuntimeTableRecord;
437
+ flow: { currentPhase: string };
438
+ },
439
+ Manifest extends ManifestContract<TableOfState<State>> = ManifestContract<
440
+ TableOfState<State>
441
+ >,
442
+ > = Omit<InteractionSpec<Collectors, State, Manifest>, "reduce"> & {
443
+ /**
444
+ * Optional compatibility slot for callers that reuse `defineInteraction`.
445
+ * The simultaneous phase barrier stores submissions and invokes the
446
+ * phase-level `resolve`; this per-submission reducer is intentionally
447
+ * ignored when present.
448
+ */
449
+ reduce?: InteractionSpec<Collectors, State, Manifest>["reduce"];
450
+ };
451
+
452
+ type PhaseDefinitionCommon<
453
+ PhaseStateSchema extends SchemaLike<object>,
454
+ State extends {
455
+ table: RuntimeTableRecord;
456
+ flow: { currentPhase: string };
457
+ phase: object;
458
+ },
459
+ Manifest extends ManifestContract<TableOfState<State>>,
460
+ > = {
461
+ name?: string;
462
+ state: PhaseStateSchema;
463
+ initialState?: (ctx: {
464
+ manifest: Manifest;
465
+ state: State;
466
+ playerIds: PlayerIdOfState<State>[];
467
+ setup: SetupSelectionOfManifest<Manifest> | null;
468
+ }) => z.infer<PhaseStateSchema>;
469
+ enter?: BivariantCallback<
470
+ PhaseEnterArgs<
471
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
472
+ Manifest
473
+ >,
474
+ ReducerResult<ScopedPhaseState<State, z.infer<PhaseStateSchema>>> | void
475
+ >;
476
+ };
477
+
478
+ export type AutoPhaseDefinition<
479
+ PhaseStateSchema extends SchemaLike<object>,
480
+ State extends {
481
+ table: RuntimeTableRecord;
482
+ flow: { currentPhase: string };
483
+ phase: object;
484
+ },
485
+ Manifest extends ManifestContract<TableOfState<State>>,
486
+ > = PhaseDefinitionCommon<PhaseStateSchema, State, Manifest> & {
487
+ kind: "auto";
488
+ actor?: never;
489
+ actors?: never;
490
+ submit?: never;
491
+ canResubmit?: never;
492
+ resolve?: never;
493
+ effects?: never;
494
+ interactions?: never;
495
+ stages?: never;
496
+ zones?: never;
497
+ cardActions?: never;
498
+ };
499
+
500
+ export type PlayerPhaseDefinition<
501
+ PhaseStateSchema extends SchemaLike<object>,
502
+ State extends {
503
+ table: RuntimeTableRecord;
504
+ flow: { currentPhase: string };
505
+ phase: object;
506
+ },
507
+ Manifest extends ManifestContract<TableOfState<State>>,
508
+ Effects extends EffectMap<State, Manifest> = Record<string, never>,
509
+ Interactions extends InteractionMap<
510
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
511
+ Manifest
512
+ > = Record<string, never>,
513
+ Stages extends StageMap<
514
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
515
+ Manifest
516
+ > = Record<string, never>,
517
+ Zones extends PhaseZoneList<Manifest> = readonly [],
518
+ CardActions extends CardActionMap<
519
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
520
+ Manifest
521
+ > = Record<string, never>,
522
+ > = PhaseDefinitionCommon<PhaseStateSchema, State, Manifest> & {
523
+ kind: "player";
524
+ /**
525
+ * Default actor selector for interactions in this phase. When omitted the
526
+ * runtime falls back to `flow.activePlayers`, preserving the existing turn
527
+ * ownership model. Returning multiple players models simultaneous actors.
528
+ */
529
+ actor?: ActorSelector<
530
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
531
+ Manifest
532
+ >;
533
+ actors?: never;
534
+ submit?: never;
535
+ canResubmit?: never;
536
+ resolve?: never;
537
+ effects?: Effects;
538
+ interactions?: Interactions;
539
+ stages?: Stages;
540
+ zones?: Zones;
541
+ cardActions?: CardActions;
542
+ };
543
+
544
+ export type SimultaneousPlayerPhaseDefinition<
545
+ PhaseStateSchema extends SchemaLike<object>,
546
+ State extends {
547
+ table: RuntimeTableRecord;
548
+ flow: { currentPhase: string };
549
+ phase: object;
550
+ },
551
+ Manifest extends ManifestContract<TableOfState<State>>,
552
+ SubmitCollectors extends Record<string, InputCollector> = Record<
553
+ string,
554
+ InputCollector
555
+ >,
556
+ Effects extends EffectMap<State, Manifest> = Record<string, never>,
557
+ Interactions extends InteractionMap<
558
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
559
+ Manifest
560
+ > = Record<string, never>,
561
+ Stages extends StageMap<
562
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
563
+ Manifest
564
+ > = Record<string, never>,
565
+ Zones extends PhaseZoneList<Manifest> = readonly [],
566
+ CardActions extends CardActionMap<
567
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
568
+ Manifest
569
+ > = Record<string, never>,
570
+ > = PhaseDefinitionCommon<PhaseStateSchema, State, Manifest> & {
571
+ kind: "simultaneousPlayer";
572
+ actor?: never;
573
+ /**
574
+ * Actor selector for `kind: "simultaneousPlayer"` phases. This is an alias
575
+ * of `actor` with wording that matches simultaneous submission semantics.
576
+ */
577
+ actors: ActorSelector<
578
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
579
+ Manifest
580
+ >;
581
+ /**
582
+ * Canonical sealed submission interaction for simultaneous phases. It is
583
+ * projected like a normal interaction, but the trusted runtime stores the
584
+ * parsed params until every actor has submitted, then calls `resolve`.
585
+ */
586
+ submit: SimultaneousSubmitSpec<
587
+ SubmitCollectors,
588
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
589
+ Manifest
590
+ >;
591
+ /**
592
+ * When false or omitted, each actor can submit once per simultaneous
593
+ * barrier. Set true to allow replacing the sealed submission before every
594
+ * required actor has submitted.
595
+ */
596
+ canResubmit?: boolean;
597
+ /**
598
+ * Batch resolver invoked once all simultaneous actors have submitted. The
599
+ * submitted params are passed together so game state mutates from one
600
+ * deterministic base state instead of one player at a time.
601
+ */
602
+ resolve: BivariantCallback<
603
+ SimultaneousResolveArgs<
604
+ SubmitCollectors,
605
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
606
+ Manifest
607
+ >,
608
+ ReducerResult<ScopedPhaseState<State, z.infer<PhaseStateSchema>>>
609
+ >;
610
+ effects?: Effects;
611
+ interactions?: Interactions;
612
+ stages?: Stages;
613
+ zones?: Zones;
614
+ cardActions?: CardActions;
615
+ };
616
+
617
+ export type PhaseDefinition<
618
+ PhaseStateSchema extends SchemaLike<object>,
619
+ State extends {
620
+ table: RuntimeTableRecord;
621
+ flow: { currentPhase: string };
622
+ phase: object;
623
+ },
624
+ Manifest extends ManifestContract<TableOfState<State>>,
625
+ SubmitCollectors extends Record<string, InputCollector> = Record<
626
+ string,
627
+ InputCollector
628
+ >,
629
+ Effects extends EffectMap<State, Manifest> = Record<string, never>,
630
+ Interactions extends InteractionMap<
631
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
632
+ Manifest
633
+ > = Record<string, never>,
634
+ Stages extends StageMap<
635
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
636
+ Manifest
637
+ > = Record<string, never>,
638
+ Zones extends PhaseZoneList<Manifest> = readonly [],
639
+ CardActions extends CardActionMap<
640
+ ScopedPhaseState<State, z.infer<PhaseStateSchema>>,
641
+ Manifest
642
+ > = Record<string, never>,
643
+ > =
644
+ | AutoPhaseDefinition<PhaseStateSchema, State, Manifest>
645
+ | PlayerPhaseDefinition<
646
+ PhaseStateSchema,
647
+ State,
648
+ Manifest,
649
+ Effects,
650
+ Interactions,
651
+ Stages,
652
+ Zones,
653
+ CardActions
654
+ >
655
+ | SimultaneousPlayerPhaseDefinition<
656
+ PhaseStateSchema,
657
+ State,
658
+ Manifest,
659
+ SubmitCollectors,
660
+ Effects,
661
+ Interactions,
662
+ Stages,
663
+ Zones,
664
+ CardActions
665
+ >;
666
+
667
+ export type ViewDefinition<
668
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
669
+ Manifest extends ManifestContract<TableOfState<State>>,
670
+ Projection = unknown,
671
+ > = {
672
+ project: (
673
+ args: ActionContext<State, Manifest> &
674
+ RuntimeHelpers<State> & {
675
+ state: State;
676
+ playerId: PlayerIdOfState<State>;
677
+ runtime: State extends {
678
+ runtime: infer RuntimeStateValue;
679
+ }
680
+ ? RuntimeStateValue
681
+ : never;
682
+ },
683
+ ) => Projection;
684
+ };
685
+
686
+ /**
687
+ * Session-scoped, once-per-init view. The `project` callback receives only
688
+ * the authored manifest — the mutable-state helpers (`state`, `playerId`,
689
+ * `runtime`, `fx`, `ops`, `accept`, `reject`, `q`) that `ViewDefinition.project`
690
+ * exposes are structurally absent, so an author cannot accidentally project
691
+ * per-tick state into the payload. The host calls this once per reducer
692
+ * session, caches the result, and merges it back into every seat view on
693
+ * the client. Moving static board topology here is what lets the adapter
694
+ * skip the ~87% of `projectSeatsDynamic` wall time that used to re-serialize
695
+ * manifest-sourced fields on every input.
696
+ */
697
+ export type StaticViewDefinition<
698
+ Manifest extends ManifestContract<RuntimeTableRecord>,
699
+ Projection = unknown,
700
+ > = {
701
+ project: (args: {
702
+ manifest: Manifest;
703
+ q: StaticViewQueries<Manifest>;
704
+ }) => Projection;
705
+ };
706
+
707
+ // --- Interaction / Stage / Zone primitives ---
708
+ //
709
+ // The new authoring surface. A `PhaseDefinition` can declare:
710
+ // - `interactions`: the set of authoring-level interactions routed by id.
711
+ // Each `InteractionSpec` has typed input collectors and a `reduce` that
712
+ // receives `params: ParamsOf<Collectors>`.
713
+ // - `stages`: first-match-wins sub-phase selectors with `allow` gating.
714
+ // - `zones`: manifest player card zones projected as behavior descriptors.
715
+
716
+ export type InputCollectorKind =
717
+ | "form"
718
+ | "board-vertex"
719
+ | "board-edge"
720
+ | "board-tile"
721
+ | "board-space"
722
+ | "card"
723
+ | "prompt"
724
+ | "rng";
725
+
726
+ export type TargetKind = "edge" | "vertex" | "space" | "tile" | "card";
727
+ export type BoardInputCollectorKind = Exclude<
728
+ InputCollectorKind,
729
+ "form" | "card" | "prompt" | "rng"
730
+ >;
731
+
732
+ export type CardInputCollectorMeta = {
733
+ readonly zoneId: string;
734
+ readonly zoneIds?: readonly string[];
735
+ readonly targetKind: "card";
736
+ };
737
+
738
+ export type BoardInputCollectorMeta = {
739
+ readonly targetKind: TargetKind;
740
+ readonly boardId: string;
741
+ readonly valueKind?: "board-id" | "player-board-space";
742
+ };
743
+
744
+ export type PromptInputCollectorMeta = {
745
+ readonly options: (
746
+ state: unknown,
747
+ playerId: unknown,
748
+ q: unknown,
749
+ ) => ReadonlyArray<{ id: unknown; label?: string }>;
750
+ readonly eligibleOptions: (
751
+ state: unknown,
752
+ playerId: unknown,
753
+ q: unknown,
754
+ ) => ReadonlyArray<{ id: unknown; label?: string }>;
755
+ };
756
+
757
+ export type RngInputCollectorMeta =
758
+ | { readonly rng: "d6"; readonly count: number }
759
+ | { readonly rng: "coin" };
760
+
761
+ export type InputCollectorMetaForKind<Kind extends InputCollectorKind> =
762
+ Kind extends "card"
763
+ ? CardInputCollectorMeta
764
+ : Kind extends BoardInputCollectorKind
765
+ ? BoardInputCollectorMeta
766
+ : Kind extends "prompt"
767
+ ? PromptInputCollectorMeta | undefined
768
+ : Kind extends "rng"
769
+ ? RngInputCollectorMeta
770
+ : never;
771
+
772
+ export type InputSelectionDescriptor =
773
+ | { readonly mode: "single" }
774
+ | {
775
+ readonly mode: "many";
776
+ readonly min: number;
777
+ readonly max?: number;
778
+ readonly distinct?: boolean;
779
+ };
780
+
781
+ export type InputDomainResolverDescriptor = {
782
+ readonly interactionKey?: string;
783
+ readonly inputKey: string;
784
+ };
785
+
786
+ export type InputDomainDependencyCase<
787
+ Domain extends InputDomainDescriptor = InputDomainDescriptor,
788
+ > = {
789
+ when: Record<string, string>;
790
+ domain: Domain;
791
+ };
792
+
793
+ export type EagerInputDomainDependencies<
794
+ Domain extends InputDomainDescriptor = InputDomainDescriptor,
795
+ > = {
796
+ readonly mode: "eager";
797
+ readonly dependentCases: readonly InputDomainDependencyCase<Domain>[];
798
+ };
799
+
800
+ export type LazyInputDomainDependencies = {
801
+ readonly mode: "lazy";
802
+ readonly dependsOn: readonly string[];
803
+ readonly resolver: InputDomainResolverDescriptor;
804
+ };
805
+
806
+ export type CardTargetDomainDescriptor =
807
+ | ResolvedCardTargetDomainDescriptor
808
+ | LazyCardTargetDomainDescriptor;
809
+
810
+ export type ResolvedCardTargetDomainDescriptor = {
811
+ readonly type: "cardTarget";
812
+ readonly projection: "resolved";
813
+ readonly targetKind: "card";
814
+ readonly zoneIds: readonly string[];
815
+ readonly eligibleTargets: readonly string[];
816
+ readonly selection?: InputSelectionDescriptor;
817
+ readonly dependencies?: EagerInputDomainDependencies<ResolvedCardTargetDomainDescriptor>;
818
+ };
819
+
820
+ export type LazyCardTargetDomainDescriptor = {
821
+ readonly type: "cardTarget";
822
+ readonly projection: "lazy";
823
+ readonly targetKind: "card";
824
+ readonly zoneIds: readonly string[];
825
+ readonly eligibleTargets?: never;
826
+ readonly selection?: InputSelectionDescriptor;
827
+ readonly dependencies: LazyInputDomainDependencies;
828
+ };
829
+
830
+ export type BoardTargetDomainDescriptor =
831
+ | ResolvedBoardTargetDomainDescriptor
832
+ | LazyBoardTargetDomainDescriptor;
833
+
834
+ export type ResolvedBoardTargetDomainDescriptor = {
835
+ readonly type: "boardTarget";
836
+ readonly projection: "resolved";
837
+ readonly targetKind: Exclude<TargetKind, "card">;
838
+ readonly boardId: string;
839
+ readonly valueKind?: "board-id" | "player-board-space";
840
+ readonly eligibleTargets: readonly string[];
841
+ readonly selection?: InputSelectionDescriptor;
842
+ readonly dependencies?: EagerInputDomainDependencies<ResolvedBoardTargetDomainDescriptor>;
843
+ };
844
+
845
+ export type LazyBoardTargetDomainDescriptor = {
846
+ readonly type: "boardTarget";
847
+ readonly projection: "lazy";
848
+ readonly targetKind: Exclude<TargetKind, "card">;
849
+ readonly boardId: string;
850
+ readonly valueKind?: "board-id" | "player-board-space";
851
+ readonly eligibleTargets?: never;
852
+ readonly selection?: InputSelectionDescriptor;
853
+ readonly dependencies: LazyInputDomainDependencies;
854
+ };
855
+
856
+ export type ResourceMapDomainDescriptor = {
857
+ type: "resourceMap";
858
+ resources: Array<{
859
+ resourceId: string;
860
+ label?: string;
861
+ icon?: string;
862
+ min: number;
863
+ max: number;
864
+ }>;
865
+ selection?: InputSelectionDescriptor;
866
+ };
867
+
868
+ export type BoundedNumberDomainDescriptor = {
869
+ type: "boundedNumber";
870
+ min: number;
871
+ max: number;
872
+ step?: number;
873
+ selection?: InputSelectionDescriptor;
874
+ };
875
+
876
+ export type ChoiceDomainDescriptor = {
877
+ type: "choice";
878
+ choices: Array<{
879
+ value: string | null;
880
+ label: string;
881
+ icon?: string;
882
+ badge?: string;
883
+ description?: string;
884
+ disabled?: boolean;
885
+ disabledReason?: string;
886
+ }>;
887
+ selection?: InputSelectionDescriptor;
888
+ dependencies?: EagerInputDomainDependencies<ChoiceDomainDescriptor>;
889
+ };
890
+
891
+ export type ChoiceListDomainDescriptor = {
892
+ type: "choiceList";
893
+ choices: Array<{
894
+ value: string;
895
+ label: string;
896
+ icon?: string;
897
+ badge?: string;
898
+ description?: string;
899
+ disabled?: boolean;
900
+ disabledReason?: string;
901
+ }>;
902
+ min?: number;
903
+ max?: number;
904
+ selection?: InputSelectionDescriptor;
905
+ dependencies?: EagerInputDomainDependencies<ChoiceListDomainDescriptor>;
906
+ };
907
+
908
+ export type InputDomainDescriptor =
909
+ | CardTargetDomainDescriptor
910
+ | BoardTargetDomainDescriptor
911
+ | ResourceMapDomainDescriptor
912
+ | BoundedNumberDomainDescriptor
913
+ | ChoiceDomainDescriptor
914
+ | ChoiceListDomainDescriptor;
915
+
916
+ type DomainProjector<Domain extends InputDomainDescriptor> = (
917
+ state: CollectorState,
918
+ playerId: string,
919
+ q: unknown,
920
+ derived: DerivedResolver,
921
+ values?: Readonly<Record<string, unknown>>,
922
+ ) => Domain;
923
+
924
+ type InputDomainForCollectorKind<Kind extends InputCollectorKind> =
925
+ Kind extends "card"
926
+ ? CardTargetDomainDescriptor
927
+ : Kind extends BoardInputCollectorKind
928
+ ? BoardTargetDomainDescriptor
929
+ : Exclude<
930
+ InputDomainDescriptor,
931
+ CardTargetDomainDescriptor | BoardTargetDomainDescriptor
932
+ >;
933
+
934
+ /**
935
+ * Base state shape every collector is generic over. Collectors that need
936
+ * narrowed ids (card / player) use `PlayerIdOfState<State>` etc. to thread
937
+ * the manifest's branded types.
938
+ */
939
+ export type CollectorState = {
940
+ table: RuntimeTableRecord;
941
+ flow: { currentPhase: string };
942
+ };
943
+
944
+ /**
945
+ * An input collector declares:
946
+ * - a Zod schema for the parameter value the interaction expects. The
947
+ * schema's `z.infer` feeds `ParamsOf<Collectors>`, so downstream
948
+ * `reduce({ input: { params } })` sees branded ids from `cardInput` /
949
+ * `boardInput` without a second declaration.
950
+ * - an optional `eligibleTargets(state, playerId, q)` hook that the runtime
951
+ * calls to enumerate server-authoritative valid values. The hook receives
952
+ * the same `q` table-queries helper that `validate` / `reduce` see, so
953
+ * board/card/prompt collectors can reuse whatever board-graph or zone
954
+ * lookups they already use for validation without rebuilding them from
955
+ * raw state. Each collector helper narrows the return type to its own
956
+ * branded id (`CardIdOfState<State>` for `cardInput`, the caller-supplied
957
+ * `Id extends string` for `boardInput.*`, etc.). At the generic interface
958
+ * level we keep inputs weak (`CollectorState`, `string`, `unknown`) and
959
+ * the return `ReadonlyArray<unknown>` so the runtime can treat all
960
+ * collectors uniformly; per-helper signatures provide the author-facing
961
+ * strong typing.
962
+ * - optional `meta` for collector-kind-specific routing (e.g. `cardInput`
963
+ * stores the `zoneId` the card must come from).
964
+ *
965
+ * Collectors without meaningful eligibility (`form`, `rng`) leave
966
+ * `eligibleTargets` undefined.
967
+ */
968
+ type InputCollectorMetaSlot<Kind extends InputCollectorKind> = [
969
+ InputCollectorMetaForKind<Kind>,
970
+ ] extends [never]
971
+ ? { readonly meta?: never }
972
+ : undefined extends InputCollectorMetaForKind<Kind>
973
+ ? {
974
+ readonly meta?: Exclude<InputCollectorMetaForKind<Kind>, undefined>;
975
+ }
976
+ : { readonly meta: InputCollectorMetaForKind<Kind> };
977
+
978
+ type InputCollectorBase<
979
+ Schema extends SchemaLike<unknown> = SchemaLike<unknown>,
980
+ // `State` is retained as a generic slot so factory helpers (`cardInput`,
981
+ // `boardInput`, etc.) can advertise branded ids in their return type, but
982
+ // the interface intentionally does *not* thread `State` into
983
+ // `eligibleTargets`'s function parameters. Doing so introduced
984
+ // contravariance that blocked passing a game-specific collector (e.g.
985
+ // `InputCollector<_, GameState>`) where the interaction spec expected
986
+ // `InputCollector<_, CollectorState>`. Strong typing lives at the factory
987
+ // boundary; the interface itself keeps the runtime-visible hook generic.
988
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
989
+ State extends CollectorState = CollectorState,
990
+ Kind extends InputCollectorKind = InputCollectorKind,
991
+ > = {
992
+ readonly kind: Kind;
993
+ readonly schema: Schema;
994
+ readonly defaultValue?: z.infer<Schema>;
995
+ readonly selection?: InputSelectionDescriptor;
996
+ readonly eligibleTargets?: (
997
+ state: CollectorState,
998
+ playerId: string,
999
+ q: unknown,
1000
+ values?: Readonly<Record<string, unknown>>,
1001
+ ) => ReadonlyArray<unknown>;
1002
+ readonly validateTarget?: (
1003
+ state: CollectorState,
1004
+ playerId: string,
1005
+ q: unknown,
1006
+ targetId: unknown,
1007
+ values?: Readonly<Record<string, unknown>>,
1008
+ ) => ValidationIssue | null | undefined;
1009
+ readonly dependsOn?: readonly string[];
1010
+ readonly resolveDefaultValue?: (
1011
+ state: CollectorState,
1012
+ playerId: string,
1013
+ q: unknown,
1014
+ derived: DerivedResolver,
1015
+ domain: InputDomainDescriptor,
1016
+ ) => z.infer<Schema> | undefined;
1017
+ } & (Kind extends "rng"
1018
+ ? { readonly domain?: never }
1019
+ : Kind extends "card" | BoardInputCollectorKind
1020
+ ? { readonly domain: DomainProjector<InputDomainForCollectorKind<Kind>> }
1021
+ : {
1022
+ readonly domain?: DomainProjector<InputDomainForCollectorKind<Kind>>;
1023
+ }) &
1024
+ InputCollectorMetaSlot<Kind>;
1025
+
1026
+ export type InputCollector<
1027
+ Schema extends SchemaLike<unknown> = SchemaLike<unknown>,
1028
+ State extends CollectorState = CollectorState,
1029
+ Kind extends InputCollectorKind = InputCollectorKind,
1030
+ > = Kind extends InputCollectorKind
1031
+ ? InputCollectorBase<Schema, State, Kind>
1032
+ : never;
1033
+
1034
+ // Infer the typed params bag from an input-collector map.
1035
+ //
1036
+ // Each collector contributes `{ [key]: z.infer<schema> }`. The result is the
1037
+ // typed shape handed to `reduce({ input: { params } })`.
1038
+ export type ParamsOf<Collectors extends Record<string, InputCollector>> = {
1039
+ [K in keyof Collectors]: Collectors[K] extends InputCollector<infer S>
1040
+ ? S extends SchemaLike<infer V>
1041
+ ? V
1042
+ : never
1043
+ : never;
1044
+ };
1045
+
1046
+ // Keys of `Collectors` whose values are engine-sampled (currently only
1047
+ // `rngInput.*` — `kind: "rng"`). Clients never submit these fields; the
1048
+ // trusted reducer bundle samples them during `submitInteraction`.
1049
+ type EngineSampledCollectorKeys<
1050
+ Collectors extends Record<string, InputCollector>,
1051
+ > = {
1052
+ [K in keyof Collectors]: Collectors[K] extends InputCollector & {
1053
+ kind: "rng";
1054
+ }
1055
+ ? K
1056
+ : never;
1057
+ }[keyof Collectors];
1058
+
1059
+ // Infer the client-facing params bag: identical to `ParamsOf<Collectors>`
1060
+ // except engine-sampled collectors (`rngInput.*`) are omitted. This is the
1061
+ // shape clients pass to `submitInteraction` / `handle.submit` — the bundle
1062
+ // fills the engine-sampled fields before handing the merged record to
1063
+ // `reduce`.
1064
+ export type ClientParamsOf<Collectors extends Record<string, InputCollector>> =
1065
+ {
1066
+ [K in keyof Collectors as K extends EngineSampledCollectorKeys<Collectors>
1067
+ ? never
1068
+ : K]: Collectors[K] extends InputCollector<infer S>
1069
+ ? S extends SchemaLike<infer V>
1070
+ ? V
1071
+ : never
1072
+ : never;
1073
+ };
1074
+
1075
+ export type InteractionReduceInput<
1076
+ Collectors extends Record<string, InputCollector>,
1077
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1078
+ > = {
1079
+ playerId: PlayerIdOfState<State>;
1080
+ params: ParamsOf<Collectors>;
1081
+ };
1082
+
1083
+ export type InteractionValidateArgs<
1084
+ Collectors extends Record<string, InputCollector>,
1085
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1086
+ Manifest extends ManifestContract<TableOfState<State>>,
1087
+ > = ActionContext<State, Manifest> &
1088
+ RuntimeHelpers<State> & {
1089
+ state: State;
1090
+ input: InteractionReduceInput<Collectors, State>;
1091
+ };
1092
+
1093
+ export type InteractionReduceArgs<
1094
+ Collectors extends Record<string, InputCollector>,
1095
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1096
+ Manifest extends ManifestContract<TableOfState<State>>,
1097
+ > = InteractionValidateArgs<Collectors, State, Manifest> &
1098
+ MutationRuntimeHelpers;
1099
+
1100
+ export type InteractionAvailabilityArgs<
1101
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1102
+ Manifest extends ManifestContract<TableOfState<State>>,
1103
+ > = ActionContext<State, Manifest> &
1104
+ RuntimeHelpers<State> & {
1105
+ state: State;
1106
+ input: { playerId: PlayerIdOfState<State> };
1107
+ };
1108
+
1109
+ export type InteractionRuleValidationResult =
1110
+ | boolean
1111
+ | ValidationIssue
1112
+ | null
1113
+ | undefined;
1114
+
1115
+ export type InteractionRule<
1116
+ Collectors extends Record<string, InputCollector> = Record<
1117
+ string,
1118
+ InputCollector
1119
+ >,
1120
+ State extends {
1121
+ table: RuntimeTableRecord;
1122
+ flow: { currentPhase: string };
1123
+ } = {
1124
+ table: RuntimeTableRecord;
1125
+ flow: { currentPhase: string };
1126
+ },
1127
+ Manifest extends ManifestContract<TableOfState<State>> = ManifestContract<
1128
+ TableOfState<State>
1129
+ >,
1130
+ > = {
1131
+ /**
1132
+ * Stable rule id for diagnostics and tests. Rule ids are author-owned and
1133
+ * should be unique within one interaction.
1134
+ */
1135
+ id: string;
1136
+ /**
1137
+ * Error code used when the rule fails. The same code is used for descriptor
1138
+ * availability and submit-time validation unless `validate` returns a
1139
+ * specific ValidationIssue.
1140
+ */
1141
+ errorCode: string;
1142
+ message?: string;
1143
+ /**
1144
+ * Projection-time rule. Runs without submitted params, so UI descriptors can
1145
+ * reflect action availability before the user clicks.
1146
+ */
1147
+ available?: BivariantCallback<
1148
+ InteractionAvailabilityArgs<State, Manifest>,
1149
+ boolean
1150
+ >;
1151
+ /**
1152
+ * Submit-time rule. Runs with parsed params and may return false, a concrete
1153
+ * ValidationIssue, null, or undefined.
1154
+ */
1155
+ validate?: BivariantCallback<
1156
+ InteractionValidateArgs<Collectors, State, Manifest>,
1157
+ InteractionRuleValidationResult
1158
+ >;
1159
+ };
1160
+
1161
+ export type InteractionCommitPolicy =
1162
+ | { mode: "manual" }
1163
+ | { mode: "autoWhenReady" };
1164
+
1165
+ type HasManyInputCollector<Collectors extends Record<string, InputCollector>> =
1166
+ Extract<
1167
+ Collectors[keyof Collectors],
1168
+ { readonly selection: { readonly mode: "many" } }
1169
+ > extends never
1170
+ ? false
1171
+ : true;
1172
+
1173
+ type InteractionCommitPolicyFor<
1174
+ Collectors extends Record<string, InputCollector>,
1175
+ > =
1176
+ HasManyInputCollector<Collectors> extends true
1177
+ ? { mode: "manual" }
1178
+ : InteractionCommitPolicy;
1179
+
1180
+ /**
1181
+ * Projection-level interaction kind, derived by the trusted bundle from
1182
+ * collector shape:
1183
+ *
1184
+ * - `"action"`: any interaction whose inputs are ordinary collectors
1185
+ * (`formInput`, `cardInput`).
1186
+ * - `"prompt"`: any interaction whose inputs include a `promptInput`
1187
+ * collector. Prompt descriptors carry addressed-player context and options
1188
+ * so UI primitives can render response controls without reducer-owned
1189
+ * placement metadata.
1190
+ *
1191
+ * Authors never set this directly — the `promptInput(...)` collector is
1192
+ * the single source of truth for prompt semantics. See {@link promptInput}
1193
+ * and {@link InteractionDescriptor.kind}.
1194
+ */
1195
+ export type InteractionKind = "action" | "prompt";
1196
+
1197
+ export type InteractionToArgs<
1198
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1199
+ Manifest extends ManifestContract<TableOfState<State>>,
1200
+ > = ActionContext<State, Manifest> & {
1201
+ state: State;
1202
+ };
1203
+
1204
+ export type InteractionSpec<
1205
+ Collectors extends Record<string, InputCollector> = Record<
1206
+ string,
1207
+ InputCollector
1208
+ >,
1209
+ State extends {
1210
+ table: RuntimeTableRecord;
1211
+ flow: { currentPhase: string };
1212
+ } = {
1213
+ table: RuntimeTableRecord;
1214
+ flow: { currentPhase: string };
1215
+ },
1216
+ Manifest extends ManifestContract<TableOfState<State>> = ManifestContract<
1217
+ TableOfState<State>
1218
+ >,
1219
+ > = {
1220
+ inputs: Collectors;
1221
+ paramsSchema?: SchemaLike<ClientParamsOf<Collectors>>;
1222
+ /** @internal Phase-local step gates are attached by `defineStepPhase`. */
1223
+ __steps?: readonly string[];
1224
+ /**
1225
+ * Draft commit policy. The input collectors still own value shape and
1226
+ * validation; this only controls whether a ready draft may be submitted
1227
+ * automatically by SDK controls.
1228
+ *
1229
+ * Multi-value collectors created with `many(...)` are always manual draft
1230
+ * interactions. They represent a selection set that should be committed by
1231
+ * explicit player intent, so `autoWhenReady` is intentionally not accepted.
1232
+ */
1233
+ commit?: InteractionCommitPolicyFor<Collectors>;
1234
+ /**
1235
+ * Addressed-player selector, used by prompt-kind interactions. When
1236
+ * present, the trusted bundle only emits this descriptor for players in
1237
+ * the returned set (or the single player, if a scalar is returned). Use
1238
+ * to thread e.g. `state.publicState.knowerPlayerId` through without
1239
+ * having to manage `activePlayers`. `undefined` / empty returns fall back
1240
+ * to the standard `activePlayers` gating used by action-kind interactions.
1241
+ */
1242
+ to?: BivariantCallback<
1243
+ InteractionToArgs<State, Manifest>,
1244
+ | PlayerIdOfState<State>
1245
+ | ReadonlyArray<PlayerIdOfState<State>>
1246
+ | null
1247
+ | undefined
1248
+ >;
1249
+ /**
1250
+ * Explicit actor selector. Overrides the phase-level actor for this
1251
+ * interaction. Prefer this over `to` for new non-prompt interactions; `to`
1252
+ * remains the prompt/addressee shorthand.
1253
+ */
1254
+ actor?: ActorSelector<State, Manifest>;
1255
+ /**
1256
+ * Descriptor visibility policy. `all` keeps non-actors visible but disabled;
1257
+ * `actorsOnly` suppresses descriptors for seats that cannot act.
1258
+ */
1259
+ visibility?: "all" | "actorsOnly";
1260
+ errorCodes?: readonly string[];
1261
+ cost?: BivariantCallback<
1262
+ InteractionValidateArgs<Collectors, State, Manifest>,
1263
+ Readonly<Record<string, number>>
1264
+ >;
1265
+ rules?: readonly InteractionRule<NoInfer<Collectors>, State, Manifest>[];
1266
+ reduce: BivariantCallback<
1267
+ InteractionReduceArgs<Collectors, State, Manifest>,
1268
+ ReducerResult<State>
1269
+ >;
1270
+ };
1271
+
1272
+ export type CardActionSpec<
1273
+ Collectors extends Record<string, InputCollector> = Record<
1274
+ string,
1275
+ InputCollector
1276
+ >,
1277
+ State extends {
1278
+ table: RuntimeTableRecord;
1279
+ flow: { currentPhase: string };
1280
+ } = {
1281
+ table: RuntimeTableRecord;
1282
+ flow: { currentPhase: string };
1283
+ },
1284
+ Manifest extends ManifestContract<TableOfState<State>> = ManifestContract<
1285
+ TableOfState<State>
1286
+ >,
1287
+ PlayFrom extends PlayerZoneIdOfManifest<Manifest> =
1288
+ PlayerZoneIdOfManifest<Manifest>,
1289
+ > = {
1290
+ cardType: CardTypeOfState<State>;
1291
+ playFrom: PlayFrom;
1292
+ inputs?: Collectors;
1293
+ paramsSchema?: SchemaLike<Record<string, unknown>>;
1294
+ /** @internal Phase-local step gates are attached by `defineStepPhase`. */
1295
+ __steps?: readonly string[];
1296
+ /**
1297
+ * Draft commit policy. Card clicks still mutate the draft first;
1298
+ * `autoWhenReady` submits only once the full interaction draft validates.
1299
+ * Multi-value collectors created with `many(...)` are always manual draft
1300
+ * interactions and cannot opt into `autoWhenReady`.
1301
+ */
1302
+ commit?: InteractionCommitPolicyFor<Collectors>;
1303
+ actor?: ActorSelector<State, Manifest>;
1304
+ visibility?: "all" | "actorsOnly";
1305
+ errorCodes?: readonly string[];
1306
+ cost?: BivariantCallback<
1307
+ InteractionValidateArgs<
1308
+ Collectors & { cardId: InputCollector<SchemaLike<CardIdOfState<State>>> },
1309
+ State,
1310
+ Manifest
1311
+ >,
1312
+ Readonly<Record<string, number>>
1313
+ >;
1314
+ rules?: readonly InteractionRule<
1315
+ NoInfer<
1316
+ Collectors & {
1317
+ cardId: InputCollector<SchemaLike<CardIdOfState<State>>>;
1318
+ }
1319
+ >,
1320
+ State,
1321
+ Manifest
1322
+ >[];
1323
+ reduce: BivariantCallback<
1324
+ InteractionReduceArgs<
1325
+ Collectors & { cardId: InputCollector<SchemaLike<CardIdOfState<State>>> },
1326
+ State,
1327
+ Manifest
1328
+ >,
1329
+ ReducerResult<State>
1330
+ >;
1331
+ };
1332
+
1333
+ export type AnyCardActionSpec<
1334
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1335
+ Manifest extends ManifestContract<TableOfState<State>>,
1336
+ > = CardActionSpec<Record<string, InputCollector>, State, Manifest>;
1337
+
1338
+ export type CardActionMap<
1339
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1340
+ Manifest extends ManifestContract<TableOfState<State>>,
1341
+ > = Record<string, AnyCardActionSpec<State, Manifest>>;
1342
+
1343
+ /**
1344
+ * Type-safe erasure of {@link InteractionSpec} used by the runtime when it
1345
+ * stores heterogeneous interactions in a single map. The collectors generic
1346
+ * is erased to the structural upper bound (`Record<string, InputCollector>`)
1347
+ * so that lookups and metadata helpers can iterate collectors without
1348
+ * committing to a specific authoring-time shape.
1349
+ */
1350
+ export type AnyInteractionSpec<
1351
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1352
+ Manifest extends ManifestContract<TableOfState<State>>,
1353
+ > = InteractionSpec<Record<string, InputCollector>, State, Manifest>;
1354
+
1355
+ export type InteractionMap<
1356
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1357
+ Manifest extends ManifestContract<TableOfState<State>>,
1358
+ > = Record<string, AnyInteractionSpec<State, Manifest>>;
1359
+
1360
+ export type StageSpec<
1361
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1362
+ Manifest extends ManifestContract<TableOfState<State>>,
1363
+ > = {
1364
+ when?: BivariantCallback<
1365
+ ActionContext<State, Manifest> & { state: State },
1366
+ boolean
1367
+ >;
1368
+ onEnter?: BivariantCallback<
1369
+ PhaseEnterArgs<State, Manifest>,
1370
+ ReducerResult<State> | void
1371
+ >;
1372
+ onExit?: BivariantCallback<
1373
+ PhaseEnterArgs<State, Manifest>,
1374
+ ReducerResult<State> | void
1375
+ >;
1376
+ allow: readonly string[];
1377
+ };
1378
+
1379
+ export type StageMap<
1380
+ State extends { table: RuntimeTableRecord; flow: { currentPhase: string } },
1381
+ Manifest extends ManifestContract<TableOfState<State>>,
1382
+ > = Record<string, StageSpec<State, Manifest>>;
1383
+
1384
+ export type PhaseZoneList<
1385
+ Manifest extends ManifestContract<RuntimeTableRecord>,
1386
+ > = readonly PlayerZoneIdOfManifest<Manifest>[];