@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,42 @@
1
+ /**
2
+ * What each kind of surface is, in protocol terms.
3
+ *
4
+ * §12.6 fixes the set of messages a surface must receive before it may paint.
5
+ * Holding that as a table rather than as four near-identical components is what
6
+ * makes a new surface kind an entry here instead of a new host implementation.
7
+ */
8
+ /**
9
+ * A surface the host can mount, named by what the specification calls it.
10
+ *
11
+ * `game` and `waiting-room` are both **player** surfaces (§6.14): a waiting room
12
+ * is a player UI in a different display context, not a reduced one, so every
13
+ * gate that asks 'is this a player surface?' admits both.
14
+ */
15
+ export type SurfaceKind = 'game' | 'session' | 'setup' | 'scenario-editor' | 'waiting-room' | 'presentation';
16
+ export interface SurfaceDescriptor {
17
+ /**
18
+ * Messages that must all arrive before the guest paints (§12.6). The guest
19
+ * enforces this for itself; the host carries the list so it can fail loudly
20
+ * when an embedder builds an incomplete initial batch, rather than leaving
21
+ * the frame stuck on its loading state with nothing to say why.
22
+ */
23
+ readonly required: readonly string[];
24
+ /**
25
+ * Messages the host sends in the initial batch that do not block painting.
26
+ * Listed so `initialBatch` can order them after the required ones.
27
+ */
28
+ readonly alsoSent: readonly string[];
29
+ /** True for the player surfaces: game and waiting room (§6.14). */
30
+ readonly isPlayerSurface: boolean;
31
+ }
32
+ export declare const SURFACES: Record<SurfaceKind, SurfaceDescriptor>;
33
+ /**
34
+ * An observer render receives no `setParticipant` (§13.3): the wrapper opens on
35
+ * `setViewerRole: 'observer'` instead, so the surface still paints with a null
36
+ * participant. Only the player surfaces have an observer render at all.
37
+ */
38
+ export declare function requiredMessagesFor(surface: SurfaceKind, options?: {
39
+ observer?: boolean;
40
+ }): readonly string[];
41
+ /** True for the surfaces a participant sits in front of (§6.14). */
42
+ export declare function isPlayerSurface(surface: SurfaceKind): boolean;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The `contrastText` every theme colour carries (§12.3).
3
+ *
4
+ * A host sends a text colour for each palette colour, meeting WCAG AA (4.5:1)
5
+ * against it, so a game drawing text on a theme colour need not work one out.
6
+ * Black or white always reaches at least 4.58:1 against any opaque colour, so
7
+ * the requirement can always be met, and an author's own choice is kept when
8
+ * it meets it too.
9
+ *
10
+ * Platform-facing: exported from
11
+ * `@seriousgaming/sdk-tools/host`.
12
+ */
13
+ import type { ThemeColorRole, ThemeContrastText, UserInterfaceTheme } from '@seriousgaming/sdk/ui';
14
+ /** The roles a theme sends, in the order §12.3 lists them. */
15
+ export declare const THEME_COLOR_ROLES: readonly ThemeColorRole[];
16
+ /** The WCAG AA minimum for normal text. */
17
+ export declare const AA_CONTRAST = 4.5;
18
+ interface Rgba {
19
+ r: number;
20
+ g: number;
21
+ b: number;
22
+ a: number;
23
+ }
24
+ /** Read a CSS hex or `rgb()` / `rgba()` colour, or null for anything else. */
25
+ export declare function parseColour(value: string): Rgba | null;
26
+ /** WCAG 2 relative luminance of an opaque colour. */
27
+ export declare function relativeLuminance({ r, g, b }: Rgba): number;
28
+ /** WCAG 2 contrast ratio between two opaque colours, from 1 to 21. */
29
+ export declare function contrastRatio(a: Rgba, b: Rgba): number;
30
+ /**
31
+ * The text colour to draw on `colour`, as an opaque `#rrggbb`.
32
+ *
33
+ * `preferred` is an author's choice, kept (made opaque by painting it over
34
+ * the colour, as the browser would) when it meets AA; otherwise black or
35
+ * white, whichever contrasts more. A translucent colour is measured as drawn
36
+ * on white. A colour that is neither hex nor `rgb()` cannot be measured, and
37
+ * gets black.
38
+ */
39
+ export declare function contrastTextFor(colour: string, preferred?: string): string;
40
+ /** One mode's colours before a host has given them their text colours. */
41
+ export type ModeColoursInput = Record<ThemeColorRole, string> & {
42
+ contrastText?: Partial<ThemeContrastText>;
43
+ };
44
+ /** A theme before a host has given its colours their text colours. */
45
+ export interface ThemeInput {
46
+ mode: 'light' | 'dark';
47
+ light: ModeColoursInput;
48
+ dark: ModeColoursInput;
49
+ }
50
+ /**
51
+ * The `setTheme` payload for a theme: every colour of both modes given its
52
+ * `contrastText`, keeping any the author supplied that meet AA.
53
+ */
54
+ export declare function withContrastText(theme: ThemeInput): UserInterfaceTheme;
55
+ export {};
package/dist/host.js ADDED
@@ -0,0 +1,583 @@
1
+ // cli/host/protocol.ts
2
+ var UI_PROTOCOL_VERSION = 4;
3
+
4
+ // cli/host/surfaces.ts
5
+ var SURFACES = {
6
+ game: {
7
+ required: [
8
+ "stateChanged",
9
+ "setSettings",
10
+ "setTheme",
11
+ "setLocale",
12
+ "setAssetUrls",
13
+ "setParticipant"
14
+ ],
15
+ alsoSent: [
16
+ "setTimer",
17
+ "setViewerRole",
18
+ "setOwnTeam",
19
+ "setOwnTeamJoinLink",
20
+ "setParticipantList",
21
+ "setTeamList",
22
+ "setRunKind",
23
+ "setRoundProcessing",
24
+ "setCrossTeamData",
25
+ "themePreferenceChanged"
26
+ ],
27
+ isPlayerSurface: true
28
+ },
29
+ "waiting-room": {
30
+ required: [
31
+ "stateChanged",
32
+ "setSettings",
33
+ "setTheme",
34
+ "setLocale",
35
+ "setAssetUrls",
36
+ "setParticipant"
37
+ ],
38
+ alsoSent: [
39
+ "setTimer",
40
+ "setViewerRole",
41
+ "setOwnTeam",
42
+ "setOwnTeamJoinLink",
43
+ "setParticipantList",
44
+ "setTeamList",
45
+ "setRunKind",
46
+ "setCrossTeamData",
47
+ "themePreferenceChanged"
48
+ ],
49
+ isPlayerSurface: true
50
+ },
51
+ session: {
52
+ required: [
53
+ "setSessionMeta",
54
+ "setSessionData",
55
+ "setSettings",
56
+ "setTheme",
57
+ "setLocale",
58
+ "setAssetUrls",
59
+ "setTeamConfiguration"
60
+ ],
61
+ alsoSent: [
62
+ "setTeamList",
63
+ "setParticipantList",
64
+ "setTeamLinks",
65
+ "setAvailableOverlays",
66
+ "setRunKind",
67
+ "setWalkthroughLink",
68
+ "themePreferenceChanged"
69
+ ],
70
+ isPlayerSurface: false
71
+ },
72
+ presentation: {
73
+ // `setPresentation` carries a `null` session when there is none, so a
74
+ // presentation is the one surface a host can mount without one.
75
+ required: ["setPresentation", "setSettings", "setTheme", "setLocale", "setAssetUrls"],
76
+ alsoSent: ["themePreferenceChanged"],
77
+ isPlayerSurface: false
78
+ },
79
+ // The two settings editors (§6.5) share a wrapper and a batch. Neither is
80
+ // told which slot it is: each is its own bundle, so it knows.
81
+ setup: {
82
+ required: ["setSettings", "setTheme", "setLocale", "setAssetUrls"],
83
+ alsoSent: ["themePreferenceChanged"],
84
+ isPlayerSurface: false
85
+ },
86
+ "scenario-editor": {
87
+ required: ["setSettings", "setTheme", "setLocale", "setAssetUrls"],
88
+ alsoSent: ["themePreferenceChanged"],
89
+ isPlayerSurface: false
90
+ }
91
+ };
92
+ function requiredMessagesFor(surface, options = {}) {
93
+ const { required, isPlayerSurface: isPlayerSurface2 } = SURFACES[surface];
94
+ if (!options.observer || !isPlayerSurface2) return required;
95
+ return required.filter((type) => type !== "setParticipant");
96
+ }
97
+ function isPlayerSurface(surface) {
98
+ return SURFACES[surface].isPlayerSurface;
99
+ }
100
+
101
+ // cli/host/host-channel.ts
102
+ var ADAPTER_REQUESTS = /* @__PURE__ */ new Set([
103
+ "callEndpoint",
104
+ "uploadBlob",
105
+ "getPastState",
106
+ "getAllTeamsParticipants"
107
+ ]);
108
+ var HostChannel = class {
109
+ options;
110
+ host;
111
+ logger;
112
+ port = null;
113
+ readyListener = null;
114
+ loadListener = null;
115
+ handshakeTimer = null;
116
+ disposed = false;
117
+ /**
118
+ * Last payload sent per message type, serialised.
119
+ *
120
+ * `setState` compares against this so an unchanged slice is not re-pushed.
121
+ * At a large cohort the session payload is the thing that grows, and
122
+ * re-sending a whole snapshot because one team's tick moved is the cost
123
+ * §12.4.2 warns about.
124
+ */
125
+ lastSent = /* @__PURE__ */ new Map();
126
+ /**
127
+ * The last value of each state message, in the order the types were first
128
+ * sent, replayed whole on every reconnect (§12.7 step 3).
129
+ *
130
+ * A reloading frame has seen nothing, and the embedder has no reason to
131
+ * push again: its state has not changed, only the frame under it. Without
132
+ * this the guest re-handshakes into silence and blocks its first paint for
133
+ * good, which is what a surface fixed after a crash used to do (#564).
134
+ *
135
+ * Only the state slices are kept. A one-shot the host sent once, such as a
136
+ * validator's refusal or an asset-auth request, belongs to the moment it
137
+ * happened, and replaying it would show the new frame a rejection of a
138
+ * submission it never made.
139
+ */
140
+ sticky = /* @__PURE__ */ new Map();
141
+ /** One-shot messages queued until the handshake completes, flushed in order. */
142
+ outbound = [];
143
+ /** In-flight host → guest requests, keyed by `requestId`. */
144
+ pending = /* @__PURE__ */ new Map();
145
+ requestCounter = 0;
146
+ constructor(options) {
147
+ this.options = options;
148
+ this.host = options.window ?? globalThis.window;
149
+ this.logger = options.logger ?? console;
150
+ this.listenForReady();
151
+ }
152
+ /** True once the guest has handshaked and the port is open. */
153
+ get connected() {
154
+ return this.port !== null;
155
+ }
156
+ // -----------------------------------------------------------------------
157
+ // Sending
158
+ // -----------------------------------------------------------------------
159
+ /**
160
+ * Push one message, queueing it until the handshake completes.
161
+ *
162
+ * Queueing rather than dropping is what lets an embedder build the initial
163
+ * batch as soon as it mounts the frame, without racing the guest's `ready`.
164
+ */
165
+ send(message) {
166
+ if (this.disposed) return;
167
+ this.lastSent.set(message.type, stableStringify(message));
168
+ if (this.port) this.port.postMessage(message);
169
+ else this.outbound.push(message);
170
+ }
171
+ /**
172
+ * Push a state slice: delivered now if the guest is listening, and kept so
173
+ * a frame that reloads is told the same thing again.
174
+ */
175
+ sendState(message) {
176
+ if (this.disposed) return;
177
+ this.sticky.set(message.type, message);
178
+ this.lastSent.set(message.type, stableStringify(message));
179
+ this.port?.postMessage(message);
180
+ }
181
+ /**
182
+ * Push a message only when its payload differs from the last one sent of
183
+ * that type. Returns true when it went out.
184
+ */
185
+ sendIfChanged(message) {
186
+ if (this.disposed) return false;
187
+ if (this.lastSent.get(message.type) === stableStringify(message)) return false;
188
+ this.sendState(message);
189
+ return true;
190
+ }
191
+ /**
192
+ * Send the initial batch (§12.6), verifying it carries every message the
193
+ * surface blocks its first paint on.
194
+ *
195
+ * The guest enforces the same list for itself by simply not painting. That
196
+ * failure mode is a frame stuck on its loading state with nothing to say
197
+ * why, which is a bad afternoon; failing here names the missing message.
198
+ */
199
+ sendInitialBatch(messages) {
200
+ const required = requiredMessagesFor(this.options.surface, {
201
+ observer: this.options.observer
202
+ });
203
+ const supplied = new Set(messages.map((message) => message.type));
204
+ const missing = required.filter((type) => !supplied.has(type));
205
+ if (missing.length > 0) {
206
+ throw new Error(
207
+ `Initial batch for a "${this.options.surface}" surface is missing ${missing.join(", ")}. The guest blocks its first paint on ${required.join(", ")}.`
208
+ );
209
+ }
210
+ for (const message of messages) this.sendState(message);
211
+ }
212
+ /**
213
+ * Send a request the guest answers, resolving when it does.
214
+ *
215
+ * Only `refreshAssetAuth` uses this today (§16.4): the host hands the frame
216
+ * a token and the frame reports back whether redeeming it worked.
217
+ */
218
+ request(message, timeoutMs = 3e4) {
219
+ const requestId = `host-${++this.requestCounter}`;
220
+ return new Promise((resolve, reject) => {
221
+ const timer = setTimeout(() => {
222
+ this.pending.delete(requestId);
223
+ reject(new Error(`Guest did not answer "${message.type}" in ${timeoutMs}ms`));
224
+ }, timeoutMs);
225
+ this.pending.set(requestId, {
226
+ resolve: () => {
227
+ clearTimeout(timer);
228
+ resolve();
229
+ },
230
+ reject: (error) => {
231
+ clearTimeout(timer);
232
+ reject(error);
233
+ }
234
+ });
235
+ this.send({ ...message, requestId });
236
+ });
237
+ }
238
+ dispose() {
239
+ if (this.disposed) return;
240
+ this.disposed = true;
241
+ this.clearHandshakeTimer();
242
+ if (this.readyListener) {
243
+ this.host.removeEventListener("message", this.readyListener);
244
+ this.readyListener = null;
245
+ }
246
+ if (this.loadListener) {
247
+ this.options.iframe.removeEventListener?.("load", this.loadListener);
248
+ this.loadListener = null;
249
+ }
250
+ this.closePort();
251
+ this.rejectPending("Channel disposed");
252
+ this.options.onTeardown?.("disposed");
253
+ }
254
+ // -----------------------------------------------------------------------
255
+ // Handshake
256
+ // -----------------------------------------------------------------------
257
+ listenForReady() {
258
+ const listener = (event) => {
259
+ if (this.disposed) return;
260
+ const data = event.data;
261
+ if (!data || data.type !== "ready") return;
262
+ if (event.source !== this.options.iframe.contentWindow) return;
263
+ if (event.origin !== this.options.iframeOrigin) {
264
+ this.logger.warn(
265
+ `[${this.options.uiIdentifier}] ignoring a handshake from ${event.origin}; this frame is pinned to ${this.options.iframeOrigin}`
266
+ );
267
+ return;
268
+ }
269
+ const peerVersion = data.protocolVersion;
270
+ if (typeof peerVersion === "number" && peerVersion !== UI_PROTOCOL_VERSION) {
271
+ this.logger.warn(
272
+ `[${this.options.uiIdentifier}] host\u2194iframe protocol version mismatch: iframe ${peerVersion}, host ${UI_PROTOCOL_VERSION}`
273
+ );
274
+ }
275
+ this.connect();
276
+ };
277
+ this.readyListener = listener;
278
+ this.host.addEventListener("message", listener);
279
+ this.armHandshakeTimer();
280
+ this.listenForLoads();
281
+ }
282
+ /**
283
+ * Bound every document the frame loads, not only the first.
284
+ *
285
+ * A frame that connected and then replaced its own document leaves the
286
+ * host holding a port nobody answers, so `connected` alone proves nothing.
287
+ * A document's `ready` may land either side of its `load`, so a live port
288
+ * is pinged as well: a `pong` shows the document that handshaked is still
289
+ * the one in the frame, and a fresh `ready` shows a reload.
290
+ */
291
+ listenForLoads() {
292
+ const { iframe } = this.options;
293
+ if (!iframe.addEventListener) return;
294
+ const listener = () => {
295
+ if (this.disposed) return;
296
+ this.armHandshakeTimer();
297
+ this.port?.postMessage({ type: "ping" });
298
+ };
299
+ this.loadListener = listener;
300
+ iframe.addEventListener("load", listener);
301
+ }
302
+ armHandshakeTimer() {
303
+ this.clearHandshakeTimer();
304
+ const timeoutMs = this.options.handshakeTimeoutMs ?? 1e4;
305
+ this.handshakeTimer = setTimeout(() => {
306
+ this.handshakeTimer = null;
307
+ if (this.disposed) return;
308
+ this.closePort();
309
+ this.options.onTeardown?.("handshake-timeout");
310
+ }, timeoutMs);
311
+ }
312
+ /**
313
+ * Open a fresh port and hand the guest its end.
314
+ *
315
+ * Runs on every `ready`, not only the first: a reload or HMR re-announces,
316
+ * and §12.7 requires the old port closed, a new channel created, and the
317
+ * whole initial batch re-sent rather than the live port re-identified.
318
+ */
319
+ connect() {
320
+ this.closePort();
321
+ this.rejectPending("Connection reset");
322
+ this.lastSent.clear();
323
+ const replay = [...this.sticky.values()];
324
+ const channel = new MessageChannel();
325
+ this.port = channel.port1;
326
+ this.port.onmessage = (event) => this.receive(event.data);
327
+ this.port.start();
328
+ this.clearHandshakeTimer();
329
+ this.options.iframe.contentWindow?.postMessage(
330
+ {
331
+ type: "init",
332
+ protocolVersion: UI_PROTOCOL_VERSION,
333
+ sessionKey: this.options.sessionKey
334
+ },
335
+ this.options.iframeOrigin,
336
+ [channel.port2]
337
+ );
338
+ for (const message of replay) this.sendState(message);
339
+ const queued = this.outbound;
340
+ this.outbound = [];
341
+ for (const message of queued) this.port.postMessage(message);
342
+ this.options.onConnect?.();
343
+ }
344
+ closePort() {
345
+ if (!this.port) return;
346
+ this.port.onmessage = null;
347
+ this.port.close();
348
+ this.port = null;
349
+ }
350
+ clearHandshakeTimer() {
351
+ if (this.handshakeTimer === null) return;
352
+ clearTimeout(this.handshakeTimer);
353
+ this.handshakeTimer = null;
354
+ }
355
+ rejectPending(reason) {
356
+ for (const { reject } of this.pending.values()) reject(new Error(reason));
357
+ this.pending.clear();
358
+ }
359
+ // -----------------------------------------------------------------------
360
+ // Receiving
361
+ // -----------------------------------------------------------------------
362
+ receive(message) {
363
+ if (!message || typeof message.type !== "string") return;
364
+ switch (message.type) {
365
+ case "pong":
366
+ this.clearHandshakeTimer();
367
+ return;
368
+ case "refreshAssetAuth:response": {
369
+ const { requestId, ok, error } = message;
370
+ if (typeof requestId !== "string") return;
371
+ const waiting = this.pending.get(requestId);
372
+ this.pending.delete(requestId);
373
+ if (ok) waiting?.resolve();
374
+ else waiting?.reject(new Error(error ?? "Asset auth refresh failed"));
375
+ return;
376
+ }
377
+ }
378
+ if (ADAPTER_REQUESTS.has(message.type)) {
379
+ void this.answer(message);
380
+ return;
381
+ }
382
+ this.options.onMessage?.(message);
383
+ }
384
+ /**
385
+ * Run one guest request against the adapter and frame the answer.
386
+ *
387
+ * A throwing adapter becomes an `ok: false` response on the same
388
+ * `requestId`, never an unhandled rejection and never a dropped request:
389
+ * the guest's promise has to settle either way or the surface waits forever.
390
+ */
391
+ async answer(message) {
392
+ const requestId = message.requestId;
393
+ if (typeof requestId !== "string") {
394
+ this.logger.warn(
395
+ `[${this.options.uiIdentifier}] dropped a "${message.type}" with no requestId`
396
+ );
397
+ return;
398
+ }
399
+ const responseType = `${message.type}:response`;
400
+ try {
401
+ const result = await this.dispatch(message);
402
+ this.send({ type: responseType, requestId, ok: true, ...result });
403
+ } catch (error) {
404
+ this.send(
405
+ message.type === "callEndpoint" ? { type: responseType, requestId, ok: false, ...endpointFailureOf(error) } : {
406
+ type: responseType,
407
+ requestId,
408
+ ok: false,
409
+ error: error instanceof Error ? error.message : String(error)
410
+ }
411
+ );
412
+ }
413
+ }
414
+ /** Route one request to its adapter method and shape the success payload. */
415
+ async dispatch(message) {
416
+ const adapter = this.options.adapter;
417
+ const origin = {
418
+ uiIdentifier: this.options.uiIdentifier,
419
+ ...this.options.origin
420
+ };
421
+ switch (message.type) {
422
+ case "callEndpoint": {
423
+ if (!adapter?.callEndpoint) throw new Error("This host serves no endpoints");
424
+ const response = await adapter.callEndpoint(
425
+ {
426
+ endpointIdentifier: String(message.endpointIdentifier),
427
+ request: message.request
428
+ },
429
+ origin
430
+ );
431
+ return { response };
432
+ }
433
+ case "uploadBlob": {
434
+ if (!adapter?.uploadBlob) throw new Error("This host stores no blobs");
435
+ const reference = await adapter.uploadBlob(
436
+ {
437
+ data: message.data,
438
+ name: String(message.name),
439
+ mimeType: String(message.mimeType)
440
+ },
441
+ origin
442
+ );
443
+ return { reference };
444
+ }
445
+ case "getPastState": {
446
+ if (!adapter?.getPastState) throw new Error("This host serves no past state");
447
+ const entries = await adapter.getPastState(
448
+ message.query,
449
+ origin
450
+ );
451
+ return { entries };
452
+ }
453
+ case "getAllTeamsParticipants": {
454
+ const participants = await adapter?.getAllTeamsParticipants?.(origin) ?? [];
455
+ return { participants };
456
+ }
457
+ default:
458
+ throw new Error(`Unroutable request "${message.type}"`);
459
+ }
460
+ }
461
+ };
462
+ function stableStringify(value) {
463
+ if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "undefined";
464
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
465
+ const entries = Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`);
466
+ return `{${entries.join(",")}}`;
467
+ }
468
+ function endpointFailureOf(error) {
469
+ const failure = typeof error === "object" && error !== null ? error.failure : void 0;
470
+ if (typeof failure === "object" && failure !== null && typeof failure.outcome?.kind === "string" && Array.isArray(failure.applied)) {
471
+ return failure;
472
+ }
473
+ return {
474
+ outcome: {
475
+ kind: "error",
476
+ message: error instanceof Error ? error.message : String(error)
477
+ },
478
+ applied: []
479
+ };
480
+ }
481
+
482
+ // cli/host/theme.ts
483
+ var THEME_COLOR_ROLES = [
484
+ "primary",
485
+ "secondary",
486
+ "success",
487
+ "error",
488
+ "warning",
489
+ "info"
490
+ ];
491
+ var AA_CONTRAST = 4.5;
492
+ function parseColour(value) {
493
+ const text = value.trim().toLowerCase();
494
+ const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(text);
495
+ if (hex) {
496
+ let digits = hex[1];
497
+ if (digits.length <= 4) digits = [...digits].map((digit) => digit + digit).join("");
498
+ const channel = (at) => parseInt(digits.slice(at, at + 2), 16);
499
+ return {
500
+ r: channel(0),
501
+ g: channel(2),
502
+ b: channel(4),
503
+ a: digits.length === 8 ? channel(6) / 255 : 1
504
+ };
505
+ }
506
+ const functional = /^rgba?\(([^)]*)\)$/.exec(text);
507
+ if (functional) {
508
+ const parts = functional[1].split(/[\s,/]+/).filter(Boolean);
509
+ if (parts.length !== 3 && parts.length !== 4) return null;
510
+ const [r, g, b] = parts.slice(0, 3).map(
511
+ (part) => part.endsWith("%") ? parseFloat(part) / 100 * 255 : parseFloat(part)
512
+ );
513
+ const alpha = parts[3];
514
+ const a = alpha === void 0 ? 1 : alpha.endsWith("%") ? parseFloat(alpha) / 100 : parseFloat(alpha);
515
+ if ([r, g, b, a].some((n) => !Number.isFinite(n))) return null;
516
+ return { r: clamp(r, 255), g: clamp(g, 255), b: clamp(b, 255), a: clamp(a, 1) };
517
+ }
518
+ return null;
519
+ }
520
+ function clamp(value, max) {
521
+ return Math.min(max, Math.max(0, value));
522
+ }
523
+ function composite(top, bottom) {
524
+ const mix = (over, under) => over * top.a + under * (1 - top.a);
525
+ return { r: mix(top.r, bottom.r), g: mix(top.g, bottom.g), b: mix(top.b, bottom.b), a: 1 };
526
+ }
527
+ function relativeLuminance({ r, g, b }) {
528
+ const linear = (channel) => {
529
+ const c = channel / 255;
530
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
531
+ };
532
+ return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
533
+ }
534
+ function contrastRatio(a, b) {
535
+ const [light, dark] = [relativeLuminance(a), relativeLuminance(b)].sort((x, y) => y - x);
536
+ return (light + 0.05) / (dark + 0.05);
537
+ }
538
+ function toHex({ r, g, b }) {
539
+ const byte = (n) => Math.round(n).toString(16).padStart(2, "0");
540
+ return `#${byte(r)}${byte(g)}${byte(b)}`;
541
+ }
542
+ var BLACK = { r: 0, g: 0, b: 0, a: 1 };
543
+ var WHITE = { r: 255, g: 255, b: 255, a: 1 };
544
+ function contrastTextFor(colour, preferred) {
545
+ const parsed = parseColour(colour);
546
+ if (!parsed) return toHex(BLACK);
547
+ const background = parsed.a < 1 ? composite(parsed, WHITE) : parsed;
548
+ const author = preferred === void 0 ? null : parseColour(preferred);
549
+ if (author) {
550
+ const painted = composite(author, background);
551
+ if (contrastRatio(painted, background) >= AA_CONTRAST) return toHex(painted);
552
+ }
553
+ return contrastRatio(BLACK, background) >= contrastRatio(WHITE, background) ? toHex(BLACK) : toHex(WHITE);
554
+ }
555
+ function modeWithContrast(colours) {
556
+ const contrastText = Object.fromEntries(
557
+ THEME_COLOR_ROLES.map((role) => [
558
+ role,
559
+ contrastTextFor(colours[role], colours.contrastText?.[role])
560
+ ])
561
+ );
562
+ const roles = Object.fromEntries(
563
+ THEME_COLOR_ROLES.map((role) => [role, colours[role]])
564
+ );
565
+ return { ...roles, contrastText };
566
+ }
567
+ function withContrastText(theme) {
568
+ return {
569
+ mode: theme.mode,
570
+ light: modeWithContrast(theme.light),
571
+ dark: modeWithContrast(theme.dark)
572
+ };
573
+ }
574
+ export {
575
+ HostChannel,
576
+ SURFACES,
577
+ THEME_COLOR_ROLES,
578
+ UI_PROTOCOL_VERSION,
579
+ contrastTextFor,
580
+ isPlayerSurface,
581
+ requiredMessagesFor,
582
+ withContrastText
583
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Public exports for the prompts module
3
+ * Provides interactive prompts for building JSON schema properties
4
+ */
5
+ export { promptForSchemaProperty, promptForSchemaProperties, editSchemaProperty, reviewSchemaProperties, } from './schema-builder.js';
6
+ export { validatePropertyName, validateNumberValue, validateMaximumValue, PASCAL_CASE_PATTERN, } from './validators.js';
7
+ export type { PropertySchema, NumberPropertyDefaults, StringPropertyDefaults, BooleanPropertyDefaults, PropertyContext, PromptPropertyOptions, PromptPropertiesOptions, EditPropertyOptions, EditPropertyResult, ReviewPropertiesOptions, ReviewPropertiesResult, } from './types.js';