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