@dreamboard-games/cli 0.1.30-alpha.0 → 0.1.30-alpha.10

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 (156) hide show
  1. package/README.md +179 -22
  2. package/dist/agent-verifier/agent-workspace-verifier.mjs +31 -30
  3. package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
  4. package/dist/agent-verifier/{chunk-2NZNKIND.mjs → chunk-3IJBOLGT.mjs} +4 -12
  5. package/dist/agent-verifier/chunk-3IJBOLGT.mjs.map +1 -0
  6. package/dist/agent-verifier/{chunk-6A5HRJMQ.mjs → chunk-4GU3PCHV.mjs} +62 -99
  7. package/dist/agent-verifier/chunk-4GU3PCHV.mjs.map +1 -0
  8. package/dist/agent-verifier/{chunk-SYPLYRGB.mjs → chunk-6XRC5PWB.mjs} +119 -310
  9. package/dist/agent-verifier/chunk-6XRC5PWB.mjs.map +1 -0
  10. package/dist/agent-verifier/{chunk-BVVNBJM4.mjs → chunk-COB56ESI.mjs} +2 -1
  11. package/dist/agent-verifier/chunk-COB56ESI.mjs.map +1 -0
  12. package/dist/agent-verifier/{chunk-2GBBP27W.mjs → chunk-F2DIOJJZ.mjs} +1 -0
  13. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
  14. package/dist/agent-verifier/{chunk-CFU5EWIC.mjs → chunk-G42BGGG2.mjs} +7 -6
  15. package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
  16. package/dist/agent-verifier/{chunk-XYDL7GY6.mjs → chunk-H6XDQJ3N.mjs} +1 -0
  17. package/dist/agent-verifier/{chunk-LM3OZLZG.mjs → chunk-IAYRNVUC.mjs} +1 -0
  18. package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
  19. package/dist/agent-verifier/{chunk-2QMNAVV4.mjs → chunk-JZTH3EMV.mjs} +2 -1
  20. package/dist/agent-verifier/chunk-JZTH3EMV.mjs.map +1 -0
  21. package/dist/agent-verifier/chunk-KK47X7RV.mjs +14 -0
  22. package/dist/agent-verifier/chunk-KK47X7RV.mjs.map +1 -0
  23. package/dist/agent-verifier/{chunk-SHUMAVAP.mjs → chunk-M7UVBANQ.mjs} +8 -9
  24. package/dist/agent-verifier/chunk-M7UVBANQ.mjs.map +1 -0
  25. package/dist/agent-verifier/{chunk-RJBLBYHX.mjs → chunk-MGXX4WFR.mjs} +87 -22
  26. package/dist/agent-verifier/chunk-MGXX4WFR.mjs.map +1 -0
  27. package/dist/agent-verifier/{chunk-2E5P5NWG.mjs → chunk-NAK77WXW.mjs} +58 -126
  28. package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
  29. package/dist/agent-verifier/{chunk-CEQ2VJWN.mjs → chunk-POBFNXD4.mjs} +2 -1
  30. package/dist/agent-verifier/chunk-POBFNXD4.mjs.map +1 -0
  31. package/dist/agent-verifier/{chunk-6UUJEYDV.mjs → chunk-QBAF7EYR.mjs} +1 -0
  32. package/dist/agent-verifier/chunk-QBAF7EYR.mjs.map +1 -0
  33. package/dist/agent-verifier/{chunk-7653FPGJ.mjs → chunk-RHI6S4SU.mjs} +3 -2
  34. package/dist/agent-verifier/chunk-RHI6S4SU.mjs.map +1 -0
  35. package/dist/agent-verifier/{chunk-MINCYHXN.mjs → chunk-TAEQKBJB.mjs} +1 -0
  36. package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
  37. package/dist/agent-verifier/{chunk-PM3SVG6R.mjs → chunk-TLYGTHXU.mjs} +3 -2
  38. package/dist/agent-verifier/chunk-TLYGTHXU.mjs.map +1 -0
  39. package/dist/agent-verifier/{chunk-EIQWDQWJ.mjs → chunk-UWJIZML3.mjs} +13 -14
  40. package/dist/agent-verifier/chunk-UWJIZML3.mjs.map +1 -0
  41. package/dist/agent-verifier/{chunk-DTMJCPS4.mjs → chunk-VLOIZDR6.mjs} +15 -31
  42. package/dist/agent-verifier/chunk-VLOIZDR6.mjs.map +1 -0
  43. package/dist/agent-verifier/{chunk-HJFQDSTU.mjs → chunk-W2MDP5ZN.mjs} +6 -5
  44. package/dist/agent-verifier/chunk-W2MDP5ZN.mjs.map +1 -0
  45. package/dist/agent-verifier/{chunk-CEDUHGNH.mjs → chunk-XKCJBIRY.mjs} +2 -1
  46. package/dist/agent-verifier/chunk-XKCJBIRY.mjs.map +1 -0
  47. package/dist/agent-verifier/{chunk-VYJTHSYR.mjs → chunk-YDIOW2BO.mjs} +2 -1
  48. package/dist/agent-verifier/chunk-YDIOW2BO.mjs.map +1 -0
  49. package/dist/agent-verifier/{chunk-MRCUP5SW.mjs → chunk-YE7UAO3T.mjs} +1 -0
  50. package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
  51. package/dist/agent-verifier/{chunk-EOQIV6PS.mjs → chunk-YR664DJX.mjs} +111 -116
  52. package/dist/agent-verifier/chunk-YR664DJX.mjs.map +1 -0
  53. package/dist/agent-verifier/{chunk-2SZHMP6F.mjs → chunk-Z6OZWUIZ.mjs} +6 -9
  54. package/dist/agent-verifier/chunk-Z6OZWUIZ.mjs.map +1 -0
  55. package/dist/agent-verifier/{chunk-RBDDIIPM.mjs → chunk-ZEELHSY3.mjs} +1 -0
  56. package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
  57. package/dist/agent-verifier/{compile-WNCQQVOF.mjs → compile-C2VIP6VC.mjs} +27 -27
  58. package/dist/agent-verifier/compile-C2VIP6VC.mjs.map +1 -0
  59. package/dist/agent-verifier/{global-config-WX3ZZIVU.mjs → global-config-XHL7BCKN.mjs} +6 -5
  60. package/dist/agent-verifier/global-config-XHL7BCKN.mjs.map +1 -0
  61. package/dist/agent-verifier/{keychain-backend-TNOPQV3Z.mjs → keychain-backend-A3MRWLPF.mjs} +2 -1
  62. package/dist/agent-verifier/keychain-backend-A3MRWLPF.mjs.map +1 -0
  63. package/dist/agent-verifier/{local-files-MTPLP62S.mjs → local-files-ZW52HSVT.mjs} +10 -11
  64. package/dist/agent-verifier/local-files-ZW52HSVT.mjs.map +1 -0
  65. package/dist/agent-verifier/local-typecheck-3JXL2NMG.mjs +10 -0
  66. package/dist/agent-verifier/local-typecheck-3JXL2NMG.mjs.map +1 -0
  67. package/dist/agent-verifier/{materialize-workspace-EWGZIVOY.mjs → materialize-workspace-BKZLLFI4.mjs} +20 -20
  68. package/dist/agent-verifier/materialize-workspace-BKZLLFI4.mjs.map +1 -0
  69. package/dist/agent-verifier/{project-state-7GR6BQTQ.mjs → project-state-XKUSCFSV.mjs} +3 -2
  70. package/dist/agent-verifier/project-state-XKUSCFSV.mjs.map +1 -0
  71. package/dist/agent-verifier/{prompt-3BAINGAQ.mjs → prompt-VKHMCQT6.mjs} +2 -1
  72. package/dist/agent-verifier/prompt-VKHMCQT6.mjs.map +1 -0
  73. package/dist/agent-verifier/{reducer-bundle-preflight-C73LEXI2.mjs → reducer-bundle-preflight-7NYZF5ZT.mjs} +6 -9
  74. package/dist/agent-verifier/reducer-bundle-preflight-7NYZF5ZT.mjs.map +1 -0
  75. package/dist/agent-verifier/reducer-contract-preflight-COD2CO22.mjs +11 -0
  76. package/dist/agent-verifier/reducer-contract-preflight-COD2CO22.mjs.map +1 -0
  77. package/dist/agent-verifier/{reducer-native-test-harness-GMWBUISX.mjs → reducer-native-test-harness-D4VWPIAC.mjs} +14 -17
  78. package/dist/agent-verifier/reducer-native-test-harness-D4VWPIAC.mjs.map +1 -0
  79. package/dist/agent-verifier/static-scaffold-JCRBDKEH.mjs +26 -0
  80. package/dist/agent-verifier/static-scaffold-JCRBDKEH.mjs.map +1 -0
  81. package/dist/agent-verifier/{sync-LOQAH4RC.mjs → sync-UTL2IIZV.mjs} +35 -39
  82. package/dist/agent-verifier/sync-UTL2IIZV.mjs.map +1 -0
  83. package/dist/agent-verifier/{test-YOJERVHN.mjs → test-H26XCBFA.mjs} +29 -31
  84. package/dist/agent-verifier/test-H26XCBFA.mjs.map +1 -0
  85. package/dist/agent-verifier/workspace-codegen-WPZHMATU.mjs +10 -0
  86. package/dist/agent-verifier/workspace-codegen-WPZHMATU.mjs.map +1 -0
  87. package/dist/agent-verifier/{workspace-dependencies-HZ6VVS4G.mjs → workspace-dependencies-ULZZZPNX.mjs} +5 -4
  88. package/dist/agent-verifier/workspace-dependencies-ULZZZPNX.mjs.map +1 -0
  89. package/dist/{chunk-TSJVWTJO.js → chunk-GXM7RRZJ.js} +14 -11
  90. package/dist/chunk-GXM7RRZJ.js.map +1 -0
  91. package/dist/{chunk-3XNJT3RK.js → chunk-P5TITCD3.js} +808 -17878
  92. package/dist/chunk-P5TITCD3.js.map +1 -0
  93. package/dist/{global-config-UKSWNDTX.js → global-config-WPJRXVDO.js} +2 -2
  94. package/dist/global-config-WPJRXVDO.js.map +1 -0
  95. package/dist/index.js +987 -255
  96. package/dist/index.js.map +1 -1
  97. package/dist/internal.js +2 -3
  98. package/package.json +8 -7
  99. package/skills/dreamboard/references/building-your-first-game.md +510 -0
  100. package/skills/dreamboard/references/cli.md +104 -0
  101. package/skills/dreamboard/references/game-interface.md +548 -0
  102. package/skills/dreamboard/references/manifest-authoring.md +597 -0
  103. package/skills/dreamboard/references/quickstart.md +66 -0
  104. package/skills/dreamboard/references/reducer.md +864 -0
  105. package/skills/dreamboard/references/rule-authoring.md +147 -0
  106. package/skills/dreamboard/references/testing.md +249 -0
  107. package/skills/dreamboard/scripts/events-extract.mjs +218 -0
  108. package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
  109. package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
  110. package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
  111. package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
  112. package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
  113. package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
  114. package/dist/agent-verifier/static-scaffold-4YEQME5N.mjs +0 -28
  115. package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
  116. package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
  117. package/dist/chunk-3XNJT3RK.js.map +0 -1
  118. package/dist/chunk-7FOO4AJI.js +0 -50
  119. package/dist/chunk-7FOO4AJI.js.map +0 -1
  120. package/dist/chunk-TSJVWTJO.js.map +0 -1
  121. package/dist/internal.d.ts +0 -311
  122. package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
  123. package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
  124. package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
  125. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
  126. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
  127. package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
  128. package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
  129. package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
  130. package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
  131. package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
  132. package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
  133. package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
  134. package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
  135. package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
  136. package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
  137. package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
  138. package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
  139. package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
  140. package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
  141. package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
  142. package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
  143. package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
  144. package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
  145. package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
  146. package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
  147. package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
  148. package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
  149. package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
  150. package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
  151. package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
  152. package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
  153. package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
  154. package/dist/testing-KLSV6CPJ.js +0 -674
  155. package/dist/testing-KLSV6CPJ.js.map +0 -1
  156. /package/dist/{global-config-UKSWNDTX.js.map → agent-verifier/chunk-H6XDQJ3N.mjs.map} +0 -0
@@ -1,431 +0,0 @@
1
- import type {
2
- HistoryEntrySummary,
3
- HostGameplaySeatView,
4
- HostSessionStatus,
5
- InteractionDescriptor,
6
- SeatAssignment,
7
- SessionActor,
8
- SessionGameSource,
9
- ZoneHandles as WireZoneHandles,
10
- } from "@dreamboard-games/api-client";
11
- import type {
12
- PluginStateSnapshot,
13
- ZoneHandlesSnapshot,
14
- } from "@dreamboard-games/sdk/runtime/runtime-api";
15
- import {
16
- seatControlledByPrincipal,
17
- gameIdFromGameSource,
18
- } from "./actor-principal.js";
19
-
20
- type LayoutConfig = unknown;
21
- type CardDisplayConfig = unknown;
22
-
23
- export interface SessionIdentity {
24
- sessionId: string;
25
- shortCode: string;
26
- gameId: string;
27
- }
28
-
29
- export interface HistoryState {
30
- entries: HistoryEntrySummary[];
31
- currentIndex: number;
32
- canGoBack: boolean;
33
- canGoForward: boolean;
34
- }
35
-
36
- export interface SessionContextIngress {
37
- sessionId: string;
38
- shortCode: string;
39
- status: HostSessionStatus;
40
- gameSource: SessionGameSource;
41
- setupProfileId?: string | null;
42
- hostActor: SessionActor;
43
- switchablePlayerIds: string[];
44
- history?: HistoryState | null;
45
- }
46
-
47
- export interface LobbyIngress {
48
- seats: SeatAssignment[];
49
- canStart: boolean;
50
- }
51
-
52
- export interface GameplayViewportIngress {
53
- version: number;
54
- actionSetVersion: string;
55
- perspectivePlayerId: string;
56
- controllablePlayerIds: string[];
57
- shared: {
58
- activePlayers: string[];
59
- currentPhase: string | null;
60
- currentStage?: string | null;
61
- stageSeats?: string[];
62
- simultaneousPhase?: SimultaneousPhaseSnapshot | null;
63
- boardStatic?: string | null;
64
- boardStaticHash?: string | null;
65
- };
66
- interactionsByRef: Record<string, InteractionDescriptor | null | undefined>;
67
- seats: Record<string, HostGameplaySeatView | null | undefined>;
68
- }
69
-
70
- export interface SessionContext {
71
- identity: SessionIdentity;
72
- userId: string | null;
73
- seats: SeatAssignment[];
74
- canStart: boolean;
75
- status: HostSessionStatus;
76
- gameSource: SessionGameSource;
77
- setupProfileId?: string | null;
78
- hostActor: SessionActor;
79
- switchablePlayerIds: string[];
80
- history: HistoryState | null;
81
- }
82
-
83
- export interface GameplayPerspective {
84
- playerId: string;
85
- }
86
-
87
- export interface GameplayViewport {
88
- version: number;
89
- actionSetVersion: string;
90
- activePlayers: string[];
91
- currentPhase: string | null;
92
- currentStage: string | null;
93
- stageSeats: string[];
94
- simultaneousPhase: SimultaneousPhaseSnapshot | null;
95
- view: PluginStateSnapshot["view"];
96
- availableInteractions: InteractionDescriptor[];
97
- zones: Record<string, ZoneHandlesSnapshot>;
98
- boardStatic: Record<string, unknown> | null;
99
- boardStaticHash: string | null;
100
- layout?: LayoutConfig | null;
101
- cardDisplayConfigs?: CardDisplayConfig[] | null;
102
- seatProjectionsByPlayerId: Record<string, GameplaySeatProjection>;
103
- }
104
-
105
- export interface GameplaySeatProjection {
106
- version: number;
107
- actionSetVersion: string;
108
- view: PluginStateSnapshot["view"];
109
- availableInteractions: InteractionDescriptor[];
110
- zones: Record<string, ZoneHandlesSnapshot>;
111
- }
112
-
113
- export interface SimultaneousPhaseSnapshot {
114
- phaseName: string;
115
- interactionId: string;
116
- actorIds: string[];
117
- sealedPlayerIds: string[];
118
- pendingPlayerIds: string[];
119
- }
120
-
121
- export type UnifiedSessionModel =
122
- | { type: "idle" }
123
- | { type: "loading"; target?: { sessionId?: string; shortCode?: string } }
124
- | { type: "lobby"; context: SessionContext; preferredPlayerId: string | null }
125
- | {
126
- type: "gameplayLoading";
127
- context: SessionContext;
128
- requestedPlayerId: string;
129
- }
130
- | {
131
- type: "gameplay";
132
- context: SessionContext;
133
- perspective: GameplayPerspective;
134
- gameplay: GameplayViewport;
135
- }
136
- | { type: "ended"; context: SessionContext }
137
- | { type: "error"; message: string; context?: SessionContext };
138
-
139
- export type SessionPhase = UnifiedSessionModel["type"];
140
-
141
- export function toHistoryState(
142
- history: SessionContextIngress["history"] | undefined,
143
- ): HistoryState | null {
144
- return history
145
- ? {
146
- entries: history.entries,
147
- currentIndex: history.currentIndex,
148
- canGoBack: history.canGoBack,
149
- canGoForward: history.canGoForward,
150
- }
151
- : null;
152
- }
153
-
154
- export function identityFromHostContext(
155
- context: SessionContextIngress,
156
- ): SessionIdentity {
157
- return {
158
- sessionId: context.sessionId,
159
- shortCode: context.shortCode,
160
- gameId: gameIdFromGameSource(context.gameSource),
161
- };
162
- }
163
-
164
- export function deriveControlledPlayerIdsFromSeats(
165
- seats: SeatAssignment[],
166
- userId: string | null,
167
- fallbackToAllSeatsWhenUserIdMissing = false,
168
- ): string[] {
169
- if (!userId) {
170
- return fallbackToAllSeatsWhenUserIdMissing
171
- ? seats.map((seat) => seat.playerId)
172
- : [];
173
- }
174
- return seats
175
- .filter((seat) => seatControlledByPrincipal(seat, userId))
176
- .map((seat) => seat.playerId);
177
- }
178
-
179
- export function resolveControllablePlayerIds(
180
- preferredPlayerIds: string[] | null | undefined,
181
- seats: SeatAssignment[],
182
- userId: string | null,
183
- fallbackToAllSeatsWhenUserIdMissing = false,
184
- ): string[] {
185
- return preferredPlayerIds && preferredPlayerIds.length > 0
186
- ? preferredPlayerIds
187
- : deriveControlledPlayerIdsFromSeats(
188
- seats,
189
- userId,
190
- fallbackToAllSeatsWhenUserIdMissing,
191
- );
192
- }
193
-
194
- export function contextFromHostParts(
195
- wireContext: SessionContextIngress,
196
- lobby: LobbyIngress,
197
- userId: string | null,
198
- ): SessionContext {
199
- return {
200
- identity: identityFromHostContext(wireContext),
201
- userId,
202
- seats: lobby.seats,
203
- canStart: lobby.canStart,
204
- status: wireContext.status,
205
- gameSource: wireContext.gameSource,
206
- setupProfileId: wireContext.setupProfileId ?? null,
207
- hostActor: wireContext.hostActor,
208
- switchablePlayerIds: wireContext.switchablePlayerIds,
209
- history: toHistoryState(wireContext.history),
210
- };
211
- }
212
-
213
- export function contextFromHostSnapshot(
214
- snapshot: { context: SessionContextIngress; lobby: LobbyIngress },
215
- userId: string | null,
216
- ): SessionContext {
217
- return contextFromHostParts(snapshot.context, snapshot.lobby, userId);
218
- }
219
-
220
- export function contextFromHostEventContext(
221
- context: SessionContext,
222
- wireContext: SessionContextIngress,
223
- lobby?: LobbyIngress,
224
- ): SessionContext {
225
- return {
226
- ...context,
227
- identity: identityFromHostContext(wireContext),
228
- status: wireContext.status,
229
- gameSource: wireContext.gameSource,
230
- setupProfileId: wireContext.setupProfileId ?? null,
231
- seats: lobby?.seats ?? context.seats,
232
- canStart: lobby?.canStart ?? context.canStart,
233
- hostActor: wireContext.hostActor,
234
- switchablePlayerIds: wireContext.switchablePlayerIds,
235
- history:
236
- wireContext.history !== undefined
237
- ? toHistoryState(wireContext.history)
238
- : context.history,
239
- };
240
- }
241
-
242
- export function contextWithHistory(
243
- context: SessionContext,
244
- history: SessionContextIngress["history"],
245
- ): SessionContext {
246
- return { ...context, history: toHistoryState(history) };
247
- }
248
-
249
- export function safeJsonParseValue(jsonString: string): unknown {
250
- try {
251
- return JSON.parse(jsonString);
252
- } catch {
253
- return null;
254
- }
255
- }
256
-
257
- export function transformView(
258
- serializedView: string | null | undefined,
259
- ): PluginStateSnapshot["view"] {
260
- return serializedView
261
- ? (safeJsonParseValue(serializedView) as PluginStateSnapshot["view"])
262
- : null;
263
- }
264
-
265
- export function gameplayViewportFromSnapshot(
266
- snapshot: GameplayViewportIngress,
267
- previous?: GameplayViewport | null,
268
- ): GameplayViewport {
269
- const incomingBoardStatic = snapshot.shared.boardStatic
270
- ? (safeJsonParseValue(snapshot.shared.boardStatic) as Record<
271
- string,
272
- unknown
273
- > | null)
274
- : null;
275
- const incomingBoardStaticHash = snapshot.shared.boardStaticHash ?? null;
276
- const hashDisagrees =
277
- previous?.boardStaticHash !== null &&
278
- previous?.boardStaticHash !== undefined &&
279
- incomingBoardStaticHash !== null &&
280
- incomingBoardStaticHash !== previous.boardStaticHash;
281
- const interactionsByRef = snapshot.interactionsByRef ?? {};
282
- const hydrateInteractionRefs = (
283
- refs: readonly string[] | null | undefined,
284
- ): InteractionDescriptor[] =>
285
- (refs ?? [])
286
- .map((ref) => interactionsByRef[ref])
287
- .filter((descriptor): descriptor is InteractionDescriptor =>
288
- Boolean(descriptor),
289
- );
290
- const incomingSeatProjections = Object.fromEntries(
291
- Object.entries(snapshot.seats ?? {}).flatMap(([playerId, seat]) => {
292
- if (!seat) return [];
293
- return [
294
- [
295
- playerId,
296
- {
297
- version: snapshot.version,
298
- actionSetVersion:
299
- seat.actionSetVersion ?? snapshot.actionSetVersion,
300
- view: transformView(seat.view),
301
- availableInteractions: hydrateInteractionRefs(
302
- seat.availableInteractionRefs,
303
- ),
304
- zones: hydrateZones(seat.zones, hydrateInteractionRefs),
305
- } satisfies GameplaySeatProjection,
306
- ],
307
- ];
308
- }),
309
- );
310
- const seatProjectionsByPlayerId =
311
- previous?.version === snapshot.version
312
- ? {
313
- ...previous.seatProjectionsByPlayerId,
314
- ...incomingSeatProjections,
315
- }
316
- : incomingSeatProjections;
317
- const perspectiveSeat =
318
- seatProjectionsByPlayerId[snapshot.perspectivePlayerId] ?? null;
319
-
320
- return {
321
- version: snapshot.version,
322
- actionSetVersion:
323
- perspectiveSeat?.actionSetVersion ?? snapshot.actionSetVersion,
324
- activePlayers: snapshot.shared.activePlayers,
325
- currentPhase: snapshot.shared.currentPhase,
326
- currentStage:
327
- snapshot.shared.currentStage ?? previous?.currentStage ?? null,
328
- stageSeats: snapshot.shared.stageSeats ?? previous?.stageSeats ?? [],
329
- simultaneousPhase: snapshot.shared.simultaneousPhase ?? null,
330
- view: perspectiveSeat?.view ?? null,
331
- availableInteractions: perspectiveSeat?.availableInteractions ?? [],
332
- zones: perspectiveSeat?.zones ?? {},
333
- boardStatic: hashDisagrees
334
- ? (previous?.boardStatic ?? null)
335
- : (incomingBoardStatic ?? previous?.boardStatic ?? null),
336
- boardStaticHash:
337
- incomingBoardStaticHash ?? previous?.boardStaticHash ?? null,
338
- layout: previous?.layout ?? null,
339
- cardDisplayConfigs: previous?.cardDisplayConfigs ?? null,
340
- seatProjectionsByPlayerId,
341
- };
342
- }
343
-
344
- export function gameplayViewportForPlayer(
345
- gameplay: GameplayViewport,
346
- playerId: string,
347
- ): GameplayViewport | null {
348
- const seatProjection = gameplay.seatProjectionsByPlayerId[playerId];
349
- if (!seatProjection || seatProjection.version !== gameplay.version) {
350
- return null;
351
- }
352
- return {
353
- ...gameplay,
354
- actionSetVersion: seatProjection.actionSetVersion,
355
- view: seatProjection.view,
356
- availableInteractions: seatProjection.availableInteractions,
357
- zones: seatProjection.zones,
358
- };
359
- }
360
-
361
- function hydrateZones(
362
- zones: Record<string, WireZoneHandles | null | undefined> | null | undefined,
363
- hydrateInteractionRefs: (
364
- refs: readonly string[] | null | undefined,
365
- ) => InteractionDescriptor[],
366
- ): Record<string, ZoneHandlesSnapshot> {
367
- return Object.fromEntries(
368
- Object.entries(zones ?? {}).flatMap(([zoneId, zone]) => {
369
- if (!zone) return [];
370
- return [
371
- [
372
- zoneId,
373
- {
374
- cardIds: zone.cardIds,
375
- cardViewsById: zone.cardViewsById,
376
- playableByCardId: Object.fromEntries(
377
- Object.entries(zone.playableByCardId).map(([cardId, refs]) => [
378
- cardId,
379
- hydrateInteractionRefs(refs ?? []),
380
- ]),
381
- ),
382
- },
383
- ],
384
- ];
385
- }),
386
- );
387
- }
388
-
389
- export function getSessionContext(
390
- session: UnifiedSessionModel,
391
- ): SessionContext | null {
392
- switch (session.type) {
393
- case "lobby":
394
- case "gameplayLoading":
395
- case "gameplay":
396
- case "ended":
397
- return session.context;
398
- case "error":
399
- return session.context ?? null;
400
- case "idle":
401
- case "loading":
402
- return null;
403
- }
404
- }
405
-
406
- export function getGameplayViewport(
407
- session: UnifiedSessionModel,
408
- ): GameplayViewport | null {
409
- return session.type === "gameplay" ? session.gameplay : null;
410
- }
411
-
412
- export function withContext(
413
- session: UnifiedSessionModel,
414
- context: SessionContext,
415
- ): UnifiedSessionModel {
416
- switch (session.type) {
417
- case "lobby":
418
- return { ...session, context };
419
- case "gameplayLoading":
420
- return { ...session, context };
421
- case "gameplay":
422
- return { ...session, context };
423
- case "ended":
424
- return { type: "ended", context };
425
- case "error":
426
- return { type: "error", message: session.message, context };
427
- case "idle":
428
- case "loading":
429
- return { type: "lobby", context, preferredPlayerId: null };
430
- }
431
- }
@@ -1,211 +0,0 @@
1
- import type { InteractionDescriptor } from "@dreamboard-games/api-client";
2
- import type {
3
- PluginStateSnapshot,
4
- ZoneHandlesSnapshot,
5
- } from "@dreamboard-games/sdk/runtime/runtime-api";
6
- import {
7
- principalKey,
8
- principalMatchesActor,
9
- seatsForPluginSnapshot,
10
- } from "./actor-principal.js";
11
- import type {
12
- GameplayViewport,
13
- HistoryState,
14
- SessionContext,
15
- SessionIdentity,
16
- UnifiedSessionModel,
17
- } from "./session-model.js";
18
- import {
19
- getGameplayViewport,
20
- getSessionContext,
21
- resolveControllablePlayerIds,
22
- } from "./session-model.js";
23
-
24
- export interface NotificationProjectionState {
25
- notifications: PluginStateSnapshot["notifications"];
26
- syncId: number;
27
- }
28
-
29
- export interface ProjectionState {
30
- session: UnifiedSessionModel;
31
- activity: NotificationProjectionState;
32
- }
33
-
34
- export interface LobbyViewModel {
35
- identity: SessionIdentity;
36
- seats: SessionContext["seats"];
37
- canStart: boolean;
38
- hostActor: SessionContext["hostActor"];
39
- shortCode: string;
40
- isSessionHost: boolean;
41
- }
42
-
43
- export interface GameplayViewModel {
44
- context: SessionContext;
45
- perspective: { playerId: string };
46
- gameplay: GameplayViewport;
47
- }
48
-
49
- export type BootstrapStatus = "loading" | "lobby" | "renderable" | "error";
50
-
51
- const lobbyViewModelCache = new WeakMap<SessionContext, LobbyViewModel>();
52
- const gameplayViewModelCache = new WeakMap<
53
- GameplayViewport,
54
- { context: SessionContext; value: GameplayViewModel }
55
- >();
56
-
57
- export function selectSessionContext(
58
- state: Pick<ProjectionState, "session">,
59
- ): SessionContext | null {
60
- return getSessionContext(state.session);
61
- }
62
-
63
- export function selectGameplayViewport(
64
- state: Pick<ProjectionState, "session">,
65
- ): GameplayViewport | null {
66
- return getGameplayViewport(state.session);
67
- }
68
-
69
- export function selectSessionType(
70
- state: Pick<ProjectionState, "session">,
71
- ): UnifiedSessionModel["type"] {
72
- return state.session.type;
73
- }
74
-
75
- export function selectBootstrapStatus(
76
- state: Pick<ProjectionState, "session">,
77
- ): BootstrapStatus {
78
- switch (state.session.type) {
79
- case "idle":
80
- case "loading":
81
- case "gameplayLoading":
82
- return "loading";
83
- case "lobby":
84
- case "ended":
85
- return "lobby";
86
- case "gameplay":
87
- return "renderable";
88
- case "error":
89
- return "error";
90
- }
91
- }
92
-
93
- export function selectSessionError(
94
- state: Pick<ProjectionState, "session">,
95
- ): string | null {
96
- return state.session.type === "error" ? state.session.message : null;
97
- }
98
-
99
- export function selectLobbyViewModel(
100
- state: Pick<ProjectionState, "session">,
101
- ): LobbyViewModel | null {
102
- const context = getSessionContext(state.session);
103
- if (!context) return null;
104
- const cached = lobbyViewModelCache.get(context);
105
- if (cached) return cached;
106
- const viewModel = {
107
- identity: context.identity,
108
- seats: context.seats,
109
- canStart: context.canStart,
110
- hostActor: context.hostActor,
111
- shortCode: context.identity.shortCode,
112
- isSessionHost:
113
- Boolean(context.userId) &&
114
- principalMatchesActor(context.userId, context.hostActor),
115
- };
116
- lobbyViewModelCache.set(context, viewModel);
117
- return viewModel;
118
- }
119
-
120
- export function selectGameplayViewModel(
121
- state: Pick<ProjectionState, "session">,
122
- ): GameplayViewModel | null {
123
- if (state.session.type !== "gameplay") return null;
124
- const cached = gameplayViewModelCache.get(state.session.gameplay);
125
- if (cached?.context === state.session.context) return cached.value;
126
- const value = {
127
- context: state.session.context,
128
- perspective: state.session.perspective,
129
- gameplay: state.session.gameplay,
130
- };
131
- gameplayViewModelCache.set(state.session.gameplay, {
132
- context: state.session.context,
133
- value,
134
- });
135
- return value;
136
- }
137
-
138
- export function selectPluginSnapshot(
139
- state: ProjectionState,
140
- fallbackToAllSeatsWhenUserIdMissing = false,
141
- ): PluginStateSnapshot {
142
- const context = getSessionContext(state.session);
143
- const gameplay = getGameplayViewport(state.session);
144
- const perspectivePlayerId =
145
- state.session.type === "gameplay"
146
- ? state.session.perspective.playerId
147
- : null;
148
- const controllablePlayerIds = context
149
- ? resolveControllablePlayerIds(
150
- context.switchablePlayerIds,
151
- context.seats,
152
- context.userId,
153
- fallbackToAllSeatsWhenUserIdMissing,
154
- )
155
- : [];
156
- const controllingPlayerId = perspectivePlayerId;
157
- const gameplayIsRenderable =
158
- gameplay !== null && perspectivePlayerId !== null;
159
- const visibleInteractions: InteractionDescriptor[] = gameplayIsRenderable
160
- ? gameplay.availableInteractions
161
- : [];
162
- const seatView = gameplayIsRenderable ? gameplay.view : null;
163
- const boardStatic = gameplay?.boardStatic ?? null;
164
- const view: PluginStateSnapshot["view"] =
165
- boardStatic && seatView && typeof seatView === "object"
166
- ? ({
167
- ...(seatView as Record<string, unknown>),
168
- board: {
169
- ...((seatView as { board?: Record<string, unknown> }).board ?? {}),
170
- ...boardStatic,
171
- },
172
- } as PluginStateSnapshot["view"])
173
- : boardStatic && !seatView
174
- ? ({ board: boardStatic } as unknown as PluginStateSnapshot["view"])
175
- : seatView;
176
- const visibleZones: Record<string, ZoneHandlesSnapshot> = gameplayIsRenderable
177
- ? gameplay.zones
178
- : {};
179
-
180
- return {
181
- view,
182
- gameplay: {
183
- currentPhase: gameplay?.currentPhase ?? null,
184
- currentStage: gameplay?.currentStage ?? null,
185
- activePlayers: gameplay?.activePlayers ?? [],
186
- simultaneousPhase: gameplay?.simultaneousPhase ?? null,
187
- availableInteractions: visibleInteractions,
188
- zones: visibleZones,
189
- },
190
- lobby: {
191
- seats: seatsForPluginSnapshot(context?.seats ?? []),
192
- canStart: context?.canStart ?? false,
193
- hostUserId: context ? principalKey(context.hostActor) : "",
194
- },
195
- notifications: state.activity.notifications,
196
- session: {
197
- sessionId: context?.identity.sessionId ?? null,
198
- controllablePlayerIds,
199
- controllingPlayerId,
200
- userId: context?.userId ?? null,
201
- },
202
- history: context?.history ?? null,
203
- syncId: state.activity.syncId,
204
- };
205
- }
206
-
207
- export function selectHistory(
208
- state: Pick<ProjectionState, "session">,
209
- ): HistoryState | null {
210
- return getSessionContext(state.session)?.history ?? null;
211
- }
@@ -1,80 +0,0 @@
1
- export interface SessionRecoveryDetails {
2
- message: string;
3
- retryAfterMs: number;
4
- }
5
-
6
- const DEFAULT_RECOVERY_RETRY_AFTER_MS = 2_000;
7
-
8
- function asRecord(value: unknown): Record<string, unknown> | null {
9
- return value && typeof value === "object"
10
- ? (value as Record<string, unknown>)
11
- : null;
12
- }
13
-
14
- function parseRetryAfterMs(value: unknown): number | null {
15
- if (typeof value === "number" && Number.isFinite(value) && value > 0) {
16
- return value;
17
- }
18
- if (typeof value !== "string") {
19
- return null;
20
- }
21
- const parsed = Number.parseInt(value, 10);
22
- return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
23
- }
24
-
25
- function getProblemPayload(error: unknown): Record<string, unknown> | null {
26
- const direct = asRecord(error);
27
- if (!direct) {
28
- return null;
29
- }
30
- if (typeof direct.title === "string" && typeof direct.status === "number") {
31
- return direct;
32
- }
33
- for (const key of ["error", "data", "body", "cause"]) {
34
- const nested = asRecord(direct[key]);
35
- if (
36
- nested &&
37
- typeof nested.title === "string" &&
38
- typeof nested.status === "number"
39
- ) {
40
- return nested;
41
- }
42
- }
43
- return null;
44
- }
45
-
46
- export function getSessionRecoveryDetails(
47
- error: unknown,
48
- ): SessionRecoveryDetails | null {
49
- const problem = getProblemPayload(error);
50
- if (problem) {
51
- const title = typeof problem.title === "string" ? problem.title : "";
52
- const detail = typeof problem.detail === "string" ? problem.detail : "";
53
- const retryable = problem.retryable === true;
54
- const isRecovery =
55
- problem.status === 503 &&
56
- retryable &&
57
- (title === "Session recovering" ||
58
- detail.toLowerCase().includes("recovering"));
59
- if (!isRecovery) {
60
- return null;
61
- }
62
- const context = asRecord(problem.context);
63
- return {
64
- message:
65
- detail.trim() || "Session state is recovering. Retrying shortly.",
66
- retryAfterMs:
67
- parseRetryAfterMs(context?.retryAfterMs) ??
68
- DEFAULT_RECOVERY_RETRY_AFTER_MS,
69
- };
70
- }
71
-
72
- if (error instanceof Error && /SSE failed:\s*503\b/i.test(error.message)) {
73
- return {
74
- message: "Session state is recovering. Retrying shortly.",
75
- retryAfterMs: DEFAULT_RECOVERY_RETRY_AFTER_MS,
76
- };
77
- }
78
-
79
- return null;
80
- }