@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
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useTheme
3
- } from "./chunk-Q5O7GPVY.js";
3
+ } from "./chunk-45FI6XII.js";
4
4
 
5
5
  // src/ui/helpers/track-board.ts
6
6
  function positionForLayout(layout, index, count) {
@@ -101,4 +101,4 @@ export {
101
101
  parseHexColor,
102
102
  hexColor
103
103
  };
104
- //# sourceMappingURL=chunk-2LDZ5C3T.js.map
104
+ //# sourceMappingURL=chunk-FWVV2X74.js.map
@@ -1,5 +1,9 @@
1
+ import {
2
+ GENERATED_AUTHORING_METADATA
3
+ } from "./chunk-ZAS2SENW.js";
4
+
1
5
  // src/package-set.ts
2
- var DREAMBOARD_SDK_VERSION = "0.4.0-alpha.0";
6
+ var DREAMBOARD_SDK_VERSION = GENERATED_AUTHORING_METADATA.sdkVersion;
3
7
  var DREAMBOARD_SDK_PACKAGES = {
4
8
  "@dreamboard-games/sdk": DREAMBOARD_SDK_VERSION
5
9
  };
@@ -14,4 +18,4 @@ export {
14
18
  DREAMBOARD_SDK_PACKAGES,
15
19
  DREAMBOARD_SDK_PACKAGE_SET
16
20
  };
17
- //# sourceMappingURL=chunk-MNKDSGIA.js.map
21
+ //# sourceMappingURL=chunk-HWJS3VOJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/package-set.ts"],"sourcesContent":["import { GENERATED_AUTHORING_METADATA } from \"./authoring/generated-metadata.js\";\n\nexport const DREAMBOARD_SDK_VERSION = GENERATED_AUTHORING_METADATA.sdkVersion;\n\nexport const DREAMBOARD_SDK_PACKAGES = {\n \"@dreamboard-games/sdk\": DREAMBOARD_SDK_VERSION,\n} as const;\n\nexport type DreamboardSdkPackageName = keyof typeof DREAMBOARD_SDK_PACKAGES;\n\nexport type DreamboardSdkPackageSet = {\n version: 1;\n sdkVersion: string;\n packages: Record<DreamboardSdkPackageName, string>;\n};\n\nexport const DREAMBOARD_SDK_PACKAGE_SET: DreamboardSdkPackageSet = {\n version: 1,\n sdkVersion: DREAMBOARD_SDK_VERSION,\n packages: DREAMBOARD_SDK_PACKAGES,\n};\n"],"mappings":";;;;;AAEO,IAAM,yBAAyB,6BAA6B;AAE5D,IAAM,0BAA0B;AAAA,EACrC,yBAAyB;AAC3B;AAUO,IAAM,6BAAsD;AAAA,EACjE,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,UAAU;AACZ;","names":[]}
@@ -0,0 +1,328 @@
1
+ import {
2
+ HostToPluginEnvelopeSchema,
3
+ InteractionUiProvider,
4
+ PluginGameplayFrameProvider,
5
+ PluginSessionProvider,
6
+ RuntimeContext,
7
+ RuntimeJsonSchema,
8
+ usePluginSession
9
+ } from "./chunk-O6M6PN4E.js";
10
+
11
+ // src/runtime/core/create-plugin-runtime-client.ts
12
+ var defaultClock = {
13
+ now: () => Date.now()
14
+ };
15
+ var defaultIdFactory = {
16
+ nextId: (prefix) => {
17
+ const cryptoLike = globalThis.crypto;
18
+ if (cryptoLike?.randomUUID) {
19
+ try {
20
+ return `${prefix}-${cryptoLike.randomUUID()}`;
21
+ } catch {
22
+ }
23
+ }
24
+ return `${prefix}-${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
25
+ }
26
+ };
27
+ function createSubmissionError(result) {
28
+ const error = new Error(result.message ?? "Submission failed");
29
+ error.name = "SubmissionError";
30
+ error.errorCode = result.errorCode;
31
+ return error;
32
+ }
33
+ function disconnectedValidationResult() {
34
+ return {
35
+ valid: false,
36
+ errorCode: "runtime-disconnected",
37
+ message: "Plugin runtime disconnected"
38
+ };
39
+ }
40
+ function createPluginRuntimeClient(options) {
41
+ const clock = options.clock ?? defaultClock;
42
+ const idFactory = options.idFactory ?? defaultIdFactory;
43
+ const requestTimeoutMs = options.requestTimeoutMs ?? 1e4;
44
+ let session = null;
45
+ let frame = null;
46
+ let disconnected = false;
47
+ let stopTransport;
48
+ const sessionListeners = /* @__PURE__ */ new Set();
49
+ const frameListeners = /* @__PURE__ */ new Set();
50
+ const pendingValidations = /* @__PURE__ */ new Map();
51
+ const pendingSubmissions = /* @__PURE__ */ new Map();
52
+ const notifySession = () => {
53
+ for (const listener of sessionListeners) {
54
+ listener();
55
+ }
56
+ };
57
+ const notifyFrame = () => {
58
+ for (const listener of frameListeners) {
59
+ listener();
60
+ }
61
+ };
62
+ const currentBasis = () => {
63
+ if (!frame) {
64
+ throw new Error("Plugin runtime has not received a gameplay frame.");
65
+ }
66
+ return {
67
+ gameVersion: frame.gameVersion,
68
+ actionSetVersion: frame.actionSetVersion,
69
+ perspectivePlayerId: frame.perspectivePlayerId
70
+ };
71
+ };
72
+ const sendRuntimeError = (message, code) => {
73
+ if (disconnected) {
74
+ return;
75
+ }
76
+ options.transport.send({
77
+ type: "runtime.error",
78
+ message,
79
+ ...code ? { code } : {}
80
+ });
81
+ };
82
+ const handleHostMessage = (rawMessage) => {
83
+ if (disconnected) {
84
+ return;
85
+ }
86
+ const parseResult = HostToPluginEnvelopeSchema.safeParse(rawMessage);
87
+ if (!parseResult.success) {
88
+ sendRuntimeError("Invalid host-to-plugin protocol envelope.", "invalid-envelope");
89
+ return;
90
+ }
91
+ const message = parseResult.data;
92
+ const clientReceivedAtMs = clock.now();
93
+ switch (message.payload.type) {
94
+ case "runtime.init": {
95
+ session = message.payload.session;
96
+ notifySession();
97
+ options.transport.send({ type: "runtime.ready" });
98
+ options.transport.send({
99
+ type: "runtime.ack",
100
+ sequence: message.sequence,
101
+ clientReceivedAtMs
102
+ });
103
+ break;
104
+ }
105
+ case "gameplay.frame": {
106
+ frame = message.payload.frame;
107
+ notifyFrame();
108
+ const sendRenderedAck = () => {
109
+ if (disconnected) {
110
+ return;
111
+ }
112
+ options.transport.send({
113
+ type: "runtime.ack",
114
+ sequence: message.sequence,
115
+ clientReceivedAtMs,
116
+ clientRenderedAtMs: clock.now()
117
+ });
118
+ };
119
+ if (typeof requestAnimationFrame === "function") {
120
+ requestAnimationFrame(sendRenderedAck);
121
+ } else {
122
+ queueMicrotask(sendRenderedAck);
123
+ }
124
+ break;
125
+ }
126
+ case "interaction.validation-result": {
127
+ const resolve = pendingValidations.get(message.payload.requestId);
128
+ if (resolve) {
129
+ pendingValidations.delete(message.payload.requestId);
130
+ resolve(message.payload.result);
131
+ }
132
+ break;
133
+ }
134
+ case "interaction.submit-result": {
135
+ const pending = pendingSubmissions.get(message.payload.requestId);
136
+ if (!pending) {
137
+ break;
138
+ }
139
+ pendingSubmissions.delete(message.payload.requestId);
140
+ if (message.payload.result.accepted) {
141
+ pending.resolve();
142
+ } else {
143
+ pending.reject(createSubmissionError(message.payload.result));
144
+ }
145
+ break;
146
+ }
147
+ default: {
148
+ const _exhaustive = message.payload;
149
+ return _exhaustive;
150
+ }
151
+ }
152
+ };
153
+ stopTransport = options.transport.start(handleHostMessage);
154
+ const rejectPending = () => {
155
+ for (const resolve of pendingValidations.values()) {
156
+ resolve(disconnectedValidationResult());
157
+ }
158
+ pendingValidations.clear();
159
+ for (const pending of pendingSubmissions.values()) {
160
+ const error = new Error("Plugin runtime disconnected");
161
+ error.name = "SubmissionError";
162
+ error.errorCode = "runtime-disconnected";
163
+ pending.reject(error);
164
+ }
165
+ pendingSubmissions.clear();
166
+ };
167
+ return {
168
+ getSession: () => session,
169
+ subscribeSession: (listener) => {
170
+ sessionListeners.add(listener);
171
+ return () => {
172
+ sessionListeners.delete(listener);
173
+ };
174
+ },
175
+ getFrame: () => frame,
176
+ subscribeFrame: (listener) => {
177
+ frameListeners.add(listener);
178
+ return () => {
179
+ frameListeners.delete(listener);
180
+ };
181
+ },
182
+ validateInteraction: async (interactionId, params) => new Promise((resolve) => {
183
+ if (disconnected) {
184
+ resolve(disconnectedValidationResult());
185
+ return;
186
+ }
187
+ let basis;
188
+ try {
189
+ basis = currentBasis();
190
+ } catch (error) {
191
+ resolve({
192
+ valid: false,
193
+ errorCode: "runtime-not-ready",
194
+ message: error instanceof Error ? error.message : "Plugin runtime is not ready."
195
+ });
196
+ return;
197
+ }
198
+ const parsedParams = RuntimeJsonSchema.safeParse(params);
199
+ if (!parsedParams.success) {
200
+ resolve({
201
+ valid: false,
202
+ errorCode: "invalid-runtime-json",
203
+ message: "Interaction params must be runtime JSON."
204
+ });
205
+ return;
206
+ }
207
+ const requestId = idFactory.nextId("validate");
208
+ pendingValidations.set(requestId, resolve);
209
+ options.transport.send({
210
+ type: "interaction.validate",
211
+ requestId,
212
+ basis,
213
+ interactionId,
214
+ params: parsedParams.data
215
+ });
216
+ setTimeout(() => {
217
+ if (!pendingValidations.delete(requestId)) {
218
+ return;
219
+ }
220
+ resolve({
221
+ valid: false,
222
+ errorCode: "validation-timeout",
223
+ message: "Validation request timed out"
224
+ });
225
+ }, requestTimeoutMs);
226
+ }),
227
+ submitInteraction: async (interactionId, params) => new Promise((resolve, reject) => {
228
+ if (disconnected) {
229
+ const error = new Error("Plugin runtime disconnected");
230
+ error.name = "SubmissionError";
231
+ error.errorCode = "runtime-disconnected";
232
+ reject(error);
233
+ return;
234
+ }
235
+ const parsedParams = RuntimeJsonSchema.safeParse(params);
236
+ if (!parsedParams.success) {
237
+ const error = new Error(
238
+ "Interaction params must be runtime JSON."
239
+ );
240
+ error.name = "SubmissionError";
241
+ error.errorCode = "invalid-runtime-json";
242
+ reject(error);
243
+ return;
244
+ }
245
+ let basis;
246
+ try {
247
+ basis = currentBasis();
248
+ } catch (error) {
249
+ const submissionError = new Error(
250
+ error instanceof Error ? error.message : "Plugin runtime is not ready."
251
+ );
252
+ submissionError.name = "SubmissionError";
253
+ submissionError.errorCode = "runtime-not-ready";
254
+ reject(submissionError);
255
+ return;
256
+ }
257
+ const requestId = idFactory.nextId("submit");
258
+ pendingSubmissions.set(requestId, { resolve, reject });
259
+ options.transport.send({
260
+ type: "interaction.submit",
261
+ requestId,
262
+ basis,
263
+ interactionId,
264
+ params: parsedParams.data
265
+ });
266
+ setTimeout(() => {
267
+ const pending = pendingSubmissions.get(requestId);
268
+ if (!pending) {
269
+ return;
270
+ }
271
+ pendingSubmissions.delete(requestId);
272
+ const error = new Error("Submission request timed out");
273
+ error.name = "SubmissionError";
274
+ error.errorCode = "submission-timeout";
275
+ pending.reject(error);
276
+ }, requestTimeoutMs);
277
+ }),
278
+ disconnect: () => {
279
+ disconnected = true;
280
+ stopTransport?.();
281
+ stopTransport = void 0;
282
+ sessionListeners.clear();
283
+ frameListeners.clear();
284
+ rejectPending();
285
+ session = null;
286
+ frame = null;
287
+ }
288
+ };
289
+ }
290
+
291
+ // src/runtime/components/PluginRuntimeBoundary.tsx
292
+ import { useMemo } from "react";
293
+ import { jsx } from "react/jsx-runtime";
294
+ function runtimeApiFromClient(runtime) {
295
+ return {
296
+ validateInteraction: (interactionId, params) => runtime.validateInteraction(interactionId, params),
297
+ submitInteraction: (interactionId, params) => runtime.submitInteraction(interactionId, params),
298
+ getSessionState: () => {
299
+ const session = runtime.getSession();
300
+ const frame = runtime.getFrame();
301
+ return {
302
+ status: session ? "ready" : "loading",
303
+ sessionId: session?.sessionId ?? null,
304
+ controllingPlayerId: frame?.perspectivePlayerId ?? null
305
+ };
306
+ },
307
+ disconnect: () => runtime.disconnect()
308
+ };
309
+ }
310
+ function PluginRuntimeBoundary({
311
+ runtime,
312
+ children
313
+ }) {
314
+ const runtimeApi = useMemo(() => runtimeApiFromClient(runtime), [runtime]);
315
+ return /* @__PURE__ */ jsx(RuntimeContext.Provider, { value: runtimeApi, children: /* @__PURE__ */ jsx(PluginSessionProvider, { runtime, children: /* @__PURE__ */ jsx(PluginGameplayFrameProvider, { runtime, children: /* @__PURE__ */ jsx(SessionScopedInteractionUiProvider, { children }) }) }) });
316
+ }
317
+ function SessionScopedInteractionUiProvider({
318
+ children
319
+ }) {
320
+ const { controllingPlayerId } = usePluginSession();
321
+ return /* @__PURE__ */ jsx(InteractionUiProvider, { children }, controllingPlayerId ?? "__no_player__");
322
+ }
323
+
324
+ export {
325
+ createPluginRuntimeClient,
326
+ PluginRuntimeBoundary
327
+ };
328
+ //# sourceMappingURL=chunk-K5ZRJTZZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/core/create-plugin-runtime-client.ts","../src/runtime/components/PluginRuntimeBoundary.tsx"],"sourcesContent":["import {\n HostToPluginEnvelopeSchema,\n RuntimeJsonSchema,\n type HostToPluginEnvelope,\n type PluginGameplayFrame,\n type PluginInteractionBasis,\n type PluginSessionDescriptor,\n type SubmissionResult,\n type ValidationResult,\n} from \"@dreamboard-games/plugin-runtime-contract\";\nimport type {\n PluginRuntimeClient,\n PluginRuntimeClientOptions,\n RuntimeClock,\n RuntimeIdFactory,\n} from \"./types.js\";\n\nconst defaultClock: RuntimeClock = {\n now: () => Date.now(),\n};\n\nconst defaultIdFactory: RuntimeIdFactory = {\n nextId: (prefix) => {\n const cryptoLike = (\n globalThis as typeof globalThis & {\n crypto?: { randomUUID?: () => string };\n }\n ).crypto;\n if (cryptoLike?.randomUUID) {\n try {\n return `${prefix}-${cryptoLike.randomUUID()}`;\n } catch {\n // Fall through to deterministic-enough fallback for older test DOMs.\n }\n }\n return `${prefix}-${Date.now().toString(16)}-${Math.random()\n .toString(16)\n .slice(2)}`;\n },\n};\n\nfunction createSubmissionError(\n result: Extract<SubmissionResult, { accepted: false }>,\n): Error & { errorCode?: string } {\n const error = new Error(result.message ?? \"Submission failed\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = result.errorCode;\n return error;\n}\n\nfunction disconnectedValidationResult(): ValidationResult {\n return {\n valid: false,\n errorCode: \"runtime-disconnected\",\n message: \"Plugin runtime disconnected\",\n };\n}\n\nexport function createPluginRuntimeClient(\n options: PluginRuntimeClientOptions,\n): PluginRuntimeClient {\n const clock = options.clock ?? defaultClock;\n const idFactory = options.idFactory ?? defaultIdFactory;\n const requestTimeoutMs = options.requestTimeoutMs ?? 10_000;\n let session: PluginSessionDescriptor | null = null;\n let frame: PluginGameplayFrame | null = null;\n let disconnected = false;\n let stopTransport: (() => void) | undefined;\n const sessionListeners = new Set<() => void>();\n const frameListeners = new Set<() => void>();\n const pendingValidations = new Map<string, (result: ValidationResult) => void>();\n const pendingSubmissions = new Map<\n string,\n {\n resolve: () => void;\n reject: (error: Error & { errorCode?: string }) => void;\n }\n >();\n\n const notifySession = () => {\n for (const listener of sessionListeners) {\n listener();\n }\n };\n\n const notifyFrame = () => {\n for (const listener of frameListeners) {\n listener();\n }\n };\n\n const currentBasis = (): PluginInteractionBasis => {\n if (!frame) {\n throw new Error(\"Plugin runtime has not received a gameplay frame.\");\n }\n return {\n gameVersion: frame.gameVersion,\n actionSetVersion: frame.actionSetVersion,\n perspectivePlayerId: frame.perspectivePlayerId,\n };\n };\n\n const sendRuntimeError = (message: string, code?: string) => {\n if (disconnected) {\n return;\n }\n options.transport.send({\n type: \"runtime.error\",\n message,\n ...(code ? { code } : {}),\n });\n };\n\n const handleHostMessage = (rawMessage: HostToPluginEnvelope) => {\n if (disconnected) {\n return;\n }\n const parseResult = HostToPluginEnvelopeSchema.safeParse(rawMessage);\n if (!parseResult.success) {\n sendRuntimeError(\"Invalid host-to-plugin protocol envelope.\", \"invalid-envelope\");\n return;\n }\n const message = parseResult.data;\n const clientReceivedAtMs = clock.now();\n\n switch (message.payload.type) {\n case \"runtime.init\": {\n session = message.payload.session;\n notifySession();\n options.transport.send({ type: \"runtime.ready\" });\n options.transport.send({\n type: \"runtime.ack\",\n sequence: message.sequence,\n clientReceivedAtMs,\n });\n break;\n }\n case \"gameplay.frame\": {\n frame = message.payload.frame;\n notifyFrame();\n const sendRenderedAck = () => {\n if (disconnected) {\n return;\n }\n options.transport.send({\n type: \"runtime.ack\",\n sequence: message.sequence,\n clientReceivedAtMs,\n clientRenderedAtMs: clock.now(),\n });\n };\n if (typeof requestAnimationFrame === \"function\") {\n requestAnimationFrame(sendRenderedAck);\n } else {\n queueMicrotask(sendRenderedAck);\n }\n break;\n }\n case \"interaction.validation-result\": {\n const resolve = pendingValidations.get(message.payload.requestId);\n if (resolve) {\n pendingValidations.delete(message.payload.requestId);\n resolve(message.payload.result);\n }\n break;\n }\n case \"interaction.submit-result\": {\n const pending = pendingSubmissions.get(message.payload.requestId);\n if (!pending) {\n break;\n }\n pendingSubmissions.delete(message.payload.requestId);\n if (message.payload.result.accepted) {\n pending.resolve();\n } else {\n pending.reject(createSubmissionError(message.payload.result));\n }\n break;\n }\n default: {\n const _exhaustive: never = message.payload;\n return _exhaustive;\n }\n }\n };\n\n stopTransport = options.transport.start(handleHostMessage);\n\n const rejectPending = () => {\n for (const resolve of pendingValidations.values()) {\n resolve(disconnectedValidationResult());\n }\n pendingValidations.clear();\n for (const pending of pendingSubmissions.values()) {\n const error = new Error(\"Plugin runtime disconnected\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"runtime-disconnected\";\n pending.reject(error);\n }\n pendingSubmissions.clear();\n };\n\n return {\n getSession: () => session,\n subscribeSession: (listener) => {\n sessionListeners.add(listener);\n return () => {\n sessionListeners.delete(listener);\n };\n },\n getFrame: () => frame,\n subscribeFrame: (listener) => {\n frameListeners.add(listener);\n return () => {\n frameListeners.delete(listener);\n };\n },\n validateInteraction: async (interactionId, params) =>\n new Promise((resolve) => {\n if (disconnected) {\n resolve(disconnectedValidationResult());\n return;\n }\n let basis: PluginInteractionBasis;\n try {\n basis = currentBasis();\n } catch (error) {\n resolve({\n valid: false,\n errorCode: \"runtime-not-ready\",\n message:\n error instanceof Error\n ? error.message\n : \"Plugin runtime is not ready.\",\n });\n return;\n }\n const parsedParams = RuntimeJsonSchema.safeParse(params);\n if (!parsedParams.success) {\n resolve({\n valid: false,\n errorCode: \"invalid-runtime-json\",\n message: \"Interaction params must be runtime JSON.\",\n });\n return;\n }\n const requestId = idFactory.nextId(\"validate\");\n pendingValidations.set(requestId, resolve);\n options.transport.send({\n type: \"interaction.validate\",\n requestId,\n basis,\n interactionId,\n params: parsedParams.data,\n });\n setTimeout(() => {\n if (!pendingValidations.delete(requestId)) {\n return;\n }\n resolve({\n valid: false,\n errorCode: \"validation-timeout\",\n message: \"Validation request timed out\",\n });\n }, requestTimeoutMs);\n }),\n submitInteraction: async (interactionId, params) =>\n new Promise((resolve, reject) => {\n if (disconnected) {\n const error = new Error(\"Plugin runtime disconnected\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"runtime-disconnected\";\n reject(error);\n return;\n }\n const parsedParams = RuntimeJsonSchema.safeParse(params);\n if (!parsedParams.success) {\n const error = new Error(\n \"Interaction params must be runtime JSON.\",\n ) as Error & { errorCode?: string };\n error.name = \"SubmissionError\";\n error.errorCode = \"invalid-runtime-json\";\n reject(error);\n return;\n }\n let basis: PluginInteractionBasis;\n try {\n basis = currentBasis();\n } catch (error) {\n const submissionError = new Error(\n error instanceof Error\n ? error.message\n : \"Plugin runtime is not ready.\",\n ) as Error & { errorCode?: string };\n submissionError.name = \"SubmissionError\";\n submissionError.errorCode = \"runtime-not-ready\";\n reject(submissionError);\n return;\n }\n const requestId = idFactory.nextId(\"submit\");\n pendingSubmissions.set(requestId, { resolve, reject });\n options.transport.send({\n type: \"interaction.submit\",\n requestId,\n basis,\n interactionId,\n params: parsedParams.data,\n });\n setTimeout(() => {\n const pending = pendingSubmissions.get(requestId);\n if (!pending) {\n return;\n }\n pendingSubmissions.delete(requestId);\n const error = new Error(\"Submission request timed out\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"submission-timeout\";\n pending.reject(error);\n }, requestTimeoutMs);\n }),\n disconnect: () => {\n disconnected = true;\n stopTransport?.();\n stopTransport = undefined;\n sessionListeners.clear();\n frameListeners.clear();\n rejectPending();\n session = null;\n frame = null;\n },\n };\n}\n","import React, { useMemo } from \"react\";\nimport { InteractionUiProvider } from \"../context/InteractionDraftContext.js\";\nimport {\n PluginSessionProvider,\n usePluginSession,\n} from \"../context/PluginSessionContext.js\";\nimport { PluginGameplayFrameProvider } from \"../context/PluginGameplayFrameContext.js\";\nimport { RuntimeContext } from \"../context/RuntimeContext.js\";\nimport type { PluginRuntimeClient } from \"../core/types.js\";\nimport type { RuntimeAPI } from \"../types/runtime-api.js\";\n\nfunction runtimeApiFromClient(runtime: PluginRuntimeClient): RuntimeAPI {\n return {\n validateInteraction: (interactionId, params) =>\n runtime.validateInteraction(interactionId, params),\n submitInteraction: (interactionId, params) =>\n runtime.submitInteraction(interactionId, params),\n getSessionState: () => {\n const session = runtime.getSession();\n const frame = runtime.getFrame();\n return {\n status: session ? \"ready\" : \"loading\",\n sessionId: session?.sessionId ?? null,\n controllingPlayerId: frame?.perspectivePlayerId ?? null,\n };\n },\n disconnect: () => runtime.disconnect(),\n };\n}\n\nexport function PluginRuntimeBoundary({\n runtime,\n children,\n}: {\n runtime: PluginRuntimeClient;\n children: React.ReactNode;\n}) {\n const runtimeApi = useMemo(() => runtimeApiFromClient(runtime), [runtime]);\n\n return (\n <RuntimeContext.Provider value={runtimeApi}>\n <PluginSessionProvider runtime={runtime}>\n <PluginGameplayFrameProvider runtime={runtime}>\n <SessionScopedInteractionUiProvider>\n {children}\n </SessionScopedInteractionUiProvider>\n </PluginGameplayFrameProvider>\n </PluginSessionProvider>\n </RuntimeContext.Provider>\n );\n}\n\nfunction SessionScopedInteractionUiProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const { controllingPlayerId } = usePluginSession();\n return (\n <InteractionUiProvider key={controllingPlayerId ?? \"__no_player__\"}>\n {children}\n </InteractionUiProvider>\n );\n}\n"],"mappings":"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","names":[]}