dreamboard 0.1.21 → 0.1.23

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 (186) hide show
  1. package/dist/{chunk-EYYWGWTO.js → chunk-2RCUHMGL.js} +343 -1911
  2. package/dist/chunk-2RCUHMGL.js.map +1 -0
  3. package/dist/{chunk-MOVHYB6E.js → chunk-GN7232BY.js} +1025 -695
  4. package/dist/chunk-GN7232BY.js.map +1 -0
  5. package/dist/{chunk-BMYC6772.js → chunk-H3O43F5P.js} +9765 -3068
  6. package/dist/chunk-H3O43F5P.js.map +1 -0
  7. package/dist/dev-host/dev-api-proxy-plugin.ts +330 -0
  8. package/dist/dev-host/dev-diagnostics.ts +62 -0
  9. package/dist/dev-host/dev-fallback-stylesheet.ts +50 -0
  10. package/dist/dev-host/dev-host-controller.ts +686 -0
  11. package/dist/dev-host/dev-host-player-query.ts +17 -0
  12. package/dist/dev-host/dev-host-session-transport.ts +52 -0
  13. package/dist/dev-host/dev-host-storage.ts +56 -0
  14. package/dist/dev-host/dev-log-relay-plugin.ts +469 -0
  15. package/dist/dev-host/dev-runtime-config.ts +14 -0
  16. package/dist/dev-host/dev-runtime-platform.ts +419 -0
  17. package/dist/dev-host/dev-virtual-modules-plugin.ts +63 -0
  18. package/dist/dev-host/host-main.css +182 -0
  19. package/dist/dev-host/host-main.tsx +754 -0
  20. package/dist/dev-host/index.html +56 -0
  21. package/dist/dev-host/plugin-main.ts +55 -0
  22. package/dist/dev-host/plugin.html +24 -0
  23. package/dist/dev-host/start-dev-server.ts +138 -0
  24. package/dist/dev-host/virtual-modules.d.ts +27 -0
  25. package/dist/dist-FEPN3BDN.js +16543 -0
  26. package/dist/dist-FEPN3BDN.js.map +1 -0
  27. package/dist/{dist-WJRJNFLI.js → dist-FRURQI7Q.js} +4 -2
  28. package/dist/index.js +3 -3
  29. package/dist/internal.js +159 -124
  30. package/dist/internal.js.map +1 -1
  31. package/dist/runtime-packages/tailwind-config/shared-styles.css +146 -0
  32. package/dist/runtime-packages/ui/src/components/.gitkeep +0 -0
  33. package/dist/runtime-packages/ui/src/components/accordion.tsx +66 -0
  34. package/dist/runtime-packages/ui/src/components/ai-elements/actions.tsx +65 -0
  35. package/dist/runtime-packages/ui/src/components/ai-elements/artifact.tsx +147 -0
  36. package/dist/runtime-packages/ui/src/components/ai-elements/branch.tsx +215 -0
  37. package/dist/runtime-packages/ui/src/components/ai-elements/canvas.tsx +22 -0
  38. package/dist/runtime-packages/ui/src/components/ai-elements/chain-of-thought.tsx +228 -0
  39. package/dist/runtime-packages/ui/src/components/ai-elements/code-block.tsx +179 -0
  40. package/dist/runtime-packages/ui/src/components/ai-elements/confirmation.tsx +158 -0
  41. package/dist/runtime-packages/ui/src/components/ai-elements/connection.tsx +28 -0
  42. package/dist/runtime-packages/ui/src/components/ai-elements/context.tsx +408 -0
  43. package/dist/runtime-packages/ui/src/components/ai-elements/controls.tsx +18 -0
  44. package/dist/runtime-packages/ui/src/components/ai-elements/conversation.tsx +97 -0
  45. package/dist/runtime-packages/ui/src/components/ai-elements/edge.tsx +140 -0
  46. package/dist/runtime-packages/ui/src/components/ai-elements/image.tsx +24 -0
  47. package/dist/runtime-packages/ui/src/components/ai-elements/inline-citation.tsx +287 -0
  48. package/dist/runtime-packages/ui/src/components/ai-elements/loader.tsx +96 -0
  49. package/dist/runtime-packages/ui/src/components/ai-elements/message.tsx +463 -0
  50. package/dist/runtime-packages/ui/src/components/ai-elements/node.tsx +71 -0
  51. package/dist/runtime-packages/ui/src/components/ai-elements/open-in-chat.tsx +365 -0
  52. package/dist/runtime-packages/ui/src/components/ai-elements/panel.tsx +15 -0
  53. package/dist/runtime-packages/ui/src/components/ai-elements/plan.tsx +142 -0
  54. package/dist/runtime-packages/ui/src/components/ai-elements/prompt-input.tsx +1380 -0
  55. package/dist/runtime-packages/ui/src/components/ai-elements/queue.tsx +274 -0
  56. package/dist/runtime-packages/ui/src/components/ai-elements/reasoning.tsx +182 -0
  57. package/dist/runtime-packages/ui/src/components/ai-elements/response.tsx +22 -0
  58. package/dist/runtime-packages/ui/src/components/ai-elements/shimmer.tsx +64 -0
  59. package/dist/runtime-packages/ui/src/components/ai-elements/sources.tsx +77 -0
  60. package/dist/runtime-packages/ui/src/components/ai-elements/suggestion.tsx +53 -0
  61. package/dist/runtime-packages/ui/src/components/ai-elements/task.tsx +87 -0
  62. package/dist/runtime-packages/ui/src/components/ai-elements/tool.tsx +165 -0
  63. package/dist/runtime-packages/ui/src/components/ai-elements/toolbar.tsx +16 -0
  64. package/dist/runtime-packages/ui/src/components/ai-elements/web-preview.tsx +263 -0
  65. package/dist/runtime-packages/ui/src/components/alert-dialog.tsx +157 -0
  66. package/dist/runtime-packages/ui/src/components/alert.tsx +66 -0
  67. package/dist/runtime-packages/ui/src/components/avatar.tsx +53 -0
  68. package/dist/runtime-packages/ui/src/components/badge.tsx +46 -0
  69. package/dist/runtime-packages/ui/src/components/button-group.tsx +83 -0
  70. package/dist/runtime-packages/ui/src/components/button.tsx +65 -0
  71. package/dist/runtime-packages/ui/src/components/card.tsx +92 -0
  72. package/dist/runtime-packages/ui/src/components/carousel.tsx +241 -0
  73. package/dist/runtime-packages/ui/src/components/collapsible.tsx +33 -0
  74. package/dist/runtime-packages/ui/src/components/command.tsx +184 -0
  75. package/dist/runtime-packages/ui/src/components/context-menu.tsx +252 -0
  76. package/dist/runtime-packages/ui/src/components/counter.tsx +11 -0
  77. package/dist/runtime-packages/ui/src/components/dialog.tsx +146 -0
  78. package/dist/runtime-packages/ui/src/components/drawer.tsx +132 -0
  79. package/dist/runtime-packages/ui/src/components/dropdown-menu.tsx +257 -0
  80. package/dist/runtime-packages/ui/src/components/form.tsx +168 -0
  81. package/dist/runtime-packages/ui/src/components/header.tsx +13 -0
  82. package/dist/runtime-packages/ui/src/components/hover-card.tsx +44 -0
  83. package/dist/runtime-packages/ui/src/components/input-group.tsx +178 -0
  84. package/dist/runtime-packages/ui/src/components/input.tsx +21 -0
  85. package/dist/runtime-packages/ui/src/components/item.tsx +193 -0
  86. package/dist/runtime-packages/ui/src/components/label.tsx +24 -0
  87. package/dist/runtime-packages/ui/src/components/navigation-menu.tsx +168 -0
  88. package/dist/runtime-packages/ui/src/components/popover.tsx +55 -0
  89. package/dist/runtime-packages/ui/src/components/progress.tsx +31 -0
  90. package/dist/runtime-packages/ui/src/components/radio-group.tsx +45 -0
  91. package/dist/runtime-packages/ui/src/components/resizable.tsx +56 -0
  92. package/dist/runtime-packages/ui/src/components/scroll-area.tsx +58 -0
  93. package/dist/runtime-packages/ui/src/components/select.tsx +187 -0
  94. package/dist/runtime-packages/ui/src/components/separator.tsx +28 -0
  95. package/dist/runtime-packages/ui/src/components/skeleton.tsx +13 -0
  96. package/dist/runtime-packages/ui/src/components/sonner.tsx +25 -0
  97. package/dist/runtime-packages/ui/src/components/spinner.tsx +16 -0
  98. package/dist/runtime-packages/ui/src/components/switch.tsx +31 -0
  99. package/dist/runtime-packages/ui/src/components/table.tsx +137 -0
  100. package/dist/runtime-packages/ui/src/components/tabs.tsx +74 -0
  101. package/dist/runtime-packages/ui/src/components/textarea.tsx +23 -0
  102. package/dist/runtime-packages/ui/src/components/theme-provider.tsx +73 -0
  103. package/dist/runtime-packages/ui/src/components/tooltip.tsx +61 -0
  104. package/dist/runtime-packages/ui/src/components/ui/file-upload.tsx +195 -0
  105. package/dist/runtime-packages/ui/src/hooks/.gitkeep +0 -0
  106. package/dist/runtime-packages/ui/src/index.ts +68 -0
  107. package/dist/runtime-packages/ui/src/lib/utils.ts +6 -0
  108. package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +68 -0
  109. package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +359 -0
  110. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +274 -0
  111. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +214 -0
  112. package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +135 -0
  113. package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +5 -0
  114. package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +194 -0
  115. package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +1 -0
  116. package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +1 -0
  117. package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +162 -0
  118. package/dist/runtime-packages/ui-host-runtime/src/index.ts +2 -0
  119. package/dist/runtime-packages/ui-host-runtime/src/logger.ts +11 -0
  120. package/dist/runtime-packages/ui-host-runtime/src/perf.ts +253 -0
  121. package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +195 -0
  122. package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +138 -0
  123. package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +159 -0
  124. package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +524 -0
  125. package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +12 -0
  126. package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +122 -0
  127. package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +26 -0
  128. package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +477 -0
  129. package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +209 -0
  130. package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +112 -0
  131. package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +318 -0
  132. package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +211 -0
  133. package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +814 -0
  134. package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +334 -0
  135. package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +180 -0
  136. package/dist/scaffold/assets/static/app/tsconfig.framework.json +3 -1
  137. package/dist/scaffold/assets/static/ui/tsconfig.framework.json +7 -19
  138. package/package.json +52 -17
  139. package/skills/dreamboard/SKILL.md +41 -75
  140. package/LICENSE +0 -89
  141. package/NOTICE +0 -1
  142. package/dist/chunk-BMYC6772.js.map +0 -1
  143. package/dist/chunk-EYYWGWTO.js.map +0 -1
  144. package/dist/chunk-MOVHYB6E.js.map +0 -1
  145. package/dist/scaffold/assets/static/ui/App.tsx +0 -22
  146. package/dist/src-CUL7EGGG.js +0 -634
  147. package/dist/src-CUL7EGGG.js.map +0 -1
  148. package/skills/dreamboard/references/authoring-lifecycle.md +0 -102
  149. package/skills/dreamboard/references/board-surfaces.md +0 -36
  150. package/skills/dreamboard/references/board-topology.md +0 -443
  151. package/skills/dreamboard/references/boards-and-topology.md +0 -100
  152. package/skills/dreamboard/references/card-actions.md +0 -107
  153. package/skills/dreamboard/references/cli.md +0 -120
  154. package/skills/dreamboard/references/core-concepts.md +0 -514
  155. package/skills/dreamboard/references/custom-renderers.md +0 -26
  156. package/skills/dreamboard/references/derived-values.md +0 -55
  157. package/skills/dreamboard/references/effects.md +0 -111
  158. package/skills/dreamboard/references/game-contract.md +0 -89
  159. package/skills/dreamboard/references/game-definition.md +0 -89
  160. package/skills/dreamboard/references/game-shell.md +0 -80
  161. package/skills/dreamboard/references/hand-surfaces.md +0 -33
  162. package/skills/dreamboard/references/index.md +0 -112
  163. package/skills/dreamboard/references/inputs-and-targets.md +0 -160
  164. package/skills/dreamboard/references/interactions.md +0 -158
  165. package/skills/dreamboard/references/manifest-fields.md +0 -137
  166. package/skills/dreamboard/references/manifest.md +0 -81
  167. package/skills/dreamboard/references/package-surfaces.md +0 -69
  168. package/skills/dreamboard/references/phases.md +0 -145
  169. package/skills/dreamboard/references/prompts-and-choices.md +0 -55
  170. package/skills/dreamboard/references/quickstart.md +0 -71
  171. package/skills/dreamboard/references/rule-authoring.md +0 -144
  172. package/skills/dreamboard/references/setup-bootstrap.md +0 -78
  173. package/skills/dreamboard/references/stages-and-zones.md +0 -59
  174. package/skills/dreamboard/references/static-views.md +0 -67
  175. package/skills/dreamboard/references/table-queries-and-ops.md +0 -103
  176. package/skills/dreamboard/references/testing-bases.md +0 -147
  177. package/skills/dreamboard/references/testing-generated-contracts.md +0 -142
  178. package/skills/dreamboard/references/testing-runtime-assertions.md +0 -124
  179. package/skills/dreamboard/references/testing-scenarios.md +0 -148
  180. package/skills/dreamboard/references/testing-ui-tests.md +0 -174
  181. package/skills/dreamboard/references/testing.md +0 -161
  182. package/skills/dreamboard/references/ui-architecture.md +0 -137
  183. package/skills/dreamboard/references/ui-components.md +0 -34
  184. package/skills/dreamboard/references/views.md +0 -72
  185. package/skills/dreamboard/references/workspace-layout.md +0 -136
  186. /package/dist/{dist-WJRJNFLI.js.map → dist-FRURQI7Q.js.map} +0 -0
@@ -0,0 +1,334 @@
1
+ import type { HostSessionTransport } from "./host-session-transport.js";
2
+ import { defaultHostSessionTransport } from "./host-session-transport.js";
3
+ import type { LoggerLike } from "./logger.js";
4
+ import { consoleLogger } from "./logger.js";
5
+ import { PERF_MARK_NAMES, findActionIdByVersion, recordMark } from "./perf.js";
6
+ import type { HostSessionWireEvent } from "./session-ingress.js";
7
+
8
+ type HostSessionEventType = HostSessionWireEvent["type"];
9
+
10
+ type ExtractHostSessionEvent<T extends HostSessionEventType> = Extract<
11
+ HostSessionWireEvent,
12
+ { type: T }
13
+ >;
14
+
15
+ type HostSessionEventHandler<
16
+ T extends HostSessionEventType = HostSessionEventType,
17
+ > = (data: ExtractHostSessionEvent<T>) => void;
18
+ type ConnectionEventHandler = () => void;
19
+ type ErrorEventHandler = (error: unknown) => void;
20
+ type AnyHostSessionEventHandler = (data: HostSessionWireEvent) => void;
21
+ type EventHandler =
22
+ | AnyHostSessionEventHandler
23
+ | ConnectionEventHandler
24
+ | ErrorEventHandler;
25
+
26
+ export interface SSEManagerOptions {
27
+ clientId?: string;
28
+ logger?: LoggerLike;
29
+ transport?: Pick<
30
+ HostSessionTransport,
31
+ "subscribeToSessionEvents" | "disconnectSessionEvents"
32
+ >;
33
+ }
34
+
35
+ export interface SSEConnectOptions {
36
+ source?: string;
37
+ playerId?: string;
38
+ }
39
+
40
+ interface ActiveConnection {
41
+ connectionAttemptId: string;
42
+ sessionId: string;
43
+ playerId?: string;
44
+ source?: string;
45
+ }
46
+
47
+ const TAB_ID_SESSION_STORAGE_KEY = "dreamboard.sse.tab-id";
48
+
49
+ function randomId(): string {
50
+ if (
51
+ typeof crypto !== "undefined" &&
52
+ typeof crypto.randomUUID === "function"
53
+ ) {
54
+ return crypto.randomUUID();
55
+ }
56
+ return `sse-${Date.now()}-${Math.random().toString(36).slice(2)}`;
57
+ }
58
+
59
+ function getOrCreateTabId(): string {
60
+ if (typeof window === "undefined") {
61
+ return randomId();
62
+ }
63
+
64
+ try {
65
+ const existing = window.sessionStorage.getItem(TAB_ID_SESSION_STORAGE_KEY);
66
+ if (existing) {
67
+ return existing;
68
+ }
69
+
70
+ const created = randomId();
71
+ window.sessionStorage.setItem(TAB_ID_SESSION_STORAGE_KEY, created);
72
+ return created;
73
+ } catch {
74
+ return randomId();
75
+ }
76
+ }
77
+
78
+ function isAbortLikeError(error: unknown): boolean {
79
+ return error instanceof Error && error.name === "AbortError";
80
+ }
81
+
82
+ export class SSEManager {
83
+ private abortController: AbortController | null = null;
84
+ private activeConnection: ActiveConnection | null = null;
85
+ private readonly clientId: string;
86
+ private readonly transport: Pick<
87
+ HostSessionTransport,
88
+ "subscribeToSessionEvents" | "disconnectSessionEvents"
89
+ >;
90
+ private handlers: Map<string, Set<EventHandler>> = new Map();
91
+ private anyMessageHandlers: Set<AnyHostSessionEventHandler> = new Set();
92
+ private isConnected = false;
93
+ private messageBuffer: HostSessionWireEvent[] = [];
94
+ private logger: LoggerLike;
95
+ private pageHideHandler: (() => void) | null = null;
96
+
97
+ constructor(options: SSEManagerOptions = {}) {
98
+ this.clientId = options.clientId ?? getOrCreateTabId();
99
+ this.logger = options.logger ?? consoleLogger;
100
+ this.transport = options.transport ?? defaultHostSessionTransport;
101
+ }
102
+
103
+ async connect(sessionId: string, options: SSEConnectOptions) {
104
+ if (this.abortController) {
105
+ this.disconnect();
106
+ }
107
+
108
+ this.abortController = new AbortController();
109
+ const connection: ActiveConnection = {
110
+ sessionId,
111
+ playerId: options.playerId,
112
+ connectionAttemptId: randomId(),
113
+ source: options.source,
114
+ };
115
+ this.activeConnection = connection;
116
+ this.registerPageHideHandler();
117
+
118
+ try {
119
+ let connected = false;
120
+ let streamError: unknown = null;
121
+
122
+ const stream = (
123
+ await this.transport.subscribeToSessionEvents({
124
+ sessionId,
125
+ clientId: this.clientId,
126
+ connectionAttemptId: connection.connectionAttemptId,
127
+ clientSource: options.source,
128
+ playerId: connection.playerId,
129
+ signal: this.abortController.signal,
130
+ onSseError: (error) => {
131
+ if (
132
+ this.abortController?.signal.aborted ||
133
+ isAbortLikeError(error)
134
+ ) {
135
+ return;
136
+ }
137
+ streamError = error;
138
+ },
139
+ })
140
+ ).stream;
141
+
142
+ for await (const event of stream) {
143
+ if (!event) continue;
144
+ if (!connected) {
145
+ connected = true;
146
+ this.isConnected = true;
147
+ this.emit("connected", null);
148
+ }
149
+
150
+ const eventType = event.type;
151
+
152
+ if (eventType) {
153
+ // Tier-0 perf: record `t4_sse_received` the moment the SSE
154
+ // stream yields a gameplay.updated for a version we submitted.
155
+ // Stitching is done via the version -> actionId map populated
156
+ // at t3 in runtime-api.
157
+ if (eventType === "session.gameplayUpdated") {
158
+ const version = event.gameplay?.version;
159
+ if (typeof version === "number") {
160
+ const actionId = findActionIdByVersion(version);
161
+ if (actionId) {
162
+ recordMark(actionId, PERF_MARK_NAMES.T4_SSE_RECEIVED, {
163
+ extra: { version },
164
+ });
165
+ }
166
+ }
167
+ }
168
+ this.emit(eventType, event);
169
+ } else {
170
+ this.logger.error("[SSEManager] Received event without type:", event);
171
+ }
172
+ }
173
+
174
+ if (streamError) {
175
+ this.logger.error("[SSEManager] SSE error:", streamError);
176
+ this.emit("error", streamError);
177
+ this.isConnected = false;
178
+ this.emit("disconnected", null);
179
+ return;
180
+ }
181
+
182
+ this.isConnected = false;
183
+ this.emit("disconnected", null);
184
+ } catch (error) {
185
+ if (isAbortLikeError(error)) {
186
+ return;
187
+ }
188
+
189
+ this.logger.error("[SSEManager] SSE error:", error);
190
+ this.emit("error", error);
191
+ this.isConnected = false;
192
+ this.emit("disconnected", null);
193
+ } finally {
194
+ if (
195
+ this.activeConnection?.connectionAttemptId ===
196
+ connection.connectionAttemptId
197
+ ) {
198
+ this.activeConnection = null;
199
+ this.unregisterPageHideHandler();
200
+ }
201
+ }
202
+ }
203
+
204
+ on<T extends HostSessionEventType>(
205
+ eventType: T,
206
+ handler: HostSessionEventHandler<T>,
207
+ ): () => void;
208
+ on(
209
+ eventType: "connected" | "disconnected",
210
+ handler: ConnectionEventHandler,
211
+ ): () => void;
212
+ on(eventType: "error", handler: ErrorEventHandler): () => void;
213
+ on(eventType: string, handler: EventHandler): () => void {
214
+ if (!this.handlers.has(eventType)) {
215
+ this.handlers.set(eventType, new Set());
216
+ }
217
+ const handlers = this.handlers.get(eventType);
218
+ if (handlers) {
219
+ handlers.add(handler);
220
+ }
221
+
222
+ return () => {
223
+ this.handlers.get(eventType)?.delete(handler);
224
+ };
225
+ }
226
+
227
+ onAnyMessage(handler: AnyHostSessionEventHandler): () => void {
228
+ this.anyMessageHandlers.add(handler);
229
+
230
+ if (this.messageBuffer.length > 0) {
231
+ this.messageBuffer.forEach((message) => {
232
+ handler(message);
233
+ });
234
+ }
235
+
236
+ return () => {
237
+ this.anyMessageHandlers.delete(handler);
238
+ };
239
+ }
240
+
241
+ private emit(eventType: string, data: HostSessionWireEvent): void;
242
+ private emit(eventType: "connected" | "disconnected", data: null): void;
243
+ private emit(eventType: "error", error: unknown): void;
244
+ private emit(
245
+ eventType: string,
246
+ data: HostSessionWireEvent | null | unknown,
247
+ ): void {
248
+ const handlers = this.handlers.get(eventType);
249
+ if (handlers) {
250
+ handlers.forEach((handler) => {
251
+ if (eventType === "connected" || eventType === "disconnected") {
252
+ (handler as ConnectionEventHandler)();
253
+ } else if (eventType === "error") {
254
+ (handler as ErrorEventHandler)(data);
255
+ } else {
256
+ (handler as AnyHostSessionEventHandler)(data as HostSessionWireEvent);
257
+ }
258
+ });
259
+ }
260
+
261
+ if (
262
+ eventType !== "connected" &&
263
+ eventType !== "disconnected" &&
264
+ eventType !== "error"
265
+ ) {
266
+ this.messageBuffer.push(data as HostSessionWireEvent);
267
+
268
+ this.anyMessageHandlers.forEach((handler) => {
269
+ handler(data as HostSessionWireEvent);
270
+ });
271
+ }
272
+ }
273
+
274
+ disconnect() {
275
+ const activeConnection = this.activeConnection;
276
+ if (activeConnection) {
277
+ this.notifyDisconnect(activeConnection, true);
278
+ }
279
+
280
+ if (this.abortController) {
281
+ this.abortController.abort();
282
+ this.abortController = null;
283
+ }
284
+ this.activeConnection = null;
285
+ this.unregisterPageHideHandler();
286
+ this.isConnected = false;
287
+ this.handlers.clear();
288
+ this.anyMessageHandlers.clear();
289
+ this.messageBuffer = [];
290
+ }
291
+
292
+ isStreamConnected(): boolean {
293
+ return this.isConnected;
294
+ }
295
+
296
+ private notifyDisconnect(
297
+ connection: ActiveConnection,
298
+ _keepalive: boolean,
299
+ ): void {
300
+ const request = this.transport.disconnectSessionEvents({
301
+ sessionId: connection.sessionId,
302
+ clientId: this.clientId,
303
+ connectionAttemptId: connection.connectionAttemptId,
304
+ playerId: connection.playerId,
305
+ });
306
+
307
+ void request.catch((error) => {
308
+ this.logger.error("[SSEManager] Failed to notify disconnect:", error);
309
+ });
310
+ }
311
+
312
+ private registerPageHideHandler(): void {
313
+ if (typeof window === "undefined" || this.pageHideHandler) {
314
+ return;
315
+ }
316
+
317
+ this.pageHideHandler = () => {
318
+ if (this.activeConnection) {
319
+ this.notifyDisconnect(this.activeConnection, true);
320
+ }
321
+ };
322
+
323
+ window.addEventListener("pagehide", this.pageHideHandler);
324
+ }
325
+
326
+ private unregisterPageHideHandler(): void {
327
+ if (typeof window === "undefined" || !this.pageHideHandler) {
328
+ return;
329
+ }
330
+
331
+ window.removeEventListener("pagehide", this.pageHideHandler);
332
+ this.pageHideHandler = null;
333
+ }
334
+ }
@@ -0,0 +1,180 @@
1
+ import { createStore } from "zustand/vanilla";
2
+ import { subscribeWithSelector } from "zustand/middleware";
3
+ import type { StoreApi } from "zustand/vanilla";
4
+ import type { PluginStateSnapshot as UiSdkPluginStateSnapshot } from "@dreamboard/ui-sdk/reducer";
5
+ import type { LoggerLike } from "./logger.js";
6
+ import { consoleLogger } from "./logger.js";
7
+ import type { HostSessionTransport } from "./host-session-transport.js";
8
+ import { defaultHostSessionTransport } from "./host-session-transport.js";
9
+ import type { GameplayViewport } from "./session-model.js";
10
+ import {
11
+ getGameplayViewport,
12
+ getSessionContext,
13
+ resolveControllablePlayerIds,
14
+ } from "./session-model.js";
15
+ import type { SSEManagerLike } from "./session-live-runtime.js";
16
+ import { createSessionIngressController } from "./session-ingress-controller.js";
17
+ import type { SessionIngressControllerActions } from "./session-ingress-controller.js";
18
+ import {
19
+ createInitialUnifiedSessionState,
20
+ type UnifiedSessionState,
21
+ } from "./session-state-reducer.js";
22
+ import {
23
+ selectBootstrapStatus,
24
+ selectGameplayViewModel,
25
+ selectGameplayViewport,
26
+ selectHistory,
27
+ selectLobbyViewModel,
28
+ selectPluginSnapshot,
29
+ selectSessionContext,
30
+ selectSessionError,
31
+ selectSessionType,
32
+ } from "./session-projection.js";
33
+
34
+ export type {
35
+ GameplayViewport,
36
+ HistoryState,
37
+ SessionContext,
38
+ SessionIdentity,
39
+ SessionPhase,
40
+ UnifiedSessionModel,
41
+ } from "./session-model.js";
42
+ export type {
43
+ BootstrapStatus,
44
+ GameplayViewModel,
45
+ LobbyViewModel,
46
+ } from "./session-projection.js";
47
+ export type { SSEManagerLike } from "./session-live-runtime.js";
48
+ export type {
49
+ ActivityState,
50
+ ConnectionState,
51
+ DebugState,
52
+ HostFeedback,
53
+ HostFeedbackPayload,
54
+ HostFeedbackType,
55
+ Notification,
56
+ NotificationPayload,
57
+ NotificationType,
58
+ SSEEventEntry,
59
+ UnifiedSessionState,
60
+ } from "./session-state-reducer.js";
61
+
62
+ export type PluginStateSnapshot = UiSdkPluginStateSnapshot;
63
+ export type GameplayState = GameplayViewport;
64
+
65
+ export interface UnifiedSessionActions extends SessionIngressControllerActions {
66
+ getPluginSnapshot: () => PluginStateSnapshot;
67
+ getRenderableGameplay: () => GameplayViewport | null;
68
+ }
69
+
70
+ export type UnifiedSessionStore = UnifiedSessionState & UnifiedSessionActions;
71
+
72
+ export interface CreateUnifiedSessionStoreOptions {
73
+ createSseManager: () => SSEManagerLike;
74
+ transport?: HostSessionTransport;
75
+ logger?: LoggerLike;
76
+ fallbackToAllSeatsWhenUserIdMissing?: boolean;
77
+ }
78
+
79
+ let sseEventIdCounter = 0;
80
+ let notificationIdCounter = 0;
81
+ const EMPTY_ARRAY: never[] = [];
82
+
83
+ function generateNotificationId(): string {
84
+ return `notif-${++notificationIdCounter}-${Date.now()}`;
85
+ }
86
+
87
+ export function createUnifiedSessionStore(
88
+ options: CreateUnifiedSessionStoreOptions,
89
+ ): StoreApi<UnifiedSessionStore> {
90
+ const logger = options.logger ?? consoleLogger;
91
+ const transport = options.transport ?? defaultHostSessionTransport;
92
+ const fallbackToAllSeatsWhenUserIdMissing =
93
+ options.fallbackToAllSeatsWhenUserIdMissing ?? false;
94
+
95
+ return createStore<UnifiedSessionStore>()(
96
+ subscribeWithSelector((_, get, store) => {
97
+ const controller = createSessionIngressController({
98
+ store,
99
+ createSseManager: options.createSseManager,
100
+ transport,
101
+ logger,
102
+ fallbackToAllSeatsWhenUserIdMissing,
103
+ reducerEnvironment: {
104
+ fallbackToAllSeatsWhenUserIdMissing,
105
+ nextEventId: () => ++sseEventIdCounter,
106
+ nextNotificationId: generateNotificationId,
107
+ nowMs: () => Date.now(),
108
+ nowIso: () => new Date().toISOString(),
109
+ },
110
+ });
111
+
112
+ return {
113
+ ...createInitialUnifiedSessionState(),
114
+ ...controller,
115
+ getPluginSnapshot: () =>
116
+ selectPluginSnapshot(get(), fallbackToAllSeatsWhenUserIdMissing),
117
+ getRenderableGameplay: () => getGameplayViewport(get().session),
118
+ };
119
+ }),
120
+ );
121
+ }
122
+
123
+ export const unifiedSessionSelectors = {
124
+ sessionType: selectSessionType,
125
+ bootstrapStatus: selectBootstrapStatus,
126
+ sessionContext: selectSessionContext,
127
+ lobby: selectLobbyViewModel,
128
+ gameplay: selectGameplayViewModel,
129
+ gameplayViewport: selectGameplayViewport,
130
+ hasGameplayPayload: (s: UnifiedSessionStore) =>
131
+ getGameplayViewport(s.session) !== null,
132
+ history: selectHistory,
133
+ isConnected: (s: UnifiedSessionStore) => s.connection.isConnected,
134
+ connectionError: (s: UnifiedSessionStore) => s.connection.error,
135
+ isLoading: (s: UnifiedSessionStore) =>
136
+ s.session.type === "loading" || s.session.type === "gameplayLoading",
137
+ error: selectSessionError,
138
+ sessionId: (s: UnifiedSessionStore) =>
139
+ getSessionContext(s.session)?.identity.sessionId ?? null,
140
+ shortCode: (s: UnifiedSessionStore) =>
141
+ getSessionContext(s.session)?.identity.shortCode ?? "",
142
+ gameId: (s: UnifiedSessionStore) =>
143
+ getSessionContext(s.session)?.identity.gameId ?? null,
144
+ seats: (s: UnifiedSessionStore) =>
145
+ getSessionContext(s.session)?.seats ?? EMPTY_ARRAY,
146
+ canStart: (s: UnifiedSessionStore) =>
147
+ getSessionContext(s.session)?.canStart ?? false,
148
+ hostActor: (s: UnifiedSessionStore) =>
149
+ getSessionContext(s.session)?.hostActor ?? null,
150
+ isSessionHost: (s: UnifiedSessionStore) =>
151
+ selectLobbyViewModel(s)?.isSessionHost ?? false,
152
+ controllablePlayerIds: (s: UnifiedSessionStore) => {
153
+ const context = getSessionContext(s.session);
154
+ return context
155
+ ? resolveControllablePlayerIds(
156
+ context.switchablePlayerIds,
157
+ context.seats,
158
+ context.userId,
159
+ )
160
+ : EMPTY_ARRAY;
161
+ },
162
+ controllingPlayerId: (s: UnifiedSessionStore) =>
163
+ s.session.type === "gameplay" ? s.session.perspective.playerId : null,
164
+ currentPlayerId: (s: UnifiedSessionStore) =>
165
+ s.session.type === "gameplay"
166
+ ? s.session.perspective.playerId
167
+ : s.session.type === "gameplayLoading"
168
+ ? s.session.requestedPlayerId
169
+ : s.session.type === "lobby"
170
+ ? s.session.preferredPlayerId
171
+ : null,
172
+ userId: (s: UnifiedSessionStore) =>
173
+ getSessionContext(s.session)?.userId ?? null,
174
+ notifications: (s: UnifiedSessionStore) => s.activity.notifications,
175
+ hostFeedback: (s: UnifiedSessionStore) => s.activity.hostFeedback,
176
+ sseEvents: (s: UnifiedSessionStore) => s.debug.sseEvents,
177
+ syncId: (s: UnifiedSessionStore) => s.activity.syncId,
178
+ activity: (s: UnifiedSessionStore) => s.activity,
179
+ debug: (s: UnifiedSessionStore) => s.debug,
180
+ };
@@ -5,8 +5,10 @@
5
5
  "moduleResolution": "bundler",
6
6
  "strict": true,
7
7
  "esModuleInterop": true,
8
- "skipLibCheck": true,
8
+ "skipLibCheck": false,
9
+ "types": [],
9
10
  "declaration": false,
11
+ "rootDir": "..",
10
12
  "outDir": "./dist",
11
13
  "paths": {
12
14
  "@dreamboard/manifest-contract": ["../shared/manifest-contract.ts"],
@@ -6,26 +6,14 @@
6
6
  "jsx": "react-jsx",
7
7
  "strict": true,
8
8
  "esModuleInterop": true,
9
- "skipLibCheck": true,
9
+ "skipLibCheck": false,
10
+ "types": [],
10
11
  "paths": {
11
- "@dreamboard/manifest-contract": [
12
- "../shared/manifest-contract.ts"
13
- ],
14
- "@dreamboard/ui-contract": [
15
- "../shared/generated/ui-contract.ts"
16
- ],
17
- "@shared/*": [
18
- "../shared/*"
19
- ]
12
+ "@dreamboard/manifest-contract": ["../shared/manifest-contract.ts"],
13
+ "@dreamboard/ui-contract": ["../shared/generated/ui-contract.ts"],
14
+ "@shared/*": ["../shared/*"]
20
15
  }
21
16
  },
22
- "include": [
23
- "./**/*.ts",
24
- "./**/*.tsx",
25
- "../shared/**/*.ts"
26
- ],
27
- "exclude": [
28
- "node_modules",
29
- "dist"
30
- ]
17
+ "include": ["./**/*.ts", "./**/*.tsx", "../shared/**/*.ts"],
18
+ "exclude": ["node_modules", "dist"]
31
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dreamboard",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "Design board games with AI and turn ideas into playable digital prototypes.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,8 +9,6 @@
9
9
  "files": [
10
10
  "dist",
11
11
  "README.md",
12
- "LICENSE",
13
- "NOTICE",
14
12
  "skills"
15
13
  ],
16
14
  "keywords": [
@@ -44,26 +42,63 @@
44
42
  "vite": "^5.4.19",
45
43
  "zod": "4.4.3",
46
44
  "zustand": "^5.0.4",
47
- "@dreamboard/api-client": "npm:@dreamboard-games/api-client@^0.1.2",
48
- "@dreamboard/app-sdk": "npm:@dreamboard-games/app-sdk@^0.0.45",
49
- "@dreamboard/reducer-contract": "npm:@dreamboard-games/reducer-contract@^7.0.2",
50
- "@dreamboard/sdk-types": "npm:@dreamboard-games/sdk-types@^0.1.2",
51
- "@dreamboard/testing": "npm:@dreamboard-games/testing@^0.1.3",
52
- "@dreamboard/ui-sdk": "npm:@dreamboard-games/ui-sdk@^0.0.46",
53
- "@dreamboard/workspace-codegen": "npm:@dreamboard-games/workspace-codegen@^0.1.4",
45
+ "@dreamboard-games/api-client": "^0.1.0",
46
+ "@dreamboard-games/sdk-types": "^0.1.0",
47
+ "@dreamboard-games/ui-sdk": "^0.0.41",
48
+ "@hookform/resolvers": "^5.2.2",
49
+ "@radix-ui/react-accordion": "^1.2.12",
50
+ "@radix-ui/react-alert-dialog": "^1.1.14",
51
+ "@radix-ui/react-avatar": "^1.1.11",
52
+ "@radix-ui/react-collapsible": "^1.1.12",
53
+ "@radix-ui/react-context-menu": "^2.2.16",
54
+ "@radix-ui/react-dialog": "^1.1.14",
55
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
56
+ "@radix-ui/react-hover-card": "^1.1.15",
57
+ "@radix-ui/react-label": "^2.1.6",
58
+ "@radix-ui/react-navigation-menu": "^1.2.13",
59
+ "@radix-ui/react-popover": "^1.1.13",
60
+ "@radix-ui/react-progress": "^1.1.7",
61
+ "@radix-ui/react-radio-group": "^1.3.7",
62
+ "@radix-ui/react-scroll-area": "^1.2.10",
63
+ "@radix-ui/react-select": "^2.2.5",
64
+ "@radix-ui/react-separator": "^1.1.7",
65
+ "@radix-ui/react-slot": "^1.1.2",
66
+ "@radix-ui/react-switch": "^1.2.5",
67
+ "@radix-ui/react-tabs": "^1.1.12",
68
+ "@radix-ui/react-tooltip": "^1.2.8",
69
+ "@radix-ui/react-use-controllable-state": "^1.2.2",
70
+ "@xyflow/react": "^12.9.2",
71
+ "ai": "^5.0.88",
72
+ "class-variance-authority": "^0.7.1",
73
+ "clsx": "^2.1.1",
74
+ "cmdk": "^1.1.1",
75
+ "embla-carousel-react": "^8.6.0",
76
+ "framer-motion": "^12.12.1",
77
+ "motion": "^12.12.2",
78
+ "nanoid": "^5.1.6",
79
+ "next-themes": "^0.4.4",
80
+ "radix-ui": "^1.4.3",
81
+ "react-dropzone": "^14.3.8",
82
+ "react-hook-form": "^7.66.0",
83
+ "react-resizable-panels": "^3.0.6",
84
+ "react-textarea-autosize": "^8.5.9",
85
+ "shiki": "^3.15.0",
86
+ "streamdown": "^1.4.0",
87
+ "tailwind-merge": "^3.0.1",
88
+ "tokenlens": "^1.3.1",
89
+ "use-stick-to-bottom": "^1.1.1",
90
+ "vaul": "^1.1.2",
54
91
  "playwright": "^1.50.1"
55
92
  },
56
93
  "optionalDependencies": {
57
94
  "@napi-rs/keyring": "^1.2.0"
58
95
  },
59
96
  "dreamboardSdkDependencyRanges": {
60
- "@dreamboard/api-client": "npm:@dreamboard-games/api-client@^0.1.2",
61
- "@dreamboard/app-sdk": "npm:@dreamboard-games/app-sdk@^0.0.45",
62
- "@dreamboard/reducer-contract": "npm:@dreamboard-games/reducer-contract@^7.0.2",
63
- "@dreamboard/sdk-types": "npm:@dreamboard-games/sdk-types@^0.1.2",
64
- "@dreamboard/testing": "npm:@dreamboard-games/testing@^0.1.3",
65
- "@dreamboard/ui-sdk": "npm:@dreamboard-games/ui-sdk@^0.0.46",
66
- "@dreamboard/workspace-codegen": "npm:@dreamboard-games/workspace-codegen@^0.1.4"
97
+ "@dreamboard/api-client": "npm:@dreamboard-games/api-client@^0.1.0",
98
+ "@dreamboard/app-sdk": "npm:@dreamboard-games/app-sdk@^0.0.41",
99
+ "@dreamboard/sdk-types": "npm:@dreamboard-games/sdk-types@^0.1.0",
100
+ "@dreamboard/testing": "npm:@dreamboard-games/testing@^0.1.0",
101
+ "@dreamboard/ui-sdk": "npm:@dreamboard-games/ui-sdk@^0.0.41"
67
102
  },
68
103
  "license": "SEE LICENSE IN LICENSE",
69
104
  "repository": {