@dreamboard-games/sdk 0.4.0-alpha.0 → 0.4.0-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.
Files changed (84) hide show
  1. package/README.md +8 -1
  2. package/REFERENCE.md +1849 -379
  3. package/dist/{ResourceCounter-BTXklCEZ.d.ts → ResourceCounter-BuiNstXs.d.ts} +5 -1
  4. package/dist/{ThemeProvider-DvMl17Ny.d.ts → ThemeProvider-B1sIoBlX.d.ts} +1 -1
  5. package/dist/attributes-DbvyMbXw.d.ts +68 -0
  6. package/dist/authoring/index.d.ts +66 -0
  7. package/dist/authoring/index.js +560 -0
  8. package/dist/authoring/index.js.map +1 -0
  9. package/dist/browser-interaction.d.ts +246 -44
  10. package/dist/browser-interaction.js +14 -1
  11. package/dist/{chunk-Q5O7GPVY.js → chunk-45FI6XII.js} +630 -375
  12. package/dist/chunk-45FI6XII.js.map +1 -0
  13. package/dist/{chunk-4G7552LO.js → chunk-6JQFGSLD.js} +216 -47
  14. package/dist/chunk-6JQFGSLD.js.map +1 -0
  15. package/dist/{chunk-NBAEEHAU.js → chunk-CP35NPPY.js} +5926 -5266
  16. package/dist/chunk-CP35NPPY.js.map +1 -0
  17. package/dist/{chunk-2LDZ5C3T.js → chunk-FWVV2X74.js} +2 -2
  18. package/dist/{chunk-MNKDSGIA.js → chunk-HWJS3VOJ.js} +6 -2
  19. package/dist/chunk-HWJS3VOJ.js.map +1 -0
  20. package/dist/chunk-K5ZRJTZZ.js +328 -0
  21. package/dist/chunk-K5ZRJTZZ.js.map +1 -0
  22. package/dist/{chunk-U5KBV2BA.js → chunk-N6ZDIMRB.js} +444 -223
  23. package/dist/chunk-N6ZDIMRB.js.map +1 -0
  24. package/dist/chunk-O6M6PN4E.js +1225 -0
  25. package/dist/chunk-O6M6PN4E.js.map +1 -0
  26. package/dist/chunk-PF7L4BMG.js +117 -0
  27. package/dist/chunk-PF7L4BMG.js.map +1 -0
  28. package/dist/{chunk-P7F4L2FF.js → chunk-WOWFONLZ.js} +609 -1287
  29. package/dist/chunk-WOWFONLZ.js.map +1 -0
  30. package/dist/{chunk-QLG6VEMW.js → chunk-WUIVY2KE.js} +318 -21
  31. package/dist/chunk-WUIVY2KE.js.map +1 -0
  32. package/dist/chunk-ZAS2SENW.js +12 -0
  33. package/dist/chunk-ZAS2SENW.js.map +1 -0
  34. package/dist/codegen.d.ts +11 -1
  35. package/dist/codegen.js +1 -1
  36. package/dist/{components-DaIqi9QM.d.ts → components-BbWPnZCF.d.ts} +37 -70
  37. package/dist/{hex-board-view-UCUjMALd.d.ts → hex-board-view-Kz9Q_zsv.d.ts} +1 -1
  38. package/dist/index.js +2 -1
  39. package/dist/package-set.d.ts +2 -2
  40. package/dist/package-set.js +2 -1
  41. package/dist/player-state-Cqpyeql0.d.ts +371 -0
  42. package/dist/protocol-BP193lva.d.ts +267 -0
  43. package/dist/reducer/advanced.d.ts +2 -2
  44. package/dist/reducer/advanced.js +1 -1
  45. package/dist/reducer-contract.js +1 -1
  46. package/dist/reducer.d.ts +7 -7
  47. package/dist/reducer.js +190 -183
  48. package/dist/reducer.js.map +1 -1
  49. package/dist/runtime/primitives.d.ts +10 -9
  50. package/dist/runtime/primitives.js +9 -6
  51. package/dist/runtime/runtime-api.d.ts +2 -2
  52. package/dist/runtime/workspace-contract.d.ts +28 -76
  53. package/dist/runtime/workspace-contract.js +7 -5
  54. package/dist/runtime-api-BJharVaj.d.ts +198 -0
  55. package/dist/runtime-api-C6aWo9c0.d.ts +95 -0
  56. package/dist/runtime-json-CQ9QbLZ5.d.ts +5 -0
  57. package/dist/runtime.d.ts +80 -11
  58. package/dist/runtime.js +89 -445
  59. package/dist/runtime.js.map +1 -1
  60. package/dist/testing.d.ts +643 -22
  61. package/dist/testing.js +1371 -76
  62. package/dist/testing.js.map +1 -1
  63. package/dist/types-CYeN0wLK.d.ts +29 -0
  64. package/dist/{attributes-BeRyboMS.d.ts → types-DJj5MJkl.d.ts} +32 -55
  65. package/dist/types.d.ts +14 -7
  66. package/dist/ui/components.d.ts +4 -5
  67. package/dist/ui/components.js +19 -1
  68. package/dist/ui/player-state.d.ts +2 -365
  69. package/dist/ui/plugin-styles.css +1 -1
  70. package/dist/{ui-contract-BUC6iS3s.d.ts → ui-contract-CY7cxsCC.d.ts} +17 -26
  71. package/dist/ui.d.ts +8 -13
  72. package/dist/ui.js +20 -2
  73. package/dist/{views-B0hlW6IT.d.ts → views-fn2RuXOx.d.ts} +59 -44
  74. package/package.json +28 -4
  75. package/dist/chunk-4G7552LO.js.map +0 -1
  76. package/dist/chunk-MNKDSGIA.js.map +0 -1
  77. package/dist/chunk-NBAEEHAU.js.map +0 -1
  78. package/dist/chunk-P7F4L2FF.js.map +0 -1
  79. package/dist/chunk-Q5O7GPVY.js.map +0 -1
  80. package/dist/chunk-QLG6VEMW.js.map +0 -1
  81. package/dist/chunk-U5KBV2BA.js.map +0 -1
  82. package/dist/hex-color-MhOyuY-o.d.ts +0 -8
  83. package/dist/runtime-api-BXd70c2e.d.ts +0 -490
  84. /package/dist/{chunk-2LDZ5C3T.js.map → chunk-FWVV2X74.js.map} +0 -0
package/dist/runtime.js CHANGED
@@ -1,490 +1,140 @@
1
1
  import {
2
2
  createWorkspaceUIContract
3
- } from "./chunk-4G7552LO.js";
4
- import {
5
- InteractionUiProvider,
6
- RuntimeProvider,
7
- RuntimeSemanticProjectionMarker,
8
- usePluginSession
9
- } from "./chunk-P7F4L2FF.js";
10
- import "./chunk-2LDZ5C3T.js";
3
+ } from "./chunk-6JQFGSLD.js";
4
+ import "./chunk-WOWFONLZ.js";
5
+ import "./chunk-FWVV2X74.js";
11
6
  import "./chunk-T3ZKNUZ7.js";
12
7
  import {
13
8
  GameSkeleton
14
- } from "./chunk-Q5O7GPVY.js";
9
+ } from "./chunk-45FI6XII.js";
15
10
  import "./chunk-VDXOF4FW.js";
16
- import "./chunk-QLG6VEMW.js";
11
+ import {
12
+ PluginRuntimeBoundary,
13
+ createPluginRuntimeClient
14
+ } from "./chunk-K5ZRJTZZ.js";
15
+ import {
16
+ DREAMBOARD_PLUGIN_PROTOCOL,
17
+ DREAMBOARD_PLUGIN_PROTOCOL_VERSION,
18
+ HostToPluginEnvelopeSchema
19
+ } from "./chunk-O6M6PN4E.js";
20
+ import "./chunk-WUIVY2KE.js";
21
+ import "./chunk-PF7L4BMG.js";
17
22
  import "./chunk-PZ5AY32C.js";
18
23
 
19
24
  // src/runtime/hooks/usePluginRuntime.ts
20
25
  import { useState, useEffect, useRef } from "react";
21
26
 
22
- // src/runtime/api/createPluginRuntimeAPI.ts
23
- import { z } from "zod";
24
- var InitMessageSchema = z.object({
25
- type: z.literal("init"),
26
- sessionId: z.string(),
27
- controllablePlayerIds: z.array(z.string()),
28
- controllingPlayerId: z.string(),
29
- userId: z.string().nullable()
30
- });
31
- var PingMessageSchema = z.object({
32
- type: z.literal("ping")
33
- });
34
- var StateSyncMessageSchema = z.object({
35
- type: z.literal("state-sync"),
36
- syncId: z.number(),
37
- state: z.custom((data) => {
38
- return typeof data === "object" && data !== null && "session" in data && "notifications" in data;
39
- })
40
- });
41
- var ValidateInteractionResultMessageSchema = z.object({
42
- type: z.literal("validate-interaction-result"),
43
- messageId: z.string(),
44
- result: z.object({
45
- valid: z.boolean(),
46
- errorCode: z.string().nullable().optional(),
47
- message: z.string().nullable().optional()
48
- })
49
- });
50
- var SubmitResultMessageSchema = z.object({
51
- type: z.literal("submit-result"),
52
- messageId: z.string(),
53
- accepted: z.boolean(),
54
- errorCode: z.string().nullable().optional(),
55
- message: z.string().nullable().optional()
56
- });
57
- var MainToPluginMessageSchema = z.discriminatedUnion("type", [
58
- InitMessageSchema,
59
- PingMessageSchema,
60
- StateSyncMessageSchema,
61
- ValidateInteractionResultMessageSchema,
62
- SubmitResultMessageSchema
63
- ]);
64
- var mintClientActionId = () => {
65
- const cryptoLike = globalThis.crypto;
66
- if (cryptoLike?.randomUUID) {
67
- try {
68
- return cryptoLike.randomUUID();
69
- } catch {
70
- }
71
- }
72
- const rand = Math.random().toString(16).slice(2);
73
- return `cid-${Date.now().toString(16)}-${rand}`;
74
- };
75
- var PLUGIN_RUNTIME_SINGLETON_KEY = "__dreamboardPluginRuntimeApi";
76
- function createPluginRuntimeAPI(options = {}) {
77
- const existingRuntime = globalThis[PLUGIN_RUNTIME_SINGLETON_KEY];
78
- if (existingRuntime) {
79
- existingRuntime.setDiagnosticHandler?.(options.onDiagnostic);
80
- return existingRuntime;
81
- }
82
- let onDiagnostic = options.onDiagnostic;
83
- const emitDiagnostic = (event) => {
84
- if (onDiagnostic) {
85
- try {
86
- onDiagnostic(event);
87
- return;
88
- } catch {
89
- }
90
- }
91
- switch (event.type) {
92
- case "runtimeLog": {
93
- const args = [event.message, ...event.details ?? []];
94
- if (event.level === "warn") {
95
- console.warn(...args);
96
- } else if (event.level === "error") {
97
- console.error(...args);
98
- } else {
99
- console.log(...args);
100
- }
101
- break;
102
- }
103
- case "internalError":
104
- console.error(
105
- `[Plugin RuntimeAPI] ${event.code}:`,
106
- event.message,
107
- event.stack ?? ""
108
- );
109
- break;
110
- default: {
111
- const _exhaustive = event;
112
- return _exhaustive;
113
- }
114
- }
115
- };
116
- let currentStateSnapshot = null;
117
- const stateListeners = /* @__PURE__ */ new Set();
118
- const sessionState = {
119
- status: "loading",
120
- sessionId: null,
121
- controllablePlayerIds: [],
122
- controllingPlayerId: null,
123
- userId: null
124
- };
125
- const sessionStateListeners = /* @__PURE__ */ new Set();
126
- const pendingValidations = /* @__PURE__ */ new Map();
127
- let validationIdCounter = 0;
128
- const pendingSubmissions = /* @__PURE__ */ new Map();
129
- let submitIdCounter = 0;
130
- const notifySessionStateChange = () => {
131
- sessionStateListeners.forEach((listener) => {
132
- try {
133
- listener({ ...sessionState });
134
- } catch {
135
- }
136
- });
137
- };
138
- const notifyStateListeners = () => {
139
- if (!currentStateSnapshot) return;
140
- const snapshot = currentStateSnapshot;
141
- stateListeners.forEach((listener) => {
142
- try {
143
- listener(snapshot);
144
- } catch {
145
- }
146
- });
147
- };
148
- const createSubmissionError = (errorCode, message) => {
149
- const error = new Error(message ?? "Submission failed");
150
- error.name = "SubmissionError";
151
- error.errorCode = errorCode;
152
- return error;
153
- };
154
- const submitViaParent = (payload) => new Promise((resolve, reject) => {
155
- const messageId = `submit-${++submitIdCounter}`;
156
- pendingSubmissions.set(messageId, { resolve, reject });
157
- const clientSubmittedAtMs = Date.now();
158
- if (payload.clientActionId && typeof performance !== "undefined") {
159
- try {
160
- performance.mark(`dreamboard.t0_click.${payload.clientActionId}`, {
161
- detail: { clientActionId: payload.clientActionId }
162
- });
163
- } catch {
164
- }
165
- }
166
- window.parent.postMessage(
167
- { ...payload, messageId, clientSubmittedAtMs },
168
- "*"
169
- );
170
- setTimeout(() => {
171
- const pending = pendingSubmissions.get(messageId);
172
- if (!pending) {
173
- return;
174
- }
175
- pendingSubmissions.delete(messageId);
176
- pending.reject(
177
- createSubmissionError(
178
- "submission-timeout",
179
- "Submission request timed out"
180
- )
181
- );
182
- }, 1e4);
183
- });
184
- const handleMessage = (event) => {
185
- const rawMessage = event.data;
186
- const parseResult = MainToPluginMessageSchema.safeParse(rawMessage);
187
- if (!parseResult.success) {
188
- if (rawMessage?.type && typeof rawMessage.type === "string") {
189
- emitDiagnostic({
190
- type: "runtimeLog",
191
- level: "warn",
192
- message: "[Plugin RuntimeAPI] Invalid message received:",
193
- details: [rawMessage.type]
194
- });
195
- }
196
- return;
197
- }
198
- const message = parseResult.data;
199
- switch (message.type) {
200
- case "init": {
201
- emitDiagnostic({
202
- type: "runtimeLog",
203
- level: "log",
204
- message: "[Plugin RuntimeAPI] Received init message"
205
- });
206
- sessionState.status = "ready";
207
- sessionState.sessionId = message.sessionId;
208
- sessionState.controllablePlayerIds = message.controllablePlayerIds;
209
- sessionState.controllingPlayerId = message.controllingPlayerId;
210
- sessionState.userId = message.userId;
211
- notifySessionStateChange();
212
- window.parent.postMessage({ type: "ready" }, "*");
213
- break;
214
- }
215
- case "ping": {
216
- window.parent.postMessage({ type: "pong" }, "*");
217
- break;
218
- }
219
- case "state-sync": {
220
- emitDiagnostic({
221
- type: "runtimeLog",
222
- level: "log",
223
- message: "[Plugin RuntimeAPI] Received state-sync, syncId:",
224
- details: [message.syncId]
225
- });
226
- const clientReceivedAtMs = Date.now();
227
- if (typeof performance !== "undefined") {
228
- try {
229
- performance.mark(
230
- `dreamboard.t7_state_sync_received.sync-${message.syncId}`,
231
- { detail: { syncId: message.syncId } }
232
- );
233
- } catch {
234
- }
235
- }
236
- currentStateSnapshot = message.state;
237
- if (message.state.session) {
238
- sessionState.sessionId = message.state.session.sessionId;
239
- sessionState.controllablePlayerIds = message.state.session.controllablePlayerIds;
240
- sessionState.controllingPlayerId = message.state.session.controllingPlayerId;
241
- sessionState.userId = message.state.session.userId;
242
- sessionState.status = "ready";
243
- notifySessionStateChange();
244
- }
245
- notifyStateListeners();
246
- window.parent.postMessage(
247
- {
248
- type: "state-ack",
249
- syncId: message.syncId,
250
- clientReceivedAtMs
251
- },
252
- "*"
253
- );
254
- const schedulePostRender = () => {
255
- const send = () => {
256
- const clientRenderedAtMs = Date.now();
257
- if (typeof performance !== "undefined") {
258
- try {
259
- performance.mark(
260
- `dreamboard.t8_render_commit.sync-${message.syncId}`,
261
- { detail: { syncId: message.syncId } }
262
- );
263
- } catch {
264
- }
265
- }
266
- window.parent.postMessage(
267
- {
268
- type: "state-rendered",
269
- syncId: message.syncId,
270
- clientReceivedAtMs,
271
- clientRenderedAtMs
272
- },
273
- "*"
274
- );
275
- };
276
- if (typeof requestAnimationFrame === "function") {
277
- requestAnimationFrame(send);
278
- } else {
279
- queueMicrotask(send);
280
- }
281
- };
282
- queueMicrotask(schedulePostRender);
283
- break;
284
- }
285
- case "validate-interaction-result": {
286
- const resolver = pendingValidations.get(message.messageId);
287
- if (resolver) {
288
- pendingValidations.delete(message.messageId);
289
- resolver({
290
- valid: message.result.valid,
291
- errorCode: message.result.errorCode ?? void 0,
292
- message: message.result.message ?? void 0
293
- });
27
+ // src/runtime/browser/post-message-transport.ts
28
+ function createPostMessagePluginTransport(options = {}) {
29
+ const targetWindow = options.targetWindow ?? window;
30
+ const parentWindow = options.parentWindow ?? targetWindow.parent;
31
+ let channel = null;
32
+ let outboundSequence = 0;
33
+ return {
34
+ start(onMessage) {
35
+ const handleMessage = (event) => {
36
+ if (event.source !== parentWindow) {
37
+ return;
294
38
  }
295
- break;
296
- }
297
- case "submit-result": {
298
- const pending = pendingSubmissions.get(message.messageId);
299
- if (!pending) {
300
- break;
39
+ const parseResult = HostToPluginEnvelopeSchema.safeParse(event.data);
40
+ if (!parseResult.success) {
41
+ options.onInvalidMessage?.("invalid-envelope", event.data);
42
+ return;
301
43
  }
302
- if (typeof performance !== "undefined") {
303
- try {
304
- performance.mark(`dreamboard.t3b_ack.${message.messageId}`, {
305
- detail: { messageId: message.messageId }
306
- });
307
- } catch {
44
+ const envelope = parseResult.data;
45
+ if (!channel) {
46
+ if (envelope.payload.type !== "runtime.init") {
47
+ return;
308
48
  }
49
+ channel = {
50
+ channelId: envelope.channelId,
51
+ hostOrigin: event.origin,
52
+ hostWindow: event.source
53
+ };
309
54
  }
310
- pendingSubmissions.delete(message.messageId);
311
- if (message.accepted) {
312
- pending.resolve();
313
- } else {
314
- pending.reject(
315
- createSubmissionError(
316
- message.errorCode ?? void 0,
317
- message.message ?? void 0
318
- )
319
- );
55
+ if (envelope.channelId !== channel.channelId || event.origin !== channel.hostOrigin || event.source !== channel.hostWindow) {
56
+ options.onInvalidMessage?.("channel-mismatch", event.data);
57
+ return;
320
58
  }
321
- break;
322
- }
323
- }
324
- };
325
- window.addEventListener("message", handleMessage);
326
- const sendErrorToParent = (message, code, stack) => {
327
- emitDiagnostic({
328
- type: "internalError",
329
- code,
330
- message,
331
- ...stack ? { stack } : {}
332
- });
333
- window.parent.postMessage(
334
- {
335
- type: "error",
336
- message: stack ? `${message}
337
- ${stack}` : message,
338
- code
339
- },
340
- "*"
341
- );
342
- };
343
- window.onerror = (message, source, lineno, colno, error) => {
344
- const errorMessage = typeof message === "string" ? message : error?.message || "Unknown error";
345
- const location = source ? ` at ${source}:${lineno}:${colno}` : "";
346
- sendErrorToParent(errorMessage + location, "UNCAUGHT_ERROR", error?.stack);
347
- return false;
348
- };
349
- window.onunhandledrejection = (event) => {
350
- const reason = event.reason;
351
- const message = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : JSON.stringify(reason);
352
- const stack = reason instanceof Error ? reason.stack : void 0;
353
- sendErrorToParent(message, "UNHANDLED_REJECTION", stack);
354
- };
355
- emitDiagnostic({
356
- type: "runtimeLog",
357
- level: "log",
358
- message: "[Plugin RuntimeAPI] Initialized (state-sync architecture)"
359
- });
360
- const runtime = {
361
- // State-sync methods
362
- getSnapshot: () => currentStateSnapshot,
363
- subscribeToState: (listener) => {
364
- stateListeners.add(listener);
365
- if (currentStateSnapshot) {
366
- try {
367
- listener(currentStateSnapshot);
368
- } catch {
369
- }
370
- }
371
- return () => {
372
- stateListeners.delete(listener);
59
+ onMessage(envelope);
373
60
  };
374
- },
375
- validateInteraction: async (playerId, interactionId, params) => {
376
- return new Promise((resolve) => {
377
- const messageId = `validate-${++validationIdCounter}`;
378
- pendingValidations.set(messageId, resolve);
379
- window.parent.postMessage(
380
- {
381
- type: "validate-interaction",
382
- playerId,
383
- interactionId,
384
- params,
385
- messageId
386
- },
387
- "*"
388
- );
389
- setTimeout(() => {
390
- if (pendingValidations.has(messageId)) {
391
- pendingValidations.delete(messageId);
392
- resolve({
393
- valid: false,
394
- errorCode: "validation-timeout",
395
- message: "Validation request timed out"
396
- });
397
- }
398
- }, 1e4);
399
- });
400
- },
401
- submitInteraction: async (playerId, interactionId, params) => submitViaParent({
402
- type: "interaction",
403
- playerId,
404
- interactionId,
405
- params,
406
- clientActionId: mintClientActionId()
407
- }),
408
- getSessionState: () => ({ ...sessionState }),
409
- disconnect: () => {
410
- window.removeEventListener("message", handleMessage);
411
- window.onerror = null;
412
- window.onunhandledrejection = null;
413
- sessionStateListeners.clear();
414
- stateListeners.clear();
415
- pendingValidations.clear();
416
- pendingSubmissions.clear();
417
- currentStateSnapshot = null;
418
- },
419
- switchPlayer: (playerId) => {
420
- window.parent.postMessage({ type: "switch-player", playerId }, "*");
421
- },
422
- restoreHistory: (entryId) => {
423
- window.parent.postMessage({ type: "restore-history", entryId }, "*");
424
- },
425
- setDiagnosticHandler: (handler) => {
426
- onDiagnostic = handler;
427
- },
428
- emitDiagnostic,
429
- _subscribeToSessionState: (listener) => {
430
- sessionStateListeners.add(listener);
431
- listener({ ...sessionState });
61
+ targetWindow.addEventListener("message", handleMessage);
432
62
  return () => {
433
- sessionStateListeners.delete(listener);
63
+ targetWindow.removeEventListener("message", handleMessage);
64
+ channel = null;
434
65
  };
66
+ },
67
+ send(payload) {
68
+ if (!channel) {
69
+ throw new Error("Plugin transport is not initialized.");
70
+ }
71
+ channel.hostWindow.postMessage(
72
+ {
73
+ protocol: DREAMBOARD_PLUGIN_PROTOCOL,
74
+ version: DREAMBOARD_PLUGIN_PROTOCOL_VERSION,
75
+ channelId: channel.channelId,
76
+ sequence: ++outboundSequence,
77
+ payload
78
+ },
79
+ channel.hostOrigin
80
+ );
435
81
  }
436
82
  };
437
- globalThis[PLUGIN_RUNTIME_SINGLETON_KEY] = runtime;
438
- return runtime;
439
83
  }
440
84
 
441
85
  // src/runtime/hooks/usePluginRuntime.ts
442
- function hasProjectedView(snapshot) {
443
- return snapshot !== null && snapshot !== void 0 && snapshot.view !== null && snapshot.view !== void 0;
86
+ function hasProjectedView(runtime) {
87
+ const frame = runtime.getFrame();
88
+ return frame !== null && frame.view !== null && typeof frame.view !== "undefined";
444
89
  }
445
90
  function usePluginRuntime(options = {}) {
446
91
  const { timeout = 1e4, onDiagnostic } = options;
447
92
  const [runtime] = useState(
448
- () => createPluginRuntimeAPI({ onDiagnostic })
93
+ () => createPluginRuntimeClient({
94
+ transport: createPostMessagePluginTransport({
95
+ onInvalidMessage: (reason, value) => onDiagnostic?.({
96
+ type: "runtimeLog",
97
+ level: "warn",
98
+ message: `[PluginRuntime] Ignored invalid host message: ${reason}`,
99
+ details: [value]
100
+ })
101
+ })
102
+ })
449
103
  );
450
- const [isReady, setIsReady] = useState(() => {
451
- const snapshot = runtime.getSnapshot?.();
452
- return hasProjectedView(snapshot);
453
- });
104
+ const [isReady, setIsReady] = useState(() => hasProjectedView(runtime));
454
105
  const [error, setError] = useState(null);
455
106
  const hasBeenReadyRef = useRef(false);
456
107
  if (isReady) hasBeenReadyRef.current = true;
457
108
  useEffect(() => {
458
- runtime.setDiagnosticHandler?.(onDiagnostic);
459
- }, [runtime, onDiagnostic]);
109
+ void onDiagnostic;
110
+ }, [onDiagnostic]);
460
111
  useEffect(() => {
461
- const markReadyFromSnapshot = () => {
462
- const currentSnapshot = runtime.getSnapshot?.();
463
- if (!hasProjectedView(currentSnapshot)) {
112
+ const markReadyFromFrame = () => {
113
+ if (!hasProjectedView(runtime)) {
464
114
  return false;
465
115
  }
466
116
  setError(null);
467
117
  setIsReady(true);
468
118
  return true;
469
119
  };
470
- if (markReadyFromSnapshot()) {
120
+ if (markReadyFromFrame()) {
471
121
  return;
472
122
  }
473
123
  const timeoutId = setTimeout(() => {
474
- if (!markReadyFromSnapshot()) {
124
+ if (!markReadyFromFrame()) {
475
125
  setError(
476
- `Timed out waiting for the initial projected view after ${timeout}ms. Ensure the host sends a reducer-native state-sync with a seat view.`
126
+ `Timed out waiting for the initial projected view after ${timeout}ms. Ensure the host sends a gameplay frame with a seat view.`
477
127
  );
478
128
  }
479
129
  }, timeout);
480
130
  const pollId = setInterval(() => {
481
- if (markReadyFromSnapshot()) {
131
+ if (markReadyFromFrame()) {
482
132
  clearInterval(pollId);
483
133
  clearTimeout(timeoutId);
484
134
  }
485
135
  }, 100);
486
- const unsubscribe = runtime.subscribeToState?.((state) => {
487
- if (!hasProjectedView(state)) {
136
+ const unsubscribe = runtime.subscribeFrame(() => {
137
+ if (!hasProjectedView(runtime)) {
488
138
  setIsReady(false);
489
139
  return;
490
140
  }
@@ -540,19 +190,13 @@ function PluginRuntime({
540
190
  }
541
191
  );
542
192
  }
543
- return /* @__PURE__ */ jsx(RuntimeProvider, { runtime, children: /* @__PURE__ */ jsx(SessionScopedInteractionUiProvider, { children }) });
544
- }
545
- function SessionScopedInteractionUiProvider({
546
- children
547
- }) {
548
- const { controllingPlayerId } = usePluginSession();
549
- return /* @__PURE__ */ jsxs(InteractionUiProvider, { children: [
550
- /* @__PURE__ */ jsx(RuntimeSemanticProjectionMarker, {}),
551
- children
552
- ] }, controllingPlayerId ?? "__no_player__");
193
+ return /* @__PURE__ */ jsx(PluginRuntimeBoundary, { runtime, children });
553
194
  }
554
195
  export {
555
196
  PluginRuntime,
197
+ PluginRuntimeBoundary,
198
+ createPluginRuntimeClient,
199
+ createPostMessagePluginTransport,
556
200
  createWorkspaceUIContract
557
201
  };
558
202
  //# sourceMappingURL=runtime.js.map