@dreamboard-games/sdk 0.2.1-alpha.1 → 0.3.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (372) hide show
  1. package/dist/{HandView-ncJIVLhN.d.ts → HandView-PYDmehVD.d.ts} +1 -1
  2. package/dist/{ResourceCounter-CTREyF73.d.ts → ResourceCounter-BTXklCEZ.d.ts} +1 -1
  3. package/dist/{ThemeProvider-BBMVT3KG.d.ts → ThemeProvider-DvMl17Ny.d.ts} +1 -1
  4. package/dist/{chunk-NKCRKGR2.js → chunk-3RQEICD3.js} +2 -2
  5. package/dist/{chunk-ZABVH7AO.js → chunk-ADYH6PVT.js} +1336 -1363
  6. package/dist/chunk-ADYH6PVT.js.map +1 -0
  7. package/dist/{chunk-PEI3FIL2.js → chunk-P7VMTJ5D.js} +2 -2
  8. package/dist/{chunk-PEI3FIL2.js.map → chunk-P7VMTJ5D.js.map} +1 -1
  9. package/dist/{chunk-WG4JQL3S.js → chunk-QZ6X4B5P.js} +1177 -1109
  10. package/dist/chunk-QZ6X4B5P.js.map +1 -0
  11. package/dist/{chunk-MZNVHMJ5.js → chunk-TXXLS3OI.js} +405 -309
  12. package/dist/chunk-TXXLS3OI.js.map +1 -0
  13. package/dist/{chunk-FDNZTDD6.js → chunk-W6SGFWXH.js} +48 -44
  14. package/dist/chunk-W6SGFWXH.js.map +1 -0
  15. package/dist/{chunk-MKXPVOUT.js → chunk-Y2AFYBMB.js} +48 -4
  16. package/dist/chunk-Y2AFYBMB.js.map +1 -0
  17. package/dist/{index-BwqPQtBu.d.ts → codegen.d.ts} +57 -565
  18. package/dist/{infrastructure/workspace-codegen.js → codegen.js} +3 -3
  19. package/dist/{components-BoiVSYqx.d.ts → components-DaIqi9QM.d.ts} +48 -37
  20. package/dist/{hex-board-view-1iAyJRFn.d.ts → hex-board-view-UCUjMALd.d.ts} +2 -2
  21. package/dist/{infrastructure/reducer-bundle-abi.d.ts → index.d-BGqVifr_.d.ts} +289 -10
  22. package/dist/index.js +1 -1
  23. package/dist/package-set.d.ts +2 -2
  24. package/dist/package-set.js +1 -1
  25. package/dist/primitive-props-BNHDkgd7.d.ts +16 -0
  26. package/dist/reducer-contract.d.ts +3 -0
  27. package/dist/{infrastructure/reducer-bundle-abi.js → reducer-contract.js} +4 -4
  28. package/dist/reducer.d.ts +185 -179
  29. package/dist/reducer.js +1363 -1372
  30. package/dist/reducer.js.map +1 -1
  31. package/dist/runtime/primitives.d.ts +9 -9
  32. package/dist/runtime/primitives.js +7 -7
  33. package/dist/runtime/runtime-api.d.ts +2 -0
  34. package/dist/runtime/runtime-api.js +1 -0
  35. package/dist/runtime/workspace-contract.d.ts +62 -17
  36. package/dist/runtime/workspace-contract.js +5 -6
  37. package/dist/{runtime-api-CPLm_XDG.d.ts → runtime-api-tGL3ArsB.d.ts} +103 -4
  38. package/dist/runtime.d.ts +11 -57
  39. package/dist/runtime.js +487 -8
  40. package/dist/runtime.js.map +1 -1
  41. package/dist/testing.d.ts +4 -4
  42. package/dist/testing.js.map +1 -1
  43. package/dist/types.d.ts +1531 -85
  44. package/dist/types.js +1 -3
  45. package/dist/types.js.map +1 -1
  46. package/dist/ui/components.d.ts +7 -8
  47. package/dist/ui/components.js +1 -1
  48. package/dist/ui/defaults.d.ts +1 -1
  49. package/dist/ui/{types/player-state.d.ts → player-state.d.ts} +2 -2
  50. package/dist/{ui-contract-rzKBwOLC.d.ts → ui-contract-SctM4ibF.d.ts} +155 -150
  51. package/dist/ui.d.ts +10 -11
  52. package/dist/ui.js +2 -2
  53. package/package.json +30 -75
  54. package/dist/bundle-CDd5FKeD.d.ts +0 -283
  55. package/dist/cards-Sl3b40Mv.d.ts +0 -13
  56. package/dist/chunk-326PGVAA.js +0 -34
  57. package/dist/chunk-326PGVAA.js.map +0 -1
  58. package/dist/chunk-FDNZTDD6.js.map +0 -1
  59. package/dist/chunk-I46YJSOD.js +0 -1
  60. package/dist/chunk-MKXPVOUT.js.map +0 -1
  61. package/dist/chunk-MZNVHMJ5.js.map +0 -1
  62. package/dist/chunk-T52J5RMF.js +0 -1
  63. package/dist/chunk-WG4JQL3S.js.map +0 -1
  64. package/dist/chunk-XV6D3ET4.js +0 -485
  65. package/dist/chunk-XV6D3ET4.js.map +0 -1
  66. package/dist/chunk-ZABVH7AO.js.map +0 -1
  67. package/dist/generated/runtime/primitives.d.ts +0 -13
  68. package/dist/generated/runtime/primitives.js +0 -181
  69. package/dist/generated/runtime/primitives.js.map +0 -1
  70. package/dist/generated/runtime-api.d.ts +0 -3
  71. package/dist/generated/runtime-api.js +0 -2
  72. package/dist/generated/runtime.d.ts +0 -15
  73. package/dist/generated/runtime.js +0 -19
  74. package/dist/generated/runtime.js.map +0 -1
  75. package/dist/generated/workspace-contract.d.ts +0 -15
  76. package/dist/generated/workspace-contract.js +0 -15
  77. package/dist/generated/workspace-contract.js.map +0 -1
  78. package/dist/infrastructure/reducer-bundle-abi.js.map +0 -1
  79. package/dist/infrastructure/workspace-codegen.d.ts +0 -53
  80. package/dist/infrastructure/workspace-codegen.js.map +0 -1
  81. package/dist/manifest-contract-BNHVGFtU.d.ts +0 -9
  82. package/dist/primitive-props-DpKs-GCr.d.ts +0 -11
  83. package/dist/runtime/types/runtime-api.d.ts +0 -1
  84. package/dist/runtime/types/runtime-api.js +0 -2
  85. package/dist/runtime/types/runtime-api.js.map +0 -1
  86. package/dist/runtime-api-3dshj6kK.d.ts +0 -101
  87. package/dist/slots-1GPGihk8.d.ts +0 -8
  88. package/src/browser-interaction/attributes.ts +0 -211
  89. package/src/browser-interaction/canonical.ts +0 -77
  90. package/src/browser-interaction/constants.ts +0 -77
  91. package/src/browser-interaction/effects.ts +0 -176
  92. package/src/browser-interaction/index.ts +0 -111
  93. package/src/browser-interaction/normalize.ts +0 -997
  94. package/src/browser-interaction/registry.ts +0 -70
  95. package/src/browser-interaction/resolve.ts +0 -596
  96. package/src/browser-interaction/schemas.ts +0 -152
  97. package/src/browser-interaction/types.ts +0 -304
  98. package/src/browser-interaction.ts +0 -1
  99. package/src/generated/reducer-contract/builders.ts +0 -90
  100. package/src/generated/reducer-contract/version.ts +0 -9
  101. package/src/generated/reducer-contract/wire.ts +0 -100
  102. package/src/generated/reducer-contract/zod.ts +0 -103
  103. package/src/generated/runtime/primitives.ts +0 -2
  104. package/src/generated/runtime-api.ts +0 -5
  105. package/src/generated/runtime.ts +0 -35
  106. package/src/generated/workspace-contract.ts +0 -2
  107. package/src/index.ts +0 -7
  108. package/src/infrastructure/reducer-bundle-abi.ts +0 -8
  109. package/src/infrastructure/reducer-contract/bundle.ts +0 -37
  110. package/src/infrastructure/workspace-codegen/hex-geometry.ts +0 -69
  111. package/src/infrastructure/workspace-codegen/index.ts +0 -64
  112. package/src/infrastructure/workspace-codegen/manifest-contract.ts +0 -6632
  113. package/src/infrastructure/workspace-codegen/manifest-validation.ts +0 -795
  114. package/src/infrastructure/workspace-codegen/ownership.ts +0 -131
  115. package/src/infrastructure/workspace-codegen/preset-card-sets.ts +0 -169
  116. package/src/infrastructure/workspace-codegen/seeds.ts +0 -1705
  117. package/src/infrastructure/workspace-codegen.ts +0 -1
  118. package/src/package-set.ts +0 -19
  119. package/src/reducer/authoring/contract.ts +0 -157
  120. package/src/reducer/authoring/effect.ts +0 -224
  121. package/src/reducer/authoring/game.ts +0 -23
  122. package/src/reducer/authoring/interaction.ts +0 -98
  123. package/src/reducer/authoring/phase.ts +0 -300
  124. package/src/reducer/authoring/types.ts +0 -70
  125. package/src/reducer/authoring/validation.ts +0 -382
  126. package/src/reducer/authoring/view-stage.ts +0 -68
  127. package/src/reducer/authoring.ts +0 -29
  128. package/src/reducer/bundle/ingress-bundle.ts +0 -491
  129. package/src/reducer/bundle/trusted/engine-instruction-resolver.ts +0 -254
  130. package/src/reducer/bundle/trusted/flow-instruction-resolver.ts +0 -73
  131. package/src/reducer/bundle/trusted/instruction-runner.ts +0 -414
  132. package/src/reducer/bundle/trusted/interaction-authorization.ts +0 -137
  133. package/src/reducer/bundle/trusted/interaction-collectors.ts +0 -859
  134. package/src/reducer/bundle/trusted/interaction-decision.ts +0 -747
  135. package/src/reducer/bundle/trusted/interaction-resolver.ts +0 -95
  136. package/src/reducer/bundle/trusted/interaction-types.ts +0 -174
  137. package/src/reducer/bundle/trusted/lifecycle-runner.ts +0 -427
  138. package/src/reducer/bundle/trusted/projection-builder.ts +0 -680
  139. package/src/reducer/bundle/trusted/projection-context.ts +0 -39
  140. package/src/reducer/bundle/trusted/rng-sampler.ts +0 -150
  141. package/src/reducer/bundle/trusted/runtime-registry.ts +0 -120
  142. package/src/reducer/bundle/trusted/runtime-scope.ts +0 -336
  143. package/src/reducer/bundle/trusted/simultaneous-player.ts +0 -97
  144. package/src/reducer/bundle/trusted/stage-resolver.ts +0 -87
  145. package/src/reducer/bundle/trusted/static-projection.ts +0 -116
  146. package/src/reducer/bundle/trusted/trusted-runtime-args.ts +0 -97
  147. package/src/reducer/bundle/trusted/trusted-runtime-result.ts +0 -39
  148. package/src/reducer/bundle/trusted/trusted-setup-profiles.ts +0 -43
  149. package/src/reducer/bundle/trusted/trusted-state-codec.ts +0 -48
  150. package/src/reducer/bundle/trusted-bundle.ts +0 -97
  151. package/src/reducer/bundle/types.ts +0 -171
  152. package/src/reducer/bundle.ts +0 -2
  153. package/src/reducer/client-param-schemas.ts +0 -57
  154. package/src/reducer/compose.ts +0 -34
  155. package/src/reducer/core/runtime-input.ts +0 -30
  156. package/src/reducer/core/runtime-instruction.ts +0 -59
  157. package/src/reducer/core/types.ts +0 -62
  158. package/src/reducer/definition-index.ts +0 -277
  159. package/src/reducer/derived.ts +0 -106
  160. package/src/reducer/effects.ts +0 -92
  161. package/src/reducer/engine/runtime-instruction-engine.ts +0 -155
  162. package/src/reducer/ingress/decode-runtime-input.ts +0 -7
  163. package/src/reducer/ingress/decode-session-state.ts +0 -9
  164. package/src/reducer/ingress/encode-session-state.ts +0 -6
  165. package/src/reducer/ingress/input-codec.ts +0 -18
  166. package/src/reducer/ingress/phase-schemas.ts +0 -62
  167. package/src/reducer/ingress/raw-types.ts +0 -107
  168. package/src/reducer/ingress/runtime-codec.ts +0 -14
  169. package/src/reducer/ingress/runtime-payload.ts +0 -13
  170. package/src/reducer/ingress/session-codec.ts +0 -392
  171. package/src/reducer/ingress/types.ts +0 -6
  172. package/src/reducer/inputs/boardInput.ts +0 -217
  173. package/src/reducer/inputs/boardTarget.ts +0 -190
  174. package/src/reducer/inputs/cardInput.ts +0 -86
  175. package/src/reducer/inputs/cardTarget.ts +0 -101
  176. package/src/reducer/inputs/choiceTarget.ts +0 -104
  177. package/src/reducer/inputs/defineInputs.ts +0 -71
  178. package/src/reducer/inputs/formInput.ts +0 -809
  179. package/src/reducer/inputs/many.ts +0 -120
  180. package/src/reducer/inputs/promptInput.ts +0 -87
  181. package/src/reducer/inputs/rngInput.ts +0 -58
  182. package/src/reducer/inputs/targetRule.ts +0 -123
  183. package/src/reducer/inputs.ts +0 -41
  184. package/src/reducer/model/definition.ts +0 -1072
  185. package/src/reducer/model/extract.ts +0 -745
  186. package/src/reducer/model/manifest.ts +0 -570
  187. package/src/reducer/model/queries.ts +0 -641
  188. package/src/reducer/model/runtime.ts +0 -264
  189. package/src/reducer/model/spec.ts +0 -1386
  190. package/src/reducer/model/table.ts +0 -260
  191. package/src/reducer/model.ts +0 -7
  192. package/src/reducer/ops.ts +0 -1034
  193. package/src/reducer/parse-utils.ts +0 -28
  194. package/src/reducer/per-player.ts +0 -422
  195. package/src/reducer/rng.ts +0 -69
  196. package/src/reducer/schema-helpers.ts +0 -185
  197. package/src/reducer/setup-bootstrap-helpers.ts +0 -171
  198. package/src/reducer/setup-bootstrap.ts +0 -481
  199. package/src/reducer/table-ops.ts +0 -2671
  200. package/src/reducer/table-queries.ts +0 -372
  201. package/src/reducer/transaction.ts +0 -120
  202. package/src/reducer.ts +0 -314
  203. package/src/runtime/primitives.ts +0 -1
  204. package/src/runtime/types/runtime-api.ts +0 -1
  205. package/src/runtime/workspace-contract.ts +0 -32
  206. package/src/runtime-internal/components/InteractionForm.tsx +0 -1647
  207. package/src/runtime-internal/components/PluginRuntime.tsx +0 -105
  208. package/src/runtime-internal/components/board/target-layer.ts +0 -72
  209. package/src/runtime-internal/context/ClientParamSchemaContext.tsx +0 -44
  210. package/src/runtime-internal/context/InteractionDraftContext.tsx +0 -279
  211. package/src/runtime-internal/context/PluginSessionContext.tsx +0 -47
  212. package/src/runtime-internal/context/PluginStateContext.tsx +0 -303
  213. package/src/runtime-internal/context/RuntimeContext.tsx +0 -96
  214. package/src/runtime-internal/defaults/components.tsx +0 -409
  215. package/src/runtime-internal/defaults/index.ts +0 -11
  216. package/src/runtime-internal/errors/ValidationError.ts +0 -29
  217. package/src/runtime-internal/hooks/useActivePlayers.ts +0 -33
  218. package/src/runtime-internal/hooks/useBoardInteractions.ts +0 -727
  219. package/src/runtime-internal/hooks/useGameSelector.ts +0 -105
  220. package/src/runtime-internal/hooks/useGameView.ts +0 -9
  221. package/src/runtime-internal/hooks/useInteractionByKey.ts +0 -354
  222. package/src/runtime-internal/hooks/useInteractionHandle.ts +0 -438
  223. package/src/runtime-internal/hooks/useIsMyTurn.ts +0 -20
  224. package/src/runtime-internal/hooks/useLobby.ts +0 -76
  225. package/src/runtime-internal/hooks/useMe.ts +0 -48
  226. package/src/runtime-internal/hooks/usePlayerInfo.ts +0 -28
  227. package/src/runtime-internal/hooks/usePlayerTurnOrder.ts +0 -23
  228. package/src/runtime-internal/hooks/usePluginRuntime.ts +0 -147
  229. package/src/runtime-internal/hooks/useSeatInbox.ts +0 -61
  230. package/src/runtime-internal/hooks/useSimultaneousPhase.ts +0 -10
  231. package/src/runtime-internal/index.ts +0 -42
  232. package/src/runtime-internal/internal.ts +0 -43
  233. package/src/runtime-internal/plugin-styles.css +0 -250
  234. package/src/runtime-internal/primitives/board.tsx +0 -530
  235. package/src/runtime-internal/primitives/dialog-lifecycle.ts +0 -58
  236. package/src/runtime-internal/primitives/dice.tsx +0 -79
  237. package/src/runtime-internal/primitives/game-ui-provider.tsx +0 -35
  238. package/src/runtime-internal/primitives/game.tsx +0 -387
  239. package/src/runtime-internal/primitives/hand-intent-adapter.ts +0 -147
  240. package/src/runtime-internal/primitives/hand-surface.tsx +0 -594
  241. package/src/runtime-internal/primitives/index.ts +0 -196
  242. package/src/runtime-internal/primitives/interaction-form-binding.tsx +0 -56
  243. package/src/runtime-internal/primitives/interaction-submit.ts +0 -90
  244. package/src/runtime-internal/primitives/interaction.tsx +0 -1146
  245. package/src/runtime-internal/primitives/phase.tsx +0 -43
  246. package/src/runtime-internal/primitives/player-roster.tsx +0 -302
  247. package/src/runtime-internal/primitives/primitive-props.tsx +0 -101
  248. package/src/runtime-internal/primitives/prompt.tsx +0 -255
  249. package/src/runtime-internal/primitives/ui.tsx +0 -60
  250. package/src/runtime-internal/primitives/zone.tsx +0 -791
  251. package/src/runtime-internal/reducer.ts +0 -30
  252. package/src/runtime-internal/runtime/createPluginRuntimeAPI.ts +0 -605
  253. package/src/runtime-internal/types/plugin-state.ts +0 -514
  254. package/src/runtime-internal/types/reducer-state.ts +0 -24
  255. package/src/runtime-internal/types/runtime-api.ts +0 -114
  256. package/src/runtime-internal/ui-contract.ts +0 -519
  257. package/src/runtime-internal/utils/browser-interaction-effects.ts +0 -240
  258. package/src/runtime-internal/utils/card-intent-adapter.ts +0 -546
  259. package/src/runtime-internal/utils/interaction-draft-digest.ts +0 -252
  260. package/src/runtime-internal/utils/interaction-inputs.ts +0 -492
  261. package/src/runtime-internal/utils/interaction-labels.ts +0 -23
  262. package/src/runtime-internal/utils/interaction-router.ts +0 -273
  263. package/src/runtime-internal/utils/interaction-status.ts +0 -74
  264. package/src/runtime-internal/utils/semantic-projection-digest.ts +0 -407
  265. package/src/runtime-internal/workspace-contract.ts +0 -1170
  266. package/src/runtime.ts +0 -34
  267. package/src/testing/create-expect-api.ts +0 -352
  268. package/src/testing/create-test-runtime.ts +0 -381
  269. package/src/testing/definitions.ts +0 -127
  270. package/src/testing/index.ts +0 -3
  271. package/src/testing.ts +0 -1
  272. package/src/type-stubs/manifest-contract.d.ts +0 -42
  273. package/src/type-stubs/manifest-contract.js +0 -72
  274. package/src/type-stubs/ui-contract.d.ts +0 -5
  275. package/src/type-stubs/ui-contract.js +0 -1
  276. package/src/types/authoring-card-properties.type-test.ts +0 -266
  277. package/src/types/authoring.ts +0 -1282
  278. package/src/types/cards.ts +0 -19
  279. package/src/types/contracts.ts +0 -1550
  280. package/src/types/generated-helpers.ts +0 -35
  281. package/src/types/index.ts +0 -147
  282. package/src/types/slots.ts +0 -11
  283. package/src/types.ts +0 -1
  284. package/src/ui/components/ActionButton.tsx +0 -97
  285. package/src/ui/components/ActionPanel.tsx +0 -315
  286. package/src/ui/components/Card.tsx +0 -378
  287. package/src/ui/components/CardDragSurface.tsx +0 -1076
  288. package/src/ui/components/ChromeSuppressionContext.tsx +0 -70
  289. package/src/ui/components/CostDisplay.tsx +0 -145
  290. package/src/ui/components/DiceRoller.tsx +0 -581
  291. package/src/ui/components/Drawer.tsx +0 -180
  292. package/src/ui/components/ErrorBoundary.tsx +0 -275
  293. package/src/ui/components/GameEndDisplay.tsx +0 -398
  294. package/src/ui/components/GameSkeleton.tsx +0 -260
  295. package/src/ui/components/Hand.tsx +0 -468
  296. package/src/ui/components/HandDock.tsx +0 -299
  297. package/src/ui/components/HandView.tsx +0 -441
  298. package/src/ui/components/MobileHandTray.tsx +0 -381
  299. package/src/ui/components/MoreActions.tsx +0 -143
  300. package/src/ui/components/PhaseIndicator.tsx +0 -341
  301. package/src/ui/components/PlayArea.tsx +0 -146
  302. package/src/ui/components/PrimaryActionButton.tsx +0 -336
  303. package/src/ui/components/PrimaryButton.tsx +0 -45
  304. package/src/ui/components/ResourceCounter.tsx +0 -270
  305. package/src/ui/components/StagingZone.tsx +0 -134
  306. package/src/ui/components/ThemedButton.tsx +0 -113
  307. package/src/ui/components/Toast.tsx +0 -264
  308. package/src/ui/components/board/HexGrid.tsx +0 -1297
  309. package/src/ui/components/board/NetworkGraph.tsx +0 -476
  310. package/src/ui/components/board/SlotSystem.tsx +0 -388
  311. package/src/ui/components/board/SquareGrid.tsx +0 -1165
  312. package/src/ui/components/board/TrackBoard.tsx +0 -496
  313. package/src/ui/components/board/ZoneMap.tsx +0 -448
  314. package/src/ui/components/board/hex-board-view.ts +0 -123
  315. package/src/ui/components/board/index.ts +0 -142
  316. package/src/ui/components/board/interaction-accessibility.ts +0 -21
  317. package/src/ui/components/board/target-layer.ts +0 -67
  318. package/src/ui/components/card-render-content.type-test.ts +0 -27
  319. package/src/ui/components/hand-layout-math.ts +0 -163
  320. package/src/ui/components/hand-pointer-engine.ts +0 -413
  321. package/src/ui/components/index.ts +0 -245
  322. package/src/ui/components.ts +0 -1
  323. package/src/ui/defaults/components.tsx +0 -106
  324. package/src/ui/defaults/index.ts +0 -8
  325. package/src/ui/defaults.ts +0 -1
  326. package/src/ui/errors/ValidationError.ts +0 -29
  327. package/src/ui/helpers/cards.ts +0 -19
  328. package/src/ui/helpers/track-board.ts +0 -211
  329. package/src/ui/hooks/useBoardTopology.ts +0 -316
  330. package/src/ui/hooks/useCards.ts +0 -10
  331. package/src/ui/hooks/useHandCardPointer.ts +0 -381
  332. package/src/ui/hooks/useHandLayout.ts +0 -378
  333. package/src/ui/hooks/useHandPresentation.ts +0 -121
  334. package/src/ui/hooks/useHexBoard.ts +0 -74
  335. package/src/ui/hooks/useHexGrid.ts +0 -185
  336. package/src/ui/hooks/useIsMobile.ts +0 -35
  337. package/src/ui/hooks/usePanZoom.ts +0 -278
  338. package/src/ui/hooks/useSquareBoard.ts +0 -124
  339. package/src/ui/hooks/useSquareGrid.ts +0 -328
  340. package/src/ui/index.ts +0 -98
  341. package/src/ui/internal/ui/alert.tsx +0 -51
  342. package/src/ui/internal/ui/button.tsx +0 -58
  343. package/src/ui/internal/ui/dialog.tsx +0 -134
  344. package/src/ui/internal/ui/input.tsx +0 -21
  345. package/src/ui/internal/ui/label.tsx +0 -21
  346. package/src/ui/internal/ui/select.tsx +0 -129
  347. package/src/ui/internal/ui/tooltip.tsx +0 -54
  348. package/src/ui/internal/ui/utils.ts +0 -5
  349. package/src/ui/plugin-styles.css +0 -250
  350. package/src/ui/primitives/dialog-lifecycle.ts +0 -58
  351. package/src/ui/primitives/dice.tsx +0 -79
  352. package/src/ui/primitives/primitive-props.tsx +0 -101
  353. package/src/ui/theme/ThemeProvider.tsx +0 -252
  354. package/src/ui/theme/board.ts +0 -61
  355. package/src/ui/theme/css-vars.ts +0 -105
  356. package/src/ui/theme/derive.ts +0 -240
  357. package/src/ui/theme/index.ts +0 -61
  358. package/src/ui/theme/presets/arcade.ts +0 -261
  359. package/src/ui/theme/presets/studio.ts +0 -261
  360. package/src/ui/theme/presets/tabletop.ts +0 -266
  361. package/src/ui/theme/tokens.ts +0 -392
  362. package/src/ui/types/hex-color.ts +0 -20
  363. package/src/ui/types/player-state.ts +0 -463
  364. package/src/ui/types/tiled-board.ts +0 -785
  365. package/src/ui/types/visual-state.ts +0 -137
  366. package/src/ui.ts +0 -1
  367. /package/dist/{chunk-NKCRKGR2.js.map → chunk-3RQEICD3.js.map} +0 -0
  368. /package/dist/{chunk-I46YJSOD.js.map → codegen.js.map} +0 -0
  369. /package/dist/{chunk-T52J5RMF.js.map → reducer-contract.js.map} +0 -0
  370. /package/dist/{generated → runtime}/runtime-api.js.map +0 -0
  371. /package/dist/ui/{types/player-state.js → player-state.js} +0 -0
  372. /package/dist/ui/{types/player-state.js.map → player-state.js.map} +0 -0
package/dist/reducer.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  REDUCER_CONTRACT_VERSION,
3
- ReducerSessionStateSchema
4
- } from "./chunk-MKXPVOUT.js";
3
+ builders_exports,
4
+ zod_exports
5
+ } from "./chunk-Y2AFYBMB.js";
5
6
  import "./chunk-PZ5AY32C.js";
6
7
 
7
8
  // src/reducer/model/manifest.ts
@@ -1748,7 +1749,7 @@ function createRuntimeInstructionEngine({
1748
1749
  };
1749
1750
  }
1750
1751
 
1751
- // src/reducer/table-ops.ts
1752
+ // src/reducer/table/internal.ts
1752
1753
  function ppRead(value, playerId) {
1753
1754
  if (value === void 0) return void 0;
1754
1755
  return perPlayerGet(value, playerId);
@@ -1768,9 +1769,6 @@ function orderedComponentIdsForLocation(table, predicate) {
1768
1769
  (left, right) => locationPosition(left[1]) - locationPosition(right[1])
1769
1770
  ).map(([componentId]) => componentId);
1770
1771
  }
1771
- function allowedCardSetIdsForZone(table, zoneId) {
1772
- return table.zones.cardSetIdsByZoneId?.[zoneId] ?? [];
1773
- }
1774
1772
  function hasOwnKey(record, key) {
1775
1773
  return Object.prototype.hasOwnProperty.call(record, key);
1776
1774
  }
@@ -1803,51 +1801,24 @@ function assertZoneScope(table, zoneId, expectedScope, operation, argumentName)
1803
1801
  `Zone '${zoneId}' has scope '${actualScope}', but ${operation} requires ${argumentName} to be a ${expectedScope === "shared" ? "shared" : "perPlayer"} zone.`
1804
1802
  );
1805
1803
  }
1806
- function matchesSlotHost(location, host, slotId) {
1807
- return location.type === "InSlot" && location.host.kind === host.kind && location.host.id === host.id && (slotId === void 0 || location.slotId === slotId);
1808
- }
1809
- function componentPlayerId(table, componentId) {
1810
- const piece = table.pieces[componentId];
1811
- if (piece) {
1812
- return piece.ownerId ?? null;
1813
- }
1814
- const die = table.dice[componentId];
1815
- if (die) {
1816
- return die.ownerId ?? null;
1817
- }
1818
- const owner = table.ownerOfCard[componentId];
1819
- if (owner !== void 0) {
1820
- return owner ?? null;
1821
- }
1822
- return null;
1823
- }
1824
- function componentData(table, componentId) {
1825
- const piece = table.pieces[componentId];
1826
- if (piece) {
1827
- return piece.properties;
1828
- }
1829
- const die = table.dice[componentId];
1830
- if (die) {
1831
- return die.properties;
1832
- }
1833
- const card = table.cards[componentId];
1834
- if (card) {
1835
- return card.properties;
1836
- }
1837
- return void 0;
1804
+ function syncSharedZoneWithDeck(table, zoneId, nextCards) {
1805
+ table.decks[zoneId] = [...nextCards];
1806
+ table.zones.shared[zoneId] = [
1807
+ ...nextCards
1808
+ ];
1838
1809
  }
1839
- function assertCardAllowedInZone(table, zoneId, componentId) {
1840
- const card = table.cards[componentId];
1841
- if (!card) {
1842
- return;
1843
- }
1844
- const allowedCardSetIds = allowedCardSetIdsForZone(table, zoneId);
1845
- if (allowedCardSetIds.length > 0 && !allowedCardSetIds.includes(card.cardSetId)) {
1846
- throw new Error(
1847
- `Card '${componentId}' from card set '${card.cardSetId}' cannot enter zone '${zoneId}'.`
1848
- );
1849
- }
1810
+ function syncPlayerZoneWithHand(table, zoneId, playerId, nextCards) {
1811
+ table.hands[zoneId] = ppWrite(table.hands[zoneId], playerId, [
1812
+ ...nextCards
1813
+ ]);
1814
+ table.zones.perPlayer[zoneId] = ppWrite(
1815
+ table.zones.perPlayer[zoneId],
1816
+ playerId,
1817
+ [...nextCards]
1818
+ );
1850
1819
  }
1820
+
1821
+ // src/reducer/table/clone.ts
1851
1822
  function cloneRuntimeBoardState(board) {
1852
1823
  if (board.layout !== "generic") {
1853
1824
  return {
@@ -1991,623 +1962,251 @@ function cloneRuntimeTable(table) {
1991
1962
  )
1992
1963
  };
1993
1964
  }
1994
- function syncSharedZoneWithDeck(table, zoneId, nextCards) {
1995
- table.decks[zoneId] = [...nextCards];
1996
- table.zones.shared[zoneId] = [
1997
- ...nextCards
1998
- ];
1965
+
1966
+ // src/reducer/table/board-queries.ts
1967
+ function getBoard(table, boardId) {
1968
+ return table.boards.byId[boardId];
1999
1969
  }
2000
- function shufflePlayerZoneCards(table, zoneId, playerId, nextCards) {
2001
- if (nextCards === void 0) {
2002
- const fromZone = ppRead(
2003
- table.zones.perPlayer[zoneId] ?? table.hands[zoneId],
2004
- playerId
2005
- );
2006
- return [...ensureArray(fromZone)];
1970
+ function getHexBoard(table, boardId) {
1971
+ return getBoard(table, boardId);
1972
+ }
1973
+ function getTiledBoard(table, boardId) {
1974
+ return getBoard(table, boardId);
1975
+ }
1976
+ function getSquareBoard(table, boardId) {
1977
+ return getBoard(table, boardId);
1978
+ }
1979
+ function getSpace(table, boardId, spaceId) {
1980
+ return getBoard(table, boardId).spaces[spaceId];
1981
+ }
1982
+ function getHexSpace(table, boardId, spaceId) {
1983
+ return getHexBoard(table, boardId).spaces[spaceId];
1984
+ }
1985
+ function getSquareSpace(table, boardId, spaceId) {
1986
+ return getSquareBoard(table, boardId).spaces[spaceId];
1987
+ }
1988
+ function getContainer(table, boardId, containerId) {
1989
+ return getBoard(table, boardId).containers[containerId];
1990
+ }
1991
+ function getEdge(table, boardId, edgeId) {
1992
+ const edge = getTiledBoard(table, boardId).edges.find(
1993
+ (candidate) => candidate.id === edgeId
1994
+ );
1995
+ if (!edge) {
1996
+ throw new Error(`Unknown edge '${edgeId}' on board '${boardId}'.`);
2007
1997
  }
2008
- table.hands[zoneId] = ppWrite(table.hands[zoneId], playerId, [
2009
- ...nextCards
2010
- ]);
2011
- table.zones.perPlayer[zoneId] = ppWrite(
2012
- table.zones.perPlayer[zoneId],
2013
- playerId,
2014
- [...nextCards]
1998
+ return edge;
1999
+ }
2000
+ function getVertex(table, boardId, vertexId) {
2001
+ const vertex = getTiledBoard(table, boardId).vertices.find(
2002
+ (candidate) => candidate.id === vertexId
2015
2003
  );
2016
- return [...nextCards];
2004
+ if (!vertex) {
2005
+ throw new Error(`Unknown vertex '${vertexId}' on board '${boardId}'.`);
2006
+ }
2007
+ return vertex;
2017
2008
  }
2018
- function syncPlayerZoneWithHand(table, zoneId, playerId, nextCards) {
2019
- table.hands[zoneId] = ppWrite(table.hands[zoneId], playerId, [
2020
- ...nextCards
2021
- ]);
2022
- table.zones.perPlayer[zoneId] = ppWrite(
2023
- table.zones.perPlayer[zoneId],
2024
- playerId,
2025
- [...nextCards]
2009
+ function getHexSpaceAt(table, boardId, q, r) {
2010
+ return Object.values(getHexBoard(table, boardId).spaces).find(
2011
+ (space) => space.q === q && space.r === r
2026
2012
  );
2027
2013
  }
2028
- function reindexSpaceOccupants(table, boardId, spaceId) {
2029
- getComponentsOnSpace(table, boardId, spaceId).forEach(
2030
- (componentId, index) => {
2031
- const location = table.componentLocations[componentId];
2032
- if (location?.type === "OnSpace") {
2033
- table.componentLocations[componentId] = {
2034
- ...location,
2035
- position: index
2036
- };
2037
- }
2038
- }
2014
+ function getSquareSpaceAt(table, boardId, row, col) {
2015
+ return Object.values(getSquareBoard(table, boardId).spaces).find(
2016
+ (space) => space.row === row && space.col === col
2039
2017
  );
2040
2018
  }
2041
- function reindexContainerOccupants(table, boardId, containerId) {
2042
- getComponentsInContainer(table, boardId, containerId).forEach(
2043
- (componentId, index) => {
2044
- const location = table.componentLocations[componentId];
2045
- if (location?.type === "InContainer") {
2046
- table.componentLocations[componentId] = {
2047
- ...location,
2048
- position: index
2049
- };
2050
- }
2051
- }
2019
+ function getSpaceEdges(table, boardId, spaceId) {
2020
+ return getTiledBoard(table, boardId).edges.filter((edge) => edge.spaceIds.includes(spaceId)).map((edge) => edge.id);
2021
+ }
2022
+ function getSpaceVertices(table, boardId, spaceId) {
2023
+ return getTiledBoard(table, boardId).vertices.filter((vertex) => vertex.spaceIds.includes(spaceId)).map((vertex) => vertex.id);
2024
+ }
2025
+ function getIncidentEdges(table, boardId, vertexId) {
2026
+ const tiledBoard = getTiledBoard(table, boardId);
2027
+ const vertex = tiledBoard.vertices.find(
2028
+ (candidate) => candidate.id === vertexId
2052
2029
  );
2030
+ if (!vertex) {
2031
+ throw new Error(`Unknown vertex '${vertexId}' on board '${boardId}'.`);
2032
+ }
2033
+ const vertexSpaceIds = new Set(vertex.spaceIds);
2034
+ return tiledBoard.edges.filter(
2035
+ (edge) => edge.spaceIds.every((spaceId) => vertexSpaceIds.has(spaceId))
2036
+ ).map((edge) => edge.id);
2053
2037
  }
2054
- function reindexEdgeOccupants(table, boardId, edgeId) {
2055
- orderedComponentIdsForLocation(
2056
- table,
2057
- (location) => location.type === "OnEdge" && location.boardId === boardId && location.edgeId === edgeId
2058
- ).forEach((componentId, index) => {
2059
- const location = table.componentLocations[componentId];
2060
- if (location?.type === "OnEdge") {
2061
- table.componentLocations[componentId] = {
2062
- ...location,
2063
- position: index
2064
- };
2065
- }
2066
- });
2038
+ function getIncidentVertices(table, boardId, edgeId) {
2039
+ const tiledBoard = getTiledBoard(table, boardId);
2040
+ const edge = tiledBoard.edges.find((candidate) => candidate.id === edgeId);
2041
+ if (!edge) {
2042
+ throw new Error(`Unknown edge '${edgeId}' on board '${boardId}'.`);
2043
+ }
2044
+ const edgeSpaceIds = new Set(edge.spaceIds);
2045
+ return tiledBoard.vertices.filter(
2046
+ (vertex) => Array.from(edgeSpaceIds).every(
2047
+ (spaceId) => vertex.spaceIds.includes(spaceId)
2048
+ )
2049
+ ).map((vertex) => vertex.id);
2067
2050
  }
2068
- function reindexVertexOccupants(table, boardId, vertexId) {
2069
- orderedComponentIdsForLocation(
2070
- table,
2071
- (location) => location.type === "OnVertex" && location.boardId === boardId && location.vertexId === vertexId
2072
- ).forEach((componentId, index) => {
2073
- const location = table.componentLocations[componentId];
2074
- if (location?.type === "OnVertex") {
2075
- table.componentLocations[componentId] = {
2076
- ...location,
2077
- position: index
2078
- };
2051
+ function getRelatedSpaces(table, boardId, spaceId, relationTypeId) {
2052
+ const board = getBoard(table, boardId);
2053
+ const related = /* @__PURE__ */ new Set();
2054
+ for (const relation of board.relations) {
2055
+ if (relation.typeId !== relationTypeId) {
2056
+ continue;
2079
2057
  }
2080
- });
2058
+ if (relation.fromSpaceId === spaceId) {
2059
+ related.add(relation.toSpaceId);
2060
+ continue;
2061
+ }
2062
+ if (!relation.directed && relation.toSpaceId === spaceId) {
2063
+ related.add(relation.fromSpaceId);
2064
+ }
2065
+ }
2066
+ return [...related];
2081
2067
  }
2082
- function reindexSlotOccupants(table, host, slotId) {
2083
- orderedComponentIdsForLocation(
2068
+ function getAdjacentSpaces(table, boardId, spaceId) {
2069
+ return getRelatedSpaces(
2084
2070
  table,
2085
- (location) => location.type === "InSlot" && location.host.kind === host.kind && location.host.id === host.id && location.slotId === slotId
2086
- ).forEach((componentId, index) => {
2087
- const location = table.componentLocations[componentId];
2088
- if (location?.type === "InSlot") {
2089
- table.componentLocations[componentId] = {
2090
- ...location,
2091
- position: index
2092
- };
2093
- }
2094
- });
2071
+ boardId,
2072
+ spaceId,
2073
+ "adjacent"
2074
+ );
2095
2075
  }
2096
- function removeComponentFromCurrentLocation(table, componentId) {
2097
- const currentLocation = table.componentLocations[componentId];
2098
- if (!currentLocation) {
2099
- return;
2076
+ function getSpaceDistance(table, boardId, fromSpaceId, toSpaceId) {
2077
+ if (fromSpaceId === toSpaceId) {
2078
+ return 0;
2100
2079
  }
2101
- if (currentLocation.type === "InDeck") {
2102
- const nextCards = ensureArray(table.decks[currentLocation.deckId]).filter(
2103
- (candidate) => candidate !== componentId
2104
- );
2105
- syncSharedZoneWithDeck(
2106
- table,
2107
- currentLocation.deckId,
2108
- nextCards
2109
- );
2110
- nextCards.forEach((cardId, index) => {
2111
- const location = table.componentLocations[cardId];
2112
- if (location?.type === "InDeck") {
2113
- table.componentLocations[cardId] = {
2114
- ...location,
2115
- position: index
2116
- };
2117
- }
2118
- });
2119
- return;
2120
- }
2121
- if (currentLocation.type === "InHand") {
2122
- const nextCards = ensureArray(
2123
- ppRead(table.hands[currentLocation.handId], currentLocation.playerId)
2124
- ).filter((candidate) => candidate !== componentId);
2125
- syncPlayerZoneWithHand(
2126
- table,
2127
- currentLocation.handId,
2128
- currentLocation.playerId,
2129
- nextCards
2130
- );
2131
- nextCards.forEach((cardId, index) => {
2132
- const location = table.componentLocations[cardId];
2133
- if (location?.type === "InHand") {
2134
- table.componentLocations[cardId] = {
2135
- ...location,
2136
- position: index
2137
- };
2138
- }
2139
- });
2140
- return;
2141
- }
2142
- if (currentLocation.type === "OnSpace") {
2143
- delete table.componentLocations[componentId];
2144
- reindexSpaceOccupants(
2145
- table,
2146
- currentLocation.boardId,
2147
- currentLocation.spaceId
2148
- );
2149
- return;
2150
- }
2151
- if (currentLocation.type === "InZone") {
2152
- if (currentLocation.zoneId in table.zones.shared) {
2153
- const nextComponents = ensureArray(
2154
- table.zones.shared[currentLocation.zoneId]
2155
- ).filter((candidate) => candidate !== componentId);
2156
- syncSharedZoneWithDeck(
2157
- table,
2158
- currentLocation.zoneId,
2159
- nextComponents
2160
- );
2161
- nextComponents.forEach((currentComponentId, index) => {
2162
- const location = table.componentLocations[currentComponentId];
2163
- if (location?.type === "InZone") {
2164
- table.componentLocations[currentComponentId] = {
2165
- ...location,
2166
- position: index
2167
- };
2168
- }
2169
- });
2170
- }
2171
- delete table.componentLocations[componentId];
2172
- return;
2173
- }
2174
- if (currentLocation.type === "InContainer") {
2175
- delete table.componentLocations[componentId];
2176
- reindexContainerOccupants(
2177
- table,
2178
- currentLocation.boardId,
2179
- currentLocation.containerId
2180
- );
2181
- return;
2182
- }
2183
- if (currentLocation.type === "OnEdge") {
2184
- delete table.componentLocations[componentId];
2185
- reindexEdgeOccupants(
2186
- table,
2187
- currentLocation.boardId,
2188
- currentLocation.edgeId
2189
- );
2190
- return;
2191
- }
2192
- if (currentLocation.type === "OnVertex") {
2193
- delete table.componentLocations[componentId];
2194
- reindexVertexOccupants(
2195
- table,
2196
- currentLocation.boardId,
2197
- currentLocation.vertexId
2198
- );
2199
- return;
2200
- }
2201
- if (currentLocation.type === "InSlot") {
2202
- delete table.componentLocations[componentId];
2203
- reindexSlotOccupants(table, currentLocation.host, currentLocation.slotId);
2204
- return;
2205
- }
2206
- delete table.componentLocations[componentId];
2207
- }
2208
- function appendToDeck(table, deckId, cardId, playedBy = null, position = "bottom") {
2209
- const nextTable = cloneRuntimeTable(table);
2210
- assertZoneScope(
2211
- nextTable,
2212
- deckId,
2213
- "shared",
2214
- "addCardToSharedZone",
2215
- "zoneId"
2216
- );
2217
- const deckCards = [
2218
- ...ensureArray(nextTable.decks[deckId])
2219
- ];
2220
- assertCardAllowedInZone(nextTable, deckId, cardId);
2221
- if (position === "top") {
2222
- deckCards.unshift(cardId);
2223
- } else {
2224
- deckCards.push(cardId);
2225
- }
2226
- syncSharedZoneWithDeck(nextTable, deckId, deckCards);
2227
- for (const [index, currentCardId] of deckCards.entries()) {
2228
- if (currentCardId === cardId) {
2229
- nextTable.componentLocations[currentCardId] = {
2230
- type: "InDeck",
2231
- deckId,
2232
- playedBy,
2233
- position: index
2234
- };
2235
- continue;
2236
- }
2237
- const existing = nextTable.componentLocations[currentCardId];
2238
- nextTable.componentLocations[currentCardId] = {
2239
- type: "InDeck",
2240
- deckId,
2241
- playedBy: existing?.type === "InDeck" ? existing.playedBy : null,
2242
- position: index
2243
- };
2244
- }
2245
- nextTable.ownerOfCard[cardId] = playedBy;
2246
- nextTable.visibility[cardId] = {
2247
- faceUp: true
2248
- };
2249
- return nextTable;
2250
- }
2251
- function removeFromDeck(table, deckId, cardId) {
2252
- const nextTable = cloneRuntimeTable(table);
2253
- assertZoneScope(
2254
- nextTable,
2255
- deckId,
2256
- "shared",
2257
- "removeCardFromSharedZone",
2258
- "zoneId"
2259
- );
2260
- const remaining = ensureArray(nextTable.decks[deckId]).filter(
2261
- (candidate) => candidate !== cardId
2262
- );
2263
- syncSharedZoneWithDeck(nextTable, deckId, remaining);
2264
- for (const [index, currentCardId] of remaining.entries()) {
2265
- const currentLocation = nextTable.componentLocations[currentCardId];
2266
- if (currentLocation?.type === "InDeck") {
2267
- nextTable.componentLocations[currentCardId] = {
2268
- ...currentLocation,
2269
- position: index
2270
- };
2271
- }
2272
- }
2273
- return nextTable;
2274
- }
2275
- function computeVisibilityForPlayerZone(table, zoneId, playerId) {
2276
- const mode = table.handVisibility[zoneId];
2277
- if (mode === "all" || mode === "public") {
2278
- return { faceUp: true };
2279
- }
2280
- return { faceUp: false, visibleTo: [playerId] };
2281
- }
2282
- function moveFromHandToDeck(options) {
2283
- const nextTable = cloneRuntimeTable(options.table);
2284
- assertZoneScope(
2285
- nextTable,
2286
- options.handId,
2287
- "perPlayer",
2288
- "moveCardFromPlayerZoneToSharedZone",
2289
- "fromZoneId"
2290
- );
2291
- assertZoneScope(
2292
- nextTable,
2293
- options.deckId,
2294
- "shared",
2295
- "moveCardFromPlayerZoneToSharedZone",
2296
- "toZoneId"
2297
- );
2298
- const currentHand = ensureArray(
2299
- ppRead(nextTable.hands[options.handId], options.playerId)
2300
- ).filter((candidate) => candidate !== options.cardId);
2301
- syncPlayerZoneWithHand(
2302
- nextTable,
2303
- options.handId,
2304
- options.playerId,
2305
- currentHand
2306
- );
2307
- for (const [index, currentCardId] of currentHand.entries()) {
2308
- nextTable.componentLocations[currentCardId] = {
2309
- type: "InHand",
2310
- handId: options.handId,
2311
- playerId: options.playerId,
2312
- position: index
2313
- };
2314
- }
2315
- nextTable.ownerOfCard[options.cardId] = options.playedBy ?? options.playerId;
2316
- nextTable.visibility[options.cardId] = {
2317
- faceUp: true
2318
- };
2319
- return appendToDeck(
2320
- nextTable,
2321
- options.deckId,
2322
- options.cardId,
2323
- options.playedBy ?? options.playerId,
2324
- options.position ?? "bottom"
2325
- );
2326
- }
2327
- function setActivePlayers(state, activePlayers) {
2328
- return {
2329
- ...state,
2330
- flow: {
2331
- ...state.flow,
2332
- activePlayers
2333
- }
2334
- };
2335
- }
2336
- function setPhaseState(state, phaseState) {
2337
- return {
2338
- ...state,
2339
- phase: phaseState
2340
- };
2341
- }
2342
- function getSharedZoneCards(table, zoneId) {
2343
- assertZoneScope(
2344
- table,
2345
- zoneId,
2346
- "shared",
2347
- "getSharedZoneCards",
2348
- "zoneId"
2349
- );
2350
- return [
2351
- ...ensureArray(table.zones.shared[zoneId] ?? table.decks[zoneId])
2352
- ];
2353
- }
2354
- function getPlayerZoneCards(table, playerId, zoneId) {
2355
- assertZoneScope(
2356
- table,
2357
- zoneId,
2358
- "perPlayer",
2359
- "getPlayerZoneCards",
2360
- "zoneId"
2361
- );
2362
- const cards = ppRead(table.zones.perPlayer[zoneId], playerId) ?? ppRead(table.hands[zoneId], playerId);
2363
- return [
2364
- ...ensureArray(cards)
2365
- ];
2366
- }
2367
- function collectZoneIds(...sources) {
2368
- const seen = /* @__PURE__ */ new Set();
2369
- for (const source of sources) {
2370
- if (!source) continue;
2371
- for (const key of Object.keys(source)) {
2372
- seen.add(key);
2080
+ const visited = /* @__PURE__ */ new Set([fromSpaceId]);
2081
+ let frontier = [fromSpaceId];
2082
+ let distance = 0;
2083
+ while (frontier.length > 0) {
2084
+ distance += 1;
2085
+ const nextFrontier = [];
2086
+ for (const currentSpaceId of frontier) {
2087
+ for (const neighborId of getAdjacentSpaces(
2088
+ table,
2089
+ boardId,
2090
+ currentSpaceId
2091
+ )) {
2092
+ if (neighborId === toSpaceId) {
2093
+ return distance;
2094
+ }
2095
+ if (!visited.has(neighborId)) {
2096
+ visited.add(neighborId);
2097
+ nextFrontier.push(neighborId);
2098
+ }
2099
+ }
2373
2100
  }
2101
+ frontier = nextFrontier;
2374
2102
  }
2375
- return [...seen];
2103
+ return Number.POSITIVE_INFINITY;
2376
2104
  }
2377
- function getAllSharedZoneCards(table) {
2378
- const zoneIds = collectZoneIds(
2379
- table.zones.shared,
2380
- table.decks
2381
- );
2382
- const result = {};
2383
- for (const zoneId of zoneIds) {
2384
- result[zoneId] = getSharedZoneCards(
2385
- table,
2386
- zoneId
2387
- );
2388
- }
2389
- return result;
2105
+ function getSquareNeighbors(table, boardId, spaceId, options = {}) {
2106
+ const board = getSquareBoard(table, boardId);
2107
+ const space = getSquareSpace(table, boardId, spaceId);
2108
+ const offsets = options.mode === "diagonal" ? [
2109
+ [-1, -1],
2110
+ [-1, 1],
2111
+ [1, -1],
2112
+ [1, 1]
2113
+ ] : options.mode === "all" ? [
2114
+ [-1, 0],
2115
+ [0, 1],
2116
+ [1, 0],
2117
+ [0, -1],
2118
+ [-1, -1],
2119
+ [-1, 1],
2120
+ [1, -1],
2121
+ [1, 1]
2122
+ ] : [
2123
+ [-1, 0],
2124
+ [0, 1],
2125
+ [1, 0],
2126
+ [0, -1]
2127
+ ];
2128
+ return offsets.map(
2129
+ ([rowOffset, colOffset]) => Object.values(board.spaces).find(
2130
+ (candidate) => candidate.row === space.row + rowOffset && candidate.col === space.col + colOffset
2131
+ )
2132
+ ).filter((candidate) => candidate !== void 0).map((candidate) => candidate.id);
2390
2133
  }
2391
- function getAllPlayerZoneCards(table, zoneId) {
2392
- const result = {};
2393
- for (const playerId of table.playerOrder) {
2394
- result[playerId] = getPlayerZoneCards(
2395
- table,
2396
- playerId,
2397
- zoneId
2398
- );
2399
- }
2400
- return result;
2134
+ function getSquareDistance(table, boardId, fromSpaceId, toSpaceId, options = {}) {
2135
+ const from = getSquareSpace(table, boardId, fromSpaceId);
2136
+ const to = getSquareSpace(table, boardId, toSpaceId);
2137
+ const rowDistance = Math.abs(from.row - to.row);
2138
+ const colDistance = Math.abs(from.col - to.col);
2139
+ return options.metric === "chebyshev" ? Math.max(rowDistance, colDistance) : rowDistance + colDistance;
2401
2140
  }
2402
- function getCard(table, cardId) {
2403
- const card = table.cards[cardId];
2404
- return {
2405
- id: card.id,
2406
- cardType: card.cardType,
2407
- name: card.name,
2408
- text: card.text,
2409
- properties: card.properties
2410
- };
2141
+ function getBoardsByTypeId(table, typeId) {
2142
+ return Object.entries(table.boards.byId).filter(([, board]) => board.typeId === typeId).map(([boardId]) => boardId);
2411
2143
  }
2412
- function getCardsById(table, cardIds) {
2413
- return Object.fromEntries(
2414
- cardIds.map((cardId) => [
2415
- cardId,
2416
- table.cards[cardId] ? getCard(table, cardId) : void 0
2417
- ])
2418
- );
2144
+ function getSpacesByTypeId(table, boardId, typeId) {
2145
+ return Object.entries(getBoard(table, boardId).spaces).filter(([, space]) => space.typeId === typeId).map(([spaceId]) => spaceId);
2419
2146
  }
2420
- function getSharedZoneCardCollection(table, zoneId) {
2421
- const cardIds = getSharedZoneCards(table, zoneId);
2422
- return {
2423
- cardIds,
2424
- cardsById: getCardsById(table, cardIds)
2425
- };
2147
+ function getEdgesByTypeId(table, boardId, typeId) {
2148
+ return getTiledBoard(table, boardId).edges.filter((edge) => edge.typeId === typeId).map((edge) => edge.id);
2426
2149
  }
2427
- function getPlayerZoneCardCollection(table, playerId, zoneId) {
2428
- const cardIds = getPlayerZoneCards(table, playerId, zoneId);
2429
- return {
2430
- cardIds,
2431
- cardsById: getCardsById(table, cardIds)
2432
- };
2150
+ function getVerticesByTypeId(table, boardId, typeId) {
2151
+ return getTiledBoard(table, boardId).vertices.filter((vertex) => vertex.typeId === typeId).map((vertex) => vertex.id);
2433
2152
  }
2434
- function getSlotOccupants(table, host, slotId) {
2153
+ function getComponentsOnSpace(table, boardId, spaceId) {
2154
+ const zoneId = getSpace(table, boardId, spaceId).zoneId;
2435
2155
  return orderedComponentIdsForLocation(
2436
2156
  table,
2437
- (location) => matchesSlotHost(location, host, slotId)
2438
- ).map((componentId) => ({
2439
- pieceId: componentId,
2440
- playerId: componentPlayerId(
2441
- table,
2442
- componentId
2443
- ),
2444
- slotId,
2445
- data: componentData(table, componentId)
2446
- }));
2157
+ (location) => location.type === "OnSpace" && location.boardId === boardId && location.spaceId === spaceId || location.type === "InZone" && typeof zoneId === "string" && zoneId.length > 0 && location.zoneId === zoneId
2158
+ );
2447
2159
  }
2448
- function getSlotOccupantsByHost(table, host) {
2449
- const occupantsBySlot = {};
2450
- orderedComponentIdsForLocation(
2160
+ function getComponentsInContainer(table, boardId, containerId) {
2161
+ const zoneId = getContainer(table, boardId, containerId).zoneId;
2162
+ return orderedComponentIdsForLocation(
2451
2163
  table,
2452
- (location) => matchesSlotHost(location, host)
2453
- ).forEach((componentId) => {
2454
- const location = table.componentLocations[componentId];
2455
- if (!location || !matchesSlotHost(location, host)) {
2456
- return;
2457
- }
2458
- const slotOccupant = {
2459
- pieceId: componentId,
2460
- playerId: componentPlayerId(
2461
- table,
2462
- componentId
2463
- ),
2464
- slotId: location.slotId,
2465
- data: componentData(table, componentId)
2466
- };
2467
- (occupantsBySlot[location.slotId] ??= []).push(slotOccupant);
2468
- });
2469
- return occupantsBySlot;
2470
- }
2471
- function getCardOwner(table, cardId) {
2472
- return table.ownerOfCard[cardId];
2473
- }
2474
- function getCardVisibility(table, cardId) {
2475
- return table.visibility[cardId];
2476
- }
2477
- function getPlayerOrder(table) {
2478
- return table.playerOrder;
2479
- }
2480
- function getPlayerResources(table, playerId) {
2481
- return perPlayerGet(
2482
- table.resources,
2483
- playerId
2164
+ (location) => location.type === "InContainer" && location.boardId === boardId && location.containerId === containerId || location.type === "InZone" && typeof zoneId === "string" && zoneId.length > 0 && location.zoneId === zoneId
2484
2165
  );
2485
2166
  }
2486
- function getPlayerResourceAmount(table, playerId, resourceId) {
2487
- const playerResources = perPlayerGet(
2488
- table.resources,
2489
- playerId
2167
+ function getComponentsOnEdge(table, boardId, edgeId) {
2168
+ return orderedComponentIdsForLocation(
2169
+ table,
2170
+ (location) => location.type === "OnEdge" && location.boardId === boardId && location.edgeId === edgeId
2490
2171
  );
2491
- if (!playerResources) return 0;
2492
- const value = playerResources[resourceId];
2493
- return typeof value === "number" ? value : 0;
2494
2172
  }
2495
- function getPlayerResourceTotal(table, playerId) {
2496
- const playerResources = perPlayerGet(
2497
- table.resources,
2498
- playerId
2173
+ function getComponentsOnVertex(table, boardId, vertexId) {
2174
+ return orderedComponentIdsForLocation(
2175
+ table,
2176
+ (location) => location.type === "OnVertex" && location.boardId === boardId && location.vertexId === vertexId
2499
2177
  );
2500
- if (!playerResources) return 0;
2501
- let total = 0;
2502
- for (const key of Object.keys(playerResources)) {
2503
- const value = playerResources[key];
2504
- if (typeof value === "number") total += value;
2505
- }
2506
- return total;
2507
- }
2508
- function getNextPlayerInOrder(table, playerId) {
2509
- const order = table.playerOrder;
2510
- if (order.length === 0) return null;
2511
- const idx = order.indexOf(playerId);
2512
- if (idx < 0) return null;
2513
- return order[(idx + 1) % order.length] ?? null;
2514
- }
2515
- function forEachResourceEntry(amounts, visit) {
2516
- for (const resourceId of Object.keys(amounts)) {
2517
- const amount = amounts[resourceId];
2518
- if (typeof amount !== "number" || amount === 0) continue;
2519
- visit(resourceId, amount);
2520
- }
2521
- }
2522
- function canAffordResources(table, playerId, amounts) {
2523
- for (const resourceId of Object.keys(amounts)) {
2524
- const required = amounts[resourceId];
2525
- if (typeof required !== "number" || required <= 0) continue;
2526
- if (getPlayerResourceAmount(table, playerId, resourceId) < required) {
2527
- return false;
2528
- }
2529
- }
2530
- return true;
2531
- }
2532
- function getMissingResources(table, playerId, amounts) {
2533
- const missing = {};
2534
- for (const resourceId of Object.keys(amounts)) {
2535
- const required = amounts[resourceId];
2536
- if (typeof required !== "number" || required <= 0) continue;
2537
- const have = getPlayerResourceAmount(table, playerId, resourceId);
2538
- if (have < required) missing[resourceId] = required - have;
2539
- }
2540
- return missing;
2541
- }
2542
- function withPlayerResources(table, playerId, nextForPlayer) {
2543
- return {
2544
- ...table,
2545
- resources: perPlayerSet(
2546
- table.resources,
2547
- playerId,
2548
- nextForPlayer
2549
- )
2550
- };
2551
2178
  }
2552
- function addPlayerResources(table, playerId, amounts) {
2553
- const prev = perPlayerGet(
2554
- table.resources,
2555
- playerId
2556
- ) ?? {};
2557
- const next = { ...prev };
2558
- forEachResourceEntry(amounts, (resourceId, amount) => {
2559
- if (amount < 0) {
2560
- throw new Error(
2561
- `addPlayerResources: negative amount for resource '${resourceId}'. Use spendPlayerResources or transferPlayerResources instead.`
2562
- );
2563
- }
2564
- next[resourceId] = (next[resourceId] ?? 0) + amount;
2565
- });
2566
- return withPlayerResources(table, playerId, next);
2179
+
2180
+ // src/reducer/table/card-validation.ts
2181
+ function allowedCardSetIdsForZone(table, zoneId) {
2182
+ return table.zones.cardSetIdsByZoneId?.[zoneId] ?? [];
2567
2183
  }
2568
- function spendPlayerResources(table, playerId, amounts) {
2569
- if (!canAffordResources(table, playerId, amounts)) {
2570
- const missing = getMissingResources(table, playerId, amounts);
2184
+ function assertCardAllowedInZone(table, zoneId, componentId) {
2185
+ const card = table.cards[componentId];
2186
+ if (!card) {
2187
+ return;
2188
+ }
2189
+ const allowedCardSetIds = allowedCardSetIdsForZone(table, zoneId);
2190
+ if (allowedCardSetIds.length > 0 && !allowedCardSetIds.includes(card.cardSetId)) {
2571
2191
  throw new Error(
2572
- `spendPlayerResources: player '${playerId}' cannot afford ${JSON.stringify(
2573
- missing
2574
- )}. Check canAfford in your validate step first.`
2192
+ `Card '${componentId}' from card set '${card.cardSetId}' cannot enter zone '${zoneId}'.`
2575
2193
  );
2576
2194
  }
2577
- const prev = perPlayerGet(
2578
- table.resources,
2579
- playerId
2580
- ) ?? {};
2581
- const next = { ...prev };
2582
- forEachResourceEntry(amounts, (resourceId, amount) => {
2583
- if (amount < 0) {
2584
- throw new Error(
2585
- `spendPlayerResources: negative amount for resource '${resourceId}'. Pass positive amounts \u2014 the op deducts them from the player.`
2586
- );
2587
- }
2588
- next[resourceId] = Math.max(0, (next[resourceId] ?? 0) - amount);
2589
- });
2590
- return withPlayerResources(table, playerId, next);
2591
- }
2592
- function transferPlayerResources(table, fromPlayerId, toPlayerId, amounts) {
2593
- const afterSpend = spendPlayerResources(table, fromPlayerId, amounts);
2594
- return addPlayerResources(afterSpend, toPlayerId, amounts);
2595
2195
  }
2596
- function setPlayerResource(table, playerId, resourceId, amount) {
2597
- if (!Number.isFinite(amount) || amount < 0) {
2196
+ function assertCardAllowedInContainer(table, boardId, containerId, componentId) {
2197
+ const card = table.cards[componentId];
2198
+ if (!card) {
2199
+ return;
2200
+ }
2201
+ const allowedCardSetIds = getContainer(table, boardId, containerId).allowedCardSetIds ?? [];
2202
+ if (allowedCardSetIds.length > 0 && !allowedCardSetIds.includes(card.cardSetId)) {
2598
2203
  throw new Error(
2599
- `setPlayerResource: amount must be a non-negative finite number, got ${amount}.`
2204
+ `Card '${componentId}' from card set '${card.cardSetId}' cannot enter container '${containerId}' on board '${boardId}'.`
2600
2205
  );
2601
2206
  }
2602
- const prev = perPlayerGet(
2603
- table.resources,
2604
- playerId
2605
- ) ?? {};
2606
- return withPlayerResources(table, playerId, {
2607
- ...prev,
2608
- [resourceId]: amount
2609
- });
2610
2207
  }
2208
+
2209
+ // src/reducer/table/component-locations.ts
2611
2210
  function getComponentLocation(table, componentId) {
2612
2211
  return table.componentLocations[componentId];
2613
2212
  }
@@ -2726,229 +2325,493 @@ function getComponentSlotLocation(table, componentId) {
2726
2325
  location
2727
2326
  };
2728
2327
  }
2729
- function getBoard(table, boardId) {
2730
- return table.boards.byId[boardId];
2731
- }
2732
- function getHexBoard(table, boardId) {
2733
- return getBoard(table, boardId);
2734
- }
2735
- function getTiledBoard(table, boardId) {
2736
- return getBoard(table, boardId);
2737
- }
2738
- function getSquareBoard(table, boardId) {
2739
- return getBoard(table, boardId);
2328
+
2329
+ // src/reducer/table/zone-queries.ts
2330
+ function matchesSlotHost(location, host, slotId) {
2331
+ return location.type === "InSlot" && location.host.kind === host.kind && location.host.id === host.id && (slotId === void 0 || location.slotId === slotId);
2740
2332
  }
2741
- function getSpace(table, boardId, spaceId) {
2742
- return getBoard(table, boardId).spaces[spaceId];
2333
+ function componentPlayerId(table, componentId) {
2334
+ const piece = table.pieces[componentId];
2335
+ if (piece) {
2336
+ return piece.ownerId ?? null;
2337
+ }
2338
+ const die = table.dice[componentId];
2339
+ if (die) {
2340
+ return die.ownerId ?? null;
2341
+ }
2342
+ const owner = table.ownerOfCard[componentId];
2343
+ if (owner !== void 0) {
2344
+ return owner ?? null;
2345
+ }
2346
+ return null;
2743
2347
  }
2744
- function getHexSpace(table, boardId, spaceId) {
2745
- return getHexBoard(table, boardId).spaces[spaceId];
2348
+ function componentData(table, componentId) {
2349
+ const piece = table.pieces[componentId];
2350
+ if (piece) {
2351
+ return piece.properties;
2352
+ }
2353
+ const die = table.dice[componentId];
2354
+ if (die) {
2355
+ return die.properties;
2356
+ }
2357
+ const card = table.cards[componentId];
2358
+ if (card) {
2359
+ return card.properties;
2360
+ }
2361
+ return void 0;
2746
2362
  }
2747
- function getSquareSpace(table, boardId, spaceId) {
2748
- return getSquareBoard(table, boardId).spaces[spaceId];
2363
+ function getSharedZoneCards(table, zoneId) {
2364
+ assertZoneScope(
2365
+ table,
2366
+ zoneId,
2367
+ "shared",
2368
+ "getSharedZoneCards",
2369
+ "zoneId"
2370
+ );
2371
+ return [
2372
+ ...ensureArray(table.zones.shared[zoneId] ?? table.decks[zoneId])
2373
+ ];
2749
2374
  }
2750
- function getContainer(table, boardId, containerId) {
2751
- return getBoard(table, boardId).containers[containerId];
2375
+ function getPlayerZoneCards(table, playerId, zoneId) {
2376
+ assertZoneScope(
2377
+ table,
2378
+ zoneId,
2379
+ "perPlayer",
2380
+ "getPlayerZoneCards",
2381
+ "zoneId"
2382
+ );
2383
+ const cards = ppRead(table.zones.perPlayer[zoneId], playerId) ?? ppRead(table.hands[zoneId], playerId);
2384
+ return [
2385
+ ...ensureArray(cards)
2386
+ ];
2752
2387
  }
2753
- function assertCardAllowedInContainer(table, boardId, containerId, componentId) {
2754
- const card = table.cards[componentId];
2755
- if (!card) {
2756
- return;
2757
- }
2758
- const allowedCardSetIds = getContainer(table, boardId, containerId).allowedCardSetIds ?? [];
2759
- if (allowedCardSetIds.length > 0 && !allowedCardSetIds.includes(card.cardSetId)) {
2760
- throw new Error(
2761
- `Card '${componentId}' from card set '${card.cardSetId}' cannot enter container '${containerId}' on board '${boardId}'.`
2762
- );
2388
+ function collectZoneIds(...sources) {
2389
+ const seen = /* @__PURE__ */ new Set();
2390
+ for (const source of sources) {
2391
+ if (!source) continue;
2392
+ for (const key of Object.keys(source)) {
2393
+ seen.add(key);
2394
+ }
2763
2395
  }
2396
+ return [...seen];
2764
2397
  }
2765
- function getEdge(table, boardId, edgeId) {
2766
- const edge = getTiledBoard(table, boardId).edges.find(
2767
- (candidate) => candidate.id === edgeId
2398
+ function getAllSharedZoneCards(table) {
2399
+ const zoneIds = collectZoneIds(
2400
+ table.zones.shared,
2401
+ table.decks
2768
2402
  );
2769
- if (!edge) {
2770
- throw new Error(`Unknown edge '${edgeId}' on board '${boardId}'.`);
2403
+ const result = {};
2404
+ for (const zoneId of zoneIds) {
2405
+ result[zoneId] = getSharedZoneCards(
2406
+ table,
2407
+ zoneId
2408
+ );
2771
2409
  }
2772
- return edge;
2410
+ return result;
2773
2411
  }
2774
- function getVertex(table, boardId, vertexId) {
2775
- const vertex = getTiledBoard(table, boardId).vertices.find(
2776
- (candidate) => candidate.id === vertexId
2777
- );
2778
- if (!vertex) {
2779
- throw new Error(`Unknown vertex '${vertexId}' on board '${boardId}'.`);
2412
+ function getAllPlayerZoneCards(table, zoneId) {
2413
+ const result = {};
2414
+ for (const playerId of table.playerOrder) {
2415
+ result[playerId] = getPlayerZoneCards(
2416
+ table,
2417
+ playerId,
2418
+ zoneId
2419
+ );
2780
2420
  }
2781
- return vertex;
2421
+ return result;
2782
2422
  }
2783
- function getHexSpaceAt(table, boardId, q, r) {
2784
- return Object.values(getHexBoard(table, boardId).spaces).find(
2785
- (space) => space.q === q && space.r === r
2423
+ function getCard(table, cardId) {
2424
+ const card = table.cards[cardId];
2425
+ return {
2426
+ id: card.id,
2427
+ cardType: card.cardType,
2428
+ name: card.name,
2429
+ text: card.text,
2430
+ properties: card.properties
2431
+ };
2432
+ }
2433
+ function getCardsById(table, cardIds) {
2434
+ return Object.fromEntries(
2435
+ cardIds.map((cardId) => [
2436
+ cardId,
2437
+ table.cards[cardId] ? getCard(table, cardId) : void 0
2438
+ ])
2786
2439
  );
2787
2440
  }
2788
- function getSquareSpaceAt(table, boardId, row, col) {
2789
- return Object.values(getSquareBoard(table, boardId).spaces).find(
2790
- (space) => space.row === row && space.col === col
2441
+ function getSharedZoneCardCollection(table, zoneId) {
2442
+ const cardIds = getSharedZoneCards(table, zoneId);
2443
+ return {
2444
+ cardIds,
2445
+ cardsById: getCardsById(table, cardIds)
2446
+ };
2447
+ }
2448
+ function getPlayerZoneCardCollection(table, playerId, zoneId) {
2449
+ const cardIds = getPlayerZoneCards(table, playerId, zoneId);
2450
+ return {
2451
+ cardIds,
2452
+ cardsById: getCardsById(table, cardIds)
2453
+ };
2454
+ }
2455
+ function getSlotOccupants(table, host, slotId) {
2456
+ return orderedComponentIdsForLocation(
2457
+ table,
2458
+ (location) => matchesSlotHost(location, host, slotId)
2459
+ ).map((componentId) => ({
2460
+ pieceId: componentId,
2461
+ playerId: componentPlayerId(
2462
+ table,
2463
+ componentId
2464
+ ),
2465
+ slotId,
2466
+ data: componentData(table, componentId)
2467
+ }));
2468
+ }
2469
+ function getSlotOccupantsByHost(table, host) {
2470
+ const occupantsBySlot = {};
2471
+ orderedComponentIdsForLocation(
2472
+ table,
2473
+ (location) => matchesSlotHost(location, host)
2474
+ ).forEach((componentId) => {
2475
+ const location = table.componentLocations[componentId];
2476
+ if (!location || !matchesSlotHost(location, host)) {
2477
+ return;
2478
+ }
2479
+ const slotOccupant = {
2480
+ pieceId: componentId,
2481
+ playerId: componentPlayerId(
2482
+ table,
2483
+ componentId
2484
+ ),
2485
+ slotId: location.slotId,
2486
+ data: componentData(table, componentId)
2487
+ };
2488
+ (occupantsBySlot[location.slotId] ??= []).push(slotOccupant);
2489
+ });
2490
+ return occupantsBySlot;
2491
+ }
2492
+ function getCardOwner(table, cardId) {
2493
+ return table.ownerOfCard[cardId];
2494
+ }
2495
+ function getCardVisibility(table, cardId) {
2496
+ return table.visibility[cardId];
2497
+ }
2498
+
2499
+ // src/reducer/table/resource-ops.ts
2500
+ function getPlayerOrder(table) {
2501
+ return table.playerOrder;
2502
+ }
2503
+ function getPlayerResources(table, playerId) {
2504
+ return perPlayerGet(
2505
+ table.resources,
2506
+ playerId
2791
2507
  );
2792
2508
  }
2793
- function getSpaceEdges(table, boardId, spaceId) {
2794
- return getTiledBoard(table, boardId).edges.filter((edge) => edge.spaceIds.includes(spaceId)).map((edge) => edge.id);
2795
- }
2796
- function getSpaceVertices(table, boardId, spaceId) {
2797
- return getTiledBoard(table, boardId).vertices.filter((vertex) => vertex.spaceIds.includes(spaceId)).map((vertex) => vertex.id);
2509
+ function getPlayerResourceAmount(table, playerId, resourceId) {
2510
+ const playerResources = perPlayerGet(
2511
+ table.resources,
2512
+ playerId
2513
+ );
2514
+ if (!playerResources) return 0;
2515
+ const value = playerResources[resourceId];
2516
+ return typeof value === "number" ? value : 0;
2798
2517
  }
2799
- function getIncidentEdges(table, boardId, vertexId) {
2800
- const tiledBoard = getTiledBoard(table, boardId);
2801
- const vertex = tiledBoard.vertices.find(
2802
- (candidate) => candidate.id === vertexId
2518
+ function getPlayerResourceTotal(table, playerId) {
2519
+ const playerResources = perPlayerGet(
2520
+ table.resources,
2521
+ playerId
2803
2522
  );
2804
- if (!vertex) {
2805
- throw new Error(`Unknown vertex '${vertexId}' on board '${boardId}'.`);
2523
+ if (!playerResources) return 0;
2524
+ let total = 0;
2525
+ for (const key of Object.keys(playerResources)) {
2526
+ const value = playerResources[key];
2527
+ if (typeof value === "number") total += value;
2806
2528
  }
2807
- const vertexSpaceIds = new Set(vertex.spaceIds);
2808
- return tiledBoard.edges.filter(
2809
- (edge) => edge.spaceIds.every((spaceId) => vertexSpaceIds.has(spaceId))
2810
- ).map((edge) => edge.id);
2529
+ return total;
2811
2530
  }
2812
- function getIncidentVertices(table, boardId, edgeId) {
2813
- const tiledBoard = getTiledBoard(table, boardId);
2814
- const edge = tiledBoard.edges.find((candidate) => candidate.id === edgeId);
2815
- if (!edge) {
2816
- throw new Error(`Unknown edge '${edgeId}' on board '${boardId}'.`);
2531
+ function getNextPlayerInOrder(table, playerId) {
2532
+ const order = table.playerOrder;
2533
+ if (order.length === 0) return null;
2534
+ const idx = order.indexOf(playerId);
2535
+ if (idx < 0) return null;
2536
+ return order[(idx + 1) % order.length] ?? null;
2537
+ }
2538
+ function forEachResourceEntry(amounts, visit) {
2539
+ for (const resourceId of Object.keys(amounts)) {
2540
+ const amount = amounts[resourceId];
2541
+ if (typeof amount !== "number" || amount === 0) continue;
2542
+ visit(resourceId, amount);
2817
2543
  }
2818
- const edgeSpaceIds = new Set(edge.spaceIds);
2819
- return tiledBoard.vertices.filter(
2820
- (vertex) => Array.from(edgeSpaceIds).every(
2821
- (spaceId) => vertex.spaceIds.includes(spaceId)
2822
- )
2823
- ).map((vertex) => vertex.id);
2824
2544
  }
2825
- function getRelatedSpaces(table, boardId, spaceId, relationTypeId) {
2826
- const board = getBoard(table, boardId);
2827
- const related = /* @__PURE__ */ new Set();
2828
- for (const relation of board.relations) {
2829
- if (relation.typeId !== relationTypeId) {
2830
- continue;
2831
- }
2832
- if (relation.fromSpaceId === spaceId) {
2833
- related.add(relation.toSpaceId);
2834
- continue;
2835
- }
2836
- if (!relation.directed && relation.toSpaceId === spaceId) {
2837
- related.add(relation.fromSpaceId);
2545
+ function canAffordResources(table, playerId, amounts) {
2546
+ for (const resourceId of Object.keys(amounts)) {
2547
+ const required = amounts[resourceId];
2548
+ if (typeof required !== "number" || required <= 0) continue;
2549
+ if (getPlayerResourceAmount(table, playerId, resourceId) < required) {
2550
+ return false;
2838
2551
  }
2839
2552
  }
2840
- return [...related];
2841
- }
2842
- function getAdjacentSpaces(table, boardId, spaceId) {
2843
- return getRelatedSpaces(
2844
- table,
2845
- boardId,
2846
- spaceId,
2847
- "adjacent"
2848
- );
2553
+ return true;
2849
2554
  }
2850
- function getSpaceDistance(table, boardId, fromSpaceId, toSpaceId) {
2851
- if (fromSpaceId === toSpaceId) {
2852
- return 0;
2853
- }
2854
- const visited = /* @__PURE__ */ new Set([fromSpaceId]);
2855
- let frontier = [fromSpaceId];
2856
- let distance = 0;
2857
- while (frontier.length > 0) {
2858
- distance += 1;
2859
- const nextFrontier = [];
2860
- for (const currentSpaceId of frontier) {
2861
- for (const neighborId of getAdjacentSpaces(
2862
- table,
2863
- boardId,
2864
- currentSpaceId
2865
- )) {
2866
- if (neighborId === toSpaceId) {
2867
- return distance;
2868
- }
2869
- if (!visited.has(neighborId)) {
2870
- visited.add(neighborId);
2871
- nextFrontier.push(neighborId);
2872
- }
2873
- }
2874
- }
2875
- frontier = nextFrontier;
2555
+ function getMissingResources(table, playerId, amounts) {
2556
+ const missing = {};
2557
+ for (const resourceId of Object.keys(amounts)) {
2558
+ const required = amounts[resourceId];
2559
+ if (typeof required !== "number" || required <= 0) continue;
2560
+ const have = getPlayerResourceAmount(table, playerId, resourceId);
2561
+ if (have < required) missing[resourceId] = required - have;
2876
2562
  }
2877
- return Number.POSITIVE_INFINITY;
2563
+ return missing;
2878
2564
  }
2879
- function getSquareNeighbors(table, boardId, spaceId, options = {}) {
2880
- const board = getSquareBoard(table, boardId);
2881
- const space = getSquareSpace(table, boardId, spaceId);
2882
- const offsets = options.mode === "diagonal" ? [
2883
- [-1, -1],
2884
- [-1, 1],
2885
- [1, -1],
2886
- [1, 1]
2887
- ] : options.mode === "all" ? [
2888
- [-1, 0],
2889
- [0, 1],
2890
- [1, 0],
2891
- [0, -1],
2892
- [-1, -1],
2893
- [-1, 1],
2894
- [1, -1],
2895
- [1, 1]
2896
- ] : [
2897
- [-1, 0],
2898
- [0, 1],
2899
- [1, 0],
2900
- [0, -1]
2901
- ];
2902
- return offsets.map(
2903
- ([rowOffset, colOffset]) => Object.values(board.spaces).find(
2904
- (candidate) => candidate.row === space.row + rowOffset && candidate.col === space.col + colOffset
2565
+ function withPlayerResources(table, playerId, nextForPlayer) {
2566
+ return {
2567
+ ...table,
2568
+ resources: perPlayerSet(
2569
+ table.resources,
2570
+ playerId,
2571
+ nextForPlayer
2905
2572
  )
2906
- ).filter((candidate) => candidate !== void 0).map((candidate) => candidate.id);
2907
- }
2908
- function getSquareDistance(table, boardId, fromSpaceId, toSpaceId, options = {}) {
2909
- const from = getSquareSpace(table, boardId, fromSpaceId);
2910
- const to = getSquareSpace(table, boardId, toSpaceId);
2911
- const rowDistance = Math.abs(from.row - to.row);
2912
- const colDistance = Math.abs(from.col - to.col);
2913
- return options.metric === "chebyshev" ? Math.max(rowDistance, colDistance) : rowDistance + colDistance;
2914
- }
2915
- function getBoardsByTypeId(table, typeId) {
2916
- return Object.entries(table.boards.byId).filter(([, board]) => board.typeId === typeId).map(([boardId]) => boardId);
2573
+ };
2917
2574
  }
2918
- function getSpacesByTypeId(table, boardId, typeId) {
2919
- return Object.entries(getBoard(table, boardId).spaces).filter(([, space]) => space.typeId === typeId).map(([spaceId]) => spaceId);
2575
+ function addPlayerResources(table, playerId, amounts) {
2576
+ const prev = perPlayerGet(
2577
+ table.resources,
2578
+ playerId
2579
+ ) ?? {};
2580
+ const next = { ...prev };
2581
+ forEachResourceEntry(amounts, (resourceId, amount) => {
2582
+ if (amount < 0) {
2583
+ throw new Error(
2584
+ `addPlayerResources: negative amount for resource '${resourceId}'. Use spendPlayerResources or transferPlayerResources instead.`
2585
+ );
2586
+ }
2587
+ next[resourceId] = (next[resourceId] ?? 0) + amount;
2588
+ });
2589
+ return withPlayerResources(table, playerId, next);
2920
2590
  }
2921
- function getEdgesByTypeId(table, boardId, typeId) {
2922
- return getTiledBoard(table, boardId).edges.filter((edge) => edge.typeId === typeId).map((edge) => edge.id);
2591
+ function spendPlayerResources(table, playerId, amounts) {
2592
+ if (!canAffordResources(table, playerId, amounts)) {
2593
+ const missing = getMissingResources(table, playerId, amounts);
2594
+ throw new Error(
2595
+ `spendPlayerResources: player '${playerId}' cannot afford ${JSON.stringify(
2596
+ missing
2597
+ )}. Check canAfford in your validate step first.`
2598
+ );
2599
+ }
2600
+ const prev = perPlayerGet(
2601
+ table.resources,
2602
+ playerId
2603
+ ) ?? {};
2604
+ const next = { ...prev };
2605
+ forEachResourceEntry(amounts, (resourceId, amount) => {
2606
+ if (amount < 0) {
2607
+ throw new Error(
2608
+ `spendPlayerResources: negative amount for resource '${resourceId}'. Pass positive amounts \u2014 the op deducts them from the player.`
2609
+ );
2610
+ }
2611
+ next[resourceId] = Math.max(0, (next[resourceId] ?? 0) - amount);
2612
+ });
2613
+ return withPlayerResources(table, playerId, next);
2923
2614
  }
2924
- function getVerticesByTypeId(table, boardId, typeId) {
2925
- return getTiledBoard(table, boardId).vertices.filter((vertex) => vertex.typeId === typeId).map((vertex) => vertex.id);
2615
+ function transferPlayerResources(table, fromPlayerId, toPlayerId, amounts) {
2616
+ const afterSpend = spendPlayerResources(table, fromPlayerId, amounts);
2617
+ return addPlayerResources(afterSpend, toPlayerId, amounts);
2926
2618
  }
2927
- function getComponentsOnSpace(table, boardId, spaceId) {
2928
- const zoneId = getSpace(table, boardId, spaceId).zoneId;
2929
- return orderedComponentIdsForLocation(
2930
- table,
2931
- (location) => location.type === "OnSpace" && location.boardId === boardId && location.spaceId === spaceId || location.type === "InZone" && typeof zoneId === "string" && zoneId.length > 0 && location.zoneId === zoneId
2932
- );
2619
+ function setPlayerResource(table, playerId, resourceId, amount) {
2620
+ if (!Number.isFinite(amount) || amount < 0) {
2621
+ throw new Error(
2622
+ `setPlayerResource: amount must be a non-negative finite number, got ${amount}.`
2623
+ );
2624
+ }
2625
+ const prev = perPlayerGet(
2626
+ table.resources,
2627
+ playerId
2628
+ ) ?? {};
2629
+ return withPlayerResources(table, playerId, {
2630
+ ...prev,
2631
+ [resourceId]: amount
2632
+ });
2933
2633
  }
2934
- function getComponentsInContainer(table, boardId, containerId) {
2935
- const zoneId = getContainer(table, boardId, containerId).zoneId;
2936
- return orderedComponentIdsForLocation(
2937
- table,
2938
- (location) => location.type === "InContainer" && location.boardId === boardId && location.containerId === containerId || location.type === "InZone" && typeof zoneId === "string" && zoneId.length > 0 && location.zoneId === zoneId
2634
+
2635
+ // src/reducer/table/component-mutations.ts
2636
+ function reindexSpaceOccupants(table, boardId, spaceId) {
2637
+ getComponentsOnSpace(table, boardId, spaceId).forEach(
2638
+ (componentId, index) => {
2639
+ const location = table.componentLocations[componentId];
2640
+ if (location?.type === "OnSpace") {
2641
+ table.componentLocations[componentId] = {
2642
+ ...location,
2643
+ position: index
2644
+ };
2645
+ }
2646
+ }
2939
2647
  );
2940
2648
  }
2941
- function getComponentsOnEdge(table, boardId, edgeId) {
2942
- return orderedComponentIdsForLocation(
2649
+ function reindexContainerOccupants(table, boardId, containerId) {
2650
+ getComponentsInContainer(table, boardId, containerId).forEach(
2651
+ (componentId, index) => {
2652
+ const location = table.componentLocations[componentId];
2653
+ if (location?.type === "InContainer") {
2654
+ table.componentLocations[componentId] = {
2655
+ ...location,
2656
+ position: index
2657
+ };
2658
+ }
2659
+ }
2660
+ );
2661
+ }
2662
+ function reindexEdgeOccupants(table, boardId, edgeId) {
2663
+ orderedComponentIdsForLocation(
2943
2664
  table,
2944
2665
  (location) => location.type === "OnEdge" && location.boardId === boardId && location.edgeId === edgeId
2945
- );
2666
+ ).forEach((componentId, index) => {
2667
+ const location = table.componentLocations[componentId];
2668
+ if (location?.type === "OnEdge") {
2669
+ table.componentLocations[componentId] = {
2670
+ ...location,
2671
+ position: index
2672
+ };
2673
+ }
2674
+ });
2946
2675
  }
2947
- function getComponentsOnVertex(table, boardId, vertexId) {
2948
- return orderedComponentIdsForLocation(
2676
+ function reindexVertexOccupants(table, boardId, vertexId) {
2677
+ orderedComponentIdsForLocation(
2949
2678
  table,
2950
2679
  (location) => location.type === "OnVertex" && location.boardId === boardId && location.vertexId === vertexId
2951
- );
2680
+ ).forEach((componentId, index) => {
2681
+ const location = table.componentLocations[componentId];
2682
+ if (location?.type === "OnVertex") {
2683
+ table.componentLocations[componentId] = {
2684
+ ...location,
2685
+ position: index
2686
+ };
2687
+ }
2688
+ });
2689
+ }
2690
+ function reindexSlotOccupants(table, host, slotId) {
2691
+ orderedComponentIdsForLocation(
2692
+ table,
2693
+ (location) => location.type === "InSlot" && location.host.kind === host.kind && location.host.id === host.id && location.slotId === slotId
2694
+ ).forEach((componentId, index) => {
2695
+ const location = table.componentLocations[componentId];
2696
+ if (location?.type === "InSlot") {
2697
+ table.componentLocations[componentId] = {
2698
+ ...location,
2699
+ position: index
2700
+ };
2701
+ }
2702
+ });
2703
+ }
2704
+ function removeComponentFromCurrentLocation(table, componentId) {
2705
+ const currentLocation = table.componentLocations[componentId];
2706
+ if (!currentLocation) {
2707
+ return;
2708
+ }
2709
+ if (currentLocation.type === "InDeck") {
2710
+ const nextCards = ensureArray(table.decks[currentLocation.deckId]).filter(
2711
+ (candidate) => candidate !== componentId
2712
+ );
2713
+ syncSharedZoneWithDeck(
2714
+ table,
2715
+ currentLocation.deckId,
2716
+ nextCards
2717
+ );
2718
+ nextCards.forEach((cardId, index) => {
2719
+ const location = table.componentLocations[cardId];
2720
+ if (location?.type === "InDeck") {
2721
+ table.componentLocations[cardId] = {
2722
+ ...location,
2723
+ position: index
2724
+ };
2725
+ }
2726
+ });
2727
+ return;
2728
+ }
2729
+ if (currentLocation.type === "InHand") {
2730
+ const nextCards = ensureArray(
2731
+ ppRead(table.hands[currentLocation.handId], currentLocation.playerId)
2732
+ ).filter((candidate) => candidate !== componentId);
2733
+ syncPlayerZoneWithHand(
2734
+ table,
2735
+ currentLocation.handId,
2736
+ currentLocation.playerId,
2737
+ nextCards
2738
+ );
2739
+ nextCards.forEach((cardId, index) => {
2740
+ const location = table.componentLocations[cardId];
2741
+ if (location?.type === "InHand") {
2742
+ table.componentLocations[cardId] = {
2743
+ ...location,
2744
+ position: index
2745
+ };
2746
+ }
2747
+ });
2748
+ return;
2749
+ }
2750
+ if (currentLocation.type === "OnSpace") {
2751
+ delete table.componentLocations[componentId];
2752
+ reindexSpaceOccupants(
2753
+ table,
2754
+ currentLocation.boardId,
2755
+ currentLocation.spaceId
2756
+ );
2757
+ return;
2758
+ }
2759
+ if (currentLocation.type === "InZone") {
2760
+ if (currentLocation.zoneId in table.zones.shared) {
2761
+ const nextComponents = ensureArray(
2762
+ table.zones.shared[currentLocation.zoneId]
2763
+ ).filter((candidate) => candidate !== componentId);
2764
+ syncSharedZoneWithDeck(
2765
+ table,
2766
+ currentLocation.zoneId,
2767
+ nextComponents
2768
+ );
2769
+ nextComponents.forEach((currentComponentId, index) => {
2770
+ const location = table.componentLocations[currentComponentId];
2771
+ if (location?.type === "InZone") {
2772
+ table.componentLocations[currentComponentId] = {
2773
+ ...location,
2774
+ position: index
2775
+ };
2776
+ }
2777
+ });
2778
+ }
2779
+ delete table.componentLocations[componentId];
2780
+ return;
2781
+ }
2782
+ if (currentLocation.type === "InContainer") {
2783
+ delete table.componentLocations[componentId];
2784
+ reindexContainerOccupants(
2785
+ table,
2786
+ currentLocation.boardId,
2787
+ currentLocation.containerId
2788
+ );
2789
+ return;
2790
+ }
2791
+ if (currentLocation.type === "OnEdge") {
2792
+ delete table.componentLocations[componentId];
2793
+ reindexEdgeOccupants(
2794
+ table,
2795
+ currentLocation.boardId,
2796
+ currentLocation.edgeId
2797
+ );
2798
+ return;
2799
+ }
2800
+ if (currentLocation.type === "OnVertex") {
2801
+ delete table.componentLocations[componentId];
2802
+ reindexVertexOccupants(
2803
+ table,
2804
+ currentLocation.boardId,
2805
+ currentLocation.vertexId
2806
+ );
2807
+ return;
2808
+ }
2809
+ if (currentLocation.type === "InSlot") {
2810
+ delete table.componentLocations[componentId];
2811
+ reindexSlotOccupants(table, currentLocation.host, currentLocation.slotId);
2812
+ return;
2813
+ }
2814
+ delete table.componentLocations[componentId];
2952
2815
  }
2953
2816
  function moveComponentToSpace(table, componentId, boardId, spaceId) {
2954
2817
  const nextTable = cloneRuntimeTable(table);
@@ -2979,37 +2842,176 @@ function moveComponentToContainer(table, componentId, boardId, containerId) {
2979
2842
  };
2980
2843
  return nextTable;
2981
2844
  }
2982
- function moveComponentToDetached(table, componentId) {
2845
+ function moveComponentToDetached(table, componentId) {
2846
+ const nextTable = cloneRuntimeTable(table);
2847
+ removeComponentFromCurrentLocation(nextTable, componentId);
2848
+ nextTable.componentLocations[componentId] = { type: "Detached" };
2849
+ return nextTable;
2850
+ }
2851
+ function moveComponentToEdge(table, componentId, boardId, edgeId) {
2852
+ const nextTable = cloneRuntimeTable(table);
2853
+ getEdge(nextTable, boardId, edgeId);
2854
+ const position = getComponentsOnEdge(nextTable, boardId, edgeId).length;
2855
+ removeComponentFromCurrentLocation(nextTable, componentId);
2856
+ nextTable.componentLocations[componentId] = {
2857
+ type: "OnEdge",
2858
+ boardId,
2859
+ edgeId,
2860
+ position
2861
+ };
2862
+ return nextTable;
2863
+ }
2864
+ function moveComponentToVertex(table, componentId, boardId, vertexId) {
2865
+ const nextTable = cloneRuntimeTable(table);
2866
+ getVertex(nextTable, boardId, vertexId);
2867
+ const position = getComponentsOnVertex(nextTable, boardId, vertexId).length;
2868
+ removeComponentFromCurrentLocation(nextTable, componentId);
2869
+ nextTable.componentLocations[componentId] = {
2870
+ type: "OnVertex",
2871
+ boardId,
2872
+ vertexId,
2873
+ position
2874
+ };
2875
+ return nextTable;
2876
+ }
2877
+
2878
+ // src/reducer/table/card-mutations.ts
2879
+ function shufflePlayerZoneCards(table, zoneId, playerId, nextCards) {
2880
+ if (nextCards === void 0) {
2881
+ const fromZone = ppRead(
2882
+ table.zones.perPlayer[zoneId] ?? table.hands[zoneId],
2883
+ playerId
2884
+ );
2885
+ return [...ensureArray(fromZone)];
2886
+ }
2887
+ table.hands[zoneId] = ppWrite(table.hands[zoneId], playerId, [
2888
+ ...nextCards
2889
+ ]);
2890
+ table.zones.perPlayer[zoneId] = ppWrite(
2891
+ table.zones.perPlayer[zoneId],
2892
+ playerId,
2893
+ [...nextCards]
2894
+ );
2895
+ return [...nextCards];
2896
+ }
2897
+ function appendToDeck(table, deckId, cardId, playedBy = null, position = "bottom") {
2898
+ const nextTable = cloneRuntimeTable(table);
2899
+ assertZoneScope(
2900
+ nextTable,
2901
+ deckId,
2902
+ "shared",
2903
+ "addCardToSharedZone",
2904
+ "zoneId"
2905
+ );
2906
+ const deckCards = [
2907
+ ...ensureArray(nextTable.decks[deckId])
2908
+ ];
2909
+ assertCardAllowedInZone(nextTable, deckId, cardId);
2910
+ if (position === "top") {
2911
+ deckCards.unshift(cardId);
2912
+ } else {
2913
+ deckCards.push(cardId);
2914
+ }
2915
+ syncSharedZoneWithDeck(nextTable, deckId, deckCards);
2916
+ for (const [index, currentCardId] of deckCards.entries()) {
2917
+ if (currentCardId === cardId) {
2918
+ nextTable.componentLocations[currentCardId] = {
2919
+ type: "InDeck",
2920
+ deckId,
2921
+ playedBy,
2922
+ position: index
2923
+ };
2924
+ continue;
2925
+ }
2926
+ const existing = nextTable.componentLocations[currentCardId];
2927
+ nextTable.componentLocations[currentCardId] = {
2928
+ type: "InDeck",
2929
+ deckId,
2930
+ playedBy: existing?.type === "InDeck" ? existing.playedBy : null,
2931
+ position: index
2932
+ };
2933
+ }
2934
+ nextTable.ownerOfCard[cardId] = playedBy;
2935
+ nextTable.visibility[cardId] = {
2936
+ faceUp: true
2937
+ };
2938
+ return nextTable;
2939
+ }
2940
+ function removeFromDeck(table, deckId, cardId) {
2983
2941
  const nextTable = cloneRuntimeTable(table);
2984
- removeComponentFromCurrentLocation(nextTable, componentId);
2985
- nextTable.componentLocations[componentId] = { type: "Detached" };
2942
+ assertZoneScope(
2943
+ nextTable,
2944
+ deckId,
2945
+ "shared",
2946
+ "removeCardFromSharedZone",
2947
+ "zoneId"
2948
+ );
2949
+ const remaining = ensureArray(nextTable.decks[deckId]).filter(
2950
+ (candidate) => candidate !== cardId
2951
+ );
2952
+ syncSharedZoneWithDeck(nextTable, deckId, remaining);
2953
+ for (const [index, currentCardId] of remaining.entries()) {
2954
+ const currentLocation = nextTable.componentLocations[currentCardId];
2955
+ if (currentLocation?.type === "InDeck") {
2956
+ nextTable.componentLocations[currentCardId] = {
2957
+ ...currentLocation,
2958
+ position: index
2959
+ };
2960
+ }
2961
+ }
2986
2962
  return nextTable;
2987
2963
  }
2988
- function moveComponentToEdge(table, componentId, boardId, edgeId) {
2989
- const nextTable = cloneRuntimeTable(table);
2990
- getEdge(nextTable, boardId, edgeId);
2991
- const position = getComponentsOnEdge(nextTable, boardId, edgeId).length;
2992
- removeComponentFromCurrentLocation(nextTable, componentId);
2993
- nextTable.componentLocations[componentId] = {
2994
- type: "OnEdge",
2995
- boardId,
2996
- edgeId,
2997
- position
2998
- };
2999
- return nextTable;
2964
+ function computeVisibilityForPlayerZone(table, zoneId, playerId) {
2965
+ const mode = table.handVisibility[zoneId];
2966
+ if (mode === "all" || mode === "public") {
2967
+ return { faceUp: true };
2968
+ }
2969
+ return { faceUp: false, visibleTo: [playerId] };
3000
2970
  }
3001
- function moveComponentToVertex(table, componentId, boardId, vertexId) {
3002
- const nextTable = cloneRuntimeTable(table);
3003
- getVertex(nextTable, boardId, vertexId);
3004
- const position = getComponentsOnVertex(nextTable, boardId, vertexId).length;
3005
- removeComponentFromCurrentLocation(nextTable, componentId);
3006
- nextTable.componentLocations[componentId] = {
3007
- type: "OnVertex",
3008
- boardId,
3009
- vertexId,
3010
- position
2971
+ function moveFromHandToDeck(options) {
2972
+ const nextTable = cloneRuntimeTable(options.table);
2973
+ assertZoneScope(
2974
+ nextTable,
2975
+ options.handId,
2976
+ "perPlayer",
2977
+ "moveCardFromPlayerZoneToSharedZone",
2978
+ "fromZoneId"
2979
+ );
2980
+ assertZoneScope(
2981
+ nextTable,
2982
+ options.deckId,
2983
+ "shared",
2984
+ "moveCardFromPlayerZoneToSharedZone",
2985
+ "toZoneId"
2986
+ );
2987
+ const currentHand = ensureArray(
2988
+ ppRead(nextTable.hands[options.handId], options.playerId)
2989
+ ).filter((candidate) => candidate !== options.cardId);
2990
+ syncPlayerZoneWithHand(
2991
+ nextTable,
2992
+ options.handId,
2993
+ options.playerId,
2994
+ currentHand
2995
+ );
2996
+ for (const [index, currentCardId] of currentHand.entries()) {
2997
+ nextTable.componentLocations[currentCardId] = {
2998
+ type: "InHand",
2999
+ handId: options.handId,
3000
+ playerId: options.playerId,
3001
+ position: index
3002
+ };
3003
+ }
3004
+ nextTable.ownerOfCard[options.cardId] = options.playedBy ?? options.playerId;
3005
+ nextTable.visibility[options.cardId] = {
3006
+ faceUp: true
3011
3007
  };
3012
- return nextTable;
3008
+ return appendToDeck(
3009
+ nextTable,
3010
+ options.deckId,
3011
+ options.cardId,
3012
+ options.playedBy ?? options.playerId,
3013
+ options.position ?? "bottom"
3014
+ );
3013
3015
  }
3014
3016
  function moveCardFromPlayerZoneToSharedZone(options) {
3015
3017
  return moveFromHandToDeck({
@@ -3264,6 +3266,23 @@ function dealCardsFromDeckToHand(table, fromZoneId, playerId, toZoneId, count) {
3264
3266
  return nextTable;
3265
3267
  }
3266
3268
 
3269
+ // src/reducer/table/phase-state.ts
3270
+ function setActivePlayers(state, activePlayers) {
3271
+ return {
3272
+ ...state,
3273
+ flow: {
3274
+ ...state.flow,
3275
+ activePlayers
3276
+ }
3277
+ };
3278
+ }
3279
+ function setPhaseState(state, phaseState) {
3280
+ return {
3281
+ ...state,
3282
+ phase: phaseState
3283
+ };
3284
+ }
3285
+
3267
3286
  // src/reducer/rng.ts
3268
3287
  function nextRandomInt(bound, rng) {
3269
3288
  if (bound <= 0) {
@@ -4904,33 +4923,7 @@ function createTrustedInstructionRunner(scope, interactions, lifecycle) {
4904
4923
  };
4905
4924
  }
4906
4925
 
4907
- // src/reducer/parse-utils.ts
4908
- function formatIssue(label, issue) {
4909
- const path = issue.path.map(
4910
- (segment) => typeof segment === "symbol" ? segment.toString() : String(segment)
4911
- ).join(".");
4912
- return `${path || label}: ${issue.message}`;
4913
- }
4914
- function safeParseOrThrow(schema, value, label) {
4915
- const parsed = schema.safeParse(value);
4916
- if (!parsed.success) {
4917
- const message = parsed.error.issues.map((issue) => formatIssue(label, issue)).join("; ");
4918
- throw new Error(message || `Invalid ${label}`);
4919
- }
4920
- return parsed.data;
4921
- }
4922
-
4923
- // src/reducer/bundle/trusted/interaction-types.ts
4924
- function makeValidationError(errorCode, message) {
4925
- return {
4926
- valid: false,
4927
- errorCode,
4928
- message
4929
- };
4930
- }
4931
-
4932
- // src/reducer/bundle/trusted/interaction-collectors.ts
4933
- var MAX_EAGER_DEPENDENT_DOMAIN_CASES = 64;
4926
+ // src/reducer/bundle/trusted/collector-introspection.ts
4934
4927
  function collectTargetDomainMetadata(collector) {
4935
4928
  switch (collector.kind) {
4936
4929
  case "card": {
@@ -4952,389 +4945,105 @@ function collectTargetDomainMetadata(collector) {
4952
4945
  valueKind: meta.valueKind
4953
4946
  };
4954
4947
  }
4955
- default:
4956
- return {};
4957
- }
4958
- }
4959
- function withSelection(domain, collector) {
4960
- if (!collector.selection) return domain;
4961
- return { ...domain, selection: collector.selection };
4962
- }
4963
- function lazyTargetDomainFromCollectorMetadata(key, collector, dependencies) {
4964
- const metadata = collectTargetDomainMetadata(collector);
4965
- if (collector.kind === "card") {
4966
- return withSelection(
4967
- {
4968
- type: "cardTarget",
4969
- projection: "lazy",
4970
- targetKind: "card",
4971
- zoneIds: metadata.zoneIds ?? (metadata.zoneId === void 0 ? [] : [metadata.zoneId]),
4972
- dependencies: {
4973
- mode: "lazy",
4974
- dependsOn: dependencies,
4975
- resolver: { inputKey: key }
4976
- }
4977
- },
4978
- collector
4979
- );
4980
- }
4981
- if (collector.kind === "board-edge" || collector.kind === "board-space" || collector.kind === "board-tile" || collector.kind === "board-vertex") {
4982
- return withSelection(
4983
- {
4984
- type: "boardTarget",
4985
- projection: "lazy",
4986
- targetKind: metadata.targetKind ?? collector.kind.replace("board-", ""),
4987
- boardId: metadata.boardId ?? "",
4988
- ...metadata.valueKind ? { valueKind: metadata.valueKind } : {},
4989
- dependencies: {
4990
- mode: "lazy",
4991
- dependsOn: dependencies,
4992
- resolver: { inputKey: key }
4993
- }
4994
- },
4995
- collector
4996
- );
4997
- }
4998
- return null;
4999
- }
5000
- function finiteValuesForDependency(key, domain) {
5001
- if (!domain) {
5002
- throw new Error(
5003
- `Interaction input '${key}' is declared as a dependency before it has a projected domain.`
5004
- );
5005
- }
5006
- if (domain.type === "cardTarget" || domain.type === "boardTarget") {
5007
- if (domain.projection !== "resolved") {
5008
- throw new Error(
5009
- `Interaction input '${key}' cannot be used as a dependency because its target domain is not finite.`
5010
- );
5011
- }
5012
- return [...domain.eligibleTargets];
5013
- }
5014
- if (domain.type === "choice") {
5015
- return domain.choices.flatMap(
5016
- (choice) => choice.value === null ? [] : [choice.value]
5017
- );
5018
- }
5019
- throw new Error(
5020
- `Interaction input '${key}' cannot be used as a dependency. V1 supports finite target and choice dependencies only.`
5021
- );
5022
- }
5023
- function cartesianDependencyTuples(dependencies, domainsByKey) {
5024
- return dependencies.reduce(
5025
- (tuples, key) => {
5026
- const values = finiteValuesForDependency(key, domainsByKey[key]);
5027
- return tuples.flatMap(
5028
- (tuple) => values.map((value) => ({ ...tuple, [key]: value }))
5029
- );
5030
- },
5031
- [{}]
5032
- );
5033
- }
5034
- function withoutDependentProjection(domain) {
5035
- const { dependencies: _dependencies, ...rest } = domain;
5036
- return rest;
5037
- }
5038
- function toLazyTargetDomain(key, domain, dependencies) {
5039
- if (domain.type === "cardTarget") {
5040
- return {
5041
- type: "cardTarget",
5042
- projection: "lazy",
5043
- targetKind: "card",
5044
- zoneIds: domain.zoneIds,
5045
- ...domain.selection ? { selection: domain.selection } : {},
5046
- dependencies: {
5047
- mode: "lazy",
5048
- dependsOn: dependencies,
5049
- resolver: { inputKey: key }
5050
- }
5051
- };
5052
- }
5053
- if (domain.type === "boardTarget") {
5054
- return {
5055
- type: "boardTarget",
5056
- projection: "lazy",
5057
- targetKind: domain.targetKind,
5058
- boardId: domain.boardId,
5059
- ...domain.valueKind ? { valueKind: domain.valueKind } : {},
5060
- ...domain.selection ? { selection: domain.selection } : {},
5061
- dependencies: {
5062
- mode: "lazy",
5063
- dependsOn: dependencies,
5064
- resolver: { inputKey: key }
5065
- }
5066
- };
4948
+ default:
4949
+ return {};
5067
4950
  }
5068
- return null;
5069
- }
5070
- function dependencyCaseCount(dependencies, domainsByKey) {
5071
- return dependencies.map((key) => finiteValuesForDependency(key, domainsByKey[key]).length).reduce((total, count) => total * count, 1);
5072
- }
5073
- function unsupportedDefaultInputError(key, collector) {
5074
- return new Error(
5075
- `Interaction input '${key}' uses a '${collector.kind}' collector without a default-renderable domain or target metadata. Use formInput.choice(...), formInput.choiceList(...), formInput.number(...), formInput.resourceMap(...), cardInput(...), or boardInput(...). For custom payloads, use a custom interaction surface with paramsSchema instead of the default InteractionForm.`
5076
- );
5077
4951
  }
5078
4952
  function interactionInputsOf(interaction) {
5079
4953
  return interaction.inputs;
5080
4954
  }
5081
- function collectEligibleTargets(interaction, domainState, playerId, options = {}) {
4955
+ function collectFirstCardZoneId(interaction) {
5082
4956
  const collectors = interactionInputsOf(interaction);
5083
- const result = {};
5084
- let queriesLazy = options.queries ?? null;
5085
- const queries = () => queriesLazy ??= createStateQueries(
5086
- domainState
5087
- );
5088
- for (const [key, collector] of Object.entries(collectors)) {
5089
- if (!collector.eligibleTargets) continue;
5090
- const cacheKey = options.eligibleTargetCachePrefix ? `${options.eligibleTargetCachePrefix}:${key}` : null;
5091
- const cached = cacheKey ? options.eligibleTargetCache?.get(cacheKey) : void 0;
5092
- if (cached) {
5093
- result[key] = cached;
5094
- continue;
5095
- }
5096
- const targets = collector.eligibleTargets(
5097
- domainState,
5098
- playerId,
5099
- queries()
5100
- );
5101
- const resolved = Array.from(targets).map(
5102
- (t) => String(t)
5103
- );
5104
- result[key] = resolved;
5105
- if (cacheKey) {
5106
- options.eligibleTargetCache?.set(cacheKey, resolved);
4957
+ for (const collector of Object.values(collectors)) {
4958
+ if (collector.kind === "card") {
4959
+ if (collector.meta.zoneId.length > 0) {
4960
+ return collector.meta.zoneId;
4961
+ }
5107
4962
  }
5108
4963
  }
5109
- return result;
4964
+ return void 0;
5110
4965
  }
5111
- function collectInputDomains(interaction, domainState, playerId, eligibleTargets, options = {}) {
4966
+ function collectCardZoneIds(interaction) {
5112
4967
  const collectors = interactionInputsOf(interaction);
5113
- let queriesLazy = options.queries ?? null;
5114
- const queries = () => queriesLazy ??= createStateQueries(
5115
- domainState
5116
- );
5117
- let derivedLazy = options.derived ?? null;
5118
- const derived = () => derivedLazy ??= createDerivedResolver(domainState, { q: queries() });
5119
- const result = {};
5120
- for (const [key, collector] of Object.entries(collectors)) {
5121
- if (collector.kind === "rng") {
5122
- continue;
5123
- }
5124
- if (collector.kind === "prompt") {
5125
- const optionFactory = collector.meta?.options;
5126
- if (!optionFactory) continue;
5127
- result[key] = {
5128
- type: "choice",
5129
- choices: optionFactory(domainState, playerId, queries()).map(
5130
- (option) => ({
5131
- value: String(option.id),
5132
- label: option.label ?? String(option.id),
5133
- ...(() => {
5134
- const issue = collector.validateTarget?.(
5135
- domainState,
5136
- playerId,
5137
- queries(),
5138
- String(option.id)
5139
- );
5140
- return issue ? {
5141
- disabled: true,
5142
- disabledReason: issue.message ?? issue.errorCode
5143
- } : {};
5144
- })()
5145
- })
5146
- )
5147
- };
5148
- continue;
5149
- }
5150
- if (collector.domain) {
5151
- const domainProjector = collector.domain;
5152
- const dependencies = collector.dependsOn ?? [];
5153
- if (options.includeEligibleTargets === false && !Object.prototype.hasOwnProperty.call(eligibleTargets, key)) {
5154
- const lazyDomain2 = lazyTargetDomainFromCollectorMetadata(
5155
- key,
5156
- collector,
5157
- dependencies
5158
- );
5159
- if (lazyDomain2) {
5160
- result[key] = lazyDomain2;
5161
- continue;
5162
- }
5163
- }
5164
- const baseDomain = withSelection(
5165
- domainProjector(
5166
- domainState,
5167
- playerId,
5168
- queries(),
5169
- derived(),
5170
- {}
5171
- ),
5172
- collector
5173
- );
5174
- if (dependencies.length === 0) {
5175
- result[key] = baseDomain;
5176
- continue;
5177
- }
5178
- const caseCount = dependencyCaseCount(dependencies, result);
5179
- const lazyDomain = caseCount > MAX_EAGER_DEPENDENT_DOMAIN_CASES ? toLazyTargetDomain(key, baseDomain, dependencies) : null;
5180
- if (lazyDomain) {
5181
- result[key] = lazyDomain;
5182
- continue;
4968
+ const zoneIds = /* @__PURE__ */ new Set();
4969
+ for (const collector of Object.values(collectors)) {
4970
+ if (collector.kind === "card") {
4971
+ for (const zoneId of collector.meta.zoneIds ?? [collector.meta.zoneId]) {
4972
+ if (zoneId.length > 0) zoneIds.add(zoneId);
5183
4973
  }
5184
- const dependentCases = cartesianDependencyTuples(
5185
- dependencies,
5186
- result
5187
- ).map((values) => ({
5188
- when: values,
5189
- domain: withoutDependentProjection(
5190
- withSelection(
5191
- domainProjector(
5192
- domainState,
5193
- playerId,
5194
- queries(),
5195
- derived(),
5196
- values
5197
- ),
5198
- collector
5199
- )
5200
- )
5201
- }));
5202
- result[key] = {
5203
- ...baseDomain,
5204
- dependencies: {
5205
- mode: "eager",
5206
- dependentCases
5207
- }
5208
- };
5209
- continue;
5210
4974
  }
5211
- throw unsupportedDefaultInputError(key, collector);
5212
4975
  }
5213
- return result;
4976
+ return [...zoneIds];
5214
4977
  }
5215
- function collectInteractionInputs(interaction, domainState, playerId, options = {}) {
4978
+ function findCardInputKey(interaction) {
4979
+ return Object.entries(interactionInputsOf(interaction)).find(
4980
+ ([, collector]) => collector.kind === "card"
4981
+ )?.[0];
4982
+ }
4983
+ function findCardInputKeyForZone(interaction, zoneId) {
4984
+ return Object.entries(interactionInputsOf(interaction)).find(
4985
+ ([, collector]) => collector.kind === "card" && (collector.meta.zoneIds ?? [collector.meta.zoneId]).map(String).includes(zoneId)
4986
+ )?.[0];
4987
+ }
4988
+
4989
+ // src/reducer/bundle/trusted/collector-eligibility.ts
4990
+ function collectEligibleTargets(interaction, domainState, playerId, options = {}) {
5216
4991
  const collectors = interactionInputsOf(interaction);
5217
- const dependencyKeys = new Set(
5218
- Object.values(collectors).flatMap((collector) => [
5219
- ...collector.dependsOn ?? []
5220
- ])
5221
- );
5222
- const collectedEligibleTargets = options.includeEligibleTargets === false && dependencyKeys.size === 0 ? {} : collectEligibleTargets(interaction, domainState, playerId, options);
5223
- const eligibleTargets = options.includeEligibleTargets === false ? Object.fromEntries(
5224
- Object.entries(collectedEligibleTargets).filter(
5225
- ([key]) => dependencyKeys.has(key)
5226
- )
5227
- ) : collectedEligibleTargets;
5228
- const domainsByKey = collectInputDomains(
5229
- interaction,
5230
- domainState,
5231
- playerId,
5232
- eligibleTargets,
5233
- options
5234
- );
4992
+ const result = {};
5235
4993
  let queriesLazy = options.queries ?? null;
5236
4994
  const queries = () => queriesLazy ??= createStateQueries(
5237
4995
  domainState
5238
4996
  );
5239
- let derivedLazy = options.derived ?? null;
5240
- const derived = () => derivedLazy ??= createDerivedResolver(domainState, { q: queries() });
5241
- return Object.entries(collectors).flatMap(([key, collector]) => {
5242
- if (collector.kind === "rng") {
5243
- return [];
5244
- }
5245
- const domain = domainsByKey[key];
5246
- if (!domain && collector.kind === "prompt") {
5247
- return [];
5248
- }
5249
- if (!domain) {
5250
- throw unsupportedDefaultInputError(key, collector);
5251
- }
5252
- const dynamicDefault = collector.resolveDefaultValue?.(
5253
- domainState,
5254
- playerId,
5255
- queries(),
5256
- derived(),
5257
- domain
5258
- );
5259
- const defaultValue = "defaultValue" in collector ? collector.defaultValue : dynamicDefault;
5260
- warnConcreteDependentChoiceDefault({
5261
- inputKey: key,
5262
- collector,
5263
- domain,
5264
- defaultValue,
5265
- dependencyKeys
5266
- });
5267
- return [
5268
- {
5269
- key,
5270
- kind: collector.kind,
5271
- domain,
5272
- ...defaultValue !== void 0 ? { defaultValue } : {}
5273
- }
5274
- ];
5275
- });
5276
- }
5277
- var concreteDependentChoiceDefaultWarnings = /* @__PURE__ */ new Set();
5278
- function shouldEmitAuthoringWarning() {
5279
- const env = globalThis.process?.env;
5280
- return env?.NODE_ENV !== "production" && env?.DREAMBOARD_SUPPRESS_AUTHORING_WARNINGS !== "1";
5281
- }
5282
- function warnConcreteDependentChoiceDefault({
5283
- inputKey,
5284
- collector,
5285
- domain,
5286
- defaultValue,
5287
- dependencyKeys
5288
- }) {
5289
- if (!shouldEmitAuthoringWarning() || !dependencyKeys.has(inputKey) || collector.kind !== "form" || domain.type !== "choice" || defaultValue === void 0 || defaultValue === null) {
5290
- return;
5291
- }
5292
- const warningKey = `${inputKey}:${String(defaultValue)}`;
5293
- if (concreteDependentChoiceDefaultWarnings.has(warningKey)) {
5294
- return;
5295
- }
5296
- concreteDependentChoiceDefaultWarnings.add(warningKey);
5297
- console.warn(
5298
- `[dreamboard] Form choice input "${inputKey}" feeds another collector and defaulted to "${String(
5299
- defaultValue
5300
- )}". Dependent choices that select the object an action applies to should usually use defaultValue: () => undefined so collection stays explicit.`
5301
- );
5302
- }
5303
- function collectFirstCardZoneId(interaction) {
5304
- const collectors = interactionInputsOf(interaction);
5305
- for (const collector of Object.values(collectors)) {
5306
- if (collector.kind === "card") {
5307
- if (collector.meta.zoneId.length > 0) {
5308
- return collector.meta.zoneId;
5309
- }
4997
+ for (const [key, collector] of Object.entries(collectors)) {
4998
+ if (!collector.eligibleTargets) continue;
4999
+ const cacheKey = options.eligibleTargetCachePrefix ? `${options.eligibleTargetCachePrefix}:${key}` : null;
5000
+ const cached = cacheKey ? options.eligibleTargetCache?.get(cacheKey) : void 0;
5001
+ if (cached) {
5002
+ result[key] = cached;
5003
+ continue;
5310
5004
  }
5311
- }
5312
- return void 0;
5313
- }
5314
- function collectCardZoneIds(interaction) {
5315
- const collectors = interactionInputsOf(interaction);
5316
- const zoneIds = /* @__PURE__ */ new Set();
5317
- for (const collector of Object.values(collectors)) {
5318
- if (collector.kind === "card") {
5319
- for (const zoneId of collector.meta.zoneIds ?? [collector.meta.zoneId]) {
5320
- if (zoneId.length > 0) zoneIds.add(zoneId);
5321
- }
5005
+ const targets = collector.eligibleTargets(
5006
+ domainState,
5007
+ playerId,
5008
+ queries()
5009
+ );
5010
+ const resolved = Array.from(targets).map(
5011
+ (t) => String(t)
5012
+ );
5013
+ result[key] = resolved;
5014
+ if (cacheKey) {
5015
+ options.eligibleTargetCache?.set(cacheKey, resolved);
5322
5016
  }
5323
5017
  }
5324
- return [...zoneIds];
5018
+ return result;
5325
5019
  }
5326
- function collectPromptOptions(interaction, domainState, playerId, queries) {
5327
- for (const collector of Object.values(interaction.inputs)) {
5328
- if (collector.kind !== "prompt") continue;
5329
- const factory = collector.meta?.options;
5330
- if (!factory) continue;
5331
- return factory(domainState, playerId, queries).map((option) => ({
5332
- id: String(option.id),
5333
- ...option.label !== void 0 ? { label: option.label } : {}
5334
- }));
5020
+
5021
+ // src/reducer/parse-utils.ts
5022
+ function formatIssue(label, issue) {
5023
+ const path = issue.path.map(
5024
+ (segment) => typeof segment === "symbol" ? segment.toString() : String(segment)
5025
+ ).join(".");
5026
+ return `${path || label}: ${issue.message}`;
5027
+ }
5028
+ function safeParseOrThrow(schema, value, label) {
5029
+ const parsed = schema.safeParse(value);
5030
+ if (!parsed.success) {
5031
+ const message = parsed.error.issues.map((issue) => formatIssue(label, issue)).join("; ");
5032
+ throw new Error(message || `Invalid ${label}`);
5335
5033
  }
5336
- return void 0;
5034
+ return parsed.data;
5035
+ }
5036
+
5037
+ // src/reducer/bundle/trusted/interaction-types.ts
5038
+ function makeValidationError(errorCode, message) {
5039
+ return {
5040
+ valid: false,
5041
+ errorCode,
5042
+ message
5043
+ };
5337
5044
  }
5045
+
5046
+ // src/reducer/bundle/trusted/collector-params.ts
5338
5047
  function parseInteractionParams(interaction, rawParams, options = {}) {
5339
5048
  const collectors = interactionInputsOf(interaction);
5340
5049
  const record = rawParams ?? {};
@@ -5490,16 +5199,6 @@ function stableValueKey(value) {
5490
5199
  return `json:${JSON.stringify(value)}`;
5491
5200
  }
5492
5201
  }
5493
- function findCardInputKey(interaction) {
5494
- return Object.entries(interactionInputsOf(interaction)).find(
5495
- ([, collector]) => collector.kind === "card"
5496
- )?.[0];
5497
- }
5498
- function findCardInputKeyForZone(interaction, zoneId) {
5499
- return Object.entries(interactionInputsOf(interaction)).find(
5500
- ([, collector]) => collector.kind === "card" && (collector.meta.zoneIds ?? [collector.meta.zoneId]).map(String).includes(zoneId)
5501
- )?.[0];
5502
- }
5503
5202
 
5504
5203
  // src/reducer/bundle/trusted/interaction-authorization.ts
5505
5204
  function resolvePromptToSet(to) {
@@ -5548,55 +5247,373 @@ function createInteractionAuthorization(scope) {
5548
5247
  )
5549
5248
  };
5550
5249
  }
5551
- if (phase.actor) {
5552
- const resolved = phase.actor({
5553
- ...scope.buildRuntimeArgs(
5554
- state,
5555
- {
5556
- state: projection?.domainState ?? scope.toDomainState(state)
5557
- },
5558
- projection
5250
+ if (phase.actor) {
5251
+ const resolved = phase.actor({
5252
+ ...scope.buildRuntimeArgs(
5253
+ state,
5254
+ {
5255
+ state: projection?.domainState ?? scope.toDomainState(state)
5256
+ },
5257
+ projection
5258
+ )
5259
+ });
5260
+ return {
5261
+ mode: "actors",
5262
+ actors: resolvePromptToSet(resolved)
5263
+ };
5264
+ }
5265
+ return { mode: "active" };
5266
+ }
5267
+ function isActorAuthorized(state, playerId, authorization) {
5268
+ if (authorization.mode === "addressees") {
5269
+ return authorization.addressees.has(playerId);
5270
+ }
5271
+ if (authorization.mode === "actors") {
5272
+ return authorization.actors.has(playerId);
5273
+ }
5274
+ const active = state.flow.activePlayers;
5275
+ if (active.length === 0) {
5276
+ return true;
5277
+ }
5278
+ return active.includes(playerId);
5279
+ }
5280
+ function isInteractionVisible(interaction, authorization, authorized) {
5281
+ return !(authorization.mode === "addressees" && !authorized) && !(interaction.visibility === "actorsOnly" && !authorized);
5282
+ }
5283
+ return {
5284
+ isActorAuthorized,
5285
+ isInteractionVisible,
5286
+ resolveInteractionActorAuthorization
5287
+ };
5288
+ }
5289
+
5290
+ // src/reducer/bundle/trusted/collector-domains.ts
5291
+ var MAX_EAGER_DEPENDENT_DOMAIN_CASES = 64;
5292
+ function withSelection(domain, collector) {
5293
+ if (!collector.selection) return domain;
5294
+ return { ...domain, selection: collector.selection };
5295
+ }
5296
+ function lazyTargetDomainFromCollectorMetadata(key, collector, dependencies) {
5297
+ const metadata = collectTargetDomainMetadata(collector);
5298
+ if (collector.kind === "card") {
5299
+ return withSelection(
5300
+ {
5301
+ type: "cardTarget",
5302
+ projection: "lazy",
5303
+ targetKind: "card",
5304
+ zoneIds: metadata.zoneIds ?? (metadata.zoneId === void 0 ? [] : [metadata.zoneId]),
5305
+ dependencies: {
5306
+ mode: "lazy",
5307
+ dependsOn: dependencies,
5308
+ resolver: { inputKey: key }
5309
+ }
5310
+ },
5311
+ collector
5312
+ );
5313
+ }
5314
+ if (collector.kind === "board-edge" || collector.kind === "board-space" || collector.kind === "board-tile" || collector.kind === "board-vertex") {
5315
+ return withSelection(
5316
+ {
5317
+ type: "boardTarget",
5318
+ projection: "lazy",
5319
+ targetKind: metadata.targetKind ?? collector.kind.replace("board-", ""),
5320
+ boardId: metadata.boardId ?? "",
5321
+ ...metadata.valueKind ? { valueKind: metadata.valueKind } : {},
5322
+ dependencies: {
5323
+ mode: "lazy",
5324
+ dependsOn: dependencies,
5325
+ resolver: { inputKey: key }
5326
+ }
5327
+ },
5328
+ collector
5329
+ );
5330
+ }
5331
+ return null;
5332
+ }
5333
+ function finiteValuesForDependency(key, domain) {
5334
+ if (!domain) {
5335
+ throw new Error(
5336
+ `Interaction input '${key}' is declared as a dependency before it has a projected domain.`
5337
+ );
5338
+ }
5339
+ if (domain.type === "cardTarget" || domain.type === "boardTarget") {
5340
+ if (domain.projection !== "resolved") {
5341
+ throw new Error(
5342
+ `Interaction input '${key}' cannot be used as a dependency because its target domain is not finite.`
5343
+ );
5344
+ }
5345
+ return [...domain.eligibleTargets];
5346
+ }
5347
+ if (domain.type === "choice") {
5348
+ return domain.choices.flatMap(
5349
+ (choice) => choice.value === null ? [] : [choice.value]
5350
+ );
5351
+ }
5352
+ throw new Error(
5353
+ `Interaction input '${key}' cannot be used as a dependency. V1 supports finite target and choice dependencies only.`
5354
+ );
5355
+ }
5356
+ function cartesianDependencyTuples(dependencies, domainsByKey) {
5357
+ return dependencies.reduce(
5358
+ (tuples, key) => {
5359
+ const values = finiteValuesForDependency(key, domainsByKey[key]);
5360
+ return tuples.flatMap(
5361
+ (tuple) => values.map((value) => ({ ...tuple, [key]: value }))
5362
+ );
5363
+ },
5364
+ [{}]
5365
+ );
5366
+ }
5367
+ function withoutDependentProjection(domain) {
5368
+ const { dependencies: _dependencies, ...rest } = domain;
5369
+ return rest;
5370
+ }
5371
+ function toLazyTargetDomain(key, domain, dependencies) {
5372
+ if (domain.type === "cardTarget") {
5373
+ return {
5374
+ type: "cardTarget",
5375
+ projection: "lazy",
5376
+ targetKind: "card",
5377
+ zoneIds: domain.zoneIds,
5378
+ ...domain.selection ? { selection: domain.selection } : {},
5379
+ dependencies: {
5380
+ mode: "lazy",
5381
+ dependsOn: dependencies,
5382
+ resolver: { inputKey: key }
5383
+ }
5384
+ };
5385
+ }
5386
+ if (domain.type === "boardTarget") {
5387
+ return {
5388
+ type: "boardTarget",
5389
+ projection: "lazy",
5390
+ targetKind: domain.targetKind,
5391
+ boardId: domain.boardId,
5392
+ ...domain.valueKind ? { valueKind: domain.valueKind } : {},
5393
+ ...domain.selection ? { selection: domain.selection } : {},
5394
+ dependencies: {
5395
+ mode: "lazy",
5396
+ dependsOn: dependencies,
5397
+ resolver: { inputKey: key }
5398
+ }
5399
+ };
5400
+ }
5401
+ return null;
5402
+ }
5403
+ function dependencyCaseCount(dependencies, domainsByKey) {
5404
+ return dependencies.map((key) => finiteValuesForDependency(key, domainsByKey[key]).length).reduce((total, count) => total * count, 1);
5405
+ }
5406
+ function unsupportedDefaultInputError(key, collector) {
5407
+ return new Error(
5408
+ `Interaction input '${key}' uses a '${collector.kind}' collector without a default-renderable domain or target metadata. Use formInput.choice(...), formInput.choiceList(...), formInput.number(...), formInput.resourceMap(...), cardInput(...), or boardInput(...). For custom payloads, use a custom interaction surface with paramsSchema instead of the default InteractionForm.`
5409
+ );
5410
+ }
5411
+ function collectInputDomains(interaction, domainState, playerId, eligibleTargets, options = {}) {
5412
+ const collectors = interactionInputsOf(interaction);
5413
+ let queriesLazy = options.queries ?? null;
5414
+ const queries = () => queriesLazy ??= createStateQueries(
5415
+ domainState
5416
+ );
5417
+ let derivedLazy = options.derived ?? null;
5418
+ const derived = () => derivedLazy ??= createDerivedResolver(domainState, { q: queries() });
5419
+ const result = {};
5420
+ for (const [key, collector] of Object.entries(collectors)) {
5421
+ if (collector.kind === "rng") {
5422
+ continue;
5423
+ }
5424
+ if (collector.kind === "prompt") {
5425
+ const optionFactory = collector.meta?.options;
5426
+ if (!optionFactory) continue;
5427
+ result[key] = {
5428
+ type: "choice",
5429
+ choices: optionFactory(domainState, playerId, queries()).map(
5430
+ (option) => ({
5431
+ value: String(option.id),
5432
+ label: option.label ?? String(option.id),
5433
+ ...(() => {
5434
+ const issue = collector.validateTarget?.(
5435
+ domainState,
5436
+ playerId,
5437
+ queries(),
5438
+ String(option.id)
5439
+ );
5440
+ return issue ? {
5441
+ disabled: true,
5442
+ disabledReason: issue.message ?? issue.errorCode
5443
+ } : {};
5444
+ })()
5445
+ })
5446
+ )
5447
+ };
5448
+ continue;
5449
+ }
5450
+ if (collector.domain) {
5451
+ const domainProjector = collector.domain;
5452
+ const dependencies = collector.dependsOn ?? [];
5453
+ if (options.includeEligibleTargets === false && !Object.prototype.hasOwnProperty.call(eligibleTargets, key)) {
5454
+ const lazyDomain2 = lazyTargetDomainFromCollectorMetadata(
5455
+ key,
5456
+ collector,
5457
+ dependencies
5458
+ );
5459
+ if (lazyDomain2) {
5460
+ result[key] = lazyDomain2;
5461
+ continue;
5462
+ }
5463
+ }
5464
+ const baseDomain = withSelection(
5465
+ domainProjector(
5466
+ domainState,
5467
+ playerId,
5468
+ queries(),
5469
+ derived(),
5470
+ {}
5471
+ ),
5472
+ collector
5473
+ );
5474
+ if (dependencies.length === 0) {
5475
+ result[key] = baseDomain;
5476
+ continue;
5477
+ }
5478
+ const caseCount = dependencyCaseCount(dependencies, result);
5479
+ const lazyDomain = caseCount > MAX_EAGER_DEPENDENT_DOMAIN_CASES ? toLazyTargetDomain(key, baseDomain, dependencies) : null;
5480
+ if (lazyDomain) {
5481
+ result[key] = lazyDomain;
5482
+ continue;
5483
+ }
5484
+ const dependentCases = cartesianDependencyTuples(
5485
+ dependencies,
5486
+ result
5487
+ ).map((values) => ({
5488
+ when: values,
5489
+ domain: withoutDependentProjection(
5490
+ withSelection(
5491
+ domainProjector(
5492
+ domainState,
5493
+ playerId,
5494
+ queries(),
5495
+ derived(),
5496
+ values
5497
+ ),
5498
+ collector
5499
+ )
5559
5500
  )
5560
- });
5561
- return {
5562
- mode: "actors",
5563
- actors: resolvePromptToSet(resolved)
5501
+ }));
5502
+ result[key] = {
5503
+ ...baseDomain,
5504
+ dependencies: {
5505
+ mode: "eager",
5506
+ dependentCases
5507
+ }
5564
5508
  };
5509
+ continue;
5565
5510
  }
5566
- return { mode: "active" };
5511
+ throw unsupportedDefaultInputError(key, collector);
5567
5512
  }
5568
- function isActorAuthorized(state, playerId, authorization) {
5569
- if (authorization.mode === "addressees") {
5570
- return authorization.addressees.has(playerId);
5513
+ return result;
5514
+ }
5515
+ function collectInteractionInputs(interaction, domainState, playerId, options = {}) {
5516
+ const collectors = interactionInputsOf(interaction);
5517
+ const dependencyKeys = new Set(
5518
+ Object.values(collectors).flatMap((collector) => [
5519
+ ...collector.dependsOn ?? []
5520
+ ])
5521
+ );
5522
+ const collectedEligibleTargets = options.includeEligibleTargets === false && dependencyKeys.size === 0 ? {} : collectEligibleTargets(interaction, domainState, playerId, options);
5523
+ const eligibleTargets = options.includeEligibleTargets === false ? Object.fromEntries(
5524
+ Object.entries(collectedEligibleTargets).filter(
5525
+ ([key]) => dependencyKeys.has(key)
5526
+ )
5527
+ ) : collectedEligibleTargets;
5528
+ const domainsByKey = collectInputDomains(
5529
+ interaction,
5530
+ domainState,
5531
+ playerId,
5532
+ eligibleTargets,
5533
+ options
5534
+ );
5535
+ let queriesLazy = options.queries ?? null;
5536
+ const queries = () => queriesLazy ??= createStateQueries(
5537
+ domainState
5538
+ );
5539
+ let derivedLazy = options.derived ?? null;
5540
+ const derived = () => derivedLazy ??= createDerivedResolver(domainState, { q: queries() });
5541
+ return Object.entries(collectors).flatMap(([key, collector]) => {
5542
+ if (collector.kind === "rng") {
5543
+ return [];
5571
5544
  }
5572
- if (authorization.mode === "actors") {
5573
- return authorization.actors.has(playerId);
5545
+ const domain = domainsByKey[key];
5546
+ if (!domain && collector.kind === "prompt") {
5547
+ return [];
5574
5548
  }
5575
- const active = state.flow.activePlayers;
5576
- if (active.length === 0) {
5577
- return true;
5549
+ if (!domain) {
5550
+ throw unsupportedDefaultInputError(key, collector);
5578
5551
  }
5579
- return active.includes(playerId);
5552
+ const dynamicDefault = collector.resolveDefaultValue?.(
5553
+ domainState,
5554
+ playerId,
5555
+ queries(),
5556
+ derived(),
5557
+ domain
5558
+ );
5559
+ const defaultValue = "defaultValue" in collector ? collector.defaultValue : dynamicDefault;
5560
+ warnConcreteDependentChoiceDefault({
5561
+ inputKey: key,
5562
+ collector,
5563
+ domain,
5564
+ defaultValue,
5565
+ dependencyKeys
5566
+ });
5567
+ return [
5568
+ {
5569
+ key,
5570
+ kind: collector.kind,
5571
+ domain,
5572
+ ...defaultValue !== void 0 ? { defaultValue } : {}
5573
+ }
5574
+ ];
5575
+ });
5576
+ }
5577
+ var concreteDependentChoiceDefaultWarnings = /* @__PURE__ */ new Set();
5578
+ var AUTHORING_WARNINGS_FLAG = "__DREAMBOARD_AUTHORING_WARNINGS__";
5579
+ function shouldEmitAuthoringWarning() {
5580
+ return globalThis[AUTHORING_WARNINGS_FLAG] === true;
5581
+ }
5582
+ function warnConcreteDependentChoiceDefault({
5583
+ inputKey,
5584
+ collector,
5585
+ domain,
5586
+ defaultValue,
5587
+ dependencyKeys
5588
+ }) {
5589
+ if (!shouldEmitAuthoringWarning() || !dependencyKeys.has(inputKey) || collector.kind !== "form" || domain.type !== "choice" || defaultValue === void 0 || defaultValue === null) {
5590
+ return;
5580
5591
  }
5581
- function isInteractionVisible(interaction, authorization, authorized) {
5582
- return !(authorization.mode === "addressees" && !authorized) && !(interaction.visibility === "actorsOnly" && !authorized);
5592
+ const warningKey = `${inputKey}:${String(defaultValue)}`;
5593
+ if (concreteDependentChoiceDefaultWarnings.has(warningKey)) {
5594
+ return;
5583
5595
  }
5584
- return {
5585
- isActorAuthorized,
5586
- isInteractionVisible,
5587
- resolveInteractionActorAuthorization
5588
- };
5589
- }
5590
-
5591
- // src/reducer/bundle/trusted/interaction-decision.ts
5592
- function issueFromRule(rule) {
5593
- return { errorCode: rule.errorCode, message: rule.message };
5596
+ concreteDependentChoiceDefaultWarnings.add(warningKey);
5597
+ console.warn(
5598
+ `[dreamboard] Form choice input "${inputKey}" feeds another collector and defaulted to "${String(
5599
+ defaultValue
5600
+ )}". Dependent choices that select the object an action applies to should usually use defaultValue: () => undefined so collection stays explicit.`
5601
+ );
5594
5602
  }
5595
- function issueFromRuleValidationResult(rule, result) {
5596
- if (result === false) return issueFromRule(rule);
5597
- if (result && typeof result === "object") return result;
5603
+ function collectPromptOptions(interaction, domainState, playerId, queries) {
5604
+ for (const collector of Object.values(interaction.inputs)) {
5605
+ if (collector.kind !== "prompt") continue;
5606
+ const factory = collector.meta?.options;
5607
+ if (!factory) continue;
5608
+ return factory(domainState, playerId, queries).map((option) => ({
5609
+ id: String(option.id),
5610
+ ...option.label !== void 0 ? { label: option.label } : {}
5611
+ }));
5612
+ }
5598
5613
  return void 0;
5599
5614
  }
5615
+
5616
+ // src/reducer/bundle/trusted/interaction-descriptor.ts
5600
5617
  function humanizeInteractionId(id) {
5601
5618
  if (!id) return id;
5602
5619
  const withSpaces = id.replace(/[-_]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").trim();
@@ -5738,6 +5755,78 @@ function interactionAvailabilityFromDecision(decision) {
5738
5755
  reason: decision.unavailableReason ?? "Interaction unavailable"
5739
5756
  };
5740
5757
  }
5758
+ function buildInteractionDescriptor(scope, state, playerId, interactionId, interaction, decision, options = {}) {
5759
+ const domainState = options.projection?.domainState ?? scope.toDomainState(state);
5760
+ const phaseName = state.flow.currentPhase;
5761
+ const interactionInputs = interactionInputsOf(interaction);
5762
+ const metadata = projectInteractionMetadata({
5763
+ ...interaction,
5764
+ inputs: interactionInputs
5765
+ });
5766
+ const queries = options.projection?.q ?? createStateQueries(domainState);
5767
+ const derived = options.projection?.derived;
5768
+ const shouldMaterializeInputDomains = decision.available || decision.unavailableReason !== "Not your turn";
5769
+ const promptContext = metadata.kind === "prompt" ? {
5770
+ to: playerId,
5771
+ title: humanizeInteractionId(interactionId),
5772
+ options: shouldMaterializeInputDomains ? collectPromptOptions(
5773
+ { inputs: interactionInputs },
5774
+ domainState,
5775
+ playerId,
5776
+ queries
5777
+ ) : void 0
5778
+ } : void 0;
5779
+ const inputs = shouldMaterializeInputDomains ? enrichResourceInputPresentation(
5780
+ collectInteractionInputs(interaction, domainState, playerId, {
5781
+ queries,
5782
+ derived,
5783
+ eligibleTargetCache: options.projection?.eligibleTargets,
5784
+ eligibleTargetCachePrefix: `${phaseName}:${String(
5785
+ interactionId
5786
+ )}:${String(playerId)}`,
5787
+ includeEligibleTargets: options.includeEligibleTargets
5788
+ }),
5789
+ scope.definition.contract.manifest
5790
+ ) : [];
5791
+ const baseDescriptor = {
5792
+ phaseName,
5793
+ interactionKey: `${phaseName}.${interactionId}`,
5794
+ interactionId,
5795
+ commit: metadata.commit,
5796
+ zoneId: collectFirstCardZoneId(interaction),
5797
+ zoneIds: collectCardZoneIds(interaction),
5798
+ inputs,
5799
+ cost: decision.cost ? { ...decision.cost } : void 0,
5800
+ currentResources: decision.cost ? {
5801
+ ...queries.player.resources(playerId)
5802
+ } : void 0,
5803
+ availability: interactionAvailabilityFromDecision(decision)
5804
+ };
5805
+ if (metadata.kind === "prompt") {
5806
+ return {
5807
+ ...baseDescriptor,
5808
+ kind: "prompt",
5809
+ context: promptContext ?? {
5810
+ to: playerId,
5811
+ title: humanizeInteractionId(interactionId)
5812
+ }
5813
+ };
5814
+ }
5815
+ return {
5816
+ ...baseDescriptor,
5817
+ kind: "action"
5818
+ };
5819
+ }
5820
+
5821
+ // src/reducer/bundle/trusted/interaction-decision.ts
5822
+ function issueFromRule(rule) {
5823
+ return { errorCode: rule.errorCode, message: rule.message };
5824
+ }
5825
+ function issueFromRuleValidationResult(rule, result) {
5826
+ if (result === false) return issueFromRule(rule);
5827
+ if (result && typeof result === "object") return result;
5828
+ return void 0;
5829
+ }
5741
5830
  function createInteractionDecisionResolver(scope, stages, authorization) {
5742
5831
  function evaluateInteractionCost(state, interaction, playerId, params, projection) {
5743
5832
  if (!interaction.cost) {
@@ -5760,68 +5849,6 @@ function createInteractionDecisionResolver(scope, stages, authorization) {
5760
5849
  return { error };
5761
5850
  }
5762
5851
  }
5763
- function buildBaseDescriptor(state, playerId, interactionId, interaction, decision, options = {}) {
5764
- const domainState = options.projection?.domainState ?? scope.toDomainState(state);
5765
- const phaseName = state.flow.currentPhase;
5766
- const interactionInputs = interactionInputsOf(interaction);
5767
- const metadata = projectInteractionMetadata({
5768
- ...interaction,
5769
- inputs: interactionInputs
5770
- });
5771
- const queries = options.projection?.q ?? createStateQueries(domainState);
5772
- const derived = options.projection?.derived;
5773
- const shouldMaterializeInputDomains = decision.available || decision.unavailableReason !== "Not your turn";
5774
- const promptContext = metadata.kind === "prompt" ? {
5775
- to: playerId,
5776
- title: humanizeInteractionId(interactionId),
5777
- options: shouldMaterializeInputDomains ? collectPromptOptions(
5778
- { inputs: interactionInputs },
5779
- domainState,
5780
- playerId,
5781
- queries
5782
- ) : void 0
5783
- } : void 0;
5784
- const inputs = shouldMaterializeInputDomains ? enrichResourceInputPresentation(
5785
- collectInteractionInputs(interaction, domainState, playerId, {
5786
- queries,
5787
- derived,
5788
- eligibleTargetCache: options.projection?.eligibleTargets,
5789
- eligibleTargetCachePrefix: `${phaseName}:${String(
5790
- interactionId
5791
- )}:${String(playerId)}`,
5792
- includeEligibleTargets: options.includeEligibleTargets
5793
- }),
5794
- scope.definition.contract.manifest
5795
- ) : [];
5796
- const baseDescriptor = {
5797
- phaseName,
5798
- interactionKey: `${phaseName}.${interactionId}`,
5799
- interactionId,
5800
- commit: metadata.commit,
5801
- zoneId: collectFirstCardZoneId(interaction),
5802
- zoneIds: collectCardZoneIds(interaction),
5803
- inputs,
5804
- cost: decision.cost ? { ...decision.cost } : void 0,
5805
- currentResources: decision.cost ? {
5806
- ...queries.player.resources(playerId)
5807
- } : void 0,
5808
- availability: interactionAvailabilityFromDecision(decision)
5809
- };
5810
- if (metadata.kind === "prompt") {
5811
- return {
5812
- ...baseDescriptor,
5813
- kind: "prompt",
5814
- context: promptContext ?? {
5815
- to: playerId,
5816
- title: humanizeInteractionId(interactionId)
5817
- }
5818
- };
5819
- }
5820
- return {
5821
- ...baseDescriptor,
5822
- kind: "action"
5823
- };
5824
- }
5825
5852
  function resolveInteractionDecision({
5826
5853
  state,
5827
5854
  playerId,
@@ -5856,7 +5883,8 @@ function createInteractionDecisionResolver(scope, stages, authorization) {
5856
5883
  interaction,
5857
5884
  parsedParams: {},
5858
5885
  visible: true,
5859
- descriptor: buildBaseDescriptor(
5886
+ descriptor: buildInteractionDescriptor(
5887
+ scope,
5860
5888
  state,
5861
5889
  playerId,
5862
5890
  trustedInteractionId,
@@ -6030,7 +6058,8 @@ function createInteractionDecisionResolver(scope, stages, authorization) {
6030
6058
  }
6031
6059
  const available = stageAllowed && stepAllowed && authorized && !ruleAvailabilityIssue && costAffordable && !authoredValidation;
6032
6060
  const unavailableReason = available ? void 0 : !authorized ? "Not your turn" : !stageAllowed ? "Interaction not allowed in current stage" : !stepAllowed ? "Interaction not allowed in current step" : ruleAvailabilityIssue ? ruleAvailabilityIssue.message ?? ruleAvailabilityIssue.errorCode : !costAffordable ? "INSUFFICIENT_RESOURCES" : mode === "card" ? authoredValidation?.message ?? "Interaction unavailable" : "Interaction unavailable";
6033
- const descriptor = buildBaseDescriptor(
6061
+ const descriptor = buildInteractionDescriptor(
6062
+ scope,
6034
6063
  state,
6035
6064
  playerId,
6036
6065
  trustedInteractionId,
@@ -7768,7 +7797,7 @@ function createIngressRuntimeCodec(definition) {
7768
7797
  },
7769
7798
  parseState(rawState) {
7770
7799
  const envelope = safeParseOrThrow(
7771
- ReducerSessionStateSchema,
7800
+ zod_exports.ReducerSessionStateSchema,
7772
7801
  rawState,
7773
7802
  "state"
7774
7803
  );
@@ -7848,44 +7877,6 @@ function createIngressRuntimeCodec(definition) {
7848
7877
  };
7849
7878
  }
7850
7879
 
7851
- // src/generated/reducer-contract/builders.ts
7852
- function createEffectIdMinter() {
7853
- let i = 0;
7854
- return () => `ef${i++}`;
7855
- }
7856
- function createEffectBuilders(mint) {
7857
- return {
7858
- transition(args, continuation) {
7859
- const effect = { effectId: mint(), type: "transition", to: args.to };
7860
- return continuation === void 0 ? effect : Object.assign(effect, { __continuation: continuation });
7861
- },
7862
- rollDie(args, continuation) {
7863
- const effect = { effectId: mint(), type: "rollDie", dieId: args.dieId };
7864
- return continuation === void 0 ? effect : Object.assign(effect, { __continuation: continuation });
7865
- },
7866
- shuffleSharedZone(args, continuation) {
7867
- const effect = { effectId: mint(), type: "shuffleSharedZone", zoneId: args.zoneId };
7868
- return continuation === void 0 ? effect : Object.assign(effect, { __continuation: continuation });
7869
- },
7870
- shufflePlayerZone(args, continuation) {
7871
- const effect = { effectId: mint(), type: "shufflePlayerZone", zoneId: args.zoneId, playerId: args.playerId };
7872
- return continuation === void 0 ? effect : Object.assign(effect, { __continuation: continuation });
7873
- }
7874
- };
7875
- }
7876
- function materializeAccept(pending) {
7877
- const effects = [];
7878
- const continuations = {};
7879
- for (const pe of pending) {
7880
- const { __continuation, ...effect } = pe;
7881
- effects.push(effect);
7882
- if (__continuation !== void 0) {
7883
- continuations[effect.effectId] = __continuation;
7884
- }
7885
- }
7886
- return { effects, continuations };
7887
- }
7888
-
7889
7880
  // src/reducer/bundle/ingress-bundle.ts
7890
7881
  function routeInteraction(input) {
7891
7882
  return {
@@ -7942,12 +7933,12 @@ function toWireReduceResult(result, serializeState) {
7942
7933
  message: result.message
7943
7934
  };
7944
7935
  }
7945
- const mint = createEffectIdMinter();
7946
- const fx = createEffectBuilders(mint);
7936
+ const mint = builders_exports.createEffectIdMinter();
7937
+ const fx = builders_exports.createEffectBuilders(mint);
7947
7938
  const pending = (result.instructions ?? []).map(
7948
7939
  (instruction) => toPendingEffect(instruction, fx)
7949
7940
  );
7950
- const { effects, continuations } = materializeAccept(pending);
7941
+ const { effects, continuations } = builders_exports.materializeAccept(pending);
7951
7942
  return {
7952
7943
  kind: "accept",
7953
7944
  state: serializeState(result.state),
@@ -7963,8 +7954,8 @@ function toWireDispatchResult(result, serializeState) {
7963
7954
  message: result.message
7964
7955
  };
7965
7956
  }
7966
- const mint = createEffectIdMinter();
7967
- const fx = createEffectBuilders(mint);
7957
+ const mint = builders_exports.createEffectIdMinter();
7958
+ const fx = builders_exports.createEffectBuilders(mint);
7968
7959
  const trace = [];
7969
7960
  for (const entry of result.trace) {
7970
7961
  switch (entry.type) {
@@ -7997,7 +7988,7 @@ function toWireDispatchResult(result, serializeState) {
7997
7988
  entry.instruction,
7998
7989
  fx
7999
7990
  );
8000
- const { effects, continuations } = materializeAccept([
7991
+ const { effects, continuations } = builders_exports.materializeAccept([
8001
7992
  pending
8002
7993
  ]);
8003
7994
  const [wireEffect] = effects;