@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,47 @@
|
|
|
1
|
+
import i18n from 'i18next';
|
|
2
|
+
import { initReactI18next } from 'react-i18next';
|
|
3
|
+
|
|
4
|
+
// Translation resources
|
|
5
|
+
const resources = {
|
|
6
|
+
en: {
|
|
7
|
+
translation: {
|
|
8
|
+
greeting: 'Hello, World!',
|
|
9
|
+
welcomeMessage: 'Welcome to your Serious Gaming User Interface.',
|
|
10
|
+
dataExample:
|
|
11
|
+
"The component below demonstrates reading and writing data to the game's shared state by using a capability.",
|
|
12
|
+
currentValue: 'Current value: {% raw %}{{value}}{% endraw %}',
|
|
13
|
+
updateButton: 'Increment Value',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
it: {
|
|
17
|
+
translation: {
|
|
18
|
+
greeting: 'Ciao, mondo!',
|
|
19
|
+
welcomeMessage: 'Benvenuto nella tua interfaccia utente di Serious Gaming.',
|
|
20
|
+
dataExample:
|
|
21
|
+
'Il componente sottostante dimostra come leggere e scrivere dati nello stato condiviso della simulazione utilizzando una capability.',
|
|
22
|
+
currentValue: 'Valore corrente: {% raw %}{{value}}{% endraw %}',
|
|
23
|
+
updateButton: 'Incrementa valore',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
ar: {
|
|
27
|
+
translation: {
|
|
28
|
+
greeting: 'أهلاً بالعالم!',
|
|
29
|
+
welcomeMessage: 'مرحبًا بك في واجهة مستخدم كونشيرتو الخاصة بك.',
|
|
30
|
+
dataExample:
|
|
31
|
+
'يوضح المكون أدناه قراءة البيانات وكتابتها إلى الحالة المشتركة للمحاكاة باستخدام إحدى الإمكانات.',
|
|
32
|
+
currentValue: 'القيمة الحالية: {% raw %}{{value}}{% endraw %}',
|
|
33
|
+
updateButton: 'زيادة القيمة',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
i18n.use(initReactI18next).init({
|
|
39
|
+
resources,
|
|
40
|
+
lng: 'en', // default language
|
|
41
|
+
fallbackLng: 'en',
|
|
42
|
+
interpolation: {
|
|
43
|
+
escapeValue: false, // React already escapes
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export default i18n;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import createCache from '@emotion/cache';
|
|
2
|
+
import { CacheProvider } from '@emotion/react';
|
|
3
|
+
import '@fontsource-variable/roboto-mono';
|
|
4
|
+
import '@fontsource-variable/work-sans';
|
|
5
|
+
import rtlPlugin from '@mui/stylis-plugin-rtl';
|
|
6
|
+
import { UserInterfaceWrapper, useUserInterfaceLocale } from '@seriousgaming/sdk/ui';
|
|
7
|
+
|
|
8
|
+
import './i18n';
|
|
9
|
+
import i18n from 'i18next';
|
|
10
|
+
import React, { StrictMode, useEffect } from 'react';
|
|
11
|
+
import { createRoot } from 'react-dom/client';
|
|
12
|
+
import { prefixer } from 'stylis';
|
|
13
|
+
|
|
14
|
+
import App from './App';
|
|
15
|
+
|
|
16
|
+
// Create RTL cache
|
|
17
|
+
const cacheRtl = createCache({
|
|
18
|
+
key: 'muirtl',
|
|
19
|
+
stylisPlugins: [prefixer, rtlPlugin],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const cacheLtr = createCache({
|
|
23
|
+
key: 'muiltr',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Wrapper component to sync locale with i18next and setup RTL
|
|
27
|
+
function RootWrapper({ children }: { children: React.ReactNode }) {
|
|
28
|
+
const { locale } = useUserInterfaceLocale();
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const i18nextLocale = locale.split('-')[0];
|
|
32
|
+
i18n.changeLanguage(i18nextLocale);
|
|
33
|
+
}, [locale]);
|
|
34
|
+
|
|
35
|
+
const isRtl = i18n.dir(locale.split('-')[0]) === 'rtl';
|
|
36
|
+
|
|
37
|
+
return <CacheProvider value={isRtl ? cacheRtl : cacheLtr}>{children}</CacheProvider>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
createRoot(document.getElementById('root')!).render(
|
|
41
|
+
<StrictMode>
|
|
42
|
+
<UserInterfaceWrapper>
|
|
43
|
+
<RootWrapper>
|
|
44
|
+
<App />
|
|
45
|
+
</RootWrapper>
|
|
46
|
+
</UserInterfaceWrapper>
|
|
47
|
+
</StrictMode>
|
|
48
|
+
);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{% raw %}import { createTheme } from '@mui/material/styles';
|
|
2
|
+
import { useUserInterfaceTheme } from '@seriousgaming/sdk/ui';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The host owns the palette, the game owns the typography and the component
|
|
7
|
+
* shapes. Reading `theme.mode` rather than the browser's preference is what
|
|
8
|
+
* keeps a participant's screen and the facilitator's looking like one product.
|
|
9
|
+
*/
|
|
10
|
+
export const useAppTheme = () => {
|
|
11
|
+
const theme = useUserInterfaceTheme();
|
|
12
|
+
|
|
13
|
+
return useMemo(() => {
|
|
14
|
+
const colors = theme.mode === 'light' ? theme.light : theme.dark;
|
|
15
|
+
return createTheme({
|
|
16
|
+
palette: {
|
|
17
|
+
mode: theme.mode,
|
|
18
|
+
primary: { main: colors.primary, contrastText: colors.contrastText.primary },
|
|
19
|
+
secondary: { main: colors.secondary, contrastText: colors.contrastText.secondary },
|
|
20
|
+
success: { main: colors.success, contrastText: colors.contrastText.success },
|
|
21
|
+
error: { main: colors.error, contrastText: colors.contrastText.error },
|
|
22
|
+
warning: { main: colors.warning, contrastText: colors.contrastText.warning },
|
|
23
|
+
info: { main: colors.info, contrastText: colors.contrastText.info },
|
|
24
|
+
},
|
|
25
|
+
shape: { borderRadius: 10 },
|
|
26
|
+
components: {
|
|
27
|
+
MuiButton: { styleOverrides: { root: { textTransform: 'none' } } },
|
|
28
|
+
MuiTab: {
|
|
29
|
+
styleOverrides: { root: { textTransform: 'none', fontSize: '0.95rem' } },
|
|
30
|
+
},
|
|
31
|
+
MuiToggleButton: { styleOverrides: { root: { textTransform: 'none' } } },
|
|
32
|
+
MuiTableCell: {
|
|
33
|
+
styleOverrides: {
|
|
34
|
+
head: {
|
|
35
|
+
fontSize: '0.75rem',
|
|
36
|
+
fontWeight: 700,
|
|
37
|
+
letterSpacing: '0.07em',
|
|
38
|
+
textTransform: 'uppercase',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}, [theme]);
|
|
45
|
+
};
|
|
46
|
+
{% endraw %}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { UpdateData } from './logic';
|
|
3
|
+
import type { Context, Settings } from '../types';
|
|
4
|
+
import type { LogicMeta } from '@seriousgaming/sdk';
|
|
5
|
+
|
|
6
|
+
// The run-wide facts the host supplies: the session locale, its random seed,
|
|
7
|
+
// whether this is the game being played or a walkthrough beside it, and when
|
|
8
|
+
// the operation started.
|
|
9
|
+
const meta: LogicMeta = { locale: 'en', seed: 'test-seed', runKind: 'session', now: Date.UTC(2026, 0, 1) };
|
|
10
|
+
|
|
11
|
+
// Who submitted the mutation. Swap for `{ role: 'observer', teamId: 'team-1' }`
|
|
12
|
+
// to cover a facilitator observing the team on the same surface.
|
|
13
|
+
const actor = {
|
|
14
|
+
role: 'participant',
|
|
15
|
+
participant: {
|
|
16
|
+
id: '1',
|
|
17
|
+
teamId: 'team-1',
|
|
18
|
+
name: 'Participant 1',
|
|
19
|
+
index: 0,
|
|
20
|
+
connected: true,
|
|
21
|
+
},
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
describe('{{ identifier }}', () => {
|
|
25
|
+
describe('UpdateData', () => {
|
|
26
|
+
it('accepts a valid mutation', async () => {
|
|
27
|
+
const previous: Context = {
|
|
28
|
+
// TODO: Add context values based on required capabilities
|
|
29
|
+
} as Context;
|
|
30
|
+
const next: Context = {
|
|
31
|
+
// TODO: Add proposed next-state values
|
|
32
|
+
} as Context;
|
|
33
|
+
const settings: Settings = {
|
|
34
|
+
// TODO: Add values for the settings resources this reads
|
|
35
|
+
} as Settings;
|
|
36
|
+
|
|
37
|
+
const result = await UpdateData({ previous, next, actor, settings, meta, participants: [actor.participant] });
|
|
38
|
+
|
|
39
|
+
expect(result.ok).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ValidatorFunction } from '../types';
|
|
2
|
+
|
|
3
|
+
// A validator gates what a participant does, one export per action. This one
|
|
4
|
+
// is `UpdateData`, the gate on a context write. Export `RequestTick` as well
|
|
5
|
+
// (typed `RequestTickFunction` from '../types') to gate a participant's request
|
|
6
|
+
// for the next tick: it receives `{ context, requestedTick, actor, settings, meta }`.
|
|
7
|
+
export const UpdateData: ValidatorFunction = async ({ previous, next, actor, settings }) => {
|
|
8
|
+
// Validators gate UI-submitted mutations before they're applied.
|
|
9
|
+
// Return { ok: true } to allow, { ok: false, message: '...' } to reject.
|
|
10
|
+
// The proposed `next` state is what would be applied if every referenced
|
|
11
|
+
// validator returns ok.
|
|
12
|
+
//
|
|
13
|
+
// `actor` says who submitted it: a participant, or a facilitator observing
|
|
14
|
+
// the team on the same surface. Both are held to this rule unless you say
|
|
15
|
+
// otherwise, e.g.:
|
|
16
|
+
//
|
|
17
|
+
// if (actor.role === 'observer') return { ok: true };
|
|
18
|
+
//
|
|
19
|
+
// Narrow on `actor.role` before reading `actor.participant`.
|
|
20
|
+
return { ok: true };
|
|
21
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{ name }}</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="./src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{% raw %}import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import {
|
|
4
|
+
UserInterfaceDataContext,
|
|
5
|
+
UserInterfaceOwnTeamContext,
|
|
6
|
+
UserInterfaceParticipantContext,
|
|
7
|
+
UserInterfaceParticipantsContext,
|
|
8
|
+
UserInterfaceThemeContext,
|
|
9
|
+
} from '@seriousgaming/sdk/ui';
|
|
10
|
+
import { createMockTheme } from '@seriousgaming/sdk/ui/testing';
|
|
11
|
+
import './i18n';
|
|
12
|
+
import App from './App';
|
|
13
|
+
|
|
14
|
+
// A waiting room UI is a player UI, so it renders under the same context
|
|
15
|
+
// providers. These replace the iframe communication the real app uses.
|
|
16
|
+
const SELF = { id: 'p1', name: 'Ada', index: 0, connected: true, teamId: 'team-1' };
|
|
17
|
+
const ROSTER = [
|
|
18
|
+
{ ...SELF, connected: true },
|
|
19
|
+
{ id: 'p2', name: 'Grace', index: 1, teamId: 'team-1', connected: false },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const renderApp = (completedTicks = 0) =>
|
|
23
|
+
render(
|
|
24
|
+
<UserInterfaceThemeContext.Provider value={createMockTheme()}>
|
|
25
|
+
<UserInterfaceDataContext.Provider
|
|
26
|
+
value={{ data: {}, settings: {}, completedTicks, isRoundProcessing: false, setData: vi.fn() }}
|
|
27
|
+
>
|
|
28
|
+
<UserInterfaceOwnTeamContext.Provider
|
|
29
|
+
value={{ teamId: 'team-1', index: 0, name: 'Team 1' }}
|
|
30
|
+
>
|
|
31
|
+
<UserInterfaceParticipantContext.Provider value={SELF}>
|
|
32
|
+
<UserInterfaceParticipantsContext.Provider value={ROSTER}>
|
|
33
|
+
<App />
|
|
34
|
+
</UserInterfaceParticipantsContext.Provider>
|
|
35
|
+
</UserInterfaceParticipantContext.Provider>
|
|
36
|
+
</UserInterfaceOwnTeamContext.Provider>
|
|
37
|
+
</UserInterfaceDataContext.Provider>
|
|
38
|
+
</UserInterfaceThemeContext.Provider>
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
describe('App', () => {
|
|
42
|
+
it('says the session has not begun at tick 0', () => {
|
|
43
|
+
renderApp(0);
|
|
44
|
+
expect(screen.getByText(/waiting to begin/i)).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('says the session is paused once ticks have run', () => {
|
|
48
|
+
renderApp(3);
|
|
49
|
+
expect(screen.getByText(/session paused/i)).toBeInTheDocument();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('lists the team roster and marks the reader', () => {
|
|
53
|
+
renderApp();
|
|
54
|
+
expect(screen.getByText(/ada \(you\)/i)).toBeInTheDocument();
|
|
55
|
+
expect(screen.getByText('Grace')).toBeInTheDocument();
|
|
56
|
+
});
|
|
57
|
+
});{% endraw %}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{% raw %}import React from 'react';
|
|
2
|
+
import { Box, CssBaseline, ThemeProvider, Typography } from '@mui/material';
|
|
3
|
+
import {
|
|
4
|
+
useUserInterfaceOwnTeam,
|
|
5
|
+
useUserInterfaceData,
|
|
6
|
+
useUserInterfaceParticipant,
|
|
7
|
+
useUserInterfaceParticipants,
|
|
8
|
+
} from '@seriousgaming/sdk/ui';
|
|
9
|
+
import { useTranslation } from 'react-i18next';
|
|
10
|
+
import { Context, Settings } from '../types';
|
|
11
|
+
import { useAppTheme } from './theme';
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
This UI requires the following dependencies:
|
|
15
|
+
- @mui/material
|
|
16
|
+
- @emotion/react
|
|
17
|
+
- @emotion/styled
|
|
18
|
+
- stylis
|
|
19
|
+
- @mui/stylis-plugin-rtl
|
|
20
|
+
- @fontsource-variable/roboto-mono
|
|
21
|
+
- @fontsource-variable/work-sans
|
|
22
|
+
- i18next
|
|
23
|
+
- react-i18next
|
|
24
|
+
|
|
25
|
+
Make sure to install them in your project, e.g.:
|
|
26
|
+
pnpm add @mui/material @emotion/react @emotion/styled stylis @mui/stylis-plugin-rtl @fontsource-variable/roboto-mono @fontsource-variable/work-sans i18next react-i18next
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
A waiting room user interface is a player user interface shown in a different
|
|
31
|
+
place: the host mounts it instead of the game UIs while the facilitator has the
|
|
32
|
+
session's waiting room open, and swaps back the moment they close it. Every
|
|
33
|
+
player hook and callback works here exactly as it does in a game UI, so this
|
|
34
|
+
file uses `useUserInterfaceData` and friends rather than a waiting-room-specific
|
|
35
|
+
API.
|
|
36
|
+
|
|
37
|
+
Two things are worth knowing while you build one:
|
|
38
|
+
|
|
39
|
+
1. The room can be opened at any point, not only before the session starts. Read
|
|
40
|
+
`completedTicks` to tell the two apart — 0 means the session has not begun,
|
|
41
|
+
anything higher means the facilitator has parked a session already in play.
|
|
42
|
+
2. Opening the room does not stop the clock. If you want automatic ticks to
|
|
43
|
+
pause while players wait, read `waitingRoomOpen` in your tick controller and
|
|
44
|
+
return `enabled: false`.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
function App() {
|
|
48
|
+
const { completedTicks } = useUserInterfaceData<Context, Settings>();
|
|
49
|
+
const { t } = useTranslation();
|
|
50
|
+
const theme = useAppTheme();
|
|
51
|
+
const ownTeam = useUserInterfaceOwnTeam();
|
|
52
|
+
const participants = useUserInterfaceParticipants();
|
|
53
|
+
const self = useUserInterfaceParticipant();
|
|
54
|
+
|
|
55
|
+
const roster = [...participants].sort((a, b) => a.index - b.index);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<ThemeProvider theme={theme}>
|
|
59
|
+
<CssBaseline enableColorScheme />
|
|
60
|
+
<Box
|
|
61
|
+
sx={{
|
|
62
|
+
display: 'flex',
|
|
63
|
+
flexDirection: 'column',
|
|
64
|
+
alignItems: 'center',
|
|
65
|
+
justifyContent: 'center',
|
|
66
|
+
gap: 2,
|
|
67
|
+
minHeight: '100vh',
|
|
68
|
+
p: 3,
|
|
69
|
+
textAlign: 'center',
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
<Typography variant="h4" component="h1">
|
|
73
|
+
{completedTicks === 0 ? t('headingBeforeStart') : t('headingPaused')}
|
|
74
|
+
</Typography>
|
|
75
|
+
|
|
76
|
+
<Typography variant="body1" color="text.secondary">
|
|
77
|
+
{ownTeam
|
|
78
|
+
? t('joinedTeam', { team: ownTeam.name })
|
|
79
|
+
: t('waitingForFacilitator')}
|
|
80
|
+
</Typography>
|
|
81
|
+
|
|
82
|
+
<Box component="ul" sx={{ listStyle: 'none', p: 0, m: 0 }}>
|
|
83
|
+
{roster.map((participant) => (
|
|
84
|
+
<Box
|
|
85
|
+
component="li"
|
|
86
|
+
key={participant.id}
|
|
87
|
+
sx={{
|
|
88
|
+
display: 'flex',
|
|
89
|
+
alignItems: 'center',
|
|
90
|
+
justifyContent: 'center',
|
|
91
|
+
gap: 1,
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
<Box
|
|
95
|
+
aria-hidden
|
|
96
|
+
sx={{
|
|
97
|
+
width: 8,
|
|
98
|
+
height: 8,
|
|
99
|
+
borderRadius: '50%',
|
|
100
|
+
bgcolor: participant.connected
|
|
101
|
+
? 'success.main'
|
|
102
|
+
: 'text.disabled',
|
|
103
|
+
}}
|
|
104
|
+
/>
|
|
105
|
+
<Typography variant="body2">
|
|
106
|
+
{participant.id === self?.id
|
|
107
|
+
? t('participantSelf', { name: participant.name })
|
|
108
|
+
: participant.name}
|
|
109
|
+
</Typography>
|
|
110
|
+
</Box>
|
|
111
|
+
))}
|
|
112
|
+
</Box>
|
|
113
|
+
</Box>
|
|
114
|
+
</ThemeProvider>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export default App;{% endraw %}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import i18n from 'i18next';
|
|
2
|
+
import { initReactI18next } from 'react-i18next';
|
|
3
|
+
|
|
4
|
+
// Translation resources
|
|
5
|
+
const resources = {
|
|
6
|
+
en: {
|
|
7
|
+
translation: {
|
|
8
|
+
headingBeforeStart: 'Waiting to begin',
|
|
9
|
+
headingPaused: 'Session paused',
|
|
10
|
+
joinedTeam: "You've joined {% raw %}{{team}}{% endraw %}. The facilitator will continue shortly.",
|
|
11
|
+
waitingForFacilitator: 'The facilitator will continue shortly.',
|
|
12
|
+
participantSelf: '{% raw %}{{name}}{% endraw %} (you)',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
it: {
|
|
16
|
+
translation: {
|
|
17
|
+
headingBeforeStart: 'In attesa di iniziare',
|
|
18
|
+
headingPaused: 'Sessione in pausa',
|
|
19
|
+
joinedTeam: 'Ti sei unito a {% raw %}{{team}}{% endraw %}. Il facilitatore proseguirà a breve.',
|
|
20
|
+
waitingForFacilitator: 'Il facilitatore proseguirà a breve.',
|
|
21
|
+
participantSelf: '{% raw %}{{name}}{% endraw %} (tu)',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
ar: {
|
|
25
|
+
translation: {
|
|
26
|
+
headingBeforeStart: 'في انتظار البدء',
|
|
27
|
+
headingPaused: 'الجلسة متوقفة مؤقتًا',
|
|
28
|
+
joinedTeam: 'لقد انضممت إلى {% raw %}{{team}}{% endraw %}. سيتابع الميسر قريبًا.',
|
|
29
|
+
waitingForFacilitator: 'سيتابع الميسر قريبًا.',
|
|
30
|
+
participantSelf: '{% raw %}{{name}}{% endraw %} (أنت)',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
i18n.use(initReactI18next).init({
|
|
36
|
+
resources,
|
|
37
|
+
lng: 'en', // default language
|
|
38
|
+
fallbackLng: 'en',
|
|
39
|
+
interpolation: {
|
|
40
|
+
escapeValue: false, // React already escapes
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export default i18n;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import createCache from '@emotion/cache';
|
|
2
|
+
import { CacheProvider } from '@emotion/react';
|
|
3
|
+
import '@fontsource-variable/roboto-mono';
|
|
4
|
+
import '@fontsource-variable/work-sans';
|
|
5
|
+
import rtlPlugin from '@mui/stylis-plugin-rtl';
|
|
6
|
+
import { UserInterfaceWrapper, useUserInterfaceLocale } from '@seriousgaming/sdk/ui';
|
|
7
|
+
|
|
8
|
+
import './i18n';
|
|
9
|
+
import i18n from 'i18next';
|
|
10
|
+
import React, { StrictMode, useEffect } from 'react';
|
|
11
|
+
import { createRoot } from 'react-dom/client';
|
|
12
|
+
import { prefixer } from 'stylis';
|
|
13
|
+
|
|
14
|
+
import App from './App';
|
|
15
|
+
|
|
16
|
+
// Create RTL cache
|
|
17
|
+
const cacheRtl = createCache({
|
|
18
|
+
key: 'muirtl',
|
|
19
|
+
stylisPlugins: [prefixer, rtlPlugin],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const cacheLtr = createCache({
|
|
23
|
+
key: 'muiltr',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Wrapper component to sync locale with i18next and setup RTL
|
|
27
|
+
function RootWrapper({ children }: { children: React.ReactNode }) {
|
|
28
|
+
const { locale } = useUserInterfaceLocale();
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const i18nextLocale = locale.split('-')[0];
|
|
32
|
+
i18n.changeLanguage(i18nextLocale);
|
|
33
|
+
}, [locale]);
|
|
34
|
+
|
|
35
|
+
const isRtl = i18n.dir(locale.split('-')[0]) === 'rtl';
|
|
36
|
+
|
|
37
|
+
return <CacheProvider value={isRtl ? cacheRtl : cacheLtr}>{children}</CacheProvider>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
createRoot(document.getElementById('root')!).render(
|
|
41
|
+
<StrictMode>
|
|
42
|
+
<UserInterfaceWrapper>
|
|
43
|
+
<RootWrapper>
|
|
44
|
+
<App />
|
|
45
|
+
</RootWrapper>
|
|
46
|
+
</UserInterfaceWrapper>
|
|
47
|
+
</StrictMode>
|
|
48
|
+
);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{% raw %}import { createTheme } from '@mui/material/styles';
|
|
2
|
+
import { useUserInterfaceTheme } from '@seriousgaming/sdk/ui';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The host owns the palette, the game owns the typography and the component
|
|
7
|
+
* shapes. Reading `theme.mode` rather than the browser's preference is what
|
|
8
|
+
* keeps a participant's screen and the facilitator's looking like one product.
|
|
9
|
+
*/
|
|
10
|
+
export const useAppTheme = () => {
|
|
11
|
+
const theme = useUserInterfaceTheme();
|
|
12
|
+
|
|
13
|
+
return useMemo(() => {
|
|
14
|
+
const colors = theme.mode === 'light' ? theme.light : theme.dark;
|
|
15
|
+
return createTheme({
|
|
16
|
+
palette: {
|
|
17
|
+
mode: theme.mode,
|
|
18
|
+
primary: { main: colors.primary, contrastText: colors.contrastText.primary },
|
|
19
|
+
secondary: { main: colors.secondary, contrastText: colors.contrastText.secondary },
|
|
20
|
+
success: { main: colors.success, contrastText: colors.contrastText.success },
|
|
21
|
+
error: { main: colors.error, contrastText: colors.contrastText.error },
|
|
22
|
+
warning: { main: colors.warning, contrastText: colors.contrastText.warning },
|
|
23
|
+
info: { main: colors.info, contrastText: colors.contrastText.info },
|
|
24
|
+
},
|
|
25
|
+
shape: { borderRadius: 10 },
|
|
26
|
+
components: {
|
|
27
|
+
MuiButton: { styleOverrides: { root: { textTransform: 'none' } } },
|
|
28
|
+
MuiTab: {
|
|
29
|
+
styleOverrides: { root: { textTransform: 'none', fontSize: '0.95rem' } },
|
|
30
|
+
},
|
|
31
|
+
MuiToggleButton: { styleOverrides: { root: { textTransform: 'none' } } },
|
|
32
|
+
MuiTableCell: {
|
|
33
|
+
styleOverrides: {
|
|
34
|
+
head: {
|
|
35
|
+
fontSize: '0.75rem',
|
|
36
|
+
fontWeight: 700,
|
|
37
|
+
letterSpacing: '0.07em',
|
|
38
|
+
textTransform: 'uppercase',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}, [theme]);
|
|
45
|
+
};
|
|
46
|
+
{% endraw %}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource metadata registry — the single source of truth for how each resource
|
|
3
|
+
* type is laid out on disk and how it is referenced by other resources.
|
|
4
|
+
*
|
|
5
|
+
* Before #282 every `templating/<type>.ts` file hand-copied the same
|
|
6
|
+
* create/update/delete/find/update-references skeleton, so a bug in the shared
|
|
7
|
+
* idiom had to be fixed 15 times and each type's reference coverage drifted
|
|
8
|
+
* independently (capability delete only scanned the engine and UIs;
|
|
9
|
+
* scenario/facilitator-guide renames orphaned their references). The generic
|
|
10
|
+
* engine in `engine.ts` reads this registry so every type applies the same,
|
|
11
|
+
* complete rewriting.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* How references to a resource appear inside a referrer's `definition`.
|
|
15
|
+
*
|
|
16
|
+
* - `stringArray` — `definition[path]: string[]` of identifiers. An optional
|
|
17
|
+
* `labelSuffix` tags the reference label ('reads' / 'writes' /
|
|
18
|
+
* 'crossTeamReads' for the capability fan-out).
|
|
19
|
+
* - `keyedMap` — `definition[path]: Record<identifier, {...}>`; the
|
|
20
|
+
* identifier is the key, so a rename re-keys and a delete drops the entry.
|
|
21
|
+
* A scenario's `settings` is one, keyed by settings identifier.
|
|
22
|
+
*/
|
|
23
|
+
export type ReferenceShape = {
|
|
24
|
+
kind: 'stringArray';
|
|
25
|
+
path: string;
|
|
26
|
+
labelSuffix?: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: 'keyedMap';
|
|
29
|
+
path: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The referrer key standing for the manifest itself rather than a list of
|
|
33
|
+
* bundle files. A package is a game (#421), so the settings that reference
|
|
34
|
+
* resources by identifier sit at the manifest's top level.
|
|
35
|
+
*/
|
|
36
|
+
export declare const MANIFEST_REFERRER = "__manifest__";
|
|
37
|
+
/** One place a resource type is referenced: which referrer files, and how. */
|
|
38
|
+
export interface ReferenceSite {
|
|
39
|
+
/**
|
|
40
|
+
* Manifest keys (in seriousgaming.sdk.json) of the referrer files to scan,
|
|
41
|
+
* or {@link MANIFEST_REFERRER} for the manifest itself.
|
|
42
|
+
*/
|
|
43
|
+
referrerKeys: string[];
|
|
44
|
+
shape: ReferenceShape;
|
|
45
|
+
}
|
|
46
|
+
export type ResourceKind = 'logic' | 'ui' | 'composition' | 'content';
|
|
47
|
+
/** Every registered resource type, so a stale type name is a compile error. */
|
|
48
|
+
export declare const RESOURCE_TYPES: readonly ["capability", "engine", "ui", "session", "waiting_room", "presentation", "setup", "scenario_editor", "scenario", "guide", "tick_controller", "hook", "validator", "endpoint", "settings"];
|
|
49
|
+
export type ResourceType = (typeof RESOURCE_TYPES)[number];
|
|
50
|
+
/**
|
|
51
|
+
* Where a resource's code sits inside its own directory, and what the
|
|
52
|
+
* entrypoint is called.
|
|
53
|
+
*
|
|
54
|
+
* The CLI fabricates this block: `new` writes it into the bundle and `update`
|
|
55
|
+
* leaves it alone, so an authored value was read by nothing. It is written down
|
|
56
|
+
* once here because the guard on authored input has to reject exactly what the
|
|
57
|
+
* templater is about to write, and a second copy could disagree with it (#473).
|
|
58
|
+
*/
|
|
59
|
+
export type ResourceLayout = {
|
|
60
|
+
logic: {
|
|
61
|
+
directory: string;
|
|
62
|
+
entrypoint: string;
|
|
63
|
+
};
|
|
64
|
+
} | {
|
|
65
|
+
ui: {
|
|
66
|
+
entrypoint: string;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Where a resource lives in its package: a fixed slot for a type a game holds
|
|
71
|
+
* exactly one of, which is not named because the slot is the whole of its
|
|
72
|
+
* address, or a directory of named resources for every other type.
|
|
73
|
+
*/
|
|
74
|
+
export type ResourcePlacement = {
|
|
75
|
+
/** The fixed directory a singular resource lives in, e.g. `engine`. */
|
|
76
|
+
slot: ResourceType;
|
|
77
|
+
pluralDir?: undefined;
|
|
78
|
+
} | {
|
|
79
|
+
slot?: undefined;
|
|
80
|
+
/** Directory holding all resources of this type, e.g. `hooks`. */
|
|
81
|
+
pluralDir: string;
|
|
82
|
+
};
|
|
83
|
+
export type PluralResourceMeta = Extract<ResourceMeta, {
|
|
84
|
+
pluralDir: string;
|
|
85
|
+
}>;
|
|
86
|
+
export type ResourceMeta = ResourcePlacement & {
|
|
87
|
+
type: ResourceType;
|
|
88
|
+
/**
|
|
89
|
+
* The code layout the templater writes into this type's bundle. Absent for
|
|
90
|
+
* the types that carry neither logic nor a UI.
|
|
91
|
+
*/
|
|
92
|
+
layout?: ResourceLayout;
|
|
93
|
+
/** Bundle filename inside each resource directory, e.g. `engine.sdk.json`. */
|
|
94
|
+
bundleFile: string;
|
|
95
|
+
/** Key under which bundle paths are listed in seriousgaming.sdk.json. */
|
|
96
|
+
manifestKey: string;
|
|
97
|
+
kind: ResourceKind;
|
|
98
|
+
/** Human label used in reference output when this type is a referrer. */
|
|
99
|
+
label: string;
|
|
100
|
+
/** Merge the new definition onto the existing one (capability keeps `scope`). */
|
|
101
|
+
mergeDefinition: boolean;
|
|
102
|
+
/** Definition carries a `reads: string[]` of capability identifiers. */
|
|
103
|
+
hasReads: boolean;
|
|
104
|
+
/** Definition carries a `writes: string[]` of capability identifiers. */
|
|
105
|
+
hasWrites: boolean;
|
|
106
|
+
/** Definition carries a `crossTeamReads: string[]` of capability identifiers. */
|
|
107
|
+
hasCrossTeamReads: boolean;
|
|
108
|
+
/** Definition carries an `endpoints: string[]` of endpoint refs. */
|
|
109
|
+
declaresEndpoints: boolean;
|
|
110
|
+
/** Definition carries a `settings: string[]` of settings identifiers. */
|
|
111
|
+
readsSettings: boolean;
|
|
112
|
+
/** How other resources reference this one (target perspective). */
|
|
113
|
+
referenceSites: ReferenceSite[];
|
|
114
|
+
};
|
|
115
|
+
export declare const RESOURCE_METADATA: readonly ResourceMeta[];
|
|
116
|
+
export declare const RESOURCE_METADATA_BY_MANIFEST_KEY: ReadonlyMap<string, ResourceMeta>;
|
|
117
|
+
/** Metadata for a resource type, or undefined for a non-resource (`package`). */
|
|
118
|
+
export declare function findResourceMeta(type: string): ResourceMeta | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Nothing labels this resource, so it carries no `locales`.
|
|
121
|
+
*
|
|
122
|
+
* A game holds one of each interface, so no list ever names one and the name
|
|
123
|
+
* was never rendered (#448). The guide is the counter-example a hand-written
|
|
124
|
+
* list kept getting wrong: it fills a slot too, and it is genuinely titled. So
|
|
125
|
+
* is the presentation, the one interface a host lists outside a session, in a
|
|
126
|
+
* game's library, and so labels.
|
|
127
|
+
*/
|
|
128
|
+
export declare function isNamelessInterface(meta: ResourceMeta): boolean;
|
|
129
|
+
export declare function getResourceMeta(type: ResourceType): ResourceMeta;
|
|
130
|
+
/** Metadata for a type a package may hold several of, named by directory. */
|
|
131
|
+
export declare function getPluralResourceMeta(type: ResourceType): PluralResourceMeta;
|