@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.
Files changed (391) hide show
  1. package/LICENSE +93 -0
  2. package/README.md +36 -2
  3. package/dist/bundling/logic-exports.d.ts +34 -0
  4. package/dist/bundling/node-builtins.d.ts +21 -0
  5. package/dist/bundling/transpiler.d.ts +7 -0
  6. package/dist/cli.js +27368 -0
  7. package/dist/client/dev-server.d.ts +59 -0
  8. package/dist/client/index.d.ts +28 -0
  9. package/dist/client/stub-services.d.ts +32 -0
  10. package/dist/client/test-session.d.ts +195 -0
  11. package/dist/client.js +16884 -0
  12. package/dist/core/asset-reference-translator.d.ts +46 -0
  13. package/dist/core/clock.d.ts +57 -0
  14. package/dist/core/faults.d.ts +65 -0
  15. package/dist/core/game-settings.d.ts +65 -0
  16. package/dist/core/history.d.ts +89 -0
  17. package/dist/core/listen-with-fallback.d.ts +30 -0
  18. package/dist/core/mutation-queue.d.ts +61 -0
  19. package/dist/core/package-scenario.d.ts +89 -0
  20. package/dist/core/participant-registry.d.ts +109 -0
  21. package/dist/core/pending-changes.d.ts +14 -0
  22. package/dist/core/protocol.d.ts +83 -0
  23. package/dist/core/scenario-drafts.d.ts +32 -0
  24. package/dist/core/session-endpoints.d.ts +108 -0
  25. package/dist/core/session-gates.d.ts +75 -0
  26. package/dist/core/session-host.d.ts +94 -0
  27. package/dist/core/session-refusals.d.ts +56 -0
  28. package/dist/core/session-rewind.d.ts +32 -0
  29. package/dist/core/session-roster.d.ts +128 -0
  30. package/dist/core/session-surfaces.d.ts +32 -0
  31. package/dist/core/session-ticks.d.ts +18 -0
  32. package/dist/core/session-timers.d.ts +84 -0
  33. package/dist/core/session-writes.d.ts +40 -0
  34. package/dist/core/session.d.ts +385 -0
  35. package/dist/core/settings-locks.d.ts +22 -0
  36. package/dist/core/team-names.d.ts +52 -0
  37. package/dist/core/team-state-store.d.ts +209 -0
  38. package/dist/core/tick-timer.d.ts +75 -0
  39. package/dist/dev/blob-links.d.ts +10 -0
  40. package/dist/dev/console/assets/index-DgFglsnA.js +204 -0
  41. package/dist/dev/console/index.html +12 -0
  42. package/dist/dev/console-path.d.ts +19 -0
  43. package/dist/dev/lockfile.d.ts +124 -0
  44. package/dist/dev/package-watcher.d.ts +21 -0
  45. package/dist/dev/routes.d.ts +67 -0
  46. package/dist/dev/shell.d.ts +260 -0
  47. package/dist/dev/surfaces.d.ts +41 -0
  48. package/dist/dev/tools-identity.d.ts +23 -0
  49. package/dist/dev/view/batch.d.ts +172 -0
  50. package/dist/dev/view/commands.d.ts +75 -0
  51. package/dist/dev/view/route.d.ts +58 -0
  52. package/dist/dev/view/view.d.ts +78 -0
  53. package/dist/dev/view/viewer.d.ts +32 -0
  54. package/dist/discovery/config.d.ts +9 -0
  55. package/dist/discovery/manifest-paths.d.ts +21 -0
  56. package/dist/discovery/removed-fields.d.ts +90 -0
  57. package/dist/docs/api/deck.md +386 -0
  58. package/dist/docs/api/index.md +67 -0
  59. package/dist/docs/api/sdk-commands.md +286 -0
  60. package/dist/docs/api/sdk-e2e.md +433 -0
  61. package/dist/docs/api/sdk-projection.md +207 -0
  62. package/dist/docs/api/sdk-testing.md +214 -0
  63. package/dist/docs/api/sdk-tools-client.md +560 -0
  64. package/dist/docs/api/sdk-ui-testing.md +231 -0
  65. package/dist/docs/api/sdk-ui.md +1269 -0
  66. package/dist/docs/api/sdk.md +2140 -0
  67. package/dist/docs/changelog-0.x.md +1156 -0
  68. package/dist/docs/changelog.md +236 -0
  69. package/dist/docs/cli-and-dev-server.md +217 -0
  70. package/dist/docs/cli-error-codes.md +154 -0
  71. package/dist/docs/cli-reference.md +2488 -0
  72. package/dist/docs/cli-simulation-testing.md +222 -0
  73. package/dist/docs/concepts/index.md +46 -0
  74. package/dist/docs/concepts/terminology.md +322 -0
  75. package/dist/docs/environment-variables.md +102 -0
  76. package/dist/docs/getting-started.md +145 -0
  77. package/dist/docs/guides/ai-facilitation.md +220 -0
  78. package/dist/docs/guides/capabilities.md +460 -0
  79. package/dist/docs/guides/endpoints.md +335 -0
  80. package/dist/docs/guides/engine-testing.md +477 -0
  81. package/dist/docs/guides/engine.md +527 -0
  82. package/dist/docs/guides/file-handling.md +405 -0
  83. package/dist/docs/guides/games.md +176 -0
  84. package/dist/docs/guides/global-settings.md +94 -0
  85. package/dist/docs/guides/guide.md +123 -0
  86. package/dist/docs/guides/hooks.md +183 -0
  87. package/dist/docs/guides/index.md +51 -0
  88. package/dist/docs/guides/internationalization.md +288 -0
  89. package/dist/docs/guides/llm-integration.md +635 -0
  90. package/dist/docs/guides/multi-team-games.md +586 -0
  91. package/dist/docs/guides/patterns.md +391 -0
  92. package/dist/docs/guides/presentation.md +196 -0
  93. package/dist/docs/guides/production-constraints.md +130 -0
  94. package/dist/docs/guides/scenario-editor.md +143 -0
  95. package/dist/docs/guides/scenarios.md +515 -0
  96. package/dist/docs/guides/session.md +972 -0
  97. package/dist/docs/guides/settings.md +458 -0
  98. package/dist/docs/guides/setup.md +193 -0
  99. package/dist/docs/guides/speech-generation.md +233 -0
  100. package/dist/docs/guides/starter-game.md +164 -0
  101. package/dist/docs/guides/testing.md +575 -0
  102. package/dist/docs/guides/tick-controller.md +569 -0
  103. package/dist/docs/guides/type-safety.md +516 -0
  104. package/dist/docs/guides/ui.md +1389 -0
  105. package/dist/docs/guides/upgrading.md +636 -0
  106. package/dist/docs/guides/validators.md +217 -0
  107. package/dist/docs/guides/waiting-room.md +244 -0
  108. package/dist/docs/index.md +41 -0
  109. package/dist/docs/recipes/act-on-the-session-from-an-endpoint.md +95 -0
  110. package/dist/docs/recipes/adapt-a-game-for-walkthroughs.md +133 -0
  111. package/dist/docs/recipes/adapt-ui-for-observers.md +74 -0
  112. package/dist/docs/recipes/call-endpoint-from-ui.md +109 -0
  113. package/dist/docs/recipes/check-a-package-from-a-script.md +117 -0
  114. package/dist/docs/recipes/create-capability.md +66 -0
  115. package/dist/docs/recipes/create-endpoint.md +127 -0
  116. package/dist/docs/recipes/create-engine.md +111 -0
  117. package/dist/docs/recipes/create-game.md +70 -0
  118. package/dist/docs/recipes/create-guide.md +75 -0
  119. package/dist/docs/recipes/create-hook.md +80 -0
  120. package/dist/docs/recipes/create-presentation.md +142 -0
  121. package/dist/docs/recipes/create-scenario-editor.md +102 -0
  122. package/dist/docs/recipes/create-scenario.md +98 -0
  123. package/dist/docs/recipes/create-session-ui.md +116 -0
  124. package/dist/docs/recipes/create-settings.md +88 -0
  125. package/dist/docs/recipes/create-setup.md +115 -0
  126. package/dist/docs/recipes/create-tick-controller.md +65 -0
  127. package/dist/docs/recipes/create-user-interface.md +96 -0
  128. package/dist/docs/recipes/create-validator.md +67 -0
  129. package/dist/docs/recipes/create-waiting-room-ui.md +109 -0
  130. package/dist/docs/recipes/declare-api-uses.md +67 -0
  131. package/dist/docs/recipes/design-state-for-concurrent-writes.md +96 -0
  132. package/dist/docs/recipes/distribute-package.md +80 -0
  133. package/dist/docs/recipes/e2e-testing.md +116 -0
  134. package/dist/docs/recipes/end-game-on-condition.md +154 -0
  135. package/dist/docs/recipes/fix-duplicate-packages.md +101 -0
  136. package/dist/docs/recipes/index.md +86 -0
  137. package/dist/docs/recipes/make-an-endpoint-external.md +101 -0
  138. package/dist/docs/recipes/negotiate-across-teams.md +164 -0
  139. package/dist/docs/recipes/observe-other-teams-state.md +119 -0
  140. package/dist/docs/recipes/publish-a-package.md +139 -0
  141. package/dist/docs/recipes/remember-a-viewers-choice.md +55 -0
  142. package/dist/docs/recipes/review-a-past-day.md +73 -0
  143. package/dist/docs/recipes/share-assets-across-scenarios.md +120 -0
  144. package/dist/docs/recipes/share-logic-between-engine-and-ui.md +130 -0
  145. package/dist/docs/recipes/show-all-teams-participants.md +109 -0
  146. package/dist/docs/recipes/start-from-an-empty-package.md +169 -0
  147. package/dist/docs/recipes/take-a-file-in-an-endpoint.md +82 -0
  148. package/dist/docs/recipes/test-a-multi-role-game.md +51 -0
  149. package/dist/docs/recipes/test-user-interface.md +95 -0
  150. package/dist/docs/recipes/test-with-engine.md +115 -0
  151. package/dist/docs/recipes/upload-and-display-files.md +148 -0
  152. package/dist/docs/recipes/use-request-play.md +65 -0
  153. package/dist/docs/recipes/use-request-tick.md +75 -0
  154. package/dist/docs/troubleshooting.md +816 -0
  155. package/dist/execution/blob-inputs.d.ts +57 -0
  156. package/dist/execution/bundle-reload.d.ts +42 -0
  157. package/dist/execution/config-resolver.d.ts +127 -0
  158. package/dist/execution/configuration-builder.d.ts +66 -0
  159. package/dist/execution/context-composition.d.ts +161 -0
  160. package/dist/execution/endpoint-actions.d.ts +9 -0
  161. package/dist/execution/endpoint-payloads.d.ts +32 -0
  162. package/dist/execution/endpoint-runner.d.ts +129 -0
  163. package/dist/execution/engine-state.d.ts +40 -0
  164. package/dist/execution/executor-callbacks.d.ts +56 -0
  165. package/dist/execution/executor.d.ts +436 -0
  166. package/dist/execution/gates.d.ts +45 -0
  167. package/dist/execution/hook-chain.d.ts +25 -0
  168. package/dist/execution/logic-calls.d.ts +190 -0
  169. package/dist/execution/logic-failure.d.ts +84 -0
  170. package/dist/execution/logic-loader.d.ts +54 -0
  171. package/dist/execution/logic-result.d.ts +76 -0
  172. package/dist/execution/tick-controller-call.d.ts +32 -0
  173. package/dist/execution/types.d.ts +48 -0
  174. package/dist/generation/ts-type.d.ts +39 -0
  175. package/dist/guide/locale.d.ts +12 -0
  176. package/dist/guide/video-registry.d.ts +42 -0
  177. package/dist/help-examples.d.ts +125 -0
  178. package/dist/host/adapter.d.ts +67 -0
  179. package/dist/host/host-channel.d.ts +222 -0
  180. package/dist/host/index.d.ts +20 -0
  181. package/dist/host/protocol.d.ts +783 -0
  182. package/dist/host/surfaces.d.ts +42 -0
  183. package/dist/host/theme.d.ts +55 -0
  184. package/dist/host.js +583 -0
  185. package/dist/prompts/index.d.ts +7 -0
  186. package/dist/prompts/schema-builder.d.ts +29 -0
  187. package/dist/prompts/types.d.ts +108 -0
  188. package/dist/prompts/validators.d.ts +32 -0
  189. package/dist/runtime/capability-scope.d.ts +6 -0
  190. package/dist/runtime/context-merge.d.ts +29 -0
  191. package/dist/runtime/context-projection.d.ts +41 -0
  192. package/dist/runtime/guarded-callbacks.d.ts +15 -0
  193. package/dist/runtime/index.d.ts +27 -0
  194. package/dist/runtime/manifest-version.d.ts +55 -0
  195. package/dist/runtime/tick-validation.d.ts +25 -0
  196. package/dist/runtime.js +346 -0
  197. package/dist/schema.json +1546 -0
  198. package/dist/server/vite-plugin.d.ts +46 -0
  199. package/dist/services/tts/client.d.ts +51 -0
  200. package/dist/services/tts/elevenlabs.d.ts +24 -0
  201. package/dist/services/tts/types.d.ts +44 -0
  202. package/dist/storage/asset-resolver.d.ts +49 -0
  203. package/dist/storage/blob-store.d.ts +41 -0
  204. package/dist/templates/endpoint/logic.test.ts.liquid +61 -0
  205. package/dist/templates/endpoint/logic.ts.liquid +25 -0
  206. package/dist/templates/engine/init.json.liquid +7 -0
  207. package/dist/templates/engine/logic-aggregate.test.ts.liquid +90 -0
  208. package/dist/templates/engine/logic-aggregate.ts.liquid +46 -0
  209. package/dist/templates/engine/logic.test.ts.liquid +61 -0
  210. package/dist/templates/engine/logic.ts.liquid +32 -0
  211. package/dist/templates/engine/run.json.liquid +7 -0
  212. package/dist/templates/guide/01-at-a-glance.md.liquid +19 -0
  213. package/dist/templates/guide/02-preparation.md.liquid +18 -0
  214. package/dist/templates/guide/03-running-the-session.md.liquid +37 -0
  215. package/dist/templates/hook/logic.test.ts.liquid +46 -0
  216. package/dist/templates/hook/logic.ts.liquid +12 -0
  217. package/dist/templates/package/CLAUDE.md.template +338 -0
  218. package/dist/templates/package/DESIGN.md.liquid +144 -0
  219. package/dist/templates/package/README.md.liquid +143 -0
  220. package/dist/templates/package/claude/rules/workflow-create-capability.md +26 -0
  221. package/dist/templates/package/claude/rules/workflow-create-endpoint.md +35 -0
  222. package/dist/templates/package/claude/rules/workflow-create-engine.md +35 -0
  223. package/dist/templates/package/claude/rules/workflow-create-guide.md +40 -0
  224. package/dist/templates/package/claude/rules/workflow-create-presentation.md +37 -0
  225. package/dist/templates/package/claude/rules/workflow-create-user-interface.md +31 -0
  226. package/dist/templates/package/claude/rules/workflow-publish-package.md +54 -0
  227. package/dist/templates/package/claude/rules/workflow-test-engine-or-ui.md +30 -0
  228. package/dist/templates/package/claude/rules/workflow-update-sdk-version.md +43 -0
  229. package/dist/templates/package/claude/settings.json.template +16 -0
  230. package/dist/templates/package/gitignore.template +15 -0
  231. package/dist/templates/package/global-setup.ts.template +21 -0
  232. package/dist/templates/package/globals.d.ts.template +2 -0
  233. package/dist/templates/package/oxfmtrc.json.template +14 -0
  234. package/dist/templates/package/oxlintrc.json.template +238 -0
  235. package/dist/templates/package/package.json.liquid +65 -0
  236. package/dist/templates/package/playwright.config.ts.liquid +19 -0
  237. package/dist/templates/package/pnpm-workspace.yaml.template +27 -0
  238. package/dist/templates/package/test-setup.ts.liquid +7 -0
  239. package/dist/templates/package/tsconfig.json.liquid +15 -0
  240. package/dist/templates/package/vite.config.ts.liquid +19 -0
  241. package/dist/templates/package/vitest.config.ts.liquid +25 -0
  242. package/dist/templates/package/vitest.engine.config.ts.liquid +12 -0
  243. package/dist/templates/presentation/index.html.liquid +20 -0
  244. package/dist/templates/presentation/src/App.tsx.liquid +49 -0
  245. package/dist/templates/presentation/src/Slides.tsx.liquid +81 -0
  246. package/dist/templates/presentation/src/i18n.ts.liquid +54 -0
  247. package/dist/templates/presentation/src/main.tsx.liquid +14 -0
  248. package/dist/templates/scenario_editor/src/App.test.tsx.liquid +30 -0
  249. package/dist/templates/scenario_editor/src/App.tsx.liquid +95 -0
  250. package/dist/templates/scenario_editor/src/i18n.ts.liquid +44 -0
  251. package/dist/templates/session/src/App.test.tsx.liquid +60 -0
  252. package/dist/templates/session/src/App.tsx.liquid +128 -0
  253. package/dist/templates/session/src/i18n.ts.liquid +53 -0
  254. package/dist/templates/session/src/main.tsx.liquid +48 -0
  255. package/dist/templates/session/src/theme.ts.liquid +46 -0
  256. package/dist/templates/settings-editor/index.html.liquid +12 -0
  257. package/dist/templates/settings-editor/src/main.tsx.liquid +48 -0
  258. package/dist/templates/settings-editor/src/theme.ts.liquid +24 -0
  259. package/dist/templates/setup/src/App.test.tsx.liquid +39 -0
  260. package/dist/templates/setup/src/App.tsx.liquid +102 -0
  261. package/dist/templates/setup/src/i18n.ts.liquid +47 -0
  262. package/dist/templates/starter-game/capabilities/briefing/capability.sdk.json +18 -0
  263. package/dist/templates/starter-game/capabilities/plan/capability.sdk.json +17 -0
  264. package/dist/templates/starter-game/capabilities/results/capability.sdk.json +61 -0
  265. package/dist/templates/starter-game/capabilities/roles/capability.sdk.json +17 -0
  266. package/dist/templates/starter-game/capabilities/weather/capability.sdk.json +23 -0
  267. package/dist/templates/starter-game/engine/defaults.ts +81 -0
  268. package/dist/templates/starter-game/engine/engine.sdk.json +12 -0
  269. package/dist/templates/starter-game/engine/logic.test.ts +221 -0
  270. package/dist/templates/starter-game/engine/logic.ts +149 -0
  271. package/dist/templates/starter-game/engine/test-helpers.ts +74 -0
  272. package/dist/templates/starter-game/engine/types.ts +139 -0
  273. package/dist/templates/starter-game/guide/content/en/01-at-a-glance.md +51 -0
  274. package/dist/templates/starter-game/guide/content/en/02-preparation.md +35 -0
  275. package/dist/templates/starter-game/guide/content/en/03-running-the-day.md +58 -0
  276. package/dist/templates/starter-game/guide/guide.sdk.json +10 -0
  277. package/dist/templates/starter-game/guide/guide.test.ts +108 -0
  278. package/dist/templates/starter-game/hooks/assignproducts/defaults.ts +37 -0
  279. package/dist/templates/starter-game/hooks/assignproducts/hook.sdk.json +13 -0
  280. package/dist/templates/starter-game/hooks/assignproducts/logic/logic.test.ts +77 -0
  281. package/dist/templates/starter-game/hooks/assignproducts/logic/logic.ts +47 -0
  282. package/dist/templates/starter-game/hooks/assignproducts/types.ts +55 -0
  283. package/dist/templates/starter-game/package.json +68 -0
  284. package/dist/templates/starter-game/playwright.config.ts +19 -0
  285. package/dist/templates/starter-game/scenarios/heatwave/scenario.sdk.json +20 -0
  286. package/dist/templates/starter-game/scenarios/ordinary_week/scenario.sdk.json +12 -0
  287. package/dist/templates/starter-game/seriousgaming.sdk.json +23 -0
  288. package/dist/templates/starter-game/session/defaults.ts +80 -0
  289. package/dist/templates/starter-game/session/index.html +12 -0
  290. package/dist/templates/starter-game/session/session.sdk.json +11 -0
  291. package/dist/templates/starter-game/session/src/App.test.tsx +307 -0
  292. package/dist/templates/starter-game/session/src/App.tsx +309 -0
  293. package/dist/templates/starter-game/session/src/Section.tsx +37 -0
  294. package/dist/templates/starter-game/session/src/TeamDoor.tsx +96 -0
  295. package/dist/templates/starter-game/session/src/format.ts +8 -0
  296. package/dist/templates/starter-game/session/src/i18n.ts +51 -0
  297. package/dist/templates/starter-game/session/src/main.tsx +48 -0
  298. package/dist/templates/starter-game/session/src/theme.ts +45 -0
  299. package/dist/templates/starter-game/session/types.ts +135 -0
  300. package/dist/templates/starter-game/settings/engine/settings.sdk.json +50 -0
  301. package/dist/templates/starter-game/settings/menu/settings.sdk.json +78 -0
  302. package/dist/templates/starter-game/settings/session/settings.sdk.json +23 -0
  303. package/dist/templates/starter-game/settings/ui/settings.sdk.json +25 -0
  304. package/dist/templates/starter-game/test-setup.ts +7 -0
  305. package/dist/templates/starter-game/testing/e2e/game.spec.ts +139 -0
  306. package/dist/templates/starter-game/testing/e2e/global-setup.ts +21 -0
  307. package/dist/templates/starter-game/testing/engine/game.engine.test.ts +171 -0
  308. package/dist/templates/starter-game/tsconfig.json +19 -0
  309. package/dist/templates/starter-game/ui/defaults.ts +60 -0
  310. package/dist/templates/starter-game/ui/index.html +12 -0
  311. package/dist/templates/starter-game/ui/src/App.test.tsx +138 -0
  312. package/dist/templates/starter-game/ui/src/App.tsx +175 -0
  313. package/dist/templates/starter-game/ui/src/DayBar.test.tsx +78 -0
  314. package/dist/templates/starter-game/ui/src/DayBar.tsx +72 -0
  315. package/dist/templates/starter-game/ui/src/HistoryPanel.test.tsx +74 -0
  316. package/dist/templates/starter-game/ui/src/HistoryPanel.tsx +120 -0
  317. package/dist/templates/starter-game/ui/src/MakeRow.tsx +129 -0
  318. package/dist/templates/starter-game/ui/src/Section.tsx +37 -0
  319. package/dist/templates/starter-game/ui/src/ThemeToggle.tsx +49 -0
  320. package/dist/templates/starter-game/ui/src/TodayPanel.test.tsx +179 -0
  321. package/dist/templates/starter-game/ui/src/TodayPanel.tsx +92 -0
  322. package/dist/templates/starter-game/ui/src/YesterdayPanel.tsx +142 -0
  323. package/dist/templates/starter-game/ui/src/format.ts +12 -0
  324. package/dist/templates/starter-game/ui/src/i18n.ts +95 -0
  325. package/dist/templates/starter-game/ui/src/main.tsx +48 -0
  326. package/dist/templates/starter-game/ui/src/menu.ts +18 -0
  327. package/dist/templates/starter-game/ui/src/test-helpers.ts +58 -0
  328. package/dist/templates/starter-game/ui/src/theme.ts +45 -0
  329. package/dist/templates/starter-game/ui/src/writes.ts +43 -0
  330. package/dist/templates/starter-game/ui/types.ts +137 -0
  331. package/dist/templates/starter-game/ui/ui.sdk.json +11 -0
  332. package/dist/templates/starter-game/validators/capacity/defaults.ts +37 -0
  333. package/dist/templates/starter-game/validators/capacity/logic/logic.test.ts +96 -0
  334. package/dist/templates/starter-game/validators/capacity/logic/logic.ts +45 -0
  335. package/dist/templates/starter-game/validators/capacity/types.ts +55 -0
  336. package/dist/templates/starter-game/validators/capacity/validator.sdk.json +11 -0
  337. package/dist/templates/starter-game/vite.config.ts +19 -0
  338. package/dist/templates/starter-game/vitest.config.ts +15 -0
  339. package/dist/templates/starter-game/vitest.engine.config.ts +19 -0
  340. package/dist/templates/starter-game/waiting_room/defaults.ts +40 -0
  341. package/dist/templates/starter-game/waiting_room/index.html +12 -0
  342. package/dist/templates/starter-game/waiting_room/src/App.test.tsx +102 -0
  343. package/dist/templates/starter-game/waiting_room/src/App.tsx +194 -0
  344. package/dist/templates/starter-game/waiting_room/src/i18n.ts +33 -0
  345. package/dist/templates/starter-game/waiting_room/src/main.tsx +48 -0
  346. package/dist/templates/starter-game/waiting_room/src/theme.ts +45 -0
  347. package/dist/templates/starter-game/waiting_room/types.ts +59 -0
  348. package/dist/templates/starter-game/waiting_room/waiting_room.sdk.json +10 -0
  349. package/dist/templates/tick-controller/logic.ts.liquid +8 -0
  350. package/dist/templates/ui/index.html.liquid +12 -0
  351. package/dist/templates/ui/src/App.test.tsx.liquid +41 -0
  352. package/dist/templates/ui/src/App.tsx.liquid +103 -0
  353. package/dist/templates/ui/src/i18n.ts.liquid +47 -0
  354. package/dist/templates/ui/src/main.tsx.liquid +48 -0
  355. package/dist/templates/ui/src/theme.ts.liquid +46 -0
  356. package/dist/templates/validator/logic.test.ts.liquid +42 -0
  357. package/dist/templates/validator/logic.ts.liquid +21 -0
  358. package/dist/templates/waiting-room/index.html.liquid +12 -0
  359. package/dist/templates/waiting-room/src/App.test.tsx.liquid +57 -0
  360. package/dist/templates/waiting-room/src/App.tsx.liquid +118 -0
  361. package/dist/templates/waiting-room/src/i18n.ts.liquid +44 -0
  362. package/dist/templates/waiting-room/src/main.tsx.liquid +48 -0
  363. package/dist/templates/waiting-room/src/theme.ts.liquid +46 -0
  364. package/dist/templating/resource-metadata.d.ts +131 -0
  365. package/dist/types.d.ts +14 -0
  366. package/dist/utils/atomic-write.d.ts +40 -0
  367. package/dist/utils/cli-error.d.ts +64 -0
  368. package/dist/utils/document-parser-client.d.ts +20 -0
  369. package/dist/utils/env-loader.d.ts +40 -0
  370. package/dist/utils/error-codes.d.ts +335 -0
  371. package/dist/utils/errors.d.ts +19 -0
  372. package/dist/utils/global-settings.d.ts +65 -0
  373. package/dist/utils/llm-client.d.ts +34 -0
  374. package/dist/utils/logger.d.ts +36 -0
  375. package/dist/utils/output.d.ts +109 -0
  376. package/dist/utils/platform.d.ts +14 -0
  377. package/dist/utils/prompt.d.ts +36 -0
  378. package/dist/utils/real-path.d.ts +6 -0
  379. package/dist/utils/schema-properties.d.ts +35 -0
  380. package/dist/validation/ajv.d.ts +17 -0
  381. package/dist/validation/facilitator-guide-validator.d.ts +27 -0
  382. package/dist/validation/findings.d.ts +40 -0
  383. package/dist/validation/game-constraints.d.ts +10 -0
  384. package/dist/validation/game-validator.d.ts +34 -0
  385. package/dist/validation/package-validation.d.ts +41 -0
  386. package/dist/validation/package-validator.d.ts +19 -0
  387. package/dist/validation/resource-validator.d.ts +79 -0
  388. package/dist/validation/schema-defaults-validator.d.ts +29 -0
  389. package/dist/validation/schema-validation.d.ts +115 -0
  390. package/dist/validation/semver.d.ts +9 -0
  391. package/package.json +122 -3
@@ -0,0 +1,130 @@
1
+ # Production security constraints
2
+
3
+ In production your UI bundle runs cross-origin, behind a strict content security policy and a short-lived auth cookie, and talks to the host only through a typed message channel. The dev server mirrors this policy, so a UI that works locally will work in production. This guide explains the constraints and the things to do and avoid so you never ship a UI that passes locally and breaks live.
4
+
5
+ ## What you'll learn
6
+
7
+ - Why your UI is sandboxed in production and what that means in practice
8
+ - What your UI is allowed to do inside its frame, and what it is not
9
+ - The exact content security policy your bundle runs under
10
+ - What to do and what to avoid when building UIs
11
+ - How to recognise and fix the most common policy violations
12
+ - The write, retry and logic rules that hold beyond the frame
13
+
14
+ ## The two-origin model
15
+
16
+ The platform serves the app and your content from two separate domains:
17
+
18
+ - App host (for example `businesssimulations.com`): the single-page app, the REST APIs, and the page that embeds your iframe
19
+ - Asset host (a per-brand content domain, for example `assets.businesssimulations.com`): your bundle, scenario assets, and blobs
20
+
21
+ Your iframe points at the asset host, so your code is cross-origin to the parent app. This cross-origin isolation is the primary sandbox: it keeps uploaded simulation code away from the main host's cookies and APIs. Access to your bundle is gated by a short-lived, automatically managed cookie, so your same-origin requests to the asset host just work without any credential handling on your part.
22
+
23
+ ## The content security policy
24
+
25
+ Your bundle runs under this policy on the asset host:
26
+
27
+ ```
28
+ default-src 'self'
29
+ connect-src 'self'
30
+ img-src 'self' data:
31
+ media-src 'self' blob: data:
32
+ font-src 'self' data:
33
+ style-src 'self' 'unsafe-inline'
34
+ script-src 'self' 'unsafe-inline'
35
+ frame-src 'self' https://www.youtube.com https://www.youtube-nocookie.com
36
+ form-action 'self'
37
+ frame-ancestors *
38
+ ```
39
+
40
+ The headline rule is `default-src 'self'`: everything your UI loads must be first-party to the asset host or bundled into your build. Inline scripts and styles are allowed, but external origins are not.
41
+
42
+ ## What your UI may do inside its frame
43
+
44
+ The policy above governs what your UI can _load_. A second set of limits, set on the iframe itself, governs what it can _do_. These are fixed: there is nothing to declare in your bundle, and every UI type gets the same set.
45
+
46
+ Your UI can:
47
+
48
+ - Copy to the clipboard, so a 'copy join link' or 'copy your code' button works
49
+ - Print, via `window.print()`
50
+ - Offer downloads, so a results CSV or a team report reaches the participant
51
+ - Go fullscreen
52
+ - Play audio automatically, which is what makes generated speech playback work
53
+ - Hold a screen wake lock, so a tablet does not sleep mid-session
54
+ - Present to a second screen
55
+ - Open an external link in a new tab, with `target="_blank" rel="noopener noreferrer"`. A `mailto:` or `tel:` link needs the same treatment: a bare one is blocked, because the surface itself cannot navigate to an external protocol handler
56
+ - Ask the browser for the microphone, camera, or location. The participant still sees the browser's own permission prompt, so treat a refusal as a normal outcome and design a path through it
57
+ - Use picture-in-picture, the Web Share sheet, a gamepad, multi-screen window placement, and speaker selection
58
+
59
+ Your UI cannot:
60
+
61
+ - Read the clipboard. Writing is allowed, reading is not
62
+ - Navigate the top-level page away from the session. The page your surface sits in stays put, which is why an outbound link opens in a new tab rather than in place
63
+ - Capture the screen, or detect whether the participant is idle
64
+ - Reach USB, serial, HID, Bluetooth, or MIDI devices
65
+ - Use the Payment Request API, WebAuthn, or any other credential API
66
+ - Read motion, orientation, light, or pressure sensors, or enumerate local fonts
67
+ - Submit a form to another origin. `form-action 'self'` confines submission to your own origin, just as `connect-src` confines `fetch`
68
+
69
+ Nothing here needs declaring. If your UI needs something on the second list, it belongs in an endpoint or the engine, not in the frame.
70
+
71
+ ## Being granted a capability is not the same as having it
72
+
73
+ The list above is what the host grants. What the browser on a participant's device actually implements is a separate question, and the two do not always meet:
74
+
75
+ - Printing, downloads, fullscreen, and autoplay are broadly supported
76
+ - Multi-screen window placement and speaker selection are Chromium-only
77
+ - Clipboard writing is granted as a Permissions Policy feature in Chromium, while Safari and Firefox instead require the write to happen inside a user gesture
78
+
79
+ The pattern that works everywhere is to call `navigator.clipboard.writeText()` directly inside a click handler, never after an `await` or in a timeout, and to feature-detect anything beyond the broadly supported four. Participants join on their own devices, iPads included, so treat an unsupported capability as a normal case and give the participant another way through.
80
+
81
+ One thing to keep in mind about `alert()`, `confirm()`, and `prompt()`: they work, but they block the surface that raises one until it is dismissed. In a live facilitated session that is usually the wrong choice. Prefer an in-page dialog.
82
+
83
+ ## Content types are not sniffed
84
+
85
+ Alongside the policy, the asset host sends `X-Content-Type-Options: nosniff` on every response. The browser will not guess an asset's type from its bytes: a script must arrive as JavaScript, a stylesheet as CSS. An asset served with a missing or wrong `Content-Type` is refused rather than loaded. The dev server mirrors this header too, so a build that leans on MIME sniffing fails on localhost instead of only in production.
86
+
87
+ ## What to do
88
+
89
+ - Bundle every asset into your build so it resolves to `'self'`: fonts, icons, CSS, images, and scripts
90
+ - Self-host fonts: import an `@fontsource` package, or drop `.woff2` files in your UI directory and reference them with a relative path. The example games use `@fontsource-variable/work-sans` and `@fontsource-variable/roboto-mono`, both bundled at build time
91
+ - Use the `asset:`, `shared:`, and `blob:` scheme for files: it resolves to runtime-served URLs on the asset host (see [File handling](./file-handling.md))
92
+ - Embed video through YouTube (standard or no-cookie); other frame sources are blocked
93
+ - Route any outbound network call through an engine, an endpoint, or a host capability rather than fetching from the UI (see [LLM integration](./llm-integration.md) and [Endpoints](./endpoints.md))
94
+
95
+ ## What to avoid
96
+
97
+ - Loading fonts, CSS, or scripts from a third-party CDN (Google Fonts, jsDelivr, unpkg). These are blocked: bundle them instead
98
+ - Web workers created from a `blob:` URL. There is no `worker-src`, so a blob worker falls back to `script-src 'self' 'unsafe-inline'` and is blocked. Configure libraries that spin up workers (PDF.js, transformers.js, ONNX runtime, and others) to load a bundled worker file, or avoid them
99
+ - `eval` and `new Function`: `unsafe-eval` is not granted, so runtime code evaluation fails
100
+ - `fetch` or `XMLHttpRequest` to any third-party origin: `connect-src 'self'` allows the asset host only
101
+ - Relying on CSP nonces or hashes: none are issued, so do not build around them
102
+
103
+ ## How the dev server helps
104
+
105
+ The dev server serves your game UIs under the same policy, and sets the same limits on the iframe itself, so violations surface on localhost instead of in production. The single deliberate difference is `connect-src`, which is widened to allow the Vite hot-reload websocket so development still works. Everything else matches production exactly.
106
+
107
+ This matters most for the frame limits. The dev server serves your UI from its own origin, on a port of its own, just as production serves it from the asset host. A cross-origin frame is denied capabilities like clipboard access and fullscreen unless the host grants them explicitly, so the dev server grants exactly what production does: a copy button or a fullscreen toggle that works locally works in a live session too.
108
+
109
+ It also means your UI cannot reach the dev server's own API, only the host messages. Code that fetches `/api/...` directly fails in the dev server exactly as it would in production, where no runtime allows it.
110
+
111
+ If you see a CSP violation in the dev server console, fix it there: it would otherwise have reached production unnoticed.
112
+
113
+ ## Beyond the frame: writes and logic
114
+
115
+ Three more rules hold in production, and the dev server enforces each of them the same way. A fourth is a habit rather than a check:
116
+
117
+ - **A UI writes only what it declares.** A game or waiting room UI's `setData` may change only the capabilities in its `writes`. Anything else, including a `deletes` path into a capability it only reads, is refused as `denied` and nothing of the write lands. The host decides which UI sent a write; the page cannot claim to be another
118
+ - **A UI never retries on its own.** A production host may lose a race with a tick and retries the write itself before reporting `conflict`. When a `conflict` reaches your UI the host has given up, so show it and offer a 'Try again' button (`failure.retry` from `useMutationReporter`) rather than re-sending automatically. The dev server serialises writes, so it produces a `conflict` only when you arm one with `sdk fault conflict`
119
+ - **Game logic cannot import Node built-ins.** Engine, hook, validator, endpoint and tick controller logic runs on the ECMAScript intrinsics alone, with no `require`. An import of `node:fs`, `crypto`, `path` or any other built-in fails `sdk build`, `sdk dev` and `tick` with `LOGIC_NODE_BUILTIN`, naming the file and the import (see [the language environment](./engine.md#the-language-environment-your-logic-runs-in))
120
+ - **Game logic reads the time from `meta.now`, never `Date.now()`.** A production runtime may run one tick more than once and keeps only the last run, so a clock read in logic differs between the runs. `meta.now` is the instant the operation started, the same for every call in it and for a re-run of it (see [the time](./engine.md#the-time)). Derive randomness from `meta.seed` for the same reason
121
+
122
+ ## A note on caching
123
+
124
+ Published bundles are cached as immutable for a year, so cache-busting comes from publishing a fresh version, never from editing files in place. Always ship a new version rather than mutating a deployed bundle.
125
+
126
+ ## Related
127
+
128
+ - [Building user interfaces](./ui.md)
129
+ - [File handling (blobs)](./file-handling.md)
130
+ - [LLM integration](./llm-integration.md)
@@ -0,0 +1,143 @@
1
+ # Building a scenario editor
2
+
3
+ The `scenario_editor` slot holds the screen people use to build new scenarios for a released game, without rebuilding it. It works at any time, with no session, and what it produces is a lasting scenario. This guide covers creating one, what it may and may not do, and when you need one at all.
4
+
5
+ ## What you'll learn
6
+
7
+ - What the scenario editor is for, and how it differs from setup
8
+ - When a game needs one, and when descriptive settings schemas are enough
9
+ - How to create an editor and choose the settings it edits
10
+ - Which endpoints the editor may call, and what they receive
11
+ - How saving works in a hosted runtime and in the dev server
12
+
13
+ ## What the scenario editor is
14
+
15
+ A game holds at most one scenario editor, at `scenario_editor/`. It is a slot, like `session` or `setup`, so it carries no name of its own: the slot is its identifier.
16
+
17
+ | Aspect | Setup | Scenario editor |
18
+ | -------------------- | --------------------------------------- | ---------------------------- |
19
+ | **When shown** | When a session is created | At any time, with no session |
20
+ | **What it does** | A short form for this session | Authoring a lasting scenario |
21
+ | **Output** | Session overrides for this session only | A saved scenario |
22
+ | **Save as scenario** | Never offered | Offered by the host |
23
+ | **Guide** | [Setup](./setup.md) | This page |
24
+
25
+ The host offers save-as-scenario from the scenario editor only, never from setup. Setup changes one session; the editor is where reusable work happens, so there is room for a richer flow here: several steps, previews, uploaded media, an assistant behind an endpoint.
26
+
27
+ ## Do you need one?
28
+
29
+ The editor is optional. What switches custom scenarios on is one declaration in `seriousgaming.sdk.json`:
30
+
31
+ ```json
32
+ {
33
+ "customScenarios": { "supported": true }
34
+ }
35
+ ```
36
+
37
+ With it, a hosted runtime persists scenarios authored for the game and lists them beside its built-in ones. Without an editor, a scenario can still be authored: by a facilitator in the runtime's own generic form, or by an AI agent working from the settings schemas. That only works if the schemas say what each value means, so describe every setting:
38
+
39
+ - `title` and `description`: what the value is and what changing it does
40
+ - Units in the description or title ('in pounds', 'per tick', 'as a fraction of revenue')
41
+ - `minimum` and `maximum` (or `exclusiveMinimum` and `exclusiveMaximum`) for ranges
42
+ - `enum` for a closed set of choices
43
+
44
+ ```json
45
+ "BaseDemand": {
46
+ "type": "number",
47
+ "title": "Base demand",
48
+ "description": "Units customers would buy each tick at a price of zero",
49
+ "minimum": 0,
50
+ "maximum": 100000,
51
+ "default": 10000
52
+ }
53
+ ```
54
+
55
+ Once facilitators have saved scenarios, a release can leave them behind. When you remove, rename, or reshape a setting, change what a value means, or change how the game loads scenario assets, bump `scenarioFormat` in `seriousgaming.sdk.json` (it starts at 1), and a runtime refuses the older scenarios rather than applying them wrongly. A new setting with a default needs no bump. See [Scenario format: when to bump it](./scenarios.md#scenario-format-when-to-bump-it).
56
+
57
+ Build an editor when a form is not enough: values that only make sense together, uploaded assets, a preview of what participants will see, or guidance a facilitator needs while choosing.
58
+
59
+ ## Creating a scenario editor
60
+
61
+ ```bash
62
+ pnpm run sdk new scenario_editor '{
63
+ "definition": {
64
+ "configures": ["engine", "ui"]
65
+ },
66
+ "rootDirectory": ".",
67
+ "ui": { "entrypoint": "index.html" }
68
+ }'
69
+ ```
70
+
71
+ `configures` names the [settings resources](./settings.md) the editor edits, by identifier. It receives the resolved values of exactly those settings and can change nothing else (an `updateSettings` call naming any other settings resource is refused, and none of it is applied), and the build fails if you name a settings resource the package does not declare. Settings the editor does not configure keep the values the scenario starts from. List `game` to let the editor set the scenario's number of rounds and team settings, which it saves under the scenario's `settings.game` (see [The game settings](./settings.md#the-game-settings)). An edit that changes a setting the game locks with `readOnly`, or sets a value outside its schema's range, is refused the same way, and the draft keeps none of it. The editor is sent values, not schemas, so show a locked field as read-only, as the factory example's editor does (see [Lock a setting](./settings.md#lock-a-setting)).
72
+
73
+ ```
74
+ scenario_editor/
75
+ ├── scenario_editor.sdk.json
76
+ ├── index.html
77
+ ├── types.ts # generated
78
+ ├── defaults.ts # generated
79
+ └── src/
80
+ ├── main.tsx
81
+ ├── App.tsx
82
+ ├── i18n.ts
83
+ └── theme.ts
84
+ ```
85
+
86
+ ## Building the editor
87
+
88
+ The editor uses the same wrapper and hooks as setup: `SettingsEditorWrapper` in `src/main.tsx`, and `useSettingsEditor()` for `{ settings, updateSettings, configures }`. The generated `Settings` and `defaultSettings` are keyed by settings identifier. The [setup guide](./setup.md#building-the-form) shows a form; everything there applies here.
89
+
90
+ Two differences:
91
+
92
+ - **No `requestPlay`.** There may be no session to start. The callback exists on `useSettingsEditorCallbacks()`, because one wrapper serves both slots, but the host ignores it from the editor
93
+ - **No save button of your own.** The host owns saving: it supplies the name, decides where the scenario is stored, and offers the action in its own chrome. The editor only edits values
94
+
95
+ `useSettingsEditorCallbacks()` also gives `uploadBlob`, `getAssetUrl`, `readAsset`, and the `endpoints` the bundle declares. An uploaded `blob:` reference stored in a setting travels with the saved scenario.
96
+
97
+ ## Calling endpoints
98
+
99
+ The editor has no session, so an endpoint it lists must be session-scoped and declare no `reads`, `writes` or `actions`: there is no game state for it to read, change or act on. The build refuses one that does with `EDITOR_ENDPOINT_STATEFUL`, pointing at the entry in `endpoints`. To use one that needs game state elsewhere, give the editor an endpoint of its own.
100
+
101
+ What such an endpoint receives is its declared `settings`, resolved from the scenario being edited with the editor's unsaved changes over it, so it sees the draft without the editor sending the values in the request. `context` and `participants` are empty, `session` has played nothing and holds no teams, and `caller` is `{ role: 'author', userInterfaceIdentifier: 'scenario_editor' }`, with no `sessionId`. The person editing a scenario may not be a facilitator, so the editor's calls never report `'facilitator'`. See [Calls from the scenario editor](./endpoints.md#calls-from-the-scenario-editor).
102
+
103
+ ```json
104
+ {
105
+ "definition": {
106
+ "scope": "session",
107
+ "settings": ["engine", "ui"],
108
+ "uses": ["generateText"],
109
+ "requestSchema": { "type": "object", "properties": {}, "additionalProperties": false },
110
+ "responseSchema": { "type": "object", "properties": {}, "additionalProperties": false }
111
+ }
112
+ }
113
+ ```
114
+
115
+ ## Dev server behaviour
116
+
117
+ The dev drawer's **Scenario** tab opens the editor: **Add scenario** creates a scenario and opens the editor on it, and **Edit** opens it on an existing one. It runs on `/scenario-editor`, always on one scenario, in a new tab.
118
+
119
+ What you edit there is a draft of that scenario, which the dev server keeps apart from its session. The session running beside the editor stays on the scenario it was on, and an edit changes none of its settings, now or when it starts play. Endpoints the editor calls read the draft. Each scenario open in an editor has its own draft, and reloading the editor's tab keeps it.
120
+
121
+ **Save** in the page's toolbar writes the draft into `scenarios/<identifier>/scenario.sdk.json`, materialising any `blob:` references as files under the scenario's `assets/shared/`. It replaces the scenario's `settings` and nothing else, so its names, descriptions and other fields stay as you wrote them. A session sees the values once it is started on that scenario. That is author-time work in your own source tree; a hosted runtime saves to its own store instead. See [Save as a scenario](./scenarios.md#save-as-a-scenario-dev-server).
122
+
123
+ ## Managing the slot
124
+
125
+ ```bash
126
+ pnpm run sdk update scenario_editor '{
127
+ "definition": { "configures": ["engine"] },
128
+ "rootDirectory": ".",
129
+ "ui": { "entrypoint": "index.html" }
130
+ }'
131
+ pnpm run sdk delete scenario_editor
132
+ ```
133
+
134
+ ## Testing
135
+
136
+ `renderSettingsEditor` from `@seriousgaming/sdk/ui/testing` renders a component inside every settings editor provider, as for setup. Start from `defaultSettings` and override what the screen under test reads.
137
+
138
+ ## See also
139
+
140
+ - [Setup](./setup.md): the short form at session creation
141
+ - [Scenarios](./scenarios.md): built-in and custom scenarios
142
+ - [Settings](./settings.md): declaring settings, and describing them well
143
+ - [Create a scenario editor](../recipes/create-scenario-editor.md)