@seriousgaming/sdk-tools 0.0.0-stage → 1.0.0-alpha.2
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 +38 -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 +27404 -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 +16920 -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 +218 -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 +241 -0
- package/dist/docs/cli-and-dev-server.md +217 -0
- package/dist/docs/cli-error-codes.md +156 -0
- package/dist/docs/cli-reference.md +2489 -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 +577 -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 +339 -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 +123 -3
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a client may ask the session to do, and what it hears back.
|
|
3
|
+
*
|
|
4
|
+
* One closed command set and one closed event set, shared by every client:
|
|
5
|
+
* the browser console, the CLI, and an agent driving it over HTTP. There is no
|
|
6
|
+
* second vocabulary for the CLI, which is what let the two drift before.
|
|
7
|
+
*
|
|
8
|
+
* The event set is small on purpose. The old protocol had seventeen event
|
|
9
|
+
* kinds, most of which were a slice of session state with its own payload
|
|
10
|
+
* shape: `context-updated`, `config-reloaded`, `initialized`,
|
|
11
|
+
* `participants-updated`, `waiting-room-changed`, `timer-updated`. They are all
|
|
12
|
+
* the same sentence, so there is one {@link StateEvent} carrying the whole
|
|
13
|
+
* projection, and a client renders from it. What remains distinct is what is
|
|
14
|
+
* genuinely not state: diagnostics, transient signals, and correlated replies.
|
|
15
|
+
*/
|
|
16
|
+
import type { RunKind, ValidationRejection } from '@seriousgaming/sdk';
|
|
17
|
+
import type { Actor, Command, MutationCommand, QueryCommand, QueryResult, TeamScope, ViewerRole } from '@seriousgaming/sdk/commands';
|
|
18
|
+
import type { MutationResult, StateProjection } from '@seriousgaming/sdk/projection';
|
|
19
|
+
export type { Actor, Command, MutationCommand, QueryCommand, QueryResult, TeamScope, ViewerRole };
|
|
20
|
+
/** Whether a command reads rather than mutates, and so bypasses the queue. */
|
|
21
|
+
export declare function isQuery(command: Command): command is QueryCommand;
|
|
22
|
+
/**
|
|
23
|
+
* Whether a command, addressed to `run`, replaces the walkthrough rather than
|
|
24
|
+
* reaching it.
|
|
25
|
+
*
|
|
26
|
+
* A `reset` sent to the walkthrough is one: a walkthrough always starts at
|
|
27
|
+
* tick 0 with one team (§5.7), so rewinding it has nothing to offer over
|
|
28
|
+
* rebuilding it, and a rewind keeps the scenario, locale and configuration the
|
|
29
|
+
* run was first built on rather than following the session's current ones.
|
|
30
|
+
*/
|
|
31
|
+
export declare function rebuildsWalkthrough(command: Command, run: RunKind): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The session's state, whole, after something changed it.
|
|
34
|
+
*
|
|
35
|
+
* One event rather than a family of partial ones. A client re-renders from the
|
|
36
|
+
* projection and never has to reconcile six differently-shaped updates into a
|
|
37
|
+
* picture of the same session.
|
|
38
|
+
*/
|
|
39
|
+
export interface StateEvent {
|
|
40
|
+
type: 'state';
|
|
41
|
+
state: StateProjection;
|
|
42
|
+
/**
|
|
43
|
+
* Why it changed, for diagnostics and for a console that wants to say so.
|
|
44
|
+
* Never load-bearing: a client that ignores it still renders correctly.
|
|
45
|
+
*/
|
|
46
|
+
cause: string;
|
|
47
|
+
}
|
|
48
|
+
/** A failure the operator should see (§14.5, and tick failures). */
|
|
49
|
+
export interface ErrorEvent {
|
|
50
|
+
type: 'error';
|
|
51
|
+
message: string;
|
|
52
|
+
/** Where it came from, e.g. `tick`, `hook:participantJoin`, `endpoint:narrate`. */
|
|
53
|
+
source: string;
|
|
54
|
+
teamId?: string;
|
|
55
|
+
}
|
|
56
|
+
/** Validators refused a UI-submitted write (§15). */
|
|
57
|
+
export interface ValidationRejectedEvent {
|
|
58
|
+
type: 'validation-rejected';
|
|
59
|
+
rejections: ValidationRejection[];
|
|
60
|
+
teamIndex?: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A round is being processed, so a surface can say so rather than appearing to
|
|
64
|
+
* have stopped responding (§12.4.4). Transient, and never state: a client that
|
|
65
|
+
* missed it is not wrong about the session.
|
|
66
|
+
*/
|
|
67
|
+
export interface RoundProcessingEvent {
|
|
68
|
+
type: 'round-processing';
|
|
69
|
+
processing: boolean;
|
|
70
|
+
/** Absent for a cohort tick that genuinely covers every team. */
|
|
71
|
+
teamIndex?: number;
|
|
72
|
+
}
|
|
73
|
+
export type Event = StateEvent | ErrorEvent | ValidationRejectedEvent | RoundProcessingEvent;
|
|
74
|
+
export type { MutationResult };
|
|
75
|
+
/**
|
|
76
|
+
* Why this is not a command, or null when it is one.
|
|
77
|
+
*
|
|
78
|
+
* Deliberately names the field and what was expected. The failure this replaces
|
|
79
|
+
* was `{"type":"addParticipant","team":1}` being accepted for a command whose
|
|
80
|
+
* field is `teamId`, and then failing three steps later with nothing pointing
|
|
81
|
+
* back here.
|
|
82
|
+
*/
|
|
83
|
+
export declare function commandError(value: unknown): string | null;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The scenario editor's unsaved edits (§6.5), one draft per scenario being
|
|
3
|
+
* edited.
|
|
4
|
+
*
|
|
5
|
+
* A draft belongs to no session. The dev server runs a session beside the
|
|
6
|
+
* editor, and the editor's edits used to land in that session's override
|
|
7
|
+
* layer, so editing a scenario quietly reconfigured the session and an
|
|
8
|
+
* endpoint the editor called read the session's setup edits as the draft.
|
|
9
|
+
* Kept here instead, each draft is only its own edits, sparse as the session
|
|
10
|
+
* layer is (§8.2), and resolved over the scenario it was opened on. It
|
|
11
|
+
* reaches a session only once it is saved as that scenario.
|
|
12
|
+
*
|
|
13
|
+
* Held by the session object because the dev server has one process and one
|
|
14
|
+
* place for state, not because a draft is part of the session: nothing a
|
|
15
|
+
* session does, a restart included, touches one.
|
|
16
|
+
*/
|
|
17
|
+
import type { SessionSettingsOverrides } from '../execution/types';
|
|
18
|
+
export declare class ScenarioDrafts {
|
|
19
|
+
private readonly drafts;
|
|
20
|
+
/** Open a draft of a scenario, keeping one already open on it. */
|
|
21
|
+
open(scenarioId: string | null): void;
|
|
22
|
+
isOpen(scenarioId: string | null): boolean;
|
|
23
|
+
/** The unsaved edits to a scenario, or null when no editor is open on it. */
|
|
24
|
+
edits(scenarioId: string | null): SessionSettingsOverrides | null;
|
|
25
|
+
/** Fold an edit, already reduced to what changed, into an open draft. */
|
|
26
|
+
record(scenarioId: string | null, changed: Record<string, unknown>): void;
|
|
27
|
+
/** Empty a draft once it has been saved: the scenario now holds its edits. */
|
|
28
|
+
saved(scenarioId: string | null): void;
|
|
29
|
+
/** Drop the drafts of scenarios the package no longer declares. */
|
|
30
|
+
retain(scenarioIds: ReadonlySet<string>): void;
|
|
31
|
+
scenarioIds(): (string | null)[];
|
|
32
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Endpoint calls as the session serves them (§6.12): who may make one, what
|
|
3
|
+
* the handler is told about the session, and how its effects land.
|
|
4
|
+
*
|
|
5
|
+
* An endpoint is a read that may end in writes and actions, so it runs beside
|
|
6
|
+
* the mutation queue (§9.7) and only its effects go on it, as one job, checked
|
|
7
|
+
* first against the boards the handler read so that nothing lands on a board a
|
|
8
|
+
* tick replaced meanwhile. The caller's role and team are the host's
|
|
9
|
+
* bookkeeping, never the request's, and every call that changed something is
|
|
10
|
+
* kept in an audit, since afterwards an agent's change is otherwise
|
|
11
|
+
* indistinguishable from the game's own. Running the handler itself is the
|
|
12
|
+
* executor's.
|
|
13
|
+
*/
|
|
14
|
+
import type { EndpointAuditEntry } from '@seriousgaming/sdk/projection';
|
|
15
|
+
import type { QueryCommand, QueryResult } from './protocol';
|
|
16
|
+
import type { SessionHost } from './session-host';
|
|
17
|
+
type CallEndpoint = Extract<QueryCommand, {
|
|
18
|
+
type: 'callEndpoint';
|
|
19
|
+
}>;
|
|
20
|
+
type EndpointHost = Pick<SessionHost, 'executor' | 'state' | 'participants' | 'faults' | 'clock' | 'timers' | 'pendingChanges' | 'mode' | 'settings' | 'tickLimit' | 'scenarioBeingEdited' | 'waitingRoomOpen' | 'positionOf' | 'indexOfTeamId' | 'teamAt' | 'roster' | 'declaredSurface' | 'enqueue' | 'apply'>;
|
|
21
|
+
export declare class SessionEndpoints {
|
|
22
|
+
private readonly host;
|
|
23
|
+
private readonly audit;
|
|
24
|
+
constructor(host: EndpointHost);
|
|
25
|
+
/** Endpoint calls that changed something, oldest first (§6.12). */
|
|
26
|
+
auditLog(): readonly EndpointAuditEntry[];
|
|
27
|
+
/**
|
|
28
|
+
* Answer an endpoint call. A failure is an answer, so every transport
|
|
29
|
+
* carries it as it stands rather than flattening a throw into a message.
|
|
30
|
+
*/
|
|
31
|
+
answer(command: CallEndpoint): Promise<QueryResult>;
|
|
32
|
+
/** The endpoints a caller may see: every one, or the published ones outside the game. */
|
|
33
|
+
list(external: boolean | undefined): QueryResult;
|
|
34
|
+
/**
|
|
35
|
+
* Run one endpoint call (§6.12): who may make it, the handler, its effects
|
|
36
|
+
* and, for an endpoint that answers in two phases, `Respond`. Throws on any
|
|
37
|
+
* failure; {@link answer} turns the throw into an `EndpointFailure`.
|
|
38
|
+
*/
|
|
39
|
+
private call;
|
|
40
|
+
/** Whether the scenario editor made this call, which runs with no session (§6.5). */
|
|
41
|
+
private fromScenarioEditor;
|
|
42
|
+
/**
|
|
43
|
+
* A call from the scenario editor (§6.5, §6.12). The editor edits a
|
|
44
|
+
* scenario rather than a session, so the handler is given the settings as
|
|
45
|
+
* that scenario would resolve them, the draft included, and nothing of the
|
|
46
|
+
* session this host happens to be running beside it: no board, no team, no
|
|
47
|
+
* roster, and a caller with no session. The build refuses an editor that
|
|
48
|
+
* lists an endpoint needing more, but the dev server runs a package the
|
|
49
|
+
* build refuses, so the call is refused here as well.
|
|
50
|
+
*/
|
|
51
|
+
private callFromEditor;
|
|
52
|
+
/**
|
|
53
|
+
* What a call with no session is told of one (§6.12): the game's mode and
|
|
54
|
+
* the tick limit the scenario being edited resolves to, and nothing played.
|
|
55
|
+
*/
|
|
56
|
+
private sessionless;
|
|
57
|
+
/**
|
|
58
|
+
* Carry out what an endpoint returned (§6.12): its write, then its per-team
|
|
59
|
+
* writes, then its actions, as one job on the queue, so no other mutation
|
|
60
|
+
* lands between them and none of them lands on a board a tick replaced
|
|
61
|
+
* while the handler ran.
|
|
62
|
+
*
|
|
63
|
+
* Everything that can be checked without applying is checked before the
|
|
64
|
+
* job is queued, so a bad team id or an undeclared action applies nothing. What cannot be checked in advance, such as an engine
|
|
65
|
+
* failing the tick an action asked for, stops the sequence where it fails:
|
|
66
|
+
* the steps before it have landed, and the caller is told how many.
|
|
67
|
+
*/
|
|
68
|
+
private applyEffects;
|
|
69
|
+
/**
|
|
70
|
+
* The session command an endpoint's action stands for (§6.12), with its
|
|
71
|
+
* team resolved. An omitted `teamId` is the call's own team on a
|
|
72
|
+
* team-scoped endpoint and the whole session on a session-scoped one.
|
|
73
|
+
*/
|
|
74
|
+
private actionCommand;
|
|
75
|
+
/**
|
|
76
|
+
* Keep a record of an endpoint call that changed something (§6.12): which
|
|
77
|
+
* endpoint, who called it, and what it changed. An agent's change is
|
|
78
|
+
* otherwise indistinguishable from the game's own after the fact.
|
|
79
|
+
*/
|
|
80
|
+
private record;
|
|
81
|
+
/**
|
|
82
|
+
* The team a team-scoped endpoint call runs for (§6.12): by index, else by
|
|
83
|
+
* id, else the session's only team.
|
|
84
|
+
*
|
|
85
|
+
* Refused when a session of several teams names none. The handler is
|
|
86
|
+
* promised a `team`, and the only board left to hand it is whichever the
|
|
87
|
+
* executor last worked with, which is one team's figures under no name.
|
|
88
|
+
*/
|
|
89
|
+
private position;
|
|
90
|
+
/** Whether this endpoint declared anything that lives on a team board. */
|
|
91
|
+
private readsTeams;
|
|
92
|
+
/**
|
|
93
|
+
* Every team's board, for a session-scoped endpoint's non-shared reads
|
|
94
|
+
* (§6.12). Stable-index order, with the display name resolved as the §20.1
|
|
95
|
+
* projection resolves it: an endpoint commonly answers its caller in words,
|
|
96
|
+
* and it has no other route to a team's name.
|
|
97
|
+
*/
|
|
98
|
+
private teams;
|
|
99
|
+
/** The ticks every board stands at now, for an endpoint's read (§6.12, 6a). */
|
|
100
|
+
private boardTicks;
|
|
101
|
+
/**
|
|
102
|
+
* Where the session stands, for an endpoint's `session` (§6.12). Status
|
|
103
|
+
* only: no team's context, so its cost is the team count and not the
|
|
104
|
+
* size of anybody's board.
|
|
105
|
+
*/
|
|
106
|
+
private session;
|
|
107
|
+
}
|
|
108
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who stands behind an action, and so whether the validators see it (§15).
|
|
3
|
+
*
|
|
4
|
+
* A validator gates a write or a tick request from a surface a participant or
|
|
5
|
+
* an observer is looking at, and nothing else: the CLI, the session surface,
|
|
6
|
+
* the engine, a hook and an endpoint are system-trusted. Telling those apart
|
|
7
|
+
* from a player surface that lost its participant is the whole difficulty
|
|
8
|
+
* (#566), so the attribution, the refusal of what cannot be attributed, and
|
|
9
|
+
* the putting of an attributed action to its gate live together here, where
|
|
10
|
+
* one reading of an actor serves both gates. Running the validators
|
|
11
|
+
* themselves is the executor's.
|
|
12
|
+
*/
|
|
13
|
+
import type { ValidatorActor } from '@seriousgaming/sdk';
|
|
14
|
+
import type { GameContext } from '../execution/executor';
|
|
15
|
+
import type { ParticipantRecord } from './participant-registry';
|
|
16
|
+
import type { Actor, TeamScope } from './protocol';
|
|
17
|
+
import type { SessionHost } from './session-host';
|
|
18
|
+
type ActorHost = Pick<SessionHost, 'participants' | 'state'>;
|
|
19
|
+
type GateHost = Pick<SessionHost, 'executor' | 'participants' | 'state' | 'mode' | 'positionOf' | 'emit'>;
|
|
20
|
+
/**
|
|
21
|
+
* The participant behind a write, or `undefined` where there honestly is
|
|
22
|
+
* none.
|
|
23
|
+
*
|
|
24
|
+
* §15.1 gates validators on a write being participant-bearing, and three
|
|
25
|
+
* callers bear no participant legitimately: the CLI, a session surface,
|
|
26
|
+
* and an observer (§13.3). Absence on its own cannot say which, so a
|
|
27
|
+
* player surface whose slot the console had failed to resolve was read as
|
|
28
|
+
* one more of them, and its writes were applied unvalidated (#566).
|
|
29
|
+
*
|
|
30
|
+
* `viewerRole` is what separates them. A surface the host holds as a
|
|
31
|
+
* participant's, arriving with nobody on it, is a write the session cannot
|
|
32
|
+
* attribute, and an unattributable write is refused rather than trusted:
|
|
33
|
+
* the runtime cannot run an actor-aware check without an actor, so the
|
|
34
|
+
* honest outcome is to refuse rather than to skip.
|
|
35
|
+
*
|
|
36
|
+
* §13.2 step 3 is the same refusal reached from the other side, and is
|
|
37
|
+
* resolved here too. The team is the one the write names, or the one it
|
|
38
|
+
* would land on when it names none, so a write cannot walk past the check
|
|
39
|
+
* by omitting the team.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveActor(host: ActorHost, command: Actor, position: number): ParticipantRecord | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Who a validator is told submitted this write, or `undefined` for a write
|
|
44
|
+
* no validator sees.
|
|
45
|
+
*
|
|
46
|
+
* The test is the surface, not the participant (§15.1). An observer is
|
|
47
|
+
* rendered the same play surface a participant is, with the same controls
|
|
48
|
+
* on it, so its writes go to validators on the same terms and the game
|
|
49
|
+
* decides what an observer may do (§13.3). What stays ungated is a caller
|
|
50
|
+
* looking at something else: the session surface, the CLI, the engine, a
|
|
51
|
+
* hook, an endpoint. None of those carries a viewer role.
|
|
52
|
+
*
|
|
53
|
+
* The participant record is already the shape a validator wants (§13.1),
|
|
54
|
+
* so it is passed as it stands rather than rebuilt as a reduced copy.
|
|
55
|
+
*/
|
|
56
|
+
export declare function submitterOf(host: ActorHost, command: Actor, position: number): ValidatorActor | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Put a participant's tick request to the validators that gate it (§15).
|
|
59
|
+
*
|
|
60
|
+
* Only a request from a surface a participant or observer is looking at
|
|
61
|
+
* names a participant or a viewer role, so a facilitator's tick, the CLI's
|
|
62
|
+
* and a timer's pass straight through, exactly as their writes do: pacing is the facilitator's to set, not to be
|
|
63
|
+
* held to. The validators judge the requesting team's board as it stands,
|
|
64
|
+
* which is where a gate such as a `MaxOpenWeek` the facilitator writes
|
|
65
|
+
* lives, and the tick the request would run.
|
|
66
|
+
*/
|
|
67
|
+
export declare function gateTickRequest(host: GateHost, command: TeamScope & Actor): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Put a write to the validators it could affect (§15), refusing it when any
|
|
70
|
+
* of them rejects. Reject-only, and only for a write from a surface a
|
|
71
|
+
* participant is looking at: an engine, endpoint or system-trusted mutation
|
|
72
|
+
* has no `submitter` and is not gated.
|
|
73
|
+
*/
|
|
74
|
+
export declare function gateWrite(host: GateHost, before: GameContext, merged: GameContext, submitter: ValidatorActor | undefined, scope: TeamScope): Promise<void>;
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a session shows the parts it is built from.
|
|
3
|
+
*
|
|
4
|
+
* The session is split by concern (timers, endpoints, validator gates, writes,
|
|
5
|
+
* the roster, ticks and rewinds), and each part needs some of the session's
|
|
6
|
+
* state and some of its operations, never all of them. This is the one list
|
|
7
|
+
* of what may be reached, so each part declares the slice it uses as a `Pick`
|
|
8
|
+
* of it, and what one part can touch is read off its own signature rather
|
|
9
|
+
* than off the whole session. The session builds a single object satisfying
|
|
10
|
+
* it, from its own fields, and hands each part that.
|
|
11
|
+
*/
|
|
12
|
+
import type { Participant, RunKind, TeamInfo } from '@seriousgaming/sdk';
|
|
13
|
+
import type { MutationResult, SessionMode } from '@seriousgaming/sdk/projection';
|
|
14
|
+
import type { GameContext, GameExecutor } from '../execution/executor';
|
|
15
|
+
import type { BlobRetention } from '../storage/blob-store';
|
|
16
|
+
import type { Clock } from './clock';
|
|
17
|
+
import type { FaultInjector } from './faults';
|
|
18
|
+
import type { ResolvedGameSettings } from './game-settings';
|
|
19
|
+
import type { ParticipantRegistry } from './participant-registry';
|
|
20
|
+
import type { PendingChanges } from './pending-changes';
|
|
21
|
+
import type { Event, MutationCommand } from './protocol';
|
|
22
|
+
import type { ParticipantCounts } from './session-roster';
|
|
23
|
+
import type { SurfaceBundle } from './session-surfaces';
|
|
24
|
+
import type { SessionTimers } from './session-timers';
|
|
25
|
+
import type { TeamStateStore } from './team-state-store';
|
|
26
|
+
/** A team-count range as a game declares it, either end optional (§5.4). */
|
|
27
|
+
export interface TeamBounds {
|
|
28
|
+
min?: number;
|
|
29
|
+
max?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface SessionHost {
|
|
32
|
+
readonly executor: GameExecutor;
|
|
33
|
+
readonly state: TeamStateStore;
|
|
34
|
+
readonly participants: ParticipantRegistry;
|
|
35
|
+
readonly faults: FaultInjector;
|
|
36
|
+
readonly clock: Clock;
|
|
37
|
+
/** Which kind of run this is (§5.7), fixed for the session's life. */
|
|
38
|
+
readonly runKind: RunKind;
|
|
39
|
+
/** The automatic tick timers (§11), which ticks and rewinds re-evaluate. */
|
|
40
|
+
timers(): SessionTimers;
|
|
41
|
+
/** The teams and seeds the session was asked to start with. */
|
|
42
|
+
startingShape(): {
|
|
43
|
+
teams?: number;
|
|
44
|
+
participants?: ParticipantCounts;
|
|
45
|
+
};
|
|
46
|
+
locale(): string;
|
|
47
|
+
waitingRoomOpen(): boolean;
|
|
48
|
+
/** True while the game's `setup` slot still owes a Play (§8.3). */
|
|
49
|
+
inSetup(): boolean;
|
|
50
|
+
/** Edits on disk the session has not applied, as a copy (#640). */
|
|
51
|
+
pendingChanges(): PendingChanges;
|
|
52
|
+
mode(): SessionMode;
|
|
53
|
+
/** The `game` settings as they resolve now, through every layer (§6.10, §8.2). */
|
|
54
|
+
settings(): ResolvedGameSettings;
|
|
55
|
+
/**
|
|
56
|
+
* What a call from the scenario editor resolves against (§6.5, §6.12):
|
|
57
|
+
* the scenario it is editing, and its draft over that scenario's
|
|
58
|
+
* settings, the `game` settings included. Absent names the one in force.
|
|
59
|
+
*/
|
|
60
|
+
scenarioBeingEdited(scenarioId: string | null | undefined): {
|
|
61
|
+
settings: Record<string, Record<string, unknown>>;
|
|
62
|
+
};
|
|
63
|
+
teamBounds(): TeamBounds;
|
|
64
|
+
tickLimit(): number | null;
|
|
65
|
+
/** Whether any tick has been committed and not since rewound. */
|
|
66
|
+
hasTicked(): boolean;
|
|
67
|
+
/** The position of a stable team index, or a refusal when it names no team. */
|
|
68
|
+
positionOf(teamIndex: number): number;
|
|
69
|
+
/** The stable index behind a team id, or undefined when it names no team. */
|
|
70
|
+
indexOfTeamId(teamId: string): number | undefined;
|
|
71
|
+
/** A team's display name as it reads now, a rename included (§5.4). */
|
|
72
|
+
teamNameAt(index: number): string;
|
|
73
|
+
/** The team at a position, as an endpoint is told it (§6.12). */
|
|
74
|
+
teamAt(position: number): TeamInfo;
|
|
75
|
+
/** Every participant, in stable-index order and then join order. */
|
|
76
|
+
roster(): Participant[];
|
|
77
|
+
declaredSurface(identifier: string): SurfaceBundle;
|
|
78
|
+
/** Build tick-0 state for every team, and seed the histories. */
|
|
79
|
+
buildInitialState(preserveShared?: GameContext): Promise<void>;
|
|
80
|
+
/** §14.4: re-fire `participantJoin` for everyone after a rebuild. */
|
|
81
|
+
replayParticipantJoins(): Promise<void>;
|
|
82
|
+
/** Start over from the package as it is on disk (#640). */
|
|
83
|
+
applyPendingChanges(): Promise<number>;
|
|
84
|
+
/** Delete this run's blobs of the given retentions (§16.2). */
|
|
85
|
+
clearBlobs(retentions: readonly BlobRetention[]): Promise<void>;
|
|
86
|
+
/** Queue `work` as one operation (§9.7, §10.2). */
|
|
87
|
+
enqueue<T>(work: () => Promise<T>): Promise<T>;
|
|
88
|
+
/** Run one command now, inside whatever job is already running. */
|
|
89
|
+
apply(command: MutationCommand): Promise<MutationResult>;
|
|
90
|
+
submit(command: MutationCommand): Promise<MutationResult>;
|
|
91
|
+
report(message: string, source: string, teamId?: string): void;
|
|
92
|
+
emit(event: Event): void;
|
|
93
|
+
emitState(cause: string): void;
|
|
94
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ways a session operation says no, and how each reaches the caller.
|
|
3
|
+
*
|
|
4
|
+
* A refusal is an answer rather than a crash: nothing reached the session's
|
|
5
|
+
* state, and the outcome is the one every surface is told (§12.5.1). Two
|
|
6
|
+
* kinds carry more beside it for the author's tools, where game logic threw
|
|
7
|
+
* (#639) and which edits on disk refused it (#640), and they ride beside the
|
|
8
|
+
* outcome rather than in it so a surface sees the same shape either way.
|
|
9
|
+
* Shared by every part of the session that refuses, so that one refusal reads
|
|
10
|
+
* the same whichever operation raised it.
|
|
11
|
+
*/
|
|
12
|
+
import type { MutationResult } from '@seriousgaming/sdk/projection';
|
|
13
|
+
import { type LogicFailure } from '../execution/logic-failure';
|
|
14
|
+
import type { FaultInjector, FaultKind } from './faults';
|
|
15
|
+
import { type PendingChanges } from './pending-changes';
|
|
16
|
+
/** The failure half of a settled mutation (§12.5.1). */
|
|
17
|
+
export type Refusal = Extract<MutationResult, {
|
|
18
|
+
ok: false;
|
|
19
|
+
}>['outcome'];
|
|
20
|
+
/**
|
|
21
|
+
* A failed result carrying where game logic threw, when it did (#639). Beside
|
|
22
|
+
* the outcome rather than in it: the outcome is what every surface is told,
|
|
23
|
+
* and a source path is for the author's tools alone.
|
|
24
|
+
*/
|
|
25
|
+
export type WithLogicError<T> = T & {
|
|
26
|
+
logicError?: LogicFailure;
|
|
27
|
+
};
|
|
28
|
+
export declare function withLogicError<T extends object>(result: T, logicError: LogicFailure | undefined): WithLogicError<T>;
|
|
29
|
+
/** Nothing reached the session's own state; the caller sees why. */
|
|
30
|
+
export declare class RefusedError extends Error {
|
|
31
|
+
readonly outcome: Refusal;
|
|
32
|
+
constructor(message: string, outcome: Refusal);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A failed result carrying the edits on disk that refused it (#640). Beside
|
|
36
|
+
* the outcome for the same reason as {@link WithLogicError}: a surface is told
|
|
37
|
+
* it was denied, and the author's tools are told why in a form they can act on.
|
|
38
|
+
*/
|
|
39
|
+
export type WithStale<T> = T & {
|
|
40
|
+
stale?: PendingChanges;
|
|
41
|
+
};
|
|
42
|
+
/** Refused because an edit on disk is pending, and running it would mix the two. */
|
|
43
|
+
export declare class StaleError extends RefusedError {
|
|
44
|
+
readonly pending: PendingChanges;
|
|
45
|
+
constructor(pending: PendingChanges);
|
|
46
|
+
}
|
|
47
|
+
export declare function withStale<T extends object>(result: T, error: unknown): WithStale<T>;
|
|
48
|
+
/** `error`, marked as thrown by game logic when `failure` says it was. */
|
|
49
|
+
export declare function markIfLogic(error: Error, failure: LogicFailure | undefined): unknown;
|
|
50
|
+
/**
|
|
51
|
+
* Fire an armed fault as the refusal it stands in for (§3.3 of the design).
|
|
52
|
+
*
|
|
53
|
+
* The point is that the surface takes the same path it would on the real
|
|
54
|
+
* thing, so the outcome has to be the real outcome rather than a marker.
|
|
55
|
+
*/
|
|
56
|
+
export declare function refuseIfArmed(faults: FaultInjector, fault: FaultKind, outcome: Refusal): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Undo and reset (§9.4, §19.3): putting a team, or the whole session, back
|
|
3
|
+
* where it was.
|
|
4
|
+
*
|
|
5
|
+
* A rewind restores boards from history, and history holds whole boards, so
|
|
6
|
+
* left alone it would also restore what a rewind must never touch: the shared
|
|
7
|
+
* store other teams still read, and every capability declared
|
|
8
|
+
* `lifetime: 'session'` (§7.6). The rules for what a per-team rewind may
|
|
9
|
+
* reach, when one is refused outright because the cohort moves as one, and
|
|
10
|
+
* how session-lifetime values are carried across, sit here together so that
|
|
11
|
+
* undo and reset cannot come to disagree about them.
|
|
12
|
+
*/
|
|
13
|
+
import type { TeamScope } from './protocol';
|
|
14
|
+
import type { SessionHost } from './session-host';
|
|
15
|
+
type RewindHost = Pick<SessionHost, 'executor' | 'state' | 'mode' | 'positionOf' | 'pendingChanges' | 'applyPendingChanges' | 'buildInitialState' | 'replayParticipantJoins' | 'clearBlobs'>;
|
|
16
|
+
/**
|
|
17
|
+
* Run an undo or a reset without letting it touch any `lifetime:
|
|
18
|
+
* 'session'` capability (§7.6).
|
|
19
|
+
*
|
|
20
|
+
* Those values ride the team contexts and the shared store like any other,
|
|
21
|
+
* so a restored snapshot or a rebuilt initial board would carry them back
|
|
22
|
+
* to what they were. Capturing them first and putting them back after is
|
|
23
|
+
* what keeps them out of the tick's reach: facilitator state such as
|
|
24
|
+
* 'setup completed' survives the rewind that would otherwise wipe it.
|
|
25
|
+
* A refused operation changed nothing, so there is nothing to put back.
|
|
26
|
+
*/
|
|
27
|
+
export declare function keepingSessionLifetime(host: Pick<SessionHost, 'executor' | 'state'>, run: () => Promise<number>): Promise<number>;
|
|
28
|
+
/** Step back one round, for one team or the session (§9.4). Returns the tick it lands on. */
|
|
29
|
+
export declare function undo(host: RewindHost, scope: TeamScope): Promise<number>;
|
|
30
|
+
/** Return a team, or the session, to tick 0 (§9.4). */
|
|
31
|
+
export declare function reset(host: RewindHost, scope: TeamScope): Promise<number>;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who is in the session: its teams, the participants on them, and the hooks
|
|
3
|
+
* their arrivals and moves fire (§5.4, §5.6, §13, §14).
|
|
4
|
+
*
|
|
5
|
+
* The roster is declarative in a local session rather than the residue of a
|
|
6
|
+
* join flow, because a player surface is addressed directly and somebody has
|
|
7
|
+
* to exist for it to be. So the team count and seed counts are resolved here
|
|
8
|
+
* against the game's bounds, every team is filled to its seats, and the same
|
|
9
|
+
* rules decide when a team may be added or removed mid-session. Participant
|
|
10
|
+
* signals fire from here too, always after the change they describe, since
|
|
11
|
+
* every one of them is a consequence of a roster change and nothing else.
|
|
12
|
+
*/
|
|
13
|
+
import type { Participant } from '@seriousgaming/sdk';
|
|
14
|
+
import type { ResolvedGameSettings } from './game-settings';
|
|
15
|
+
import type { ParticipantRecord } from './participant-registry';
|
|
16
|
+
import type { MutationCommand } from './protocol';
|
|
17
|
+
import type { SessionHost, TeamBounds } from './session-host';
|
|
18
|
+
/**
|
|
19
|
+
* How many participants to seed each team with: one count for every team, or
|
|
20
|
+
* one per team in stable index order.
|
|
21
|
+
*/
|
|
22
|
+
export type ParticipantCounts = number | number[];
|
|
23
|
+
/**
|
|
24
|
+
* Why a participant count cannot seed `teams` teams, or null when it can.
|
|
25
|
+
*
|
|
26
|
+
* Zero is a count, not an error: every team is under-full at the start of a
|
|
27
|
+
* session by definition (§5.4), and in a hosted session every team starts
|
|
28
|
+
* empty and fills as people join.
|
|
29
|
+
*/
|
|
30
|
+
export declare function participantCountsError(counts: ParticipantCounts, teams: number): string | null;
|
|
31
|
+
export declare function boundsOf({ teams }: ResolvedGameSettings): TeamBounds;
|
|
32
|
+
export declare function refuseTeamCountOutsideBounds(count: number, { min, max }: TeamBounds): void;
|
|
33
|
+
/**
|
|
34
|
+
* Refuse to start play with a team count outside the bounds the settings
|
|
35
|
+
* resolved to (§5.4). Setup can move them after the teams were created, so
|
|
36
|
+
* this is checked again as play starts, and the facilitator adds or removes
|
|
37
|
+
* teams, or changes the setting, before trying again.
|
|
38
|
+
*/
|
|
39
|
+
export declare function refuseTeamCountAtPlay(count: number, { min, max }: TeamBounds): void;
|
|
40
|
+
type RosterHost = Pick<SessionHost, 'executor' | 'state' | 'participants' | 'faults' | 'runKind' | 'startingShape' | 'mode' | 'hasTicked' | 'teamBounds' | 'settings' | 'positionOf' | 'buildInitialState' | 'report'>;
|
|
41
|
+
export declare class SessionRoster {
|
|
42
|
+
private readonly host;
|
|
43
|
+
/** Seed counts chosen for one team, by stable index, over the session-wide one. */
|
|
44
|
+
private readonly seats;
|
|
45
|
+
constructor(host: RosterHost);
|
|
46
|
+
/** Every participant, in stable-index order and then join order. */
|
|
47
|
+
list(): Participant[];
|
|
48
|
+
/** Every participant's record, in stable-index order and then join order. */
|
|
49
|
+
records(): ParticipantRecord[];
|
|
50
|
+
/**
|
|
51
|
+
* Mark exactly these participants connected, and every other one not
|
|
52
|
+
* (§13.2). True when anybody's presence changed.
|
|
53
|
+
*/
|
|
54
|
+
syncPresence(connected: ReadonlySet<string>): boolean;
|
|
55
|
+
/** Settle the team count and seed counts the session starts with (§5.4, §5.7). */
|
|
56
|
+
resolveTeamCount(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Give every team the participants it is declared to have.
|
|
59
|
+
*
|
|
60
|
+
* The roster is declarative here, not the residue of a join flow: a player
|
|
61
|
+
* surface is addressed directly (`/team/2/player/1`) rather than joined, so
|
|
62
|
+
* somebody has to exist for it to be. A surface with no participant never
|
|
63
|
+
* receives `setParticipant`, which is one of the six messages a player
|
|
64
|
+
* surface blocks its first paint on (§12.6), so it sits on its loading
|
|
65
|
+
* state forever.
|
|
66
|
+
*
|
|
67
|
+
* Seeded to {@link seatsFor}, which may be none: a test of what a game does
|
|
68
|
+
* before anybody joins needs a team with nobody on it.
|
|
69
|
+
*/
|
|
70
|
+
materialise(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* §14.4: `participantJoin` re-fires for every registered participant
|
|
73
|
+
* whenever context is rebuilt, so a hook's contribution is not lost to a
|
|
74
|
+
* reset.
|
|
75
|
+
*/
|
|
76
|
+
replayJoins(): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* §5.6. An independent team joins the session as it stands; a shared-state
|
|
79
|
+
* cohort cannot be enlarged, because `InitAggregate` ran over the teams
|
|
80
|
+
* present at initialisation and a late arrival's per-team state and share
|
|
81
|
+
* of the store cannot be retrofitted.
|
|
82
|
+
*
|
|
83
|
+
* An authoring host may relax that before the first tick by re-initialising,
|
|
84
|
+
* so the aggregate observes the enlarged cohort, and this is an authoring
|
|
85
|
+
* host. The relaxation is not part of the runtime contract: a production
|
|
86
|
+
* runtime refuses throughout, and the conformance suite asserts the refusal
|
|
87
|
+
* after a tick, where every reading agrees.
|
|
88
|
+
*
|
|
89
|
+
* 'Before the first tick' is read off the clock rather than latched, so a
|
|
90
|
+
* session returned to tick 0 by a reset can still be enlarged. The price is
|
|
91
|
+
* the same either way: re-initialisation rebuilds every team's context from
|
|
92
|
+
* `Init`, so anything written into the board beforehand goes with it. The
|
|
93
|
+
* configuration does not — it is an input to `Init`, not state.
|
|
94
|
+
*/
|
|
95
|
+
addTeam(name?: string, participants?: number): Promise<undefined>;
|
|
96
|
+
/**
|
|
97
|
+
* §5.6. Independent mode only: a shared-state engine initialised over the
|
|
98
|
+
* whole cohort, so a team leaving it cannot be retrofitted, before the
|
|
99
|
+
* first tick or after. And only an empty team: participant records are
|
|
100
|
+
* permanent (§13.2), so a team holding one, connected or not, would leave
|
|
101
|
+
* it pointing at nothing.
|
|
102
|
+
*/
|
|
103
|
+
removeTeam(teamIndex: number): Promise<undefined>;
|
|
104
|
+
renameTeam(teamId: string, name: string): undefined;
|
|
105
|
+
renameOwnTeam(command: Extract<MutationCommand, {
|
|
106
|
+
type: 'renameOwnTeam';
|
|
107
|
+
}>): undefined;
|
|
108
|
+
addParticipant(teamId: string, name?: string): Promise<undefined>;
|
|
109
|
+
renameParticipant(participantId: string, name: string): undefined;
|
|
110
|
+
moveParticipant(participantId: string, toTeamId: string): Promise<undefined>;
|
|
111
|
+
findParticipantTeam(participantId: string): string | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* How many participants a team is seeded with.
|
|
114
|
+
*
|
|
115
|
+
* At least one unless somebody asked otherwise, and the game's declared
|
|
116
|
+
* `perTeam.minParticipants` where it has one, because that is the cohort
|
|
117
|
+
* the author designed for.
|
|
118
|
+
*/
|
|
119
|
+
private seatsFor;
|
|
120
|
+
/**
|
|
121
|
+
* Run `signal`'s hooks against a team's context: the participant's own
|
|
122
|
+
* team unless `dispatch.teamId` names another, with any signal-specific
|
|
123
|
+
* fields in `dispatch.payload` handed to the hook beside the participant.
|
|
124
|
+
*/
|
|
125
|
+
private fireHook;
|
|
126
|
+
private hasHook;
|
|
127
|
+
}
|
|
128
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surfaces a package declares, as the session looks them up (§12).
|
|
3
|
+
*
|
|
4
|
+
* A surface's identifier arrives from the host, which names what it mounted,
|
|
5
|
+
* and every check the session makes against a surface (what it may read back,
|
|
6
|
+
* what it may write, which endpoints it may call) starts by finding its bundle.
|
|
7
|
+
* One lookup over every `kind: 'ui'` resource, so a new surface kind is found
|
|
8
|
+
* without being listed here by hand, and one refusal for an identifier the
|
|
9
|
+
* package does not declare, so no check can treat it as a lesser surface.
|
|
10
|
+
*/
|
|
11
|
+
import type { ResolvedPackageManifest } from '@seriousgaming/sdk';
|
|
12
|
+
export type SurfaceBundle = NonNullable<ResolvedPackageManifest['ui' | 'session' | 'waiting_room' | 'presentation' | 'setup' | 'scenario_editor']>;
|
|
13
|
+
/**
|
|
14
|
+
* The UI bundle this package declares under `identifier`, of any kind.
|
|
15
|
+
*
|
|
16
|
+
* Every `kind: 'ui'` resource is searched, so a new surface kind is found
|
|
17
|
+
* without being added here by hand: one left out would be refused as a
|
|
18
|
+
* surface the package does not declare.
|
|
19
|
+
*/
|
|
20
|
+
export declare function userInterfaceBundle(config: ResolvedPackageManifest | null, identifier: string): SurfaceBundle | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* The surface a caller names, or a refusal. An identifier is the host's to
|
|
23
|
+
* supply from what it mounted, so one the package does not declare is not
|
|
24
|
+
* a lesser surface: nothing it may be held to exists, and it is refused.
|
|
25
|
+
*/
|
|
26
|
+
export declare function declaredSurface(config: ResolvedPackageManifest | null, identifier: string): SurfaceBundle;
|
|
27
|
+
/**
|
|
28
|
+
* What a surface may read back: its declared reads and writes, less any
|
|
29
|
+
* private capability (§7.4). `undefined` for a caller that names no UI,
|
|
30
|
+
* which is system-trusted and unbounded.
|
|
31
|
+
*/
|
|
32
|
+
export declare function readableCapabilities(config: ResolvedPackageManifest | null, uiIdentifier: string | undefined): Set<string> | undefined;
|