@seriousgaming/sdk-tools 0.0.0-stage → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +93 -0
- package/README.md +36 -2
- package/dist/bundling/logic-exports.d.ts +34 -0
- package/dist/bundling/node-builtins.d.ts +21 -0
- package/dist/bundling/transpiler.d.ts +7 -0
- package/dist/cli.js +27368 -0
- package/dist/client/dev-server.d.ts +59 -0
- package/dist/client/index.d.ts +28 -0
- package/dist/client/stub-services.d.ts +32 -0
- package/dist/client/test-session.d.ts +195 -0
- package/dist/client.js +16884 -0
- package/dist/core/asset-reference-translator.d.ts +46 -0
- package/dist/core/clock.d.ts +57 -0
- package/dist/core/faults.d.ts +65 -0
- package/dist/core/game-settings.d.ts +65 -0
- package/dist/core/history.d.ts +89 -0
- package/dist/core/listen-with-fallback.d.ts +30 -0
- package/dist/core/mutation-queue.d.ts +61 -0
- package/dist/core/package-scenario.d.ts +89 -0
- package/dist/core/participant-registry.d.ts +109 -0
- package/dist/core/pending-changes.d.ts +14 -0
- package/dist/core/protocol.d.ts +83 -0
- package/dist/core/scenario-drafts.d.ts +32 -0
- package/dist/core/session-endpoints.d.ts +108 -0
- package/dist/core/session-gates.d.ts +75 -0
- package/dist/core/session-host.d.ts +94 -0
- package/dist/core/session-refusals.d.ts +56 -0
- package/dist/core/session-rewind.d.ts +32 -0
- package/dist/core/session-roster.d.ts +128 -0
- package/dist/core/session-surfaces.d.ts +32 -0
- package/dist/core/session-ticks.d.ts +18 -0
- package/dist/core/session-timers.d.ts +84 -0
- package/dist/core/session-writes.d.ts +40 -0
- package/dist/core/session.d.ts +385 -0
- package/dist/core/settings-locks.d.ts +22 -0
- package/dist/core/team-names.d.ts +52 -0
- package/dist/core/team-state-store.d.ts +209 -0
- package/dist/core/tick-timer.d.ts +75 -0
- package/dist/dev/blob-links.d.ts +10 -0
- package/dist/dev/console/assets/index-DgFglsnA.js +204 -0
- package/dist/dev/console/index.html +12 -0
- package/dist/dev/console-path.d.ts +19 -0
- package/dist/dev/lockfile.d.ts +124 -0
- package/dist/dev/package-watcher.d.ts +21 -0
- package/dist/dev/routes.d.ts +67 -0
- package/dist/dev/shell.d.ts +260 -0
- package/dist/dev/surfaces.d.ts +41 -0
- package/dist/dev/tools-identity.d.ts +23 -0
- package/dist/dev/view/batch.d.ts +172 -0
- package/dist/dev/view/commands.d.ts +75 -0
- package/dist/dev/view/route.d.ts +58 -0
- package/dist/dev/view/view.d.ts +78 -0
- package/dist/dev/view/viewer.d.ts +32 -0
- package/dist/discovery/config.d.ts +9 -0
- package/dist/discovery/manifest-paths.d.ts +21 -0
- package/dist/discovery/removed-fields.d.ts +90 -0
- package/dist/docs/api/deck.md +386 -0
- package/dist/docs/api/index.md +67 -0
- package/dist/docs/api/sdk-commands.md +286 -0
- package/dist/docs/api/sdk-e2e.md +433 -0
- package/dist/docs/api/sdk-projection.md +207 -0
- package/dist/docs/api/sdk-testing.md +214 -0
- package/dist/docs/api/sdk-tools-client.md +560 -0
- package/dist/docs/api/sdk-ui-testing.md +231 -0
- package/dist/docs/api/sdk-ui.md +1269 -0
- package/dist/docs/api/sdk.md +2140 -0
- package/dist/docs/changelog-0.x.md +1156 -0
- package/dist/docs/changelog.md +236 -0
- package/dist/docs/cli-and-dev-server.md +217 -0
- package/dist/docs/cli-error-codes.md +154 -0
- package/dist/docs/cli-reference.md +2488 -0
- package/dist/docs/cli-simulation-testing.md +222 -0
- package/dist/docs/concepts/index.md +46 -0
- package/dist/docs/concepts/terminology.md +322 -0
- package/dist/docs/environment-variables.md +102 -0
- package/dist/docs/getting-started.md +145 -0
- package/dist/docs/guides/ai-facilitation.md +220 -0
- package/dist/docs/guides/capabilities.md +460 -0
- package/dist/docs/guides/endpoints.md +335 -0
- package/dist/docs/guides/engine-testing.md +477 -0
- package/dist/docs/guides/engine.md +527 -0
- package/dist/docs/guides/file-handling.md +405 -0
- package/dist/docs/guides/games.md +176 -0
- package/dist/docs/guides/global-settings.md +94 -0
- package/dist/docs/guides/guide.md +123 -0
- package/dist/docs/guides/hooks.md +183 -0
- package/dist/docs/guides/index.md +51 -0
- package/dist/docs/guides/internationalization.md +288 -0
- package/dist/docs/guides/llm-integration.md +635 -0
- package/dist/docs/guides/multi-team-games.md +586 -0
- package/dist/docs/guides/patterns.md +391 -0
- package/dist/docs/guides/presentation.md +196 -0
- package/dist/docs/guides/production-constraints.md +130 -0
- package/dist/docs/guides/scenario-editor.md +143 -0
- package/dist/docs/guides/scenarios.md +515 -0
- package/dist/docs/guides/session.md +972 -0
- package/dist/docs/guides/settings.md +458 -0
- package/dist/docs/guides/setup.md +193 -0
- package/dist/docs/guides/speech-generation.md +233 -0
- package/dist/docs/guides/starter-game.md +164 -0
- package/dist/docs/guides/testing.md +575 -0
- package/dist/docs/guides/tick-controller.md +569 -0
- package/dist/docs/guides/type-safety.md +516 -0
- package/dist/docs/guides/ui.md +1389 -0
- package/dist/docs/guides/upgrading.md +636 -0
- package/dist/docs/guides/validators.md +217 -0
- package/dist/docs/guides/waiting-room.md +244 -0
- package/dist/docs/index.md +41 -0
- package/dist/docs/recipes/act-on-the-session-from-an-endpoint.md +95 -0
- package/dist/docs/recipes/adapt-a-game-for-walkthroughs.md +133 -0
- package/dist/docs/recipes/adapt-ui-for-observers.md +74 -0
- package/dist/docs/recipes/call-endpoint-from-ui.md +109 -0
- package/dist/docs/recipes/check-a-package-from-a-script.md +117 -0
- package/dist/docs/recipes/create-capability.md +66 -0
- package/dist/docs/recipes/create-endpoint.md +127 -0
- package/dist/docs/recipes/create-engine.md +111 -0
- package/dist/docs/recipes/create-game.md +70 -0
- package/dist/docs/recipes/create-guide.md +75 -0
- package/dist/docs/recipes/create-hook.md +80 -0
- package/dist/docs/recipes/create-presentation.md +142 -0
- package/dist/docs/recipes/create-scenario-editor.md +102 -0
- package/dist/docs/recipes/create-scenario.md +98 -0
- package/dist/docs/recipes/create-session-ui.md +116 -0
- package/dist/docs/recipes/create-settings.md +88 -0
- package/dist/docs/recipes/create-setup.md +115 -0
- package/dist/docs/recipes/create-tick-controller.md +65 -0
- package/dist/docs/recipes/create-user-interface.md +96 -0
- package/dist/docs/recipes/create-validator.md +67 -0
- package/dist/docs/recipes/create-waiting-room-ui.md +109 -0
- package/dist/docs/recipes/declare-api-uses.md +67 -0
- package/dist/docs/recipes/design-state-for-concurrent-writes.md +96 -0
- package/dist/docs/recipes/distribute-package.md +80 -0
- package/dist/docs/recipes/e2e-testing.md +116 -0
- package/dist/docs/recipes/end-game-on-condition.md +154 -0
- package/dist/docs/recipes/fix-duplicate-packages.md +101 -0
- package/dist/docs/recipes/index.md +86 -0
- package/dist/docs/recipes/make-an-endpoint-external.md +101 -0
- package/dist/docs/recipes/negotiate-across-teams.md +164 -0
- package/dist/docs/recipes/observe-other-teams-state.md +119 -0
- package/dist/docs/recipes/publish-a-package.md +139 -0
- package/dist/docs/recipes/remember-a-viewers-choice.md +55 -0
- package/dist/docs/recipes/review-a-past-day.md +73 -0
- package/dist/docs/recipes/share-assets-across-scenarios.md +120 -0
- package/dist/docs/recipes/share-logic-between-engine-and-ui.md +130 -0
- package/dist/docs/recipes/show-all-teams-participants.md +109 -0
- package/dist/docs/recipes/start-from-an-empty-package.md +169 -0
- package/dist/docs/recipes/take-a-file-in-an-endpoint.md +82 -0
- package/dist/docs/recipes/test-a-multi-role-game.md +51 -0
- package/dist/docs/recipes/test-user-interface.md +95 -0
- package/dist/docs/recipes/test-with-engine.md +115 -0
- package/dist/docs/recipes/upload-and-display-files.md +148 -0
- package/dist/docs/recipes/use-request-play.md +65 -0
- package/dist/docs/recipes/use-request-tick.md +75 -0
- package/dist/docs/troubleshooting.md +816 -0
- package/dist/execution/blob-inputs.d.ts +57 -0
- package/dist/execution/bundle-reload.d.ts +42 -0
- package/dist/execution/config-resolver.d.ts +127 -0
- package/dist/execution/configuration-builder.d.ts +66 -0
- package/dist/execution/context-composition.d.ts +161 -0
- package/dist/execution/endpoint-actions.d.ts +9 -0
- package/dist/execution/endpoint-payloads.d.ts +32 -0
- package/dist/execution/endpoint-runner.d.ts +129 -0
- package/dist/execution/engine-state.d.ts +40 -0
- package/dist/execution/executor-callbacks.d.ts +56 -0
- package/dist/execution/executor.d.ts +436 -0
- package/dist/execution/gates.d.ts +45 -0
- package/dist/execution/hook-chain.d.ts +25 -0
- package/dist/execution/logic-calls.d.ts +190 -0
- package/dist/execution/logic-failure.d.ts +84 -0
- package/dist/execution/logic-loader.d.ts +54 -0
- package/dist/execution/logic-result.d.ts +76 -0
- package/dist/execution/tick-controller-call.d.ts +32 -0
- package/dist/execution/types.d.ts +48 -0
- package/dist/generation/ts-type.d.ts +39 -0
- package/dist/guide/locale.d.ts +12 -0
- package/dist/guide/video-registry.d.ts +42 -0
- package/dist/help-examples.d.ts +125 -0
- package/dist/host/adapter.d.ts +67 -0
- package/dist/host/host-channel.d.ts +222 -0
- package/dist/host/index.d.ts +20 -0
- package/dist/host/protocol.d.ts +783 -0
- package/dist/host/surfaces.d.ts +42 -0
- package/dist/host/theme.d.ts +55 -0
- package/dist/host.js +583 -0
- package/dist/prompts/index.d.ts +7 -0
- package/dist/prompts/schema-builder.d.ts +29 -0
- package/dist/prompts/types.d.ts +108 -0
- package/dist/prompts/validators.d.ts +32 -0
- package/dist/runtime/capability-scope.d.ts +6 -0
- package/dist/runtime/context-merge.d.ts +29 -0
- package/dist/runtime/context-projection.d.ts +41 -0
- package/dist/runtime/guarded-callbacks.d.ts +15 -0
- package/dist/runtime/index.d.ts +27 -0
- package/dist/runtime/manifest-version.d.ts +55 -0
- package/dist/runtime/tick-validation.d.ts +25 -0
- package/dist/runtime.js +346 -0
- package/dist/schema.json +1546 -0
- package/dist/server/vite-plugin.d.ts +46 -0
- package/dist/services/tts/client.d.ts +51 -0
- package/dist/services/tts/elevenlabs.d.ts +24 -0
- package/dist/services/tts/types.d.ts +44 -0
- package/dist/storage/asset-resolver.d.ts +49 -0
- package/dist/storage/blob-store.d.ts +41 -0
- package/dist/templates/endpoint/logic.test.ts.liquid +61 -0
- package/dist/templates/endpoint/logic.ts.liquid +25 -0
- package/dist/templates/engine/init.json.liquid +7 -0
- package/dist/templates/engine/logic-aggregate.test.ts.liquid +90 -0
- package/dist/templates/engine/logic-aggregate.ts.liquid +46 -0
- package/dist/templates/engine/logic.test.ts.liquid +61 -0
- package/dist/templates/engine/logic.ts.liquid +32 -0
- package/dist/templates/engine/run.json.liquid +7 -0
- package/dist/templates/guide/01-at-a-glance.md.liquid +19 -0
- package/dist/templates/guide/02-preparation.md.liquid +18 -0
- package/dist/templates/guide/03-running-the-session.md.liquid +37 -0
- package/dist/templates/hook/logic.test.ts.liquid +46 -0
- package/dist/templates/hook/logic.ts.liquid +12 -0
- package/dist/templates/package/CLAUDE.md.template +338 -0
- package/dist/templates/package/DESIGN.md.liquid +144 -0
- package/dist/templates/package/README.md.liquid +143 -0
- package/dist/templates/package/claude/rules/workflow-create-capability.md +26 -0
- package/dist/templates/package/claude/rules/workflow-create-endpoint.md +35 -0
- package/dist/templates/package/claude/rules/workflow-create-engine.md +35 -0
- package/dist/templates/package/claude/rules/workflow-create-guide.md +40 -0
- package/dist/templates/package/claude/rules/workflow-create-presentation.md +37 -0
- package/dist/templates/package/claude/rules/workflow-create-user-interface.md +31 -0
- package/dist/templates/package/claude/rules/workflow-publish-package.md +54 -0
- package/dist/templates/package/claude/rules/workflow-test-engine-or-ui.md +30 -0
- package/dist/templates/package/claude/rules/workflow-update-sdk-version.md +43 -0
- package/dist/templates/package/claude/settings.json.template +16 -0
- package/dist/templates/package/gitignore.template +15 -0
- package/dist/templates/package/global-setup.ts.template +21 -0
- package/dist/templates/package/globals.d.ts.template +2 -0
- package/dist/templates/package/oxfmtrc.json.template +14 -0
- package/dist/templates/package/oxlintrc.json.template +238 -0
- package/dist/templates/package/package.json.liquid +65 -0
- package/dist/templates/package/playwright.config.ts.liquid +19 -0
- package/dist/templates/package/pnpm-workspace.yaml.template +27 -0
- package/dist/templates/package/test-setup.ts.liquid +7 -0
- package/dist/templates/package/tsconfig.json.liquid +15 -0
- package/dist/templates/package/vite.config.ts.liquid +19 -0
- package/dist/templates/package/vitest.config.ts.liquid +25 -0
- package/dist/templates/package/vitest.engine.config.ts.liquid +12 -0
- package/dist/templates/presentation/index.html.liquid +20 -0
- package/dist/templates/presentation/src/App.tsx.liquid +49 -0
- package/dist/templates/presentation/src/Slides.tsx.liquid +81 -0
- package/dist/templates/presentation/src/i18n.ts.liquid +54 -0
- package/dist/templates/presentation/src/main.tsx.liquid +14 -0
- package/dist/templates/scenario_editor/src/App.test.tsx.liquid +30 -0
- package/dist/templates/scenario_editor/src/App.tsx.liquid +95 -0
- package/dist/templates/scenario_editor/src/i18n.ts.liquid +44 -0
- package/dist/templates/session/src/App.test.tsx.liquid +60 -0
- package/dist/templates/session/src/App.tsx.liquid +128 -0
- package/dist/templates/session/src/i18n.ts.liquid +53 -0
- package/dist/templates/session/src/main.tsx.liquid +48 -0
- package/dist/templates/session/src/theme.ts.liquid +46 -0
- package/dist/templates/settings-editor/index.html.liquid +12 -0
- package/dist/templates/settings-editor/src/main.tsx.liquid +48 -0
- package/dist/templates/settings-editor/src/theme.ts.liquid +24 -0
- package/dist/templates/setup/src/App.test.tsx.liquid +39 -0
- package/dist/templates/setup/src/App.tsx.liquid +102 -0
- package/dist/templates/setup/src/i18n.ts.liquid +47 -0
- package/dist/templates/starter-game/capabilities/briefing/capability.sdk.json +18 -0
- package/dist/templates/starter-game/capabilities/plan/capability.sdk.json +17 -0
- package/dist/templates/starter-game/capabilities/results/capability.sdk.json +61 -0
- package/dist/templates/starter-game/capabilities/roles/capability.sdk.json +17 -0
- package/dist/templates/starter-game/capabilities/weather/capability.sdk.json +23 -0
- package/dist/templates/starter-game/engine/defaults.ts +81 -0
- package/dist/templates/starter-game/engine/engine.sdk.json +12 -0
- package/dist/templates/starter-game/engine/logic.test.ts +221 -0
- package/dist/templates/starter-game/engine/logic.ts +149 -0
- package/dist/templates/starter-game/engine/test-helpers.ts +74 -0
- package/dist/templates/starter-game/engine/types.ts +139 -0
- package/dist/templates/starter-game/guide/content/en/01-at-a-glance.md +51 -0
- package/dist/templates/starter-game/guide/content/en/02-preparation.md +35 -0
- package/dist/templates/starter-game/guide/content/en/03-running-the-day.md +58 -0
- package/dist/templates/starter-game/guide/guide.sdk.json +10 -0
- package/dist/templates/starter-game/guide/guide.test.ts +108 -0
- package/dist/templates/starter-game/hooks/assignproducts/defaults.ts +37 -0
- package/dist/templates/starter-game/hooks/assignproducts/hook.sdk.json +13 -0
- package/dist/templates/starter-game/hooks/assignproducts/logic/logic.test.ts +77 -0
- package/dist/templates/starter-game/hooks/assignproducts/logic/logic.ts +47 -0
- package/dist/templates/starter-game/hooks/assignproducts/types.ts +55 -0
- package/dist/templates/starter-game/package.json +68 -0
- package/dist/templates/starter-game/playwright.config.ts +19 -0
- package/dist/templates/starter-game/scenarios/heatwave/scenario.sdk.json +20 -0
- package/dist/templates/starter-game/scenarios/ordinary_week/scenario.sdk.json +12 -0
- package/dist/templates/starter-game/seriousgaming.sdk.json +23 -0
- package/dist/templates/starter-game/session/defaults.ts +80 -0
- package/dist/templates/starter-game/session/index.html +12 -0
- package/dist/templates/starter-game/session/session.sdk.json +11 -0
- package/dist/templates/starter-game/session/src/App.test.tsx +307 -0
- package/dist/templates/starter-game/session/src/App.tsx +309 -0
- package/dist/templates/starter-game/session/src/Section.tsx +37 -0
- package/dist/templates/starter-game/session/src/TeamDoor.tsx +96 -0
- package/dist/templates/starter-game/session/src/format.ts +8 -0
- package/dist/templates/starter-game/session/src/i18n.ts +51 -0
- package/dist/templates/starter-game/session/src/main.tsx +48 -0
- package/dist/templates/starter-game/session/src/theme.ts +45 -0
- package/dist/templates/starter-game/session/types.ts +135 -0
- package/dist/templates/starter-game/settings/engine/settings.sdk.json +50 -0
- package/dist/templates/starter-game/settings/menu/settings.sdk.json +78 -0
- package/dist/templates/starter-game/settings/session/settings.sdk.json +23 -0
- package/dist/templates/starter-game/settings/ui/settings.sdk.json +25 -0
- package/dist/templates/starter-game/test-setup.ts +7 -0
- package/dist/templates/starter-game/testing/e2e/game.spec.ts +139 -0
- package/dist/templates/starter-game/testing/e2e/global-setup.ts +21 -0
- package/dist/templates/starter-game/testing/engine/game.engine.test.ts +171 -0
- package/dist/templates/starter-game/tsconfig.json +19 -0
- package/dist/templates/starter-game/ui/defaults.ts +60 -0
- package/dist/templates/starter-game/ui/index.html +12 -0
- package/dist/templates/starter-game/ui/src/App.test.tsx +138 -0
- package/dist/templates/starter-game/ui/src/App.tsx +175 -0
- package/dist/templates/starter-game/ui/src/DayBar.test.tsx +78 -0
- package/dist/templates/starter-game/ui/src/DayBar.tsx +72 -0
- package/dist/templates/starter-game/ui/src/HistoryPanel.test.tsx +74 -0
- package/dist/templates/starter-game/ui/src/HistoryPanel.tsx +120 -0
- package/dist/templates/starter-game/ui/src/MakeRow.tsx +129 -0
- package/dist/templates/starter-game/ui/src/Section.tsx +37 -0
- package/dist/templates/starter-game/ui/src/ThemeToggle.tsx +49 -0
- package/dist/templates/starter-game/ui/src/TodayPanel.test.tsx +179 -0
- package/dist/templates/starter-game/ui/src/TodayPanel.tsx +92 -0
- package/dist/templates/starter-game/ui/src/YesterdayPanel.tsx +142 -0
- package/dist/templates/starter-game/ui/src/format.ts +12 -0
- package/dist/templates/starter-game/ui/src/i18n.ts +95 -0
- package/dist/templates/starter-game/ui/src/main.tsx +48 -0
- package/dist/templates/starter-game/ui/src/menu.ts +18 -0
- package/dist/templates/starter-game/ui/src/test-helpers.ts +58 -0
- package/dist/templates/starter-game/ui/src/theme.ts +45 -0
- package/dist/templates/starter-game/ui/src/writes.ts +43 -0
- package/dist/templates/starter-game/ui/types.ts +137 -0
- package/dist/templates/starter-game/ui/ui.sdk.json +11 -0
- package/dist/templates/starter-game/validators/capacity/defaults.ts +37 -0
- package/dist/templates/starter-game/validators/capacity/logic/logic.test.ts +96 -0
- package/dist/templates/starter-game/validators/capacity/logic/logic.ts +45 -0
- package/dist/templates/starter-game/validators/capacity/types.ts +55 -0
- package/dist/templates/starter-game/validators/capacity/validator.sdk.json +11 -0
- package/dist/templates/starter-game/vite.config.ts +19 -0
- package/dist/templates/starter-game/vitest.config.ts +15 -0
- package/dist/templates/starter-game/vitest.engine.config.ts +19 -0
- package/dist/templates/starter-game/waiting_room/defaults.ts +40 -0
- package/dist/templates/starter-game/waiting_room/index.html +12 -0
- package/dist/templates/starter-game/waiting_room/src/App.test.tsx +102 -0
- package/dist/templates/starter-game/waiting_room/src/App.tsx +194 -0
- package/dist/templates/starter-game/waiting_room/src/i18n.ts +33 -0
- package/dist/templates/starter-game/waiting_room/src/main.tsx +48 -0
- package/dist/templates/starter-game/waiting_room/src/theme.ts +45 -0
- package/dist/templates/starter-game/waiting_room/types.ts +59 -0
- package/dist/templates/starter-game/waiting_room/waiting_room.sdk.json +10 -0
- package/dist/templates/tick-controller/logic.ts.liquid +8 -0
- package/dist/templates/ui/index.html.liquid +12 -0
- package/dist/templates/ui/src/App.test.tsx.liquid +41 -0
- package/dist/templates/ui/src/App.tsx.liquid +103 -0
- package/dist/templates/ui/src/i18n.ts.liquid +47 -0
- package/dist/templates/ui/src/main.tsx.liquid +48 -0
- package/dist/templates/ui/src/theme.ts.liquid +46 -0
- package/dist/templates/validator/logic.test.ts.liquid +42 -0
- package/dist/templates/validator/logic.ts.liquid +21 -0
- package/dist/templates/waiting-room/index.html.liquid +12 -0
- package/dist/templates/waiting-room/src/App.test.tsx.liquid +57 -0
- package/dist/templates/waiting-room/src/App.tsx.liquid +118 -0
- package/dist/templates/waiting-room/src/i18n.ts.liquid +44 -0
- package/dist/templates/waiting-room/src/main.tsx.liquid +48 -0
- package/dist/templates/waiting-room/src/theme.ts.liquid +46 -0
- package/dist/templating/resource-metadata.d.ts +131 -0
- package/dist/types.d.ts +14 -0
- package/dist/utils/atomic-write.d.ts +40 -0
- package/dist/utils/cli-error.d.ts +64 -0
- package/dist/utils/document-parser-client.d.ts +20 -0
- package/dist/utils/env-loader.d.ts +40 -0
- package/dist/utils/error-codes.d.ts +335 -0
- package/dist/utils/errors.d.ts +19 -0
- package/dist/utils/global-settings.d.ts +65 -0
- package/dist/utils/llm-client.d.ts +34 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/output.d.ts +109 -0
- package/dist/utils/platform.d.ts +14 -0
- package/dist/utils/prompt.d.ts +36 -0
- package/dist/utils/real-path.d.ts +6 -0
- package/dist/utils/schema-properties.d.ts +35 -0
- package/dist/validation/ajv.d.ts +17 -0
- package/dist/validation/facilitator-guide-validator.d.ts +27 -0
- package/dist/validation/findings.d.ts +40 -0
- package/dist/validation/game-constraints.d.ts +10 -0
- package/dist/validation/game-validator.d.ts +34 -0
- package/dist/validation/package-validation.d.ts +41 -0
- package/dist/validation/package-validator.d.ts +19 -0
- package/dist/validation/resource-validator.d.ts +79 -0
- package/dist/validation/schema-defaults-validator.d.ts +29 -0
- package/dist/validation/schema-validation.d.ts +115 -0
- package/dist/validation/semver.d.ts +9 -0
- package/package.json +122 -3
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Create a session UI
|
|
2
|
+
|
|
3
|
+
Build the facilitator's screen: every team's state side by side, with controls to change values and run the session.
|
|
4
|
+
|
|
5
|
+
**Keywords:** manage session, facilitator UI, facilitator dashboard, session overview, all teams, session user interface, admin UI, admin panel, facilitator panel, hidden from participants, facilitator-only, game master, instructor view, cross-team
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Capabilities to show and change (here `price`, `workers`, and `production`); see [Create a capability](create-capability.md)
|
|
10
|
+
- `seriousgaming.sdk.json` in your working directory
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. Declare what the session UI reads and writes. A game holds at most one, in the `session/` slot, and the starter game already fills it, so in a package made with `new package` update it:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm run sdk update session --patch '[
|
|
18
|
+
{ "op": "replace", "path": "/definition/reads", "value": ["production"] },
|
|
19
|
+
{ "op": "replace", "path": "/definition/writes", "value": ["price", "workers"] }
|
|
20
|
+
]'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
In a package without one (made with `new package --empty`), create it:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm run sdk new session '{
|
|
27
|
+
"definition": {
|
|
28
|
+
"reads": ["production"],
|
|
29
|
+
"writes": ["price", "workers"]
|
|
30
|
+
},
|
|
31
|
+
"rootDirectory": ".",
|
|
32
|
+
"ui": { "entrypoint": "index.html" }
|
|
33
|
+
}'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Either regenerates `session/types.ts`, which includes a ready-made `SessionData`.
|
|
37
|
+
|
|
38
|
+
2. Write the overview in `session/src/App.tsx`. `setData` takes the team id first, so each change lands on the team whose card it came from:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import {
|
|
42
|
+
useSessionUserInterfaceCallbacks,
|
|
43
|
+
useSessionUserInterfaceData,
|
|
44
|
+
useSessionUserInterfaceTeams,
|
|
45
|
+
} from '@seriousgaming/sdk/ui';
|
|
46
|
+
|
|
47
|
+
import type { SessionData, Settings } from '../types';
|
|
48
|
+
|
|
49
|
+
export default function App() {
|
|
50
|
+
const { sessionData, setData } = useSessionUserInterfaceData<SessionData, Settings>();
|
|
51
|
+
const teams = useSessionUserInterfaceTeams();
|
|
52
|
+
const { requestTick } = useSessionUserInterfaceCallbacks();
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<main>
|
|
56
|
+
{teams.map(({ teamId, name }) => {
|
|
57
|
+
const team = sessionData.teams[teamId];
|
|
58
|
+
if (!team) return null;
|
|
59
|
+
return (
|
|
60
|
+
<section key={teamId}>
|
|
61
|
+
<h2>{name}</h2>
|
|
62
|
+
<p>Production: {team.context.production.Production}</p>
|
|
63
|
+
<label>
|
|
64
|
+
Price
|
|
65
|
+
<input
|
|
66
|
+
type="number"
|
|
67
|
+
value={team.context.price.Price}
|
|
68
|
+
onChange={(e) =>
|
|
69
|
+
setData(teamId, {
|
|
70
|
+
price: { Price: Number(e.target.value) },
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
/>
|
|
74
|
+
</label>
|
|
75
|
+
<button onClick={() => requestTick(teamId)}>Tick</button>
|
|
76
|
+
</section>
|
|
77
|
+
);
|
|
78
|
+
})}
|
|
79
|
+
</main>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A `scope: 'shared'` capability arrives once, in `sessionData.shared.context`, and is written with the one-argument `setData(update)`. See [Writing shared capabilities](../guides/multi-team-games.md#facilitator-writable-shared-capabilities) and the [session UI hooks reference](../guides/session.md#hooks-reference) for roster control, timers, undo, and reset.
|
|
85
|
+
|
|
86
|
+
3. If you replaced the starter's session UI, delete its other components and tests under `session/src/`, which read capabilities this one no longer declares.
|
|
87
|
+
|
|
88
|
+
4. Build:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pnpm run build
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Verify
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pnpm run sdk dev
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The session UI is the console at http://localhost:3000. Change a price on one team's card, then open that team's participant view: it shows the new value.
|
|
101
|
+
|
|
102
|
+
## Troubleshooting
|
|
103
|
+
|
|
104
|
+
| Problem | Solution |
|
|
105
|
+
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
|
106
|
+
| `new session` fails with `RESOURCE_EXISTS` | The slot is filled: use `update session` (step 1), or `pnpm run sdk delete session --yes` and then `new session` |
|
|
107
|
+
| The teams list is empty | The session has no teams yet; `useSessionUserInterfaceTeams` returns `[]` until it does |
|
|
108
|
+
| A field shows a stale value | Use `value=` (controlled), not `defaultValue=` |
|
|
109
|
+
| A change lands on the wrong team | Check the first argument to `setData` is that card's `teamId` |
|
|
110
|
+
| A shared write is refused | The capability must be `scope: 'shared'` and in this UI's `writes`; a per-team capability uses `setData(teamId, update)` |
|
|
111
|
+
|
|
112
|
+
## Related
|
|
113
|
+
|
|
114
|
+
- [Session UI guide](../guides/session.md)
|
|
115
|
+
- [Create a user interface](create-user-interface.md)
|
|
116
|
+
- [Test a user interface](test-user-interface.md)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Create settings
|
|
2
|
+
|
|
3
|
+
Give a game a read-only parameter, such as a price, a difficulty, or an answer key, that its logic and screens read and that scenarios and facilitators can change before play starts.
|
|
4
|
+
|
|
5
|
+
**Keywords:** create settings, new settings, settings resource, settingsSchema, game parameters, configuration, configurable value, scenario override, answer key, difficulty
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- A package with `seriousgaming.sdk.json` in your working directory
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Create the settings resource. Every property needs a `default`, and the schema has no top-level `required`. Describe each property (`title`, `description` with units, `minimum` and `maximum`): editors and AI agents read the schema:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm run sdk new settings '{
|
|
17
|
+
"definition": {
|
|
18
|
+
"identifier": "demand",
|
|
19
|
+
"settingsSchema": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"properties": {
|
|
22
|
+
"BaseDemand": {
|
|
23
|
+
"type": "number",
|
|
24
|
+
"title": "Base demand",
|
|
25
|
+
"description": "Units customers would buy each tick at a price of zero",
|
|
26
|
+
"default": 100,
|
|
27
|
+
"minimum": 0,
|
|
28
|
+
"maximum": 10000
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"additionalProperties": false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
2. List it on each resource that reads it. For the engine and the game UI:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pnpm run sdk update engine --patch '[{ "op": "add", "path": "/definition/settings/-", "value": "demand" }]'
|
|
41
|
+
pnpm run sdk update ui --patch '[{ "op": "add", "path": "/definition/settings/-", "value": "demand" }]'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Use `"path": "/definition/settings", "value": ["demand"]` for a resource that lists no settings yet. Each command regenerates that resource's `types.ts`.
|
|
45
|
+
|
|
46
|
+
3. Read it in logic as `settings.demand`:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
export const Run: RunFunction<Context, Settings> = async ({ context, settings }) => {
|
|
50
|
+
const Sales = Math.max(0, settings.demand.BaseDemand - context.price.Price * 2);
|
|
51
|
+
return { capabilities: { ...context, sales: { ...context.sales, Sales } } };
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
4. Read it in a screen from `useUserInterfaceData()`:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
const { settings } = useUserInterfaceData<Context, Settings>();
|
|
59
|
+
return <p>Typical demand: {settings.demand.BaseDemand}</p>;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
5. Optional: override it in a scenario, keyed by settings identifier (see [Create a scenario](create-scenario.md)). To change it for every session, edit its `default`.
|
|
63
|
+
|
|
64
|
+
## Verify
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pnpm run sdk configure '{"demand":{"BaseDemand":250}}'
|
|
68
|
+
pnpm run sdk view --full
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The resolved `settings.demand.BaseDemand` is `250`, and the next `pnpm run sdk tick` plays with it.
|
|
72
|
+
|
|
73
|
+
## Troubleshooting
|
|
74
|
+
|
|
75
|
+
| Problem | Solution |
|
|
76
|
+
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| `Every settings property declares a default, and "X" does not` | Add a `default` to that property |
|
|
78
|
+
| `reads settings "demand", which this package does not declare` | The directory name and the `settings` entry differ |
|
|
79
|
+
| `settings.demand` is undefined | Add `demand` to that resource's `settings` |
|
|
80
|
+
| `Unknown settings "engine"` from `configure` or a scenario | Overrides are keyed by settings identifier, not by the resource that reads them |
|
|
81
|
+
| A participant can see a value they should not | Move it to a settings resource only the engine or an endpoint lists |
|
|
82
|
+
| The value does not change mid-game | Expected: settings are fixed when play starts. Use a capability for anything that changes during play |
|
|
83
|
+
|
|
84
|
+
## Related
|
|
85
|
+
|
|
86
|
+
- [Settings guide](../guides/settings.md): declaring, reading, overriding, and validation
|
|
87
|
+
- [Create a scenario](create-scenario.md)
|
|
88
|
+
- [Create a setup screen](create-setup.md)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Create a setup screen
|
|
2
|
+
|
|
3
|
+
Give facilitators a short form at session creation that sets a few of your game's settings for that session only.
|
|
4
|
+
|
|
5
|
+
**Keywords:** setup, setup screen, quick config, session setup, configuration step, configure session, settings form, requestPlay, configures
|
|
6
|
+
|
|
7
|
+
## What you'll build
|
|
8
|
+
|
|
9
|
+
A setup screen at `setup/` that edits the `engine` settings and starts play from its own button. A game with a `setup` slot opens at the configuration step: nothing runs until the facilitator presses Play. See the [setup guide](../guides/setup.md) for the full behaviour.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
- A settings resource for the screen to edit; see [Create a settings resource](create-settings.md)
|
|
14
|
+
- `seriousgaming.sdk.json` in your working directory
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
|
|
18
|
+
### 1. Create the slot
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm run sdk new setup '{
|
|
22
|
+
"definition": {
|
|
23
|
+
"configures": ["engine"]
|
|
24
|
+
},
|
|
25
|
+
"rootDirectory": ".",
|
|
26
|
+
"ui": { "entrypoint": "index.html" }
|
|
27
|
+
}'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This creates:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
setup/
|
|
34
|
+
├── setup.sdk.json
|
|
35
|
+
├── defaults.ts
|
|
36
|
+
├── index.html
|
|
37
|
+
├── types.ts
|
|
38
|
+
└── src/
|
|
39
|
+
├── main.tsx
|
|
40
|
+
├── App.tsx
|
|
41
|
+
├── App.test.tsx
|
|
42
|
+
├── i18n.ts
|
|
43
|
+
└── theme.ts
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Build the form
|
|
47
|
+
|
|
48
|
+
Open `setup/src/App.tsx`. Read and write the settings with `useSettingsEditor`, typed by the generated `Settings`:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useSettingsEditor, useSettingsEditorCallbacks } from '@seriousgaming/sdk/ui';
|
|
52
|
+
import { Button, Stack, TextField } from '@mui/material';
|
|
53
|
+
import type { Settings } from '../types';
|
|
54
|
+
|
|
55
|
+
function App() {
|
|
56
|
+
const { settings, updateSettings } = useSettingsEditor<Settings>();
|
|
57
|
+
const { requestPlay } = useSettingsEditorCallbacks();
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Stack spacing={2}>
|
|
61
|
+
<TextField
|
|
62
|
+
label="Base demand"
|
|
63
|
+
type="number"
|
|
64
|
+
value={settings.engine.BaseDemand}
|
|
65
|
+
onChange={(e) =>
|
|
66
|
+
void updateSettings({
|
|
67
|
+
engine: { ...settings.engine, BaseDemand: Number(e.target.value) },
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
/>
|
|
71
|
+
<Button variant="contained" onClick={() => requestPlay()}>
|
|
72
|
+
Start game
|
|
73
|
+
</Button>
|
|
74
|
+
</Stack>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default App;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`updateSettings` sends only what changed, so spreading `settings` is safe.
|
|
82
|
+
|
|
83
|
+
### 3. Run it
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pnpm run sdk dev
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The dev server opens on `/setup`.
|
|
90
|
+
|
|
91
|
+
## Verify
|
|
92
|
+
|
|
93
|
+
- [ ] The form shows each setting's resolved value
|
|
94
|
+
- [ ] Changing a value and pressing Start (or the host's Play) starts the session with that value
|
|
95
|
+
- [ ] `pnpm run sdk view` after play shows the engine acting on the new value
|
|
96
|
+
|
|
97
|
+
## Troubleshooting
|
|
98
|
+
|
|
99
|
+
**The build fails naming a settings resource**
|
|
100
|
+
|
|
101
|
+
Every identifier in `configures` must be a settings resource the package declares under `settings/`.
|
|
102
|
+
|
|
103
|
+
**`useSettingsEditor` throws**
|
|
104
|
+
|
|
105
|
+
The hook must run inside `SettingsEditorWrapper`, which the scaffolded `src/main.tsx` provides.
|
|
106
|
+
|
|
107
|
+
**The game starts at tick 0 with no form**
|
|
108
|
+
|
|
109
|
+
The configuration step exists only when the package has a `setup/setup.sdk.json`. Check the slot directory and bundle name.
|
|
110
|
+
|
|
111
|
+
## Related
|
|
112
|
+
|
|
113
|
+
- [Create a scenario editor](create-scenario-editor.md)
|
|
114
|
+
- [Use requestPlay in a setup screen](use-request-play.md)
|
|
115
|
+
- [Create a settings resource](create-settings.md)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Create a tick controller
|
|
2
|
+
|
|
3
|
+
Make ticks fire automatically, on an interval or a schedule your game's logic decides.
|
|
4
|
+
|
|
5
|
+
**Keywords:** create tick controller, new tick controller, automatic ticks, timer, tick interval, auto tick, schedule ticks
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- A capability the controller decides from (here `progress`, with a `Phase` string); see [Create a capability](create-capability.md)
|
|
10
|
+
- `seriousgaming.sdk.json` in your working directory
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. Create the tick controller. A game holds at most one, in the `tick_controller/` slot, which the starter game leaves empty:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm run sdk new tick_controller '{
|
|
18
|
+
"definition": { "reads": ["progress"] },
|
|
19
|
+
"logic": { "directory": ".", "entrypoint": "logic.ts" },
|
|
20
|
+
"rootDirectory": "."
|
|
21
|
+
}'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
2. Write `GetTickController` in `tick_controller/logic.ts`. Return a cadence with `intervalTick`, which takes milliseconds and refuses anything outside 30 seconds to 7 days:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { GetTickControllerFunction, intervalTick } from '@seriousgaming/sdk';
|
|
28
|
+
|
|
29
|
+
import type { Context, Settings } from './types';
|
|
30
|
+
|
|
31
|
+
export const GetTickController: GetTickControllerFunction<Context, Settings> = async ({
|
|
32
|
+
context,
|
|
33
|
+
}) => intervalTick(context.progress.Phase === 'early' ? 30_000 : 60_000);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
For fixed times of day, return `scheduledTick(nextDailyAt(...))`; for manual ticks only, `{ enabled: false }`. See the [cadence cookbook](../guides/tick-controller.md#cadence-cookbook).
|
|
37
|
+
|
|
38
|
+
3. Build:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pnpm run build
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Verify
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pnpm run sdk timer
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The timer reports `enabled: true` and the next tick. In the dev server, the drawer shows the countdown and ticks fire on their own. To test without waiting, see [Testing without waiting](../guides/tick-controller.md#testing-without-waiting).
|
|
51
|
+
|
|
52
|
+
## Troubleshooting
|
|
53
|
+
|
|
54
|
+
| Problem | Solution |
|
|
55
|
+
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| `new tick_controller` fails with `RESOURCE_EXISTS` | The game already has one: change it with `update tick_controller` |
|
|
57
|
+
| `intervalTick(60)` throws | `intervalMs` is in milliseconds, so `60` is below the floor. Write `60_000` for a minute |
|
|
58
|
+
| The timer never starts | Check the controller returns `enabled: true` (or an `intervalTick` result) |
|
|
59
|
+
| `context.progress` is a type error | Add `progress` to the controller's `reads` |
|
|
60
|
+
| Ticks keep firing in the waiting room | Read `waitingRoomOpen` (see [Stopping the clock](../guides/tick-controller.md#stopping-the-clock-while-the-waiting-room-is-open)) |
|
|
61
|
+
|
|
62
|
+
## Related
|
|
63
|
+
|
|
64
|
+
- [Tick controller guide](../guides/tick-controller.md): the result, bounds, scheduling, pausing, and completion
|
|
65
|
+
- [End a game when a condition is met](end-game-on-condition.md)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Create a user interface
|
|
2
|
+
|
|
3
|
+
Build the game UI: the screen each participant sees, showing the game's state and taking their decisions.
|
|
4
|
+
|
|
5
|
+
**Keywords:** create user interface, new UI, display game state, user input, participant interface, participant UI, game UI
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Capabilities to show and write (here `pricing` and `sales`); see [Create a capability](create-capability.md)
|
|
10
|
+
- An engine that fills them; see [Create an engine](create-engine.md)
|
|
11
|
+
- `seriousgaming.sdk.json` in your working directory
|
|
12
|
+
|
|
13
|
+
## Steps
|
|
14
|
+
|
|
15
|
+
1. Declare what the UI reads and writes. A game holds one UI, in the `ui/` slot, and the starter game already fills it, so in a package made with `new package` update it:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm run sdk update ui --patch '[
|
|
19
|
+
{ "op": "replace", "path": "/definition/reads", "value": ["sales"] },
|
|
20
|
+
{ "op": "replace", "path": "/definition/writes", "value": ["pricing"] }
|
|
21
|
+
]'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
In a package made with `new package --empty`, create the slot instead:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm run sdk new ui '{
|
|
28
|
+
"definition": {
|
|
29
|
+
"reads": ["sales"],
|
|
30
|
+
"writes": ["pricing"]
|
|
31
|
+
},
|
|
32
|
+
"ui": { "entrypoint": "index.html" },
|
|
33
|
+
"rootDirectory": "."
|
|
34
|
+
}'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`data` carries the union of `reads` and `writes`, so `pricing` is readable too. Either command regenerates `ui/types.ts`.
|
|
38
|
+
|
|
39
|
+
2. Write the component in `ui/src/App.tsx`. Read with `useUserInterfaceData`, and write only the fields that changed:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { useUserInterfaceData } from '@seriousgaming/sdk/ui';
|
|
43
|
+
|
|
44
|
+
import type { Context, Settings } from '../types';
|
|
45
|
+
|
|
46
|
+
export default function App() {
|
|
47
|
+
const { data, setData } = useUserInterfaceData<Context, Settings>();
|
|
48
|
+
|
|
49
|
+
const raisePrice = () =>
|
|
50
|
+
setData({ pricing: { CurrentPrice: data.pricing.CurrentPrice + 10 } });
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<main>
|
|
54
|
+
<h1>Game dashboard</h1>
|
|
55
|
+
<p>Current price: {data.pricing.CurrentPrice}</p>
|
|
56
|
+
<button onClick={raisePrice}>Raise price by 10</button>
|
|
57
|
+
<p>Daily revenue: {data.sales.Revenue}</p>
|
|
58
|
+
</main>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Never spread `data` (or a whole capability) back into `setData`: a write naming a capability outside `writes` is refused, and re-sending untouched fields overwrites a team-mate's concurrent write. See [Writing to context](../guides/ui.md#writing-to-context).
|
|
64
|
+
|
|
65
|
+
3. If you replaced the starter game's UI, delete the starter's other components and their tests under `ui/src/`: they read capabilities this UI no longer declares, so they stop type-checking.
|
|
66
|
+
|
|
67
|
+
4. Build:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pnpm run build
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Verify
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pnpm run sdk dev
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Open a team's participant view. It shows the current price and revenue, and **Raise price by 10** changes the price in every view of that team.
|
|
80
|
+
|
|
81
|
+
## Troubleshooting
|
|
82
|
+
|
|
83
|
+
| Problem | Solution |
|
|
84
|
+
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| `new ui` fails with `RESOURCE_EXISTS` | The slot is filled: use `update ui` (step 1), or `pnpm run sdk delete ui --yes` and then `new ui` |
|
|
86
|
+
| `data.pricing` is a type error | `pricing` is in neither `reads` nor `writes`; add it and let the command regenerate `types.ts` |
|
|
87
|
+
| The write is refused as `denied` | The write names a capability outside `writes`. Send only the capability you declared |
|
|
88
|
+
| A team-mate's change disappears when another saves | A write re-sends fields from a stale snapshot; send only the changed field |
|
|
89
|
+
| Translations do not appear | See the [internationalisation guide](../guides/internationalization.md) |
|
|
90
|
+
|
|
91
|
+
## Related
|
|
92
|
+
|
|
93
|
+
- [User interfaces guide](../guides/ui.md): reading and writing state, ticks, participants, timers and theming
|
|
94
|
+
- [Design state for concurrent writes](design-state-for-concurrent-writes.md)
|
|
95
|
+
- [Use requestTick in a UI](use-request-tick.md)
|
|
96
|
+
- [Test a user interface](test-user-interface.md)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Create a validator
|
|
2
|
+
|
|
3
|
+
Reject a participant's write that breaks the game's rules, before the runtime applies it.
|
|
4
|
+
|
|
5
|
+
**Keywords:** create validator, new validator, mutation validation, gate update, reject decision, reject submission, RequestTick
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- A capability participants write (here `decisions`, a map of boolean choices); see [Create a capability](create-capability.md)
|
|
10
|
+
- `seriousgaming.sdk.json` in your working directory
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. Create the validator, declaring what it reads:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm run sdk new validator '{
|
|
18
|
+
"definition": {
|
|
19
|
+
"identifier": "decisionlimit",
|
|
20
|
+
"reads": ["decisions"]
|
|
21
|
+
},
|
|
22
|
+
"logic": { "directory": "logic", "entrypoint": "logic.ts" },
|
|
23
|
+
"rootDirectory": "."
|
|
24
|
+
}'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This writes `validators/decisionlimit/` with `validator.sdk.json`, `logic/logic.ts`, and a generated `types.ts`. The directory is the whole of the wiring.
|
|
28
|
+
|
|
29
|
+
2. Write `UpdateData` in `validators/decisionlimit/logic/logic.ts`. Judge `next`, the context as it would be after the write, and either allow it or reject it with a message:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import type { ValidatorFunction } from '../types';
|
|
33
|
+
|
|
34
|
+
export const UpdateData: ValidatorFunction = async ({ next }) => {
|
|
35
|
+
const selected = Object.values(next.decisions).filter(Boolean).length;
|
|
36
|
+
return selected > 3 ? { ok: false, message: 'errors.max-three-decisions' } : { ok: true };
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
A validator never changes state. To read who wrote it, narrow on `actor.role` (see [The actor](../guides/validators.md#the-actor)).
|
|
41
|
+
|
|
42
|
+
3. Optional: gate a participant's request for the next tick by exporting `RequestTick` as well (see [Gating tick requests](../guides/validators.md#gating-tick-requests)).
|
|
43
|
+
|
|
44
|
+
4. Build:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pnpm run build
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Verify
|
|
51
|
+
|
|
52
|
+
From a participant's screen, submit a fourth choice: the write is refused, and the UI receives the rejection through `useUserInterfaceValidationRejections` (and as a `validation-rejected` outcome where it awaits the write). In a test, `session.setData(0, ...)` answers `{ ok: false, outcome: { kind: 'validation-rejected' } }` (see [Injecting decisions](../guides/engine-testing.md#injecting-decisions)).
|
|
53
|
+
|
|
54
|
+
## Troubleshooting
|
|
55
|
+
|
|
56
|
+
| Problem | Solution |
|
|
57
|
+
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
58
|
+
| The validator never runs | Check `validators/<identifier>/validator.sdk.json` exists |
|
|
59
|
+
| It allows what it should reject | Judge `next`, the proposed state, not `previous` |
|
|
60
|
+
| A CLI patch passes despite the rule | Expected: the CLI, the engine, and endpoints are trusted and bypass validators (see [What bypasses validation](../guides/validators.md#what-bypasses-validation)) |
|
|
61
|
+
| `next.decisions` is a type error | Add `decisions` to the validator's `reads` |
|
|
62
|
+
|
|
63
|
+
## Related
|
|
64
|
+
|
|
65
|
+
- [Validators guide](../guides/validators.md): the actor, ordering, settings, and what bypasses validation
|
|
66
|
+
- [Design state for concurrent writes](design-state-for-concurrent-writes.md): arbitrating contested slots
|
|
67
|
+
- [Create a hook](create-hook.md)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Create a waiting room UI
|
|
2
|
+
|
|
3
|
+
Replace the host's stock holding screen with your own, so participants see your branding and your words while the facilitator has the waiting room open.
|
|
4
|
+
|
|
5
|
+
**Keywords:** waiting room, holding screen, lobby, waiting to begin, session paused, park a session, break, waitingRoom
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- A game; see [Shape your game](create-game.md)
|
|
10
|
+
- Optionally, capabilities the room should show (here `briefing`)
|
|
11
|
+
- `seriousgaming.sdk.json` in your working directory
|
|
12
|
+
|
|
13
|
+
## Steps
|
|
14
|
+
|
|
15
|
+
1. Declare what the room reads. A game holds at most one waiting room, in the `waiting_room/` slot, and the starter game already fills it, so in a package made with `new package` update it:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm run sdk update waiting_room --patch '[
|
|
19
|
+
{ "op": "replace", "path": "/definition/reads", "value": ["briefing"] }
|
|
20
|
+
]'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
In a package without one, create it:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm run sdk new waiting_room '{
|
|
27
|
+
"definition": { "reads": ["briefing"] },
|
|
28
|
+
"rootDirectory": ".",
|
|
29
|
+
"ui": { "entrypoint": "index.html" }
|
|
30
|
+
}'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
2. Write the screen in `waiting_room/src/App.tsx`. It takes the same `useUserInterface*` hooks as the game UI. Branch on `completedTicks`, so a session parked mid-play does not say 'waiting to begin':
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import {
|
|
37
|
+
useUserInterfaceData,
|
|
38
|
+
useUserInterfaceOwnTeam,
|
|
39
|
+
useUserInterfaceParticipants,
|
|
40
|
+
} from '@seriousgaming/sdk/ui';
|
|
41
|
+
|
|
42
|
+
import type { Context, Settings } from '../types';
|
|
43
|
+
|
|
44
|
+
export default function App() {
|
|
45
|
+
const { completedTicks } = useUserInterfaceData<Context, Settings>();
|
|
46
|
+
const ownTeam = useUserInterfaceOwnTeam();
|
|
47
|
+
const participants = useUserInterfaceParticipants();
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<main>
|
|
51
|
+
<h1>{completedTicks === 0 ? 'Waiting to begin' : 'Session paused'}</h1>
|
|
52
|
+
<p>You have joined {ownTeam?.name}. The facilitator will continue shortly.</p>
|
|
53
|
+
<ul>
|
|
54
|
+
{participants.map((p) => (
|
|
55
|
+
<li key={p.id}>
|
|
56
|
+
{p.name} {p.connected ? '(here)' : ''}
|
|
57
|
+
</li>
|
|
58
|
+
))}
|
|
59
|
+
</ul>
|
|
60
|
+
</main>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
3. Optional: open the room when a session starts, so nobody lands in the game before the facilitator is ready (the starter game already does):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pnpm run sdk update package --patch '[
|
|
69
|
+
{ "op": "add", "path": "/waitingRoom", "value": { "openOnStart": true } }
|
|
70
|
+
]'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
4. Optional: stop automatic ticks while the room is open. Opening it does not pause them; read `waitingRoomOpen` in your tick controller:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
export const GetTickController: GetTickControllerFunction<Context, Settings> = async ({
|
|
77
|
+
waitingRoomOpen,
|
|
78
|
+
}) => ({ enabled: !waitingRoomOpen, intervalMs: 60_000 });
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
5. Build:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pnpm run build
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Verify
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pnpm run sdk dev
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Open http://localhost:3000, press the backtick key for the dev drawer, switch on **Waiting room**, and open a team's game UI. The room replaces the game UI at once, and switching it off brings the game back with no reload. Run a tick first to see the 'Session paused' wording.
|
|
94
|
+
|
|
95
|
+
## Troubleshooting
|
|
96
|
+
|
|
97
|
+
| Problem | Solution |
|
|
98
|
+
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
99
|
+
| `new waiting_room` fails with `RESOURCE_EXISTS` | The slot is filled: use `update waiting_room` (step 1), or `pnpm run sdk delete waiting_room --yes` first |
|
|
100
|
+
| The host's built-in panel shows instead | The package has no `waiting_room/` slot |
|
|
101
|
+
| Ticks keep firing while the room is open | Expected: read `waitingRoomOpen` in your tick controller (step 4) |
|
|
102
|
+
| `data` is empty | Add the capability to the bundle's `reads` |
|
|
103
|
+
| The roster is empty | Participants join per team; open a team's game UI rather than the console |
|
|
104
|
+
|
|
105
|
+
## Related
|
|
106
|
+
|
|
107
|
+
- [Waiting room guide](../guides/waiting-room.md): held starts, join codes, roster, and layout
|
|
108
|
+
- [Create a tick controller](create-tick-controller.md)
|
|
109
|
+
- [Test a user interface](test-user-interface.md)
|