@dreamboard-games/cli 0.1.30-alpha.1 → 0.1.30-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +179 -22
- package/dist/{chunk-C6UAT6EH.js → chunk-N7XPNNUI.js} +9 -12
- package/dist/chunk-N7XPNNUI.js.map +1 -0
- package/dist/chunk-SEGVTWSK.js +44 -0
- package/dist/{chunk-RS7UXJZV.js → chunk-TAQKH67O.js} +21300 -35881
- package/dist/chunk-TAQKH67O.js.map +1 -0
- package/dist/{global-config-AGFBDFYD.js → global-config-S4ZIPECE.js} +3 -3
- package/dist/index.js +415 -37
- package/dist/index.js.map +1 -1
- package/dist/internal.js +3 -4
- package/dist/{agent-verifier/keychain-backend-TNOPQV3Z.mjs → keychain-backend-HDF4TZDL.js} +2 -1
- package/dist/{agent-verifier/prompt-3BAINGAQ.mjs → prompt-NDV3AE5L.js} +2 -1
- package/package.json +6 -6
- package/skills/dreamboard/references/building-your-first-game.md +510 -0
- package/skills/dreamboard/references/cli.md +104 -0
- package/skills/dreamboard/references/game-interface.md +548 -0
- package/skills/dreamboard/references/manifest-authoring.md +597 -0
- package/skills/dreamboard/references/quickstart.md +66 -0
- package/skills/dreamboard/references/reducer.md +864 -0
- package/skills/dreamboard/references/rule-authoring.md +147 -0
- package/skills/dreamboard/references/testing.md +249 -0
- package/skills/dreamboard/scripts/events-extract.mjs +218 -0
- package/dist/agent-verifier/agent-workspace-verifier.mjs +0 -227
- package/dist/agent-verifier/chunk-2E5P5NWG.mjs +0 -835
- package/dist/agent-verifier/chunk-2GBBP27W.mjs +0 -301
- package/dist/agent-verifier/chunk-2QMNAVV4.mjs +0 -14522
- package/dist/agent-verifier/chunk-2SZHMP6F.mjs +0 -264
- package/dist/agent-verifier/chunk-4WD3YU2E.mjs +0 -166
- package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
- package/dist/agent-verifier/chunk-6A5HRJMQ.mjs +0 -3174
- package/dist/agent-verifier/chunk-6UUJEYDV.mjs +0 -213
- package/dist/agent-verifier/chunk-7653FPGJ.mjs +0 -381
- package/dist/agent-verifier/chunk-7E65UQLY.mjs +0 -38
- package/dist/agent-verifier/chunk-BVVNBJM4.mjs +0 -221
- package/dist/agent-verifier/chunk-CEDUHGNH.mjs +0 -74
- package/dist/agent-verifier/chunk-CEQ2VJWN.mjs +0 -149
- package/dist/agent-verifier/chunk-CFU5EWIC.mjs +0 -69
- package/dist/agent-verifier/chunk-CJEEA6NJ.mjs +0 -730
- package/dist/agent-verifier/chunk-EIQWDQWJ.mjs +0 -186
- package/dist/agent-verifier/chunk-EOQIV6PS.mjs +0 -649
- package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
- package/dist/agent-verifier/chunk-HJFQDSTU.mjs +0 -225
- package/dist/agent-verifier/chunk-JH22JNYD.mjs +0 -1681
- package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
- package/dist/agent-verifier/chunk-LM3OZLZG.mjs +0 -48
- package/dist/agent-verifier/chunk-MINCYHXN.mjs +0 -106
- package/dist/agent-verifier/chunk-MRCUP5SW.mjs +0 -128
- package/dist/agent-verifier/chunk-RBDDIIPM.mjs +0 -19
- package/dist/agent-verifier/chunk-SHUMAVAP.mjs +0 -59
- package/dist/agent-verifier/chunk-SYPLYRGB.mjs +0 -2812
- package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
- package/dist/agent-verifier/chunk-VYJTHSYR.mjs +0 -44
- package/dist/agent-verifier/chunk-XYDL7GY6.mjs +0 -10
- package/dist/agent-verifier/compile-5QSPIOUT.mjs +0 -313
- package/dist/agent-verifier/global-config-WX3ZZIVU.mjs +0 -17
- package/dist/agent-verifier/local-files-MTPLP62S.mjs +0 -46
- package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
- package/dist/agent-verifier/materialize-workspace-FKALAE2T.mjs +0 -90
- package/dist/agent-verifier/project-state-7GR6BQTQ.mjs +0 -32
- package/dist/agent-verifier/reducer-bundle-preflight-C73LEXI2.mjs +0 -23
- package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
- package/dist/agent-verifier/reducer-native-test-harness-GMWBUISX.mjs +0 -53
- package/dist/agent-verifier/static-scaffold-AJMZZQWS.mjs +0 -28
- package/dist/agent-verifier/sync-3DUQH32H.mjs +0 -594
- package/dist/agent-verifier/test-P4U5INTD.mjs +0 -356
- package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
- package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
- package/dist/agent-verifier/workspace-dependencies-HZ6VVS4G.mjs +0 -14
- package/dist/chunk-2H7UOFLK.js +0 -11
- package/dist/chunk-7FOO4AJI.js +0 -50
- package/dist/chunk-7FOO4AJI.js.map +0 -1
- package/dist/chunk-C6UAT6EH.js.map +0 -1
- package/dist/chunk-RS7UXJZV.js.map +0 -1
- package/dist/internal.d.ts +0 -311
- package/dist/keychain-backend-JHTXAKWC.js +0 -135
- package/dist/prompt-GMZABCJC.js +0 -756
- package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
- package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
- package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
- package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
- package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
- package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
- package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
- package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
- package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
- package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
- package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
- package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
- package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
- package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
- package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
- package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
- package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
- package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
- package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
- package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
- package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
- package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
- package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
- package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
- package/dist/testing-KLSV6CPJ.js +0 -674
- package/dist/testing-KLSV6CPJ.js.map +0 -1
- /package/dist/{chunk-2H7UOFLK.js.map → chunk-SEGVTWSK.js.map} +0 -0
- /package/dist/{global-config-AGFBDFYD.js.map → global-config-S4ZIPECE.js.map} +0 -0
- /package/dist/{keychain-backend-JHTXAKWC.js.map → keychain-backend-HDF4TZDL.js.map} +0 -0
- /package/dist/{prompt-GMZABCJC.js.map → prompt-NDV3AE5L.js.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
|
-
}
|