@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,382 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isManifestScopedSchema,
|
|
3
|
+
type ManifestContract,
|
|
4
|
+
type RuntimeTableRecord,
|
|
5
|
+
type SchemaLike,
|
|
6
|
+
} from "../model";
|
|
7
|
+
import type { InputCollector } from "../model";
|
|
8
|
+
import {
|
|
9
|
+
getObjectShape,
|
|
10
|
+
getZodDef,
|
|
11
|
+
isEnumKeyedRecordSchema,
|
|
12
|
+
isPlainZodString,
|
|
13
|
+
isSparseMapSchema,
|
|
14
|
+
isZodArray,
|
|
15
|
+
unwrapWrappers,
|
|
16
|
+
} from "../schema-helpers";
|
|
17
|
+
import type { AnyReducerGameContract } from "./types";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Canonical set of manifest-scoped id field names. `defineGameContract`
|
|
21
|
+
* uses this list to reject state schemas that describe one of these fields
|
|
22
|
+
* with a raw `z.string()` instead of the corresponding branded enum from
|
|
23
|
+
* `manifest.ids.*` (or `gameContract.schemas.*`).
|
|
24
|
+
*
|
|
25
|
+
* The rule of thumb is "one way to do things": if a field *is* a player id,
|
|
26
|
+
* card id, zone id, etc. in the manifest, the authored state schema must
|
|
27
|
+
* reuse the same literal/branded schema so generated types line up with the
|
|
28
|
+
* runtime checks, instead of silently widening to `string`.
|
|
29
|
+
*/
|
|
30
|
+
const MANIFEST_SCOPED_ID_NAMES = [
|
|
31
|
+
"playerId",
|
|
32
|
+
"cardId",
|
|
33
|
+
"deckId",
|
|
34
|
+
"handId",
|
|
35
|
+
"zoneId",
|
|
36
|
+
"sharedZoneId",
|
|
37
|
+
"playerZoneId",
|
|
38
|
+
"boardId",
|
|
39
|
+
"boardContainerId",
|
|
40
|
+
"boardTypeId",
|
|
41
|
+
"boardBaseId",
|
|
42
|
+
"edgeId",
|
|
43
|
+
"edgeTypeId",
|
|
44
|
+
"vertexId",
|
|
45
|
+
"vertexTypeId",
|
|
46
|
+
"spaceId",
|
|
47
|
+
"spaceTypeId",
|
|
48
|
+
"relationTypeId",
|
|
49
|
+
"resourceId",
|
|
50
|
+
"pieceId",
|
|
51
|
+
"pieceTypeId",
|
|
52
|
+
"dieId",
|
|
53
|
+
"dieTypeId",
|
|
54
|
+
"setupOptionId",
|
|
55
|
+
"setupProfileId",
|
|
56
|
+
"cardSetId",
|
|
57
|
+
"cardType",
|
|
58
|
+
] as const;
|
|
59
|
+
|
|
60
|
+
type ManifestScopedIdName = (typeof MANIFEST_SCOPED_ID_NAMES)[number];
|
|
61
|
+
|
|
62
|
+
function matchManifestScopedIdName(
|
|
63
|
+
key: string,
|
|
64
|
+
): { name: ManifestScopedIdName; kind: "singular" | "plural" } | null {
|
|
65
|
+
for (const name of MANIFEST_SCOPED_ID_NAMES) {
|
|
66
|
+
const capitalized = `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
67
|
+
if (key === name || key.endsWith(capitalized)) {
|
|
68
|
+
return { name, kind: "singular" };
|
|
69
|
+
}
|
|
70
|
+
const plural = `${name}s`;
|
|
71
|
+
const capitalizedPlural = `${capitalized}s`;
|
|
72
|
+
if (key === plural || key.endsWith(capitalizedPlural)) {
|
|
73
|
+
return { name, kind: "plural" };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function validateInteractionParamsSchema(
|
|
80
|
+
schema: unknown,
|
|
81
|
+
context: "defineInteraction" | "defineCardAction",
|
|
82
|
+
path: string,
|
|
83
|
+
): void {
|
|
84
|
+
const inner = unwrapWrappers(schema);
|
|
85
|
+
if (isEnumKeyedRecordSchema(inner) && !isSparseMapSchema(inner)) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`${context}: ${path} uses an enum-keyed z.record(...), which parses as a total map at runtime. ` +
|
|
88
|
+
`Use sparseMap(...) or sparseCounts(...) from @dreamboard-games/sdk/reducer instead so interaction params stay sparse and match runtime validation.`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const shape = getObjectShape(inner);
|
|
93
|
+
if (shape) {
|
|
94
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
95
|
+
validateInteractionParamsSchema(fieldSchema, context, `${path}.${key}`);
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const def = getZodDef(inner);
|
|
101
|
+
if (def.type === "array" && def.element) {
|
|
102
|
+
validateInteractionParamsSchema(def.element, context, `${path}[]`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (def.type === "record" && def.valueType) {
|
|
107
|
+
validateInteractionParamsSchema(def.valueType, context, `${path}.*`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function validateInteractionInputsSchema(
|
|
112
|
+
inputs: Record<string, InputCollector> | undefined,
|
|
113
|
+
context: "defineInteraction" | "defineCardAction",
|
|
114
|
+
): void {
|
|
115
|
+
if (!inputs) return;
|
|
116
|
+
for (const [key, collector] of Object.entries(inputs)) {
|
|
117
|
+
validateInteractionParamsSchema(collector.schema, context, `inputs.${key}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function validateManyCommitPolicy(input: {
|
|
122
|
+
inputs: Record<string, InputCollector> | undefined;
|
|
123
|
+
commit?: { mode: string };
|
|
124
|
+
context: string;
|
|
125
|
+
}): void {
|
|
126
|
+
if (input.commit?.mode !== "autoWhenReady") return;
|
|
127
|
+
if (
|
|
128
|
+
Object.values(input.inputs ?? {}).some(
|
|
129
|
+
(collector) => collector.selection?.mode === "many",
|
|
130
|
+
)
|
|
131
|
+
) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`${input.context}: interactions with many(...) inputs must use commit: { mode: "manual" }.`,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function validateInteractionLikeDefinition(
|
|
139
|
+
input: {
|
|
140
|
+
inputs?: Record<string, InputCollector>;
|
|
141
|
+
commit?: { mode: string };
|
|
142
|
+
paramsSchema?: unknown;
|
|
143
|
+
},
|
|
144
|
+
context: "defineInteraction" | "defineCardAction",
|
|
145
|
+
): void {
|
|
146
|
+
validateInteractionInputsSchema(input.inputs, context);
|
|
147
|
+
validateManyCommitPolicy({
|
|
148
|
+
inputs: input.inputs,
|
|
149
|
+
commit: input.commit,
|
|
150
|
+
context,
|
|
151
|
+
});
|
|
152
|
+
if (input.paramsSchema) {
|
|
153
|
+
validateInteractionParamsSchema(
|
|
154
|
+
input.paramsSchema,
|
|
155
|
+
context,
|
|
156
|
+
"paramsSchema",
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function validateStateSchemaIdBranding(
|
|
162
|
+
schema: unknown,
|
|
163
|
+
scope: "public" | "private" | "hidden",
|
|
164
|
+
): void {
|
|
165
|
+
const def = getZodDef(schema);
|
|
166
|
+
if (def.type !== "object") {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const shape = def.shape as Record<string, unknown> | undefined;
|
|
170
|
+
if (!shape) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
174
|
+
const match = matchManifestScopedIdName(key);
|
|
175
|
+
if (!match) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const inner = unwrapWrappers(fieldSchema);
|
|
179
|
+
if (match.kind === "singular") {
|
|
180
|
+
if (isPlainZodString(inner) && !isManifestScopedSchema(inner)) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`defineGameContract: state.${scope}.${key} uses a raw z.string() ` +
|
|
183
|
+
`but its name identifies it as a manifest-scoped '${match.name}'. ` +
|
|
184
|
+
`Use gameContract.schemas.${match.name} (or manifest.ids.${match.name}) ` +
|
|
185
|
+
`so the branded literal union flows through state types.`,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (match.kind === "plural" && isZodArray(inner)) {
|
|
191
|
+
const element = unwrapWrappers(getZodDef(inner).element);
|
|
192
|
+
if (isPlainZodString(element) && !isManifestScopedSchema(element)) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
`defineGameContract: state.${scope}.${key} uses z.array(z.string()) ` +
|
|
195
|
+
`but its name identifies it as manifest-scoped '${match.name}' values. ` +
|
|
196
|
+
`Use z.array(gameContract.schemas.${match.name}) ` +
|
|
197
|
+
`(or manifest.ids.${match.name}) so the branded literal union flows through state types.`,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function validateDefineGamePhaseNames(definition: {
|
|
205
|
+
contract: AnyReducerGameContract;
|
|
206
|
+
phases: Record<string, unknown>;
|
|
207
|
+
initialPhase?: string;
|
|
208
|
+
setupProfiles?: Record<string, { initialPhase?: string }>;
|
|
209
|
+
}): void {
|
|
210
|
+
const contractPhaseNames = (
|
|
211
|
+
definition.contract as AnyReducerGameContract & {
|
|
212
|
+
phaseNames?: readonly string[];
|
|
213
|
+
}
|
|
214
|
+
).phaseNames;
|
|
215
|
+
if (!Array.isArray(contractPhaseNames)) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const declared = new Set(contractPhaseNames);
|
|
219
|
+
const actual = new Set(Object.keys(definition.phases));
|
|
220
|
+
const missing = [...declared].filter((name) => !actual.has(name));
|
|
221
|
+
const extra = [...actual].filter((name) => !declared.has(name));
|
|
222
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
223
|
+
const parts: string[] = [];
|
|
224
|
+
if (missing.length > 0) {
|
|
225
|
+
parts.push(`missing: [${missing.join(", ")}]`);
|
|
226
|
+
}
|
|
227
|
+
if (extra.length > 0) {
|
|
228
|
+
parts.push(`extra: [${extra.join(", ")}]`);
|
|
229
|
+
}
|
|
230
|
+
throw new Error(
|
|
231
|
+
`defineGame: phases record does not match contract.phaseNames (${parts.join(
|
|
232
|
+
"; ",
|
|
233
|
+
)}). Update contract.phaseNames or the phases record so they agree.`,
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
if (
|
|
237
|
+
definition.initialPhase !== undefined &&
|
|
238
|
+
!declared.has(definition.initialPhase)
|
|
239
|
+
) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
`defineGame: initialPhase '${definition.initialPhase}' is not declared in contract.phaseNames.`,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (definition.setupProfiles) {
|
|
245
|
+
for (const [profileId, profile] of Object.entries(
|
|
246
|
+
definition.setupProfiles,
|
|
247
|
+
)) {
|
|
248
|
+
const initial = profile?.initialPhase;
|
|
249
|
+
if (initial !== undefined && !declared.has(initial)) {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`defineGame: setupProfiles.${profileId}.initialPhase '${initial}' is not declared in contract.phaseNames.`,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function validateDefineGameZoneWiring(definition: {
|
|
259
|
+
contract: {
|
|
260
|
+
manifest: ManifestContract<RuntimeTableRecord>;
|
|
261
|
+
};
|
|
262
|
+
phases: Record<string, unknown>;
|
|
263
|
+
}): void {
|
|
264
|
+
const manifestPlayerZoneIds = new Set(
|
|
265
|
+
definition.contract.manifest.literals.playerZoneIds ?? [],
|
|
266
|
+
);
|
|
267
|
+
for (const [phaseName, phase] of Object.entries(definition.phases)) {
|
|
268
|
+
const phaseRecord =
|
|
269
|
+
typeof phase === "object" && phase !== null
|
|
270
|
+
? (phase as {
|
|
271
|
+
zones?: Record<string, unknown>;
|
|
272
|
+
cardActions?: Record<string, unknown>;
|
|
273
|
+
})
|
|
274
|
+
: null;
|
|
275
|
+
if (!phaseRecord) continue;
|
|
276
|
+
|
|
277
|
+
if (phaseRecord.zones !== undefined && !Array.isArray(phaseRecord.zones)) {
|
|
278
|
+
const zonesRecord =
|
|
279
|
+
typeof phaseRecord.zones === "object" && phaseRecord.zones !== null
|
|
280
|
+
? (phaseRecord.zones as Record<string, unknown>)
|
|
281
|
+
: null;
|
|
282
|
+
const hasRemovedZoneSpec =
|
|
283
|
+
zonesRecord &&
|
|
284
|
+
Object.values(zonesRecord).some(
|
|
285
|
+
(zone) =>
|
|
286
|
+
typeof zone === "object" &&
|
|
287
|
+
zone !== null &&
|
|
288
|
+
("cardsFrom" in zone || "playableVia" in zone || "from" in zone),
|
|
289
|
+
);
|
|
290
|
+
if (hasRemovedZoneSpec) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
`defineGame: phases.${phaseName}.zones uses removed zone spec objects. Use zones: ["manifest-player-zone-id"] and cardActions[*].playFrom instead.`,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
throw new Error(
|
|
296
|
+
`defineGame: phases.${phaseName}.zones must be an array of manifest player zone ids.`,
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
for (const [index, zoneId] of (phaseRecord.zones ?? []).entries()) {
|
|
301
|
+
if (typeof zoneId !== "string") {
|
|
302
|
+
throw new Error(
|
|
303
|
+
`defineGame: phases.${phaseName}.zones[${index}] must be a manifest player zone id string.`,
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
if (!manifestPlayerZoneIds.has(zoneId)) {
|
|
307
|
+
throw new Error(
|
|
308
|
+
`defineGame: phases.${phaseName}.zones[${index}] '${zoneId}' is not declared in manifest.literals.playerZoneIds.`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
for (const [actionId, action] of Object.entries(
|
|
314
|
+
phaseRecord.cardActions ?? {},
|
|
315
|
+
)) {
|
|
316
|
+
const actionRecord =
|
|
317
|
+
typeof action === "object" && action !== null
|
|
318
|
+
? (action as Record<string, unknown>)
|
|
319
|
+
: null;
|
|
320
|
+
const playFrom = actionRecord?.playFrom;
|
|
321
|
+
if (
|
|
322
|
+
typeof playFrom === "string" &&
|
|
323
|
+
!manifestPlayerZoneIds.has(playFrom)
|
|
324
|
+
) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
`defineGame: phases.${phaseName}.cardActions.${actionId}.playFrom '${playFrom}' is not declared in manifest.literals.playerZoneIds.`,
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function validateDefineGameSimultaneousPhases(definition: {
|
|
334
|
+
phases: Record<string, unknown>;
|
|
335
|
+
}): void {
|
|
336
|
+
for (const [phaseName, phase] of Object.entries(definition.phases)) {
|
|
337
|
+
const phaseRecord =
|
|
338
|
+
typeof phase === "object" && phase !== null
|
|
339
|
+
? (phase as {
|
|
340
|
+
kind?: unknown;
|
|
341
|
+
submit?: { inputs?: Record<string, InputCollector> };
|
|
342
|
+
resolve?: unknown;
|
|
343
|
+
interactions?: Record<string, unknown>;
|
|
344
|
+
})
|
|
345
|
+
: null;
|
|
346
|
+
if (!phaseRecord || phaseRecord.kind !== "simultaneousPlayer") {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (!phaseRecord.submit) {
|
|
350
|
+
throw new Error(
|
|
351
|
+
`defineGame: phases.${phaseName} is kind 'simultaneousPlayer' but does not declare submit.`,
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
if (typeof phaseRecord.resolve !== "function") {
|
|
355
|
+
throw new Error(
|
|
356
|
+
`defineGame: phases.${phaseName} is kind 'simultaneousPlayer' but does not declare resolve.`,
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
if (phaseRecord.interactions?.submit) {
|
|
360
|
+
throw new Error(
|
|
361
|
+
`defineGame: phases.${phaseName}.interactions.submit conflicts with the reserved simultaneous submit interaction id.`,
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
validateInteractionInputsSchema(
|
|
365
|
+
phaseRecord.submit.inputs,
|
|
366
|
+
"defineInteraction",
|
|
367
|
+
);
|
|
368
|
+
validateManyCommitPolicy({
|
|
369
|
+
inputs: phaseRecord.submit.inputs,
|
|
370
|
+
commit: (phaseRecord.submit as { commit?: { mode: string } }).commit,
|
|
371
|
+
context: `defineGame: phases.${phaseName}.submit`,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export type ManifestIdSchemasOf<
|
|
377
|
+
Ids extends Record<string, SchemaLike<unknown>>,
|
|
378
|
+
> = {
|
|
379
|
+
readonly [Key in keyof Ids]: Ids[Key] extends SchemaLike<infer Output>
|
|
380
|
+
? Ids[Key] & import("../model").ManifestIdSchema<Output>
|
|
381
|
+
: Ids[Key];
|
|
382
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type {
|
|
3
|
+
ExactManifestContractOf,
|
|
4
|
+
SchemaLike,
|
|
5
|
+
ScopedPhaseState,
|
|
6
|
+
StageSpec,
|
|
7
|
+
StaticViewDefinition,
|
|
8
|
+
ViewDefinition,
|
|
9
|
+
} from "../model";
|
|
10
|
+
import type {
|
|
11
|
+
AnyReducerGameContract,
|
|
12
|
+
ContractManifest,
|
|
13
|
+
ContractState,
|
|
14
|
+
} from "./types";
|
|
15
|
+
|
|
16
|
+
export function defineView<Contract extends AnyReducerGameContract>() {
|
|
17
|
+
return <Projection>(
|
|
18
|
+
definition: ViewDefinition<
|
|
19
|
+
ContractState<Contract>,
|
|
20
|
+
ContractManifest<Contract>,
|
|
21
|
+
Projection
|
|
22
|
+
>,
|
|
23
|
+
): ViewDefinition<
|
|
24
|
+
ContractState<Contract>,
|
|
25
|
+
ContractManifest<Contract>,
|
|
26
|
+
Projection
|
|
27
|
+
> => definition;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Factory for the session-scoped static view (see {@link StaticViewDefinition}).
|
|
32
|
+
* Kept separate from {@link defineView} because the argument shape is
|
|
33
|
+
* structurally different: it exposes only the manifest and generated static
|
|
34
|
+
* queries, with no `state`, `playerId`, `runtime`, `fx`, `ops`, or
|
|
35
|
+
* `accept/reject`. That shape is what prevents authors from accidentally
|
|
36
|
+
* projecting per-tick state into the once-per-session payload.
|
|
37
|
+
*/
|
|
38
|
+
export function defineStaticView<Contract extends AnyReducerGameContract>() {
|
|
39
|
+
return <Projection>(
|
|
40
|
+
definition: StaticViewDefinition<
|
|
41
|
+
ExactManifestContractOf<Contract>,
|
|
42
|
+
Projection
|
|
43
|
+
>,
|
|
44
|
+
): StaticViewDefinition<ExactManifestContractOf<Contract>, Projection> =>
|
|
45
|
+
definition;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function defineStage<Contract extends AnyReducerGameContract>() {
|
|
49
|
+
return (
|
|
50
|
+
definition: StageSpec<ContractState<Contract>, ContractManifest<Contract>>,
|
|
51
|
+
): StageSpec<ContractState<Contract>, ContractManifest<Contract>> =>
|
|
52
|
+
definition;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function definePhaseStage<
|
|
56
|
+
Contract extends AnyReducerGameContract,
|
|
57
|
+
PhaseStateSchema extends SchemaLike<object>,
|
|
58
|
+
>() {
|
|
59
|
+
return (
|
|
60
|
+
definition: StageSpec<
|
|
61
|
+
ScopedPhaseState<ContractState<Contract>, z.infer<PhaseStateSchema>>,
|
|
62
|
+
ContractManifest<Contract>
|
|
63
|
+
>,
|
|
64
|
+
): StageSpec<
|
|
65
|
+
ScopedPhaseState<ContractState<Contract>, z.infer<PhaseStateSchema>>,
|
|
66
|
+
ContractManifest<Contract>
|
|
67
|
+
> => definition;
|
|
68
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export { defineGameContract } from "./authoring/contract";
|
|
2
|
+
export { defineEffect } from "./authoring/effect";
|
|
3
|
+
export { defineGame } from "./authoring/game";
|
|
4
|
+
export {
|
|
5
|
+
defineCardAction,
|
|
6
|
+
defineInteraction,
|
|
7
|
+
defineInteractionRule,
|
|
8
|
+
} from "./authoring/interaction";
|
|
9
|
+
export { definePhase, defineStepPhase } from "./authoring/phase";
|
|
10
|
+
export {
|
|
11
|
+
definePhaseStage,
|
|
12
|
+
defineStage,
|
|
13
|
+
defineStaticView,
|
|
14
|
+
defineView,
|
|
15
|
+
} from "./authoring/view-stage";
|
|
16
|
+
|
|
17
|
+
export type {
|
|
18
|
+
ReducerPhaseDefinition,
|
|
19
|
+
ReducerViewDefinition,
|
|
20
|
+
} from "./authoring/types";
|
|
21
|
+
|
|
22
|
+
export type {
|
|
23
|
+
GameStateOf,
|
|
24
|
+
InitialStateCallbacks,
|
|
25
|
+
ManifestOf,
|
|
26
|
+
PhaseMapOf,
|
|
27
|
+
ReducerGameContract,
|
|
28
|
+
ReducerGameDefinition,
|
|
29
|
+
} from "./model";
|