@dreamboard-games/cli 0.1.30-alpha.1 → 0.1.30-alpha.3

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 (163) hide show
  1. package/README.md +179 -22
  2. package/dist/agent-verifier/agent-workspace-verifier.mjs +30 -30
  3. package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
  4. package/dist/agent-verifier/{chunk-JH22JNYD.mjs → chunk-3UKQVWLV.mjs} +82 -19
  5. package/dist/agent-verifier/chunk-3UKQVWLV.mjs.map +1 -0
  6. package/dist/agent-verifier/{chunk-4WD3YU2E.mjs → chunk-776W3UGV.mjs} +4 -3
  7. package/dist/agent-verifier/chunk-776W3UGV.mjs.map +1 -0
  8. package/dist/agent-verifier/{chunk-CJEEA6NJ.mjs → chunk-7WWGFAAU.mjs} +9 -10
  9. package/dist/agent-verifier/chunk-7WWGFAAU.mjs.map +1 -0
  10. package/dist/agent-verifier/{chunk-2SZHMP6F.mjs → chunk-A64ZZUZV.mjs} +6 -9
  11. package/dist/agent-verifier/chunk-A64ZZUZV.mjs.map +1 -0
  12. package/dist/agent-verifier/{chunk-6A5HRJMQ.mjs → chunk-E7SSWJXJ.mjs} +62 -99
  13. package/dist/agent-verifier/chunk-E7SSWJXJ.mjs.map +1 -0
  14. package/dist/agent-verifier/{chunk-2GBBP27W.mjs → chunk-F2DIOJJZ.mjs} +1 -0
  15. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
  16. package/dist/agent-verifier/{chunk-CFU5EWIC.mjs → chunk-G42BGGG2.mjs} +7 -6
  17. package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
  18. package/dist/agent-verifier/{chunk-SHUMAVAP.mjs → chunk-H76MT5UR.mjs} +7 -9
  19. package/dist/agent-verifier/chunk-H76MT5UR.mjs.map +1 -0
  20. package/dist/agent-verifier/{chunk-7E65UQLY.mjs → chunk-HGMUAL33.mjs} +3 -2
  21. package/dist/agent-verifier/chunk-HGMUAL33.mjs.map +1 -0
  22. package/dist/agent-verifier/{chunk-LM3OZLZG.mjs → chunk-IAYRNVUC.mjs} +1 -0
  23. package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
  24. package/dist/agent-verifier/{chunk-VYJTHSYR.mjs → chunk-JGT4P4UD.mjs} +2 -1
  25. package/dist/agent-verifier/chunk-JGT4P4UD.mjs.map +1 -0
  26. package/dist/agent-verifier/{chunk-CEDUHGNH.mjs → chunk-LUZ7KE6H.mjs} +8 -3
  27. package/dist/agent-verifier/chunk-LUZ7KE6H.mjs.map +1 -0
  28. package/dist/agent-verifier/{chunk-2E5P5NWG.mjs → chunk-NAK77WXW.mjs} +58 -126
  29. package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
  30. package/dist/agent-verifier/{chunk-SYPLYRGB.mjs → chunk-O4YCPU7C.mjs} +116 -15
  31. package/dist/agent-verifier/chunk-O4YCPU7C.mjs.map +1 -0
  32. package/dist/agent-verifier/{chunk-BVVNBJM4.mjs → chunk-S34FRJHS.mjs} +2 -1
  33. package/dist/agent-verifier/chunk-S34FRJHS.mjs.map +1 -0
  34. package/dist/agent-verifier/{chunk-HJFQDSTU.mjs → chunk-SH5JKYOB.mjs} +6 -5
  35. package/dist/agent-verifier/chunk-SH5JKYOB.mjs.map +1 -0
  36. package/dist/agent-verifier/chunk-SKI2ESE5.mjs +44 -0
  37. package/dist/agent-verifier/{chunk-MINCYHXN.mjs → chunk-TAEQKBJB.mjs} +1 -0
  38. package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
  39. package/dist/agent-verifier/{chunk-CEQ2VJWN.mjs → chunk-UIOLGH4A.mjs} +2 -1
  40. package/dist/agent-verifier/chunk-UIOLGH4A.mjs.map +1 -0
  41. package/dist/agent-verifier/chunk-UIZNWRM6.mjs +2432 -0
  42. package/dist/agent-verifier/chunk-UIZNWRM6.mjs.map +1 -0
  43. package/dist/agent-verifier/{chunk-2QMNAVV4.mjs → chunk-VS573ERH.mjs} +2 -1
  44. package/dist/agent-verifier/chunk-VS573ERH.mjs.map +1 -0
  45. package/dist/agent-verifier/{chunk-EOQIV6PS.mjs → chunk-W3N3QJ4V.mjs} +75 -100
  46. package/dist/agent-verifier/chunk-W3N3QJ4V.mjs.map +1 -0
  47. package/dist/agent-verifier/{chunk-EIQWDQWJ.mjs → chunk-XGWCY624.mjs} +11 -12
  48. package/dist/agent-verifier/chunk-XGWCY624.mjs.map +1 -0
  49. package/dist/agent-verifier/{chunk-7653FPGJ.mjs → chunk-XQXDOBYB.mjs} +3 -2
  50. package/dist/agent-verifier/chunk-XQXDOBYB.mjs.map +1 -0
  51. package/dist/agent-verifier/{chunk-MRCUP5SW.mjs → chunk-YE7UAO3T.mjs} +1 -0
  52. package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
  53. package/dist/agent-verifier/{chunk-RBDDIIPM.mjs → chunk-ZEELHSY3.mjs} +1 -0
  54. package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
  55. package/dist/agent-verifier/{compile-5QSPIOUT.mjs → compile-TEQVA46V.mjs} +24 -25
  56. package/dist/agent-verifier/compile-TEQVA46V.mjs.map +1 -0
  57. package/dist/agent-verifier/{global-config-WX3ZZIVU.mjs → global-config-Y2NTSK4R.mjs} +6 -5
  58. package/dist/{keychain-backend-JHTXAKWC.js → agent-verifier/keychain-backend-SPQWGKZN.mjs} +2 -2
  59. package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs.map +1 -0
  60. package/dist/agent-verifier/{local-files-MTPLP62S.mjs → local-files-JFOQQZDL.mjs} +10 -11
  61. package/dist/agent-verifier/local-files-JFOQQZDL.mjs.map +1 -0
  62. package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs +10 -0
  63. package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs.map +1 -0
  64. package/dist/agent-verifier/{materialize-workspace-FKALAE2T.mjs → materialize-workspace-ZAVGQQSF.mjs} +17 -18
  65. package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs.map +1 -0
  66. package/dist/agent-verifier/{project-state-7GR6BQTQ.mjs → project-state-K576C2TE.mjs} +3 -2
  67. package/dist/agent-verifier/project-state-K576C2TE.mjs.map +1 -0
  68. package/dist/{prompt-GMZABCJC.js → agent-verifier/prompt-MJRJMOGQ.mjs} +2 -2
  69. package/dist/agent-verifier/prompt-MJRJMOGQ.mjs.map +1 -0
  70. package/dist/agent-verifier/{reducer-bundle-preflight-C73LEXI2.mjs → reducer-bundle-preflight-LXNJUBKL.mjs} +6 -9
  71. package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs.map +1 -0
  72. package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs +11 -0
  73. package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs.map +1 -0
  74. package/dist/agent-verifier/{reducer-native-test-harness-GMWBUISX.mjs → reducer-native-test-harness-CHX5MBL5.mjs} +14 -17
  75. package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs.map +1 -0
  76. package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs +27 -0
  77. package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs.map +1 -0
  78. package/dist/agent-verifier/{sync-3DUQH32H.mjs → sync-THAI546U.mjs} +31 -37
  79. package/dist/agent-verifier/sync-THAI546U.mjs.map +1 -0
  80. package/dist/agent-verifier/{test-P4U5INTD.mjs → test-AFAQFKOB.mjs} +28 -31
  81. package/dist/agent-verifier/test-AFAQFKOB.mjs.map +1 -0
  82. package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs +10 -0
  83. package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs.map +1 -0
  84. package/dist/agent-verifier/{workspace-dependencies-HZ6VVS4G.mjs → workspace-dependencies-NOOQBK6I.mjs} +5 -4
  85. package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs.map +1 -0
  86. package/dist/{chunk-C6UAT6EH.js → chunk-N7XPNNUI.js} +9 -12
  87. package/dist/chunk-N7XPNNUI.js.map +1 -0
  88. package/dist/chunk-SEGVTWSK.js +44 -0
  89. package/dist/chunk-SEGVTWSK.js.map +1 -0
  90. package/dist/{chunk-RS7UXJZV.js → chunk-TAQKH67O.js} +21300 -35881
  91. package/dist/chunk-TAQKH67O.js.map +1 -0
  92. package/dist/{global-config-AGFBDFYD.js → global-config-S4ZIPECE.js} +3 -3
  93. package/dist/global-config-S4ZIPECE.js.map +1 -0
  94. package/dist/index.js +415 -37
  95. package/dist/index.js.map +1 -1
  96. package/dist/internal.js +3 -4
  97. package/dist/{agent-verifier/keychain-backend-TNOPQV3Z.mjs → keychain-backend-HDF4TZDL.js} +2 -1
  98. package/dist/{agent-verifier/prompt-3BAINGAQ.mjs → prompt-NDV3AE5L.js} +2 -1
  99. package/package.json +8 -7
  100. package/skills/dreamboard/references/building-your-first-game.md +510 -0
  101. package/skills/dreamboard/references/cli.md +104 -0
  102. package/skills/dreamboard/references/game-interface.md +548 -0
  103. package/skills/dreamboard/references/manifest-authoring.md +597 -0
  104. package/skills/dreamboard/references/quickstart.md +66 -0
  105. package/skills/dreamboard/references/reducer.md +864 -0
  106. package/skills/dreamboard/references/rule-authoring.md +147 -0
  107. package/skills/dreamboard/references/testing.md +249 -0
  108. package/skills/dreamboard/scripts/events-extract.mjs +218 -0
  109. package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
  110. package/dist/agent-verifier/chunk-6UUJEYDV.mjs +0 -213
  111. package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
  112. package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
  113. package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
  114. package/dist/agent-verifier/chunk-XYDL7GY6.mjs +0 -10
  115. package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
  116. package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
  117. package/dist/agent-verifier/static-scaffold-AJMZZQWS.mjs +0 -28
  118. package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
  119. package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
  120. package/dist/chunk-2H7UOFLK.js +0 -11
  121. package/dist/chunk-7FOO4AJI.js +0 -50
  122. package/dist/chunk-7FOO4AJI.js.map +0 -1
  123. package/dist/chunk-C6UAT6EH.js.map +0 -1
  124. package/dist/chunk-RS7UXJZV.js.map +0 -1
  125. package/dist/internal.d.ts +0 -311
  126. package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
  127. package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
  128. package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
  129. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
  130. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
  131. package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
  132. package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
  133. package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
  134. package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
  135. package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
  136. package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
  137. package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
  138. package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
  139. package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
  140. package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
  141. package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
  142. package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
  143. package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
  144. package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
  145. package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
  146. package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
  147. package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
  148. package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
  149. package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
  150. package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
  151. package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
  152. package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
  153. package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
  154. package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
  155. package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
  156. package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
  157. package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
  158. package/dist/testing-KLSV6CPJ.js +0 -674
  159. package/dist/testing-KLSV6CPJ.js.map +0 -1
  160. /package/dist/{chunk-2H7UOFLK.js.map → agent-verifier/chunk-SKI2ESE5.mjs.map} +0 -0
  161. /package/dist/{global-config-AGFBDFYD.js.map → agent-verifier/global-config-Y2NTSK4R.mjs.map} +0 -0
  162. /package/dist/{keychain-backend-JHTXAKWC.js.map → keychain-backend-HDF4TZDL.js.map} +0 -0
  163. /package/dist/{prompt-GMZABCJC.js.map → prompt-NDV3AE5L.js.map} +0 -0
@@ -1,294 +0,0 @@
1
- import {
2
- getDemoSessionByShortCode,
3
- getDemoSessionEventBatch,
4
- getDemoSessionSnapshot,
5
- getSessionByShortCode,
6
- getSessionEventBatch,
7
- getSessionSnapshot,
8
- startDemoGame,
9
- startGame,
10
- } from "@dreamboard-games/api-client";
11
- import type { ValidationResult } from "@dreamboard-games/sdk/runtime/runtime-api";
12
- import type {
13
- HostActionSubmitWireResponse,
14
- HostSessionWireEvent,
15
- HostSessionWireSnapshot,
16
- } from "./session-ingress.js";
17
-
18
- export interface HostSessionStream {
19
- stream: AsyncIterable<HostSessionWireEvent | null | undefined>;
20
- }
21
-
22
- export interface HostSessionTransport {
23
- loadSessionByShortCode(input: {
24
- shortCode: string;
25
- requestedPlayerId?: string | null;
26
- }): Promise<HostSessionWireSnapshot>;
27
- loadSessionSnapshot(input: {
28
- sessionId: string;
29
- requestedPlayerId?: string | null;
30
- }): Promise<HostSessionWireSnapshot>;
31
- startSession(input: { sessionId: string }): Promise<HostSessionWireSnapshot>;
32
- createDevSessionSnapshot?(input: {
33
- seed?: number | null;
34
- }): Promise<HostSessionWireSnapshot>;
35
- submitInteraction(input: {
36
- sessionId: string;
37
- playerId: string;
38
- interactionId: string;
39
- expectedVersion: number;
40
- actionSetVersion: string;
41
- params: unknown;
42
- clientActionId?: string | null;
43
- }): Promise<HostActionSubmitWireResponse>;
44
- validateInteraction(input: {
45
- sessionId: string;
46
- playerId: string;
47
- interactionId: string;
48
- expectedVersion: number;
49
- actionSetVersion: string;
50
- params: unknown;
51
- }): Promise<ValidationResult>;
52
- restoreHistory(input: {
53
- sessionId: string;
54
- entryId: string;
55
- }): Promise<HostSessionWireEvent | void>;
56
- subscribeToSessionEvents(input: {
57
- sessionId: string;
58
- clientId: string;
59
- connectionAttemptId: string;
60
- clientSource?: string;
61
- playerId?: string;
62
- signal?: AbortSignal;
63
- onSseError?: (error: unknown) => void;
64
- }): Promise<HostSessionStream>;
65
- disconnectSessionEvents(input: {
66
- sessionId: string;
67
- clientId: string;
68
- connectionAttemptId: string;
69
- playerId?: string;
70
- }): Promise<void>;
71
- }
72
-
73
- const SESSION_EVENT_LONG_POLL_WAIT_MS = 25_000;
74
- const HIDDEN_TAB_EMPTY_POLL_BACKOFF_MS = 5_000;
75
-
76
- async function requireData<T>(
77
- result: { data?: T; error?: unknown },
78
- message: string,
79
- ): Promise<T> {
80
- if (result.error || !result.data) {
81
- throw result.error ?? new Error(message);
82
- }
83
- return result.data;
84
- }
85
-
86
- function isAbortLikeError(error: unknown): boolean {
87
- return error instanceof Error && error.name === "AbortError";
88
- }
89
-
90
- function isDocumentHidden(): boolean {
91
- return typeof document !== "undefined" && document.hidden === true;
92
- }
93
-
94
- function shouldBackOffHiddenEmptyBatch(batch: {
95
- timedOut?: boolean;
96
- events?: unknown[];
97
- snapshot?: unknown;
98
- }): boolean {
99
- return (
100
- batch.timedOut === true &&
101
- !batch.snapshot &&
102
- (!Array.isArray(batch.events) || batch.events.length === 0) &&
103
- isDocumentHidden()
104
- );
105
- }
106
-
107
- async function waitForVisibleOrTimeout(
108
- delayMs: number,
109
- signal?: AbortSignal,
110
- ): Promise<void> {
111
- if (delayMs <= 0 || signal?.aborted || !isDocumentHidden()) return;
112
-
113
- await new Promise<void>((resolve) => {
114
- let timer: ReturnType<typeof setTimeout> | null = null;
115
-
116
- const cleanup = () => {
117
- if (timer) {
118
- clearTimeout(timer);
119
- timer = null;
120
- }
121
- document.removeEventListener("visibilitychange", onVisibilityChange);
122
- signal?.removeEventListener("abort", onAbort);
123
- };
124
-
125
- const finish = () => {
126
- cleanup();
127
- resolve();
128
- };
129
-
130
- const onVisibilityChange = () => {
131
- if (!isDocumentHidden()) {
132
- finish();
133
- }
134
- };
135
-
136
- const onAbort = () => {
137
- finish();
138
- };
139
-
140
- timer = setTimeout(finish, delayMs);
141
- document.addEventListener("visibilitychange", onVisibilityChange);
142
- signal?.addEventListener("abort", onAbort, { once: true });
143
- });
144
- }
145
-
146
- async function* pollSessionEvents(input: {
147
- sessionId: string;
148
- clientId: string;
149
- clientSource?: string;
150
- playerId?: string;
151
- signal?: AbortSignal;
152
- onSseError?: (error: unknown) => void;
153
- batchRequester?: typeof getSessionEventBatch;
154
- }): AsyncGenerator<HostSessionWireEvent | null | undefined> {
155
- let afterCursor: number | undefined;
156
- const batchRequester = input.batchRequester ?? getSessionEventBatch;
157
-
158
- while (!input.signal?.aborted) {
159
- try {
160
- const batch = await requireData(
161
- await batchRequester({
162
- path: { sessionId: input.sessionId },
163
- query: {
164
- clientId: input.clientId,
165
- clientSource: input.clientSource,
166
- playerId: input.playerId,
167
- afterCursor,
168
- waitMs: SESSION_EVENT_LONG_POLL_WAIT_MS,
169
- },
170
- signal: input.signal,
171
- }),
172
- "Failed to poll session events",
173
- );
174
-
175
- afterCursor = batch.cursor;
176
-
177
- if (batch.snapshot) {
178
- yield {
179
- type: "session.snapshot",
180
- reason: "load",
181
- snapshot: batch.snapshot,
182
- };
183
- }
184
-
185
- for (const event of batch.events) {
186
- yield event;
187
- }
188
-
189
- if (shouldBackOffHiddenEmptyBatch(batch)) {
190
- await waitForVisibleOrTimeout(
191
- HIDDEN_TAB_EMPTY_POLL_BACKOFF_MS,
192
- input.signal,
193
- );
194
- }
195
- } catch (error) {
196
- if (input.signal?.aborted || isAbortLikeError(error)) {
197
- return;
198
- }
199
- input.onSseError?.(error);
200
- throw error;
201
- }
202
- }
203
- }
204
-
205
- export const defaultHostSessionTransport: HostSessionTransport = {
206
- async loadSessionByShortCode(input) {
207
- return requireData(
208
- await getSessionByShortCode({
209
- path: { shortCode: input.shortCode },
210
- query: input.requestedPlayerId
211
- ? { playerId: input.requestedPlayerId }
212
- : undefined,
213
- }),
214
- "Failed to load session by short code",
215
- );
216
- },
217
- async loadSessionSnapshot(input) {
218
- return requireData(
219
- await getSessionSnapshot({
220
- path: { sessionId: input.sessionId },
221
- query: input.requestedPlayerId
222
- ? { playerId: input.requestedPlayerId }
223
- : undefined,
224
- }),
225
- "Failed to load session snapshot",
226
- );
227
- },
228
- async startSession(input) {
229
- return requireData(
230
- await startGame({ path: { sessionId: input.sessionId } }),
231
- "Failed to start session",
232
- );
233
- },
234
- async submitInteraction() {
235
- throw new Error(
236
- "Backend HTTP gameplay submit has been removed; configure gameplay authority transport.",
237
- );
238
- },
239
- async validateInteraction() {
240
- return { valid: true };
241
- },
242
- async restoreHistory() {
243
- throw new Error(
244
- "History restore requires the gameplay authority transport.",
245
- );
246
- },
247
- async subscribeToSessionEvents(input) {
248
- return { stream: pollSessionEvents(input) };
249
- },
250
- async disconnectSessionEvents() {
251
- // Long-poll requests are bounded and owned by their AbortSignal.
252
- },
253
- };
254
-
255
- export const demoHostSessionTransport: HostSessionTransport = {
256
- ...defaultHostSessionTransport,
257
- async loadSessionByShortCode(input) {
258
- return requireData(
259
- await getDemoSessionByShortCode({
260
- path: { shortCode: input.shortCode },
261
- query: input.requestedPlayerId
262
- ? { playerId: input.requestedPlayerId }
263
- : undefined,
264
- }),
265
- "Failed to load demo session by short code",
266
- );
267
- },
268
- async loadSessionSnapshot(input) {
269
- return requireData(
270
- await getDemoSessionSnapshot({
271
- path: { sessionId: input.sessionId },
272
- query: input.requestedPlayerId
273
- ? { playerId: input.requestedPlayerId }
274
- : undefined,
275
- }),
276
- "Failed to load demo session snapshot",
277
- );
278
- },
279
- async startSession(input) {
280
- return requireData(
281
- await startDemoGame({ path: { sessionId: input.sessionId } }),
282
- "Failed to start demo session",
283
- );
284
- },
285
- async subscribeToSessionEvents(input) {
286
- return {
287
- stream: pollSessionEvents({
288
- ...input,
289
- batchRequester:
290
- getDemoSessionEventBatch as unknown as typeof getSessionEventBatch,
291
- }),
292
- };
293
- },
294
- };
@@ -1,3 +0,0 @@
1
- export * from "./components/index.js";
2
- export * from "./runtime/index.js";
3
- export * from "./browser-interaction.js";
@@ -1,11 +0,0 @@
1
- export interface LoggerLike {
2
- log: (...args: unknown[]) => void;
3
- warn: (...args: unknown[]) => void;
4
- error: (...args: unknown[]) => void;
5
- }
6
-
7
- export const consoleLogger: LoggerLike = {
8
- log: (...args) => console.log(...args),
9
- warn: (...args) => console.warn(...args),
10
- error: (...args) => console.error(...args),
11
- };
@@ -1,324 +0,0 @@
1
- /**
2
- * Dev-only Tier-0 input-latency perf instrumentation.
3
- *
4
- * This module is used by the web host (and re-exported for the dev HUD)
5
- * to record `t0..t8` timing marks for each submitted interaction,
6
- * keyed by the client-minted `clientActionId`. It is deliberately
7
- * stateless across page reloads (in-memory ring buffer on `window`)
8
- * and gated behind `import.meta.env.DEV` or
9
- * `localStorage.getItem("dreamboard.perf") === "1"` so prod users
10
- * pay nothing.
11
- *
12
- * Design notes
13
- * - The plugin iframe lives in a separate window/performance context,
14
- * so plugin-side `performance.mark` entries are not reachable from
15
- * the host. We work around this by shipping plugin-minted `Date.now()`
16
- * timestamps across `postMessage` boundaries and recording them on
17
- * the host-side buffer keyed by `clientActionId`. Date.now() is used
18
- * (not `performance.now()`) because it shares a wall-clock base
19
- * across the iframe and the host.
20
- * - SSE `gameplay.updated` messages do not carry `clientActionId`; they
21
- * carry `version`. The host records a `version -> actionId` mapping
22
- * on `t3_http_response` (when the POST action submit response comes back
23
- * with `version`) so downstream marks (`t4_sse_received`,
24
- * `t5_store_applied`, `t6_state_sync_posted`) can be stitched by
25
- * version. Similarly `syncId -> actionId` is captured at `t5` so
26
- * plugin-side state-ack / state-rendered callbacks (which carry
27
- * `syncId`) can resolve back to the originating action.
28
- */
29
-
30
- export const PERF_MARK_NAMES = {
31
- T0_CLICK: "t0_click",
32
- T1_HOST_RECEIVED: "t1_host_received",
33
- T2_HTTP_SENT: "t2_http_sent",
34
- T3_HTTP_RESPONSE: "t3_http_response",
35
- /**
36
- * Fires when the store applies the submitter's gameplay snapshot
37
- * directly from the HTTP response (the Phase B2 eager-apply path).
38
- * Sits between `t3_http_response` and `t5_store_applied`; its delta
39
- * vs `t3_http_response` measures pure apply-in-store cost and its
40
- * delta vs `t4_sse_received` tells us how much SSE tail the eager
41
- * apply cuts off for the submitter.
42
- */
43
- T3B_RESPONSE_APPLIED: "t3b_response_applied",
44
- T4_SSE_RECEIVED: "t4_sse_received",
45
- T5_STORE_APPLIED: "t5_store_applied",
46
- T6_STATE_SYNC_POSTED: "t6_state_sync_posted",
47
- T7_STATE_SYNC_RECEIVED: "t7_state_sync_received",
48
- T8_RENDER_COMMIT: "t8_render_commit",
49
- } as const;
50
-
51
- export type PerfMarkName =
52
- (typeof PERF_MARK_NAMES)[keyof typeof PERF_MARK_NAMES];
53
-
54
- export interface PerfMarkRecord {
55
- name: string;
56
- timestampMs: number;
57
- extra?: Record<string, unknown>;
58
- }
59
-
60
- export interface PerfEntry {
61
- clientActionId: string;
62
- version?: number;
63
- syncId?: number;
64
- createdAtMs: number;
65
- marks: PerfMarkRecord[];
66
- }
67
-
68
- export interface PerfReceiptMetrics {
69
- action_submitter_projection_visible_ms?: number;
70
- action_pending_durability_ms?: number;
71
- action_durable_confirmation_ms?: number;
72
- action_other_player_visible_ms?: number;
73
- action_render_committed_ms?: number;
74
- action_server_response_ms?: number;
75
- }
76
-
77
- export interface PerfReceipt {
78
- clientActionId: string;
79
- version?: number;
80
- syncId?: number;
81
- metrics: PerfReceiptMetrics;
82
- }
83
-
84
- interface PerfBuffer {
85
- entries: PerfEntry[];
86
- versionIndex: Map<number, string>;
87
- syncIdIndex: Map<number, string>;
88
- }
89
-
90
- const GLOBAL_KEY = "__dreamboardPerf__";
91
- const DUMP_KEY = "__dreamboardPerfDump__";
92
- const MAX_ENTRIES = 50;
93
-
94
- type PerfGlobal = typeof globalThis & {
95
- [GLOBAL_KEY]?: PerfBuffer;
96
- [DUMP_KEY]?: () => PerfEntry[];
97
- };
98
-
99
- function getBuffer(): PerfBuffer | null {
100
- if (typeof globalThis === "undefined") {
101
- return null;
102
- }
103
- const scope = globalThis as PerfGlobal;
104
- const existing = scope[GLOBAL_KEY];
105
- if (existing) {
106
- return existing;
107
- }
108
- const buffer: PerfBuffer = {
109
- entries: [],
110
- versionIndex: new Map(),
111
- syncIdIndex: new Map(),
112
- };
113
- scope[GLOBAL_KEY] = buffer;
114
- scope[DUMP_KEY] = () => buffer.entries.slice();
115
- return buffer;
116
- }
117
-
118
- /**
119
- * Perf marks + HUD are off by default in prod. Enabled in dev builds
120
- * or when a maintainer opts in via `localStorage.dreamboard.perf = 1`.
121
- */
122
- export function isPerfEnabled(): boolean {
123
- if (typeof window === "undefined") {
124
- return false;
125
- }
126
- try {
127
- const env = (import.meta as unknown as { env?: { DEV?: boolean } }).env;
128
- if (env?.DEV) {
129
- return true;
130
- }
131
- } catch {
132
- // import.meta may be unavailable in non-Vite contexts; fall through
133
- }
134
- try {
135
- return window.localStorage.getItem("dreamboard.perf") === "1";
136
- } catch {
137
- return false;
138
- }
139
- }
140
-
141
- function nowMs(): number {
142
- return Date.now();
143
- }
144
-
145
- function findOrCreateEntry(
146
- buffer: PerfBuffer,
147
- clientActionId: string,
148
- ): PerfEntry {
149
- const existing = buffer.entries.find(
150
- (entry) => entry.clientActionId === clientActionId,
151
- );
152
- if (existing) {
153
- return existing;
154
- }
155
- const created: PerfEntry = {
156
- clientActionId,
157
- createdAtMs: nowMs(),
158
- marks: [],
159
- };
160
- buffer.entries.push(created);
161
- while (buffer.entries.length > MAX_ENTRIES) {
162
- const evicted = buffer.entries.shift();
163
- if (!evicted) break;
164
- if (evicted.version !== undefined) {
165
- buffer.versionIndex.delete(evicted.version);
166
- }
167
- if (evicted.syncId !== undefined) {
168
- buffer.syncIdIndex.delete(evicted.syncId);
169
- }
170
- }
171
- return created;
172
- }
173
-
174
- export interface RecordMarkOptions {
175
- timestampMs?: number;
176
- extra?: Record<string, unknown>;
177
- }
178
-
179
- /**
180
- * Record a perf mark against a `clientActionId`. No-ops silently when
181
- * perf is disabled or the runtime has no usable window/globalThis.
182
- */
183
- export function recordMark(
184
- clientActionId: string | undefined | null,
185
- name: string,
186
- options: RecordMarkOptions = {},
187
- ): void {
188
- if (!clientActionId) return;
189
- if (!isPerfEnabled()) return;
190
- const buffer = getBuffer();
191
- if (!buffer) return;
192
-
193
- const timestampMs = options.timestampMs ?? nowMs();
194
- const entry = findOrCreateEntry(buffer, clientActionId);
195
- entry.marks.push({
196
- name,
197
- timestampMs,
198
- extra: options.extra,
199
- });
200
-
201
- if (
202
- typeof performance !== "undefined" &&
203
- typeof performance.mark === "function"
204
- ) {
205
- try {
206
- performance.mark(`dreamboard.${name}.${clientActionId}`, {
207
- detail: { clientActionId, ...options.extra },
208
- });
209
- } catch {
210
- // performance.mark detail arg not supported in older browsers; ignore
211
- }
212
- }
213
- }
214
-
215
- /**
216
- * Associate the server-returned `version` (from SubmitInputResponse)
217
- * with a client-minted actionId so downstream SSE marks keyed by
218
- * `version` can resolve back to the original action.
219
- */
220
- export function correlateVersion(
221
- clientActionId: string,
222
- version: number,
223
- ): void {
224
- if (!isPerfEnabled()) return;
225
- const buffer = getBuffer();
226
- if (!buffer) return;
227
- const entry = findOrCreateEntry(buffer, clientActionId);
228
- entry.version = version;
229
- buffer.versionIndex.set(version, clientActionId);
230
- }
231
-
232
- /**
233
- * Associate the local `syncId` assigned when the store applies the
234
- * gameplay.updated with a clientActionId, so plugin-side state-ack /
235
- * state-rendered callbacks (which carry syncId rather than actionId)
236
- * can resolve back to the original action.
237
- */
238
- export function correlateSyncId(clientActionId: string, syncId: number): void {
239
- if (!isPerfEnabled()) return;
240
- const buffer = getBuffer();
241
- if (!buffer) return;
242
- const entry = findOrCreateEntry(buffer, clientActionId);
243
- entry.syncId = syncId;
244
- buffer.syncIdIndex.set(syncId, clientActionId);
245
- }
246
-
247
- export function findActionIdByVersion(version: number): string | undefined {
248
- const buffer = getBuffer();
249
- return buffer?.versionIndex.get(version);
250
- }
251
-
252
- export function findActionIdBySyncId(syncId: number): string | undefined {
253
- const buffer = getBuffer();
254
- return buffer?.syncIdIndex.get(syncId);
255
- }
256
-
257
- export function getPerfEntries(): PerfEntry[] {
258
- const buffer = getBuffer();
259
- return buffer ? buffer.entries.slice() : [];
260
- }
261
-
262
- export function getPerfReceipts(): PerfReceipt[] {
263
- return getPerfEntries().map((entry) => ({
264
- clientActionId: entry.clientActionId,
265
- version: entry.version,
266
- syncId: entry.syncId,
267
- metrics: {
268
- action_submitter_projection_visible_ms: deltaFor(
269
- entry,
270
- PERF_MARK_NAMES.T0_CLICK,
271
- PERF_MARK_NAMES.T3B_RESPONSE_APPLIED,
272
- ),
273
- action_pending_durability_ms: deltaFor(
274
- entry,
275
- PERF_MARK_NAMES.T3B_RESPONSE_APPLIED,
276
- PERF_MARK_NAMES.T4_SSE_RECEIVED,
277
- ),
278
- action_durable_confirmation_ms: deltaFor(
279
- entry,
280
- PERF_MARK_NAMES.T0_CLICK,
281
- PERF_MARK_NAMES.T4_SSE_RECEIVED,
282
- ),
283
- action_other_player_visible_ms: deltaFor(
284
- entry,
285
- PERF_MARK_NAMES.T0_CLICK,
286
- PERF_MARK_NAMES.T5_STORE_APPLIED,
287
- ),
288
- action_render_committed_ms: deltaFor(
289
- entry,
290
- PERF_MARK_NAMES.T0_CLICK,
291
- PERF_MARK_NAMES.T8_RENDER_COMMIT,
292
- ),
293
- action_server_response_ms: deltaFor(
294
- entry,
295
- PERF_MARK_NAMES.T2_HTTP_SENT,
296
- PERF_MARK_NAMES.T3_HTTP_RESPONSE,
297
- ),
298
- },
299
- }));
300
- }
301
-
302
- /** Drop every recorded entry; used by tests and the HUD "Clear" action. */
303
- export function clearPerfEntries(): void {
304
- const buffer = getBuffer();
305
- if (!buffer) return;
306
- buffer.entries = [];
307
- buffer.versionIndex.clear();
308
- buffer.syncIdIndex.clear();
309
- }
310
-
311
- function firstMarkMs(entry: PerfEntry, name: string): number | undefined {
312
- return entry.marks.find((mark) => mark.name === name)?.timestampMs;
313
- }
314
-
315
- function deltaFor(
316
- entry: PerfEntry,
317
- startName: string,
318
- endName: string,
319
- ): number | undefined {
320
- const start = firstMarkMs(entry, startName);
321
- const end = firstMarkMs(entry, endName);
322
- if (start === undefined || end === undefined) return undefined;
323
- return Math.round((end - start) * 10) / 10;
324
- }