@dreamboard-games/sdk 0.4.0-alpha.1 → 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.
- package/REFERENCE.md +1215 -125
- package/dist/{ResourceCounter-BTXklCEZ.d.ts → ResourceCounter-BuiNstXs.d.ts} +5 -1
- package/dist/{ThemeProvider-DvMl17Ny.d.ts → ThemeProvider-B1sIoBlX.d.ts} +1 -1
- package/dist/{attributes-BrZtP9az.d.ts → attributes-DbvyMbXw.d.ts} +17 -2
- package/dist/authoring/index.d.ts +66 -0
- package/dist/authoring/index.js +560 -0
- package/dist/authoring/index.js.map +1 -0
- package/dist/browser-interaction.d.ts +205 -5
- package/dist/browser-interaction.js +14 -2
- package/dist/{chunk-7W6TQO3X.js → chunk-45FI6XII.js} +613 -366
- package/dist/chunk-45FI6XII.js.map +1 -0
- package/dist/{chunk-3K362ZKR.js → chunk-6JQFGSLD.js} +202 -38
- package/dist/chunk-6JQFGSLD.js.map +1 -0
- package/dist/{chunk-XXBSIPJX.js → chunk-CP35NPPY.js} +131 -59
- package/dist/chunk-CP35NPPY.js.map +1 -0
- package/dist/{chunk-XJYUSD5F.js → chunk-FWVV2X74.js} +2 -2
- package/dist/{chunk-IUGKW2GS.js → chunk-HWJS3VOJ.js} +6 -2
- package/dist/chunk-HWJS3VOJ.js.map +1 -0
- package/dist/chunk-K5ZRJTZZ.js +328 -0
- package/dist/chunk-K5ZRJTZZ.js.map +1 -0
- package/dist/{chunk-7LZZEI25.js → chunk-N6ZDIMRB.js} +1 -1
- package/dist/chunk-N6ZDIMRB.js.map +1 -0
- package/dist/chunk-O6M6PN4E.js +1225 -0
- package/dist/chunk-O6M6PN4E.js.map +1 -0
- package/dist/{chunk-AEUXCFGM.js → chunk-PF7L4BMG.js} +1 -8
- package/dist/{chunk-AEUXCFGM.js.map → chunk-PF7L4BMG.js.map} +1 -1
- package/dist/{chunk-CZMFAS3E.js → chunk-WOWFONLZ.js} +517 -1274
- package/dist/chunk-WOWFONLZ.js.map +1 -0
- package/dist/{chunk-MALRKLRR.js → chunk-WUIVY2KE.js} +301 -12
- package/dist/chunk-WUIVY2KE.js.map +1 -0
- package/dist/chunk-ZAS2SENW.js +12 -0
- package/dist/chunk-ZAS2SENW.js.map +1 -0
- package/dist/codegen.d.ts +11 -3
- package/dist/codegen.js +1 -1
- package/dist/{components-Dqr_LuZJ.d.ts → components-BbWPnZCF.d.ts} +37 -6
- package/dist/{hex-board-view-UCUjMALd.d.ts → hex-board-view-Kz9Q_zsv.d.ts} +1 -1
- package/dist/index.js +2 -1
- package/dist/package-set.d.ts +2 -2
- package/dist/package-set.js +2 -1
- package/dist/player-state-Cqpyeql0.d.ts +371 -0
- package/dist/protocol-BP193lva.d.ts +267 -0
- package/dist/reducer/advanced.js +1 -1
- package/dist/reducer-contract.js +1 -1
- package/dist/reducer.js +2 -2
- package/dist/reducer.js.map +1 -1
- package/dist/runtime/primitives.d.ts +10 -10
- package/dist/runtime/primitives.js +9 -7
- package/dist/runtime/runtime-api.d.ts +2 -2
- package/dist/runtime/workspace-contract.d.ts +23 -12
- package/dist/runtime/workspace-contract.js +7 -6
- package/dist/runtime-api-BJharVaj.d.ts +198 -0
- package/dist/runtime-api-C6aWo9c0.d.ts +95 -0
- package/dist/runtime.d.ts +35 -31
- package/dist/runtime.js +87 -797
- package/dist/runtime.js.map +1 -1
- package/dist/testing.d.ts +254 -140
- package/dist/testing.js +964 -149
- package/dist/testing.js.map +1 -1
- package/dist/types-CYeN0wLK.d.ts +29 -0
- package/dist/{types-BqzHkNMA.d.ts → types-DJj5MJkl.d.ts} +32 -5
- package/dist/types.d.ts +13 -8
- package/dist/ui/components.d.ts +4 -5
- package/dist/ui/components.js +19 -1
- package/dist/ui/player-state.d.ts +2 -365
- package/dist/{ui-contract-W2-kxObe.d.ts → ui-contract-CY7cxsCC.d.ts} +16 -26
- package/dist/ui.d.ts +7 -8
- package/dist/ui.js +20 -2
- package/package.json +25 -19
- package/dist/chunk-3K362ZKR.js.map +0 -1
- package/dist/chunk-7LZZEI25.js.map +0 -1
- package/dist/chunk-7W6TQO3X.js.map +0 -1
- package/dist/chunk-CZMFAS3E.js.map +0 -1
- package/dist/chunk-IUGKW2GS.js.map +0 -1
- package/dist/chunk-MALRKLRR.js.map +0 -1
- package/dist/chunk-XXBSIPJX.js.map +0 -1
- package/dist/hex-color-MhOyuY-o.d.ts +0 -8
- package/dist/runtime-api-BXd70c2e.d.ts +0 -490
- /package/dist/{chunk-XJYUSD5F.js.map → chunk-FWVV2X74.js.map} +0 -0
package/dist/runtime.js
CHANGED
|
@@ -1,844 +1,140 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createWorkspaceUIContract
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
RuntimeProvider,
|
|
7
|
-
RuntimeSemanticProjectionMarker,
|
|
8
|
-
usePluginSession
|
|
9
|
-
} from "./chunk-CZMFAS3E.js";
|
|
10
|
-
import "./chunk-XJYUSD5F.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-
|
|
9
|
+
} from "./chunk-45FI6XII.js";
|
|
15
10
|
import "./chunk-VDXOF4FW.js";
|
|
16
|
-
import "./chunk-MALRKLRR.js";
|
|
17
11
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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";
|
|
22
22
|
import "./chunk-PZ5AY32C.js";
|
|
23
23
|
|
|
24
24
|
// src/runtime/hooks/usePluginRuntime.ts
|
|
25
25
|
import { useState, useEffect, useRef } from "react";
|
|
26
26
|
|
|
27
|
-
// src/runtime/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
var PluginEnvelopeBaseSchema = z.object({
|
|
32
|
-
protocol: z.literal(DREAMBOARD_PLUGIN_PROTOCOL),
|
|
33
|
-
version: z.literal(DREAMBOARD_PLUGIN_PROTOCOL_VERSION),
|
|
34
|
-
channelId: z.string().min(32).max(256)
|
|
35
|
-
}).strict();
|
|
36
|
-
var PlayerIdSchema = z.string();
|
|
37
|
-
var RuntimeRecordSchema = z.record(z.string(), RuntimeJsonSchema);
|
|
38
|
-
var NullableRuntimeJsonSchema = RuntimeJsonSchema.nullable();
|
|
39
|
-
var SeatAssignmentSchema = z.object({
|
|
40
|
-
playerId: PlayerIdSchema,
|
|
41
|
-
controllerUserId: z.string().optional(),
|
|
42
|
-
displayName: z.string(),
|
|
43
|
-
playerColor: z.string().optional(),
|
|
44
|
-
isHost: z.boolean().optional()
|
|
45
|
-
}).strict();
|
|
46
|
-
var LobbyStateSchema = z.object({
|
|
47
|
-
seats: z.array(SeatAssignmentSchema),
|
|
48
|
-
canStart: z.boolean(),
|
|
49
|
-
hostUserId: z.string()
|
|
50
|
-
}).strict();
|
|
51
|
-
var NotificationPayloadSchema = z.discriminatedUnion("type", [
|
|
52
|
-
z.object({
|
|
53
|
-
type: z.literal("YOUR_TURN"),
|
|
54
|
-
activePlayers: z.array(PlayerIdSchema)
|
|
55
|
-
}).strict(),
|
|
56
|
-
z.object({
|
|
57
|
-
type: z.literal("PROMPT_OPENED"),
|
|
58
|
-
promptId: z.string(),
|
|
59
|
-
promptInstanceId: z.string(),
|
|
60
|
-
targetPlayer: PlayerIdSchema,
|
|
61
|
-
title: z.string().optional()
|
|
62
|
-
}).strict(),
|
|
63
|
-
z.object({
|
|
64
|
-
type: z.literal("ACTION_EXECUTED"),
|
|
65
|
-
playerId: PlayerIdSchema,
|
|
66
|
-
actionType: z.string()
|
|
67
|
-
}).strict(),
|
|
68
|
-
z.object({
|
|
69
|
-
type: z.literal("ACTION_REJECTED"),
|
|
70
|
-
reason: z.string(),
|
|
71
|
-
targetPlayer: z.string().optional()
|
|
72
|
-
}).strict(),
|
|
73
|
-
z.object({
|
|
74
|
-
type: z.literal("TURN_CHANGED"),
|
|
75
|
-
previousPlayers: z.array(PlayerIdSchema),
|
|
76
|
-
currentPlayers: z.array(PlayerIdSchema)
|
|
77
|
-
}).strict(),
|
|
78
|
-
z.object({
|
|
79
|
-
type: z.literal("STATE_CHANGED"),
|
|
80
|
-
newState: z.string()
|
|
81
|
-
}).strict(),
|
|
82
|
-
z.object({
|
|
83
|
-
type: z.literal("GAME_ENDED"),
|
|
84
|
-
winner: z.string().optional(),
|
|
85
|
-
finalScores: z.record(z.string(), z.number().finite()),
|
|
86
|
-
reason: z.string()
|
|
87
|
-
}).strict(),
|
|
88
|
-
z.object({
|
|
89
|
-
type: z.literal("ERROR"),
|
|
90
|
-
message: z.string(),
|
|
91
|
-
code: z.string().optional()
|
|
92
|
-
}).strict()
|
|
93
|
-
]);
|
|
94
|
-
var NotificationSchema = z.object({
|
|
95
|
-
id: z.string(),
|
|
96
|
-
type: z.enum([
|
|
97
|
-
"YOUR_TURN",
|
|
98
|
-
"PROMPT_OPENED",
|
|
99
|
-
"ACTION_EXECUTED",
|
|
100
|
-
"ACTION_REJECTED",
|
|
101
|
-
"TURN_CHANGED",
|
|
102
|
-
"STATE_CHANGED",
|
|
103
|
-
"GAME_ENDED",
|
|
104
|
-
"ERROR"
|
|
105
|
-
]),
|
|
106
|
-
payload: NotificationPayloadSchema,
|
|
107
|
-
timestamp: z.number().finite(),
|
|
108
|
-
read: z.boolean()
|
|
109
|
-
}).strict();
|
|
110
|
-
var PluginSessionStateSchema = z.object({
|
|
111
|
-
sessionId: z.string().nullable(),
|
|
112
|
-
controllablePlayerIds: z.array(PlayerIdSchema),
|
|
113
|
-
controllingPlayerId: PlayerIdSchema.nullable(),
|
|
114
|
-
userId: z.string().nullable()
|
|
115
|
-
}).strict();
|
|
116
|
-
var HistoryEntrySummarySchema = z.object({
|
|
117
|
-
id: z.string(),
|
|
118
|
-
version: z.number().int(),
|
|
119
|
-
timestamp: z.string(),
|
|
120
|
-
description: z.string(),
|
|
121
|
-
playerId: PlayerIdSchema.optional(),
|
|
122
|
-
actionType: z.string().optional(),
|
|
123
|
-
isCurrent: z.boolean()
|
|
124
|
-
}).strict();
|
|
125
|
-
var HistoryStateSchema = z.object({
|
|
126
|
-
entries: z.array(HistoryEntrySummarySchema),
|
|
127
|
-
currentIndex: z.number().int(),
|
|
128
|
-
canGoBack: z.boolean(),
|
|
129
|
-
canGoForward: z.boolean()
|
|
130
|
-
}).strict();
|
|
131
|
-
var SimultaneousPhaseSchema = z.object({
|
|
132
|
-
phaseName: z.string(),
|
|
133
|
-
interactionId: z.string(),
|
|
134
|
-
actorIds: z.array(PlayerIdSchema),
|
|
135
|
-
sealedPlayerIds: z.array(PlayerIdSchema),
|
|
136
|
-
pendingPlayerIds: z.array(PlayerIdSchema)
|
|
137
|
-
}).strict();
|
|
138
|
-
var InteractionCommitPolicySchema = z.discriminatedUnion("mode", [
|
|
139
|
-
z.object({ mode: z.literal("manual") }).strict(),
|
|
140
|
-
z.object({ mode: z.literal("autoWhenReady") }).strict()
|
|
141
|
-
]);
|
|
142
|
-
var InputSelectionSchema = z.discriminatedUnion("mode", [
|
|
143
|
-
z.object({ mode: z.literal("single") }).strict(),
|
|
144
|
-
z.object({
|
|
145
|
-
mode: z.literal("many"),
|
|
146
|
-
min: z.number().int(),
|
|
147
|
-
max: z.number().int().optional(),
|
|
148
|
-
distinct: z.boolean().optional()
|
|
149
|
-
}).strict()
|
|
150
|
-
]);
|
|
151
|
-
var InputDomainDependencyCaseSchema = z.object({
|
|
152
|
-
when: z.record(z.string(), z.string()),
|
|
153
|
-
domain: RuntimeRecordSchema
|
|
154
|
-
}).strict();
|
|
155
|
-
var InputDomainResolverSchema = z.discriminatedUnion("mode", [
|
|
156
|
-
z.object({
|
|
157
|
-
mode: z.literal("eager"),
|
|
158
|
-
dependentCases: z.array(InputDomainDependencyCaseSchema)
|
|
159
|
-
}).strict(),
|
|
160
|
-
z.object({
|
|
161
|
-
mode: z.literal("lazy"),
|
|
162
|
-
dependsOn: z.array(z.string()),
|
|
163
|
-
resolver: z.object({
|
|
164
|
-
interactionKey: z.string().optional(),
|
|
165
|
-
inputKey: z.string()
|
|
166
|
-
}).strict()
|
|
167
|
-
}).strict()
|
|
168
|
-
]);
|
|
169
|
-
var InputDomainSchema = z.object({
|
|
170
|
-
type: z.string(),
|
|
171
|
-
selection: InputSelectionSchema.optional(),
|
|
172
|
-
dependencies: InputDomainResolverSchema.optional()
|
|
173
|
-
}).catchall(RuntimeJsonSchema);
|
|
174
|
-
var InteractionInputDescriptorSchema = z.object({
|
|
175
|
-
key: z.string(),
|
|
176
|
-
kind: z.string(),
|
|
177
|
-
domain: InputDomainSchema,
|
|
178
|
-
defaultValue: RuntimeJsonSchema.optional()
|
|
179
|
-
}).strict();
|
|
180
|
-
var InteractionAvailabilitySchema = z.discriminatedUnion("status", [
|
|
181
|
-
z.object({ status: z.literal("available") }).strict(),
|
|
182
|
-
z.object({ status: z.literal("notYourTurn"), reason: z.string() }).strict(),
|
|
183
|
-
z.object({
|
|
184
|
-
status: z.literal("insufficientResources"),
|
|
185
|
-
reason: z.string(),
|
|
186
|
-
missingResources: z.record(z.string(), z.number().finite())
|
|
187
|
-
}).strict(),
|
|
188
|
-
z.object({
|
|
189
|
-
status: z.literal("blocked"),
|
|
190
|
-
reason: z.string(),
|
|
191
|
-
code: z.string().optional()
|
|
192
|
-
}).strict()
|
|
193
|
-
]);
|
|
194
|
-
var InteractionBaseSchema = z.object({
|
|
195
|
-
phaseName: z.string(),
|
|
196
|
-
interactionKey: z.string(),
|
|
197
|
-
interactionId: z.string(),
|
|
198
|
-
commit: InteractionCommitPolicySchema,
|
|
199
|
-
descriptorDigest: z.string().optional(),
|
|
200
|
-
actorSeat: z.number().int().optional(),
|
|
201
|
-
draftDigest: z.string().optional(),
|
|
202
|
-
zoneId: z.string().optional(),
|
|
203
|
-
zoneIds: z.array(z.string()).optional(),
|
|
204
|
-
inputs: z.array(InteractionInputDescriptorSchema),
|
|
205
|
-
cost: RuntimeRecordSchema.optional(),
|
|
206
|
-
currentResources: RuntimeRecordSchema.optional(),
|
|
207
|
-
availability: InteractionAvailabilitySchema,
|
|
208
|
-
reasons: z.array(
|
|
209
|
-
z.object({
|
|
210
|
-
ruleId: z.string(),
|
|
211
|
-
errorCode: z.string()
|
|
212
|
-
}).strict()
|
|
213
|
-
).optional()
|
|
214
|
-
}).strict();
|
|
215
|
-
var InteractionDescriptorSchema = z.discriminatedUnion("kind", [
|
|
216
|
-
InteractionBaseSchema.extend({ kind: z.literal("action") }).strict(),
|
|
217
|
-
InteractionBaseSchema.extend({
|
|
218
|
-
kind: z.literal("prompt"),
|
|
219
|
-
context: z.object({
|
|
220
|
-
to: z.string(),
|
|
221
|
-
title: z.string().optional(),
|
|
222
|
-
payload: RuntimeRecordSchema.optional(),
|
|
223
|
-
options: z.array(
|
|
224
|
-
z.object({
|
|
225
|
-
id: z.string(),
|
|
226
|
-
label: z.string().optional()
|
|
227
|
-
}).strict()
|
|
228
|
-
).optional()
|
|
229
|
-
}).strict()
|
|
230
|
-
}).strict()
|
|
231
|
-
]);
|
|
232
|
-
var ZoneHandlesSnapshotSchema = z.object({
|
|
233
|
-
cardIds: z.array(z.string()),
|
|
234
|
-
cardViewsById: z.record(z.string(), z.string()),
|
|
235
|
-
playableByCardId: z.record(
|
|
236
|
-
z.string(),
|
|
237
|
-
z.array(InteractionDescriptorSchema)
|
|
238
|
-
)
|
|
239
|
-
}).strict();
|
|
240
|
-
var GameplaySnapshotSchema = z.object({
|
|
241
|
-
currentPhase: z.string().nullable(),
|
|
242
|
-
currentStage: z.string().nullable(),
|
|
243
|
-
activePlayers: z.array(PlayerIdSchema),
|
|
244
|
-
simultaneousPhase: SimultaneousPhaseSchema.nullable().optional(),
|
|
245
|
-
availableInteractions: z.array(InteractionDescriptorSchema),
|
|
246
|
-
zones: z.record(z.string(), ZoneHandlesSnapshotSchema)
|
|
247
|
-
}).strict();
|
|
248
|
-
var PluginStateSnapshotSchema = z.object({
|
|
249
|
-
view: NullableRuntimeJsonSchema,
|
|
250
|
-
gameplay: GameplaySnapshotSchema,
|
|
251
|
-
lobby: LobbyStateSchema.nullable(),
|
|
252
|
-
notifications: z.array(NotificationSchema),
|
|
253
|
-
session: PluginSessionStateSchema,
|
|
254
|
-
history: HistoryStateSchema.nullable(),
|
|
255
|
-
syncId: z.number().int()
|
|
256
|
-
}).strict();
|
|
257
|
-
var InitPayloadSchema = z.object({
|
|
258
|
-
type: z.literal("init"),
|
|
259
|
-
sessionId: z.string(),
|
|
260
|
-
controllablePlayerIds: z.array(z.string()),
|
|
261
|
-
controllingPlayerId: z.string(),
|
|
262
|
-
userId: z.string().nullable(),
|
|
263
|
-
state: PluginStateSnapshotSchema.optional()
|
|
264
|
-
}).strict();
|
|
265
|
-
var PingPayloadSchema = z.object({ type: z.literal("ping") }).strict();
|
|
266
|
-
var StateSyncPayloadSchema = z.object({
|
|
267
|
-
type: z.literal("state-sync"),
|
|
268
|
-
syncId: z.number().int(),
|
|
269
|
-
state: PluginStateSnapshotSchema
|
|
270
|
-
}).strict();
|
|
271
|
-
var ValidateInteractionResultPayloadSchema = z.object({
|
|
272
|
-
type: z.literal("validate-interaction-result"),
|
|
273
|
-
messageId: z.string(),
|
|
274
|
-
result: z.object({
|
|
275
|
-
valid: z.boolean(),
|
|
276
|
-
errorCode: z.string().nullable().optional(),
|
|
277
|
-
message: z.string().nullable().optional()
|
|
278
|
-
}).strict()
|
|
279
|
-
}).strict();
|
|
280
|
-
var SubmitResultPayloadSchema = z.object({
|
|
281
|
-
type: z.literal("submit-result"),
|
|
282
|
-
messageId: z.string(),
|
|
283
|
-
accepted: z.boolean(),
|
|
284
|
-
errorCode: z.string().nullable().optional(),
|
|
285
|
-
message: z.string().nullable().optional()
|
|
286
|
-
}).strict();
|
|
287
|
-
var HostToPluginPayloadSchema = z.discriminatedUnion("type", [
|
|
288
|
-
InitPayloadSchema,
|
|
289
|
-
PingPayloadSchema,
|
|
290
|
-
StateSyncPayloadSchema,
|
|
291
|
-
ValidateInteractionResultPayloadSchema,
|
|
292
|
-
SubmitResultPayloadSchema
|
|
293
|
-
]);
|
|
294
|
-
var HostToPluginEnvelopeSchema = PluginEnvelopeBaseSchema.extend({
|
|
295
|
-
payload: HostToPluginPayloadSchema
|
|
296
|
-
}).strict();
|
|
297
|
-
var PluginInitEnvelopeSchema = PluginEnvelopeBaseSchema.extend({
|
|
298
|
-
payload: InitPayloadSchema
|
|
299
|
-
}).strict();
|
|
300
|
-
function assertTransportEnvelopeWithinLimits(value) {
|
|
301
|
-
assertJsonWithinLimits(value, TRANSPORT_JSON_LIMITS, "Plugin message");
|
|
302
|
-
}
|
|
303
|
-
function createPluginEnvelope(payload, channel) {
|
|
304
|
-
return {
|
|
305
|
-
protocol: DREAMBOARD_PLUGIN_PROTOCOL,
|
|
306
|
-
version: DREAMBOARD_PLUGIN_PROTOCOL_VERSION,
|
|
307
|
-
channelId: channel.channelId,
|
|
308
|
-
payload
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// src/runtime/api/createPluginRuntimeAPI.ts
|
|
313
|
-
var mintClientActionId = () => {
|
|
314
|
-
const cryptoLike = globalThis.crypto;
|
|
315
|
-
if (cryptoLike?.randomUUID) {
|
|
316
|
-
try {
|
|
317
|
-
return cryptoLike.randomUUID();
|
|
318
|
-
} catch {
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
const rand = Math.random().toString(16).slice(2);
|
|
322
|
-
return `cid-${Date.now().toString(16)}-${rand}`;
|
|
323
|
-
};
|
|
324
|
-
var PLUGIN_RUNTIME_SINGLETON_KEY = "__dreamboardPluginRuntimeApi";
|
|
325
|
-
function createPluginRuntimeAPI(options = {}) {
|
|
326
|
-
const existingRuntime = globalThis[PLUGIN_RUNTIME_SINGLETON_KEY];
|
|
327
|
-
if (existingRuntime) {
|
|
328
|
-
existingRuntime.setDiagnosticHandler?.(options.onDiagnostic);
|
|
329
|
-
return existingRuntime;
|
|
330
|
-
}
|
|
331
|
-
let onDiagnostic = options.onDiagnostic;
|
|
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;
|
|
332
31
|
let channel = null;
|
|
333
|
-
let
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
} catch {
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
switch (event.type) {
|
|
343
|
-
case "runtimeLog": {
|
|
344
|
-
const args = [event.message, ...event.details ?? []];
|
|
345
|
-
if (event.level === "warn") {
|
|
346
|
-
console.warn(...args);
|
|
347
|
-
} else if (event.level === "error") {
|
|
348
|
-
console.error(...args);
|
|
349
|
-
} else {
|
|
350
|
-
console.log(...args);
|
|
351
|
-
}
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
354
|
-
case "internalError":
|
|
355
|
-
console.error(
|
|
356
|
-
`[Plugin RuntimeAPI] ${event.code}:`,
|
|
357
|
-
event.message,
|
|
358
|
-
event.stack ?? ""
|
|
359
|
-
);
|
|
360
|
-
break;
|
|
361
|
-
default: {
|
|
362
|
-
const _exhaustive = event;
|
|
363
|
-
return _exhaustive;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
let currentStateSnapshot = null;
|
|
368
|
-
const stateListeners = /* @__PURE__ */ new Set();
|
|
369
|
-
const sessionState = {
|
|
370
|
-
status: "loading",
|
|
371
|
-
sessionId: null,
|
|
372
|
-
controllablePlayerIds: [],
|
|
373
|
-
controllingPlayerId: null,
|
|
374
|
-
userId: null
|
|
375
|
-
};
|
|
376
|
-
const sessionStateListeners = /* @__PURE__ */ new Set();
|
|
377
|
-
const pendingValidations = /* @__PURE__ */ new Map();
|
|
378
|
-
let validationIdCounter = 0;
|
|
379
|
-
const pendingSubmissions = /* @__PURE__ */ new Map();
|
|
380
|
-
let submitIdCounter = 0;
|
|
381
|
-
const postToHost = (payload) => {
|
|
382
|
-
if (channel === null || disconnected) {
|
|
383
|
-
throw new Error("Plugin runtime is not initialized.");
|
|
384
|
-
}
|
|
385
|
-
channel.hostWindow.postMessage(
|
|
386
|
-
createPluginEnvelope(payload, channel),
|
|
387
|
-
channel.hostOrigin
|
|
388
|
-
);
|
|
389
|
-
};
|
|
390
|
-
const rejectPendingRequests = () => {
|
|
391
|
-
pendingValidations.forEach((resolve) => {
|
|
392
|
-
resolve({
|
|
393
|
-
valid: false,
|
|
394
|
-
errorCode: "runtime-disconnected",
|
|
395
|
-
message: "Plugin runtime disconnected"
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
pendingValidations.clear();
|
|
399
|
-
pendingSubmissions.forEach((pending) => {
|
|
400
|
-
pending.reject(
|
|
401
|
-
createSubmissionError(
|
|
402
|
-
"runtime-disconnected",
|
|
403
|
-
"Plugin runtime disconnected"
|
|
404
|
-
)
|
|
405
|
-
);
|
|
406
|
-
});
|
|
407
|
-
pendingSubmissions.clear();
|
|
408
|
-
};
|
|
409
|
-
const notifySessionStateChange = () => {
|
|
410
|
-
sessionStateListeners.forEach((listener) => {
|
|
411
|
-
try {
|
|
412
|
-
listener({ ...sessionState });
|
|
413
|
-
} catch {
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
};
|
|
417
|
-
const notifyStateListeners = () => {
|
|
418
|
-
if (!currentStateSnapshot) return;
|
|
419
|
-
const snapshot = currentStateSnapshot;
|
|
420
|
-
stateListeners.forEach((listener) => {
|
|
421
|
-
try {
|
|
422
|
-
listener(snapshot);
|
|
423
|
-
} catch {
|
|
424
|
-
}
|
|
425
|
-
});
|
|
426
|
-
};
|
|
427
|
-
const createSubmissionError = (errorCode, message) => {
|
|
428
|
-
const error = new Error(message ?? "Submission failed");
|
|
429
|
-
error.name = "SubmissionError";
|
|
430
|
-
error.errorCode = errorCode;
|
|
431
|
-
return error;
|
|
432
|
-
};
|
|
433
|
-
const submitViaParent = (payload) => new Promise((resolve, reject) => {
|
|
434
|
-
if (channel === null || disconnected) {
|
|
435
|
-
reject(
|
|
436
|
-
createSubmissionError(
|
|
437
|
-
"runtime-not-initialized",
|
|
438
|
-
"Plugin runtime is not initialized."
|
|
439
|
-
)
|
|
440
|
-
);
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
const messageId = `submit-${++submitIdCounter}`;
|
|
444
|
-
pendingSubmissions.set(messageId, { resolve, reject });
|
|
445
|
-
const clientSubmittedAtMs = Date.now();
|
|
446
|
-
if (payload.clientActionId && typeof performance !== "undefined") {
|
|
447
|
-
try {
|
|
448
|
-
performance.mark(`dreamboard.t0_click.${payload.clientActionId}`, {
|
|
449
|
-
detail: { clientActionId: payload.clientActionId }
|
|
450
|
-
});
|
|
451
|
-
} catch {
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
try {
|
|
455
|
-
postToHost({ ...payload, messageId, clientSubmittedAtMs });
|
|
456
|
-
} catch (error) {
|
|
457
|
-
pendingSubmissions.delete(messageId);
|
|
458
|
-
reject(
|
|
459
|
-
createSubmissionError(
|
|
460
|
-
"runtime-not-initialized",
|
|
461
|
-
error instanceof Error ? error.message : "Plugin runtime is not initialized."
|
|
462
|
-
)
|
|
463
|
-
);
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
setTimeout(() => {
|
|
467
|
-
const pending = pendingSubmissions.get(messageId);
|
|
468
|
-
if (!pending) {
|
|
469
|
-
return;
|
|
470
|
-
}
|
|
471
|
-
pendingSubmissions.delete(messageId);
|
|
472
|
-
pending.reject(
|
|
473
|
-
createSubmissionError(
|
|
474
|
-
"submission-timeout",
|
|
475
|
-
"Submission request timed out"
|
|
476
|
-
)
|
|
477
|
-
);
|
|
478
|
-
}, 1e4);
|
|
479
|
-
});
|
|
480
|
-
const applyInitMessage = (message) => {
|
|
481
|
-
emitDiagnostic({
|
|
482
|
-
type: "runtimeLog",
|
|
483
|
-
level: "log",
|
|
484
|
-
message: "[Plugin RuntimeAPI] Received init message"
|
|
485
|
-
});
|
|
486
|
-
sessionState.status = "ready";
|
|
487
|
-
sessionState.sessionId = message.sessionId;
|
|
488
|
-
sessionState.controllablePlayerIds = message.controllablePlayerIds;
|
|
489
|
-
sessionState.controllingPlayerId = message.controllingPlayerId;
|
|
490
|
-
sessionState.userId = message.userId;
|
|
491
|
-
notifySessionStateChange();
|
|
492
|
-
if (message.state) {
|
|
493
|
-
applyStateSyncMessage({
|
|
494
|
-
type: "state-sync",
|
|
495
|
-
syncId: message.state.syncId,
|
|
496
|
-
state: message.state
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
};
|
|
500
|
-
const applyStateSyncMessage = (message) => {
|
|
501
|
-
emitDiagnostic({
|
|
502
|
-
type: "runtimeLog",
|
|
503
|
-
level: "log",
|
|
504
|
-
message: "[Plugin RuntimeAPI] Received state-sync, syncId:",
|
|
505
|
-
details: [message.syncId]
|
|
506
|
-
});
|
|
507
|
-
const clientReceivedAtMs = Date.now();
|
|
508
|
-
if (typeof performance !== "undefined") {
|
|
509
|
-
try {
|
|
510
|
-
performance.mark(
|
|
511
|
-
`dreamboard.t7_state_sync_received.sync-${message.syncId}`,
|
|
512
|
-
{ detail: { syncId: message.syncId } }
|
|
513
|
-
);
|
|
514
|
-
} catch {
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
currentStateSnapshot = message.state;
|
|
518
|
-
if (message.state.session) {
|
|
519
|
-
sessionState.sessionId = message.state.session.sessionId;
|
|
520
|
-
sessionState.controllablePlayerIds = message.state.session.controllablePlayerIds;
|
|
521
|
-
sessionState.controllingPlayerId = message.state.session.controllingPlayerId;
|
|
522
|
-
sessionState.userId = message.state.session.userId;
|
|
523
|
-
sessionState.status = "ready";
|
|
524
|
-
notifySessionStateChange();
|
|
525
|
-
}
|
|
526
|
-
notifyStateListeners();
|
|
527
|
-
postToHost({
|
|
528
|
-
type: "state-ack",
|
|
529
|
-
syncId: message.syncId,
|
|
530
|
-
clientReceivedAtMs
|
|
531
|
-
});
|
|
532
|
-
const schedulePostRender = () => {
|
|
533
|
-
const send = () => {
|
|
534
|
-
const clientRenderedAtMs = Date.now();
|
|
535
|
-
if (typeof performance !== "undefined") {
|
|
536
|
-
try {
|
|
537
|
-
performance.mark(
|
|
538
|
-
`dreamboard.t8_render_commit.sync-${message.syncId}`,
|
|
539
|
-
{
|
|
540
|
-
detail: { syncId: message.syncId }
|
|
541
|
-
}
|
|
542
|
-
);
|
|
543
|
-
} catch {
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
if (!disconnected && channel !== null) {
|
|
547
|
-
postToHost({
|
|
548
|
-
type: "state-rendered",
|
|
549
|
-
syncId: message.syncId,
|
|
550
|
-
clientReceivedAtMs,
|
|
551
|
-
clientRenderedAtMs
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
};
|
|
555
|
-
if (typeof requestAnimationFrame === "function") {
|
|
556
|
-
requestAnimationFrame(send);
|
|
557
|
-
} else {
|
|
558
|
-
queueMicrotask(send);
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
queueMicrotask(schedulePostRender);
|
|
562
|
-
};
|
|
563
|
-
const handleMessage = (event) => {
|
|
564
|
-
if (disconnected || event.source !== window.parent) {
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
try {
|
|
568
|
-
assertTransportEnvelopeWithinLimits(event.data);
|
|
569
|
-
} catch (error) {
|
|
570
|
-
emitDiagnostic({
|
|
571
|
-
type: "runtimeLog",
|
|
572
|
-
level: "warn",
|
|
573
|
-
message: "[Plugin RuntimeAPI] Rejected oversized or non-JSON message:",
|
|
574
|
-
details: [error instanceof Error ? error.name : "unknown"]
|
|
575
|
-
});
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
if (channel === null) {
|
|
579
|
-
const initResult = PluginInitEnvelopeSchema.safeParse(event.data);
|
|
580
|
-
if (!initResult.success) {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
channel = {
|
|
584
|
-
channelId: initResult.data.channelId,
|
|
585
|
-
hostOrigin: event.origin,
|
|
586
|
-
hostWindow: window.parent
|
|
587
|
-
};
|
|
588
|
-
applyInitMessage(initResult.data.payload);
|
|
589
|
-
postToHost({ type: "ready" });
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
if (event.source !== channel.hostWindow || event.origin !== channel.hostOrigin) {
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
const parseResult = HostToPluginEnvelopeSchema.safeParse(event.data);
|
|
596
|
-
if (!parseResult.success || parseResult.data.channelId !== channel.channelId) {
|
|
597
|
-
const rawPayload = event.data?.payload;
|
|
598
|
-
if (typeof rawPayload?.type === "string") {
|
|
599
|
-
emitDiagnostic({
|
|
600
|
-
type: "runtimeLog",
|
|
601
|
-
level: "warn",
|
|
602
|
-
message: "[Plugin RuntimeAPI] Invalid message received:",
|
|
603
|
-
details: [rawPayload.type]
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
return;
|
|
607
|
-
}
|
|
608
|
-
const message = parseResult.data.payload;
|
|
609
|
-
switch (message.type) {
|
|
610
|
-
case "init": {
|
|
611
|
-
break;
|
|
612
|
-
}
|
|
613
|
-
case "ping": {
|
|
614
|
-
postToHost({ type: "pong" });
|
|
615
|
-
break;
|
|
616
|
-
}
|
|
617
|
-
case "state-sync": {
|
|
618
|
-
applyStateSyncMessage(message);
|
|
619
|
-
break;
|
|
620
|
-
}
|
|
621
|
-
case "validate-interaction-result": {
|
|
622
|
-
const resolver = pendingValidations.get(message.messageId);
|
|
623
|
-
if (resolver) {
|
|
624
|
-
pendingValidations.delete(message.messageId);
|
|
625
|
-
resolver({
|
|
626
|
-
valid: message.result.valid,
|
|
627
|
-
errorCode: message.result.errorCode ?? void 0,
|
|
628
|
-
message: message.result.message ?? void 0
|
|
629
|
-
});
|
|
32
|
+
let outboundSequence = 0;
|
|
33
|
+
return {
|
|
34
|
+
start(onMessage) {
|
|
35
|
+
const handleMessage = (event) => {
|
|
36
|
+
if (event.source !== parentWindow) {
|
|
37
|
+
return;
|
|
630
38
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
if (!pending) {
|
|
636
|
-
break;
|
|
39
|
+
const parseResult = HostToPluginEnvelopeSchema.safeParse(event.data);
|
|
40
|
+
if (!parseResult.success) {
|
|
41
|
+
options.onInvalidMessage?.("invalid-envelope", event.data);
|
|
42
|
+
return;
|
|
637
43
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
});
|
|
643
|
-
} catch {
|
|
44
|
+
const envelope = parseResult.data;
|
|
45
|
+
if (!channel) {
|
|
46
|
+
if (envelope.payload.type !== "runtime.init") {
|
|
47
|
+
return;
|
|
644
48
|
}
|
|
49
|
+
channel = {
|
|
50
|
+
channelId: envelope.channelId,
|
|
51
|
+
hostOrigin: event.origin,
|
|
52
|
+
hostWindow: event.source
|
|
53
|
+
};
|
|
645
54
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
pending.resolve();
|
|
649
|
-
} else {
|
|
650
|
-
pending.reject(
|
|
651
|
-
createSubmissionError(
|
|
652
|
-
message.errorCode ?? void 0,
|
|
653
|
-
message.message ?? void 0
|
|
654
|
-
)
|
|
655
|
-
);
|
|
656
|
-
}
|
|
657
|
-
break;
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
};
|
|
661
|
-
window.addEventListener("message", handleMessage);
|
|
662
|
-
const sendErrorToParent = (message, code, stack) => {
|
|
663
|
-
emitDiagnostic({
|
|
664
|
-
type: "internalError",
|
|
665
|
-
code,
|
|
666
|
-
message,
|
|
667
|
-
...stack ? { stack } : {}
|
|
668
|
-
});
|
|
669
|
-
if (channel !== null && !disconnected) {
|
|
670
|
-
postToHost({
|
|
671
|
-
type: "error",
|
|
672
|
-
message: stack ? `${message}
|
|
673
|
-
${stack}` : message,
|
|
674
|
-
code
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
};
|
|
678
|
-
window.onerror = (message, source, lineno, colno, error) => {
|
|
679
|
-
const errorMessage = typeof message === "string" ? message : error?.message || "Unknown error";
|
|
680
|
-
const location = source ? ` at ${source}:${lineno}:${colno}` : "";
|
|
681
|
-
sendErrorToParent(errorMessage + location, "UNCAUGHT_ERROR", error?.stack);
|
|
682
|
-
return false;
|
|
683
|
-
};
|
|
684
|
-
window.onunhandledrejection = (event) => {
|
|
685
|
-
const reason = event.reason;
|
|
686
|
-
const message = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : JSON.stringify(reason);
|
|
687
|
-
const stack = reason instanceof Error ? reason.stack : void 0;
|
|
688
|
-
sendErrorToParent(message, "UNHANDLED_REJECTION", stack);
|
|
689
|
-
};
|
|
690
|
-
emitDiagnostic({
|
|
691
|
-
type: "runtimeLog",
|
|
692
|
-
level: "log",
|
|
693
|
-
message: "[Plugin RuntimeAPI] Initialized (state-sync architecture)"
|
|
694
|
-
});
|
|
695
|
-
const runtime = {
|
|
696
|
-
// State-sync methods
|
|
697
|
-
getSnapshot: () => currentStateSnapshot,
|
|
698
|
-
subscribeToState: (listener) => {
|
|
699
|
-
stateListeners.add(listener);
|
|
700
|
-
if (currentStateSnapshot) {
|
|
701
|
-
try {
|
|
702
|
-
listener(currentStateSnapshot);
|
|
703
|
-
} catch {
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
return () => {
|
|
707
|
-
stateListeners.delete(listener);
|
|
708
|
-
};
|
|
709
|
-
},
|
|
710
|
-
validateInteraction: async (playerId, interactionId, params) => {
|
|
711
|
-
return new Promise((resolve) => {
|
|
712
|
-
if (channel === null || disconnected) {
|
|
713
|
-
resolve({
|
|
714
|
-
valid: false,
|
|
715
|
-
errorCode: "runtime-not-initialized",
|
|
716
|
-
message: "Plugin runtime is not initialized."
|
|
717
|
-
});
|
|
55
|
+
if (envelope.channelId !== channel.channelId || event.origin !== channel.hostOrigin || event.source !== channel.hostWindow) {
|
|
56
|
+
options.onInvalidMessage?.("channel-mismatch", event.data);
|
|
718
57
|
return;
|
|
719
58
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
postToHost({
|
|
724
|
-
type: "validate-interaction",
|
|
725
|
-
playerId,
|
|
726
|
-
interactionId,
|
|
727
|
-
params,
|
|
728
|
-
messageId
|
|
729
|
-
});
|
|
730
|
-
} catch {
|
|
731
|
-
pendingValidations.delete(messageId);
|
|
732
|
-
resolve({
|
|
733
|
-
valid: false,
|
|
734
|
-
errorCode: "runtime-not-initialized",
|
|
735
|
-
message: "Plugin runtime is not initialized."
|
|
736
|
-
});
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
|
-
setTimeout(() => {
|
|
740
|
-
if (pendingValidations.has(messageId)) {
|
|
741
|
-
pendingValidations.delete(messageId);
|
|
742
|
-
resolve({
|
|
743
|
-
valid: false,
|
|
744
|
-
errorCode: "validation-timeout",
|
|
745
|
-
message: "Validation request timed out"
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
}, 1e4);
|
|
749
|
-
});
|
|
750
|
-
},
|
|
751
|
-
submitInteraction: async (playerId, interactionId, params) => submitViaParent({
|
|
752
|
-
type: "interaction",
|
|
753
|
-
playerId,
|
|
754
|
-
interactionId,
|
|
755
|
-
params,
|
|
756
|
-
clientActionId: mintClientActionId()
|
|
757
|
-
}),
|
|
758
|
-
getSessionState: () => ({ ...sessionState }),
|
|
759
|
-
disconnect: () => {
|
|
760
|
-
window.removeEventListener("message", handleMessage);
|
|
761
|
-
window.onerror = null;
|
|
762
|
-
window.onunhandledrejection = null;
|
|
763
|
-
disconnected = true;
|
|
764
|
-
channel = null;
|
|
765
|
-
sessionStateListeners.clear();
|
|
766
|
-
stateListeners.clear();
|
|
767
|
-
rejectPendingRequests();
|
|
768
|
-
currentStateSnapshot = null;
|
|
769
|
-
},
|
|
770
|
-
switchPlayer: (playerId) => {
|
|
771
|
-
postToHost({ type: "switch-player", playerId });
|
|
772
|
-
},
|
|
773
|
-
restoreHistory: (entryId) => {
|
|
774
|
-
postToHost({ type: "restore-history", entryId });
|
|
775
|
-
},
|
|
776
|
-
markNotificationRead: (notificationId) => {
|
|
777
|
-
postToHost({ type: "mark-notification-read", notificationId });
|
|
778
|
-
},
|
|
779
|
-
setDiagnosticHandler: (handler) => {
|
|
780
|
-
onDiagnostic = handler;
|
|
781
|
-
},
|
|
782
|
-
emitDiagnostic,
|
|
783
|
-
_subscribeToSessionState: (listener) => {
|
|
784
|
-
sessionStateListeners.add(listener);
|
|
785
|
-
listener({ ...sessionState });
|
|
59
|
+
onMessage(envelope);
|
|
60
|
+
};
|
|
61
|
+
targetWindow.addEventListener("message", handleMessage);
|
|
786
62
|
return () => {
|
|
787
|
-
|
|
63
|
+
targetWindow.removeEventListener("message", handleMessage);
|
|
64
|
+
channel = null;
|
|
788
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
|
+
);
|
|
789
81
|
}
|
|
790
82
|
};
|
|
791
|
-
globalThis[PLUGIN_RUNTIME_SINGLETON_KEY] = runtime;
|
|
792
|
-
return runtime;
|
|
793
83
|
}
|
|
794
84
|
|
|
795
85
|
// src/runtime/hooks/usePluginRuntime.ts
|
|
796
|
-
function hasProjectedView(
|
|
797
|
-
|
|
86
|
+
function hasProjectedView(runtime) {
|
|
87
|
+
const frame = runtime.getFrame();
|
|
88
|
+
return frame !== null && frame.view !== null && typeof frame.view !== "undefined";
|
|
798
89
|
}
|
|
799
90
|
function usePluginRuntime(options = {}) {
|
|
800
91
|
const { timeout = 1e4, onDiagnostic } = options;
|
|
801
92
|
const [runtime] = useState(
|
|
802
|
-
() =>
|
|
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
|
+
})
|
|
803
103
|
);
|
|
804
|
-
const [isReady, setIsReady] = useState(() =>
|
|
805
|
-
const snapshot = runtime.getSnapshot?.();
|
|
806
|
-
return hasProjectedView(snapshot);
|
|
807
|
-
});
|
|
104
|
+
const [isReady, setIsReady] = useState(() => hasProjectedView(runtime));
|
|
808
105
|
const [error, setError] = useState(null);
|
|
809
106
|
const hasBeenReadyRef = useRef(false);
|
|
810
107
|
if (isReady) hasBeenReadyRef.current = true;
|
|
811
108
|
useEffect(() => {
|
|
812
|
-
|
|
813
|
-
}, [
|
|
109
|
+
void onDiagnostic;
|
|
110
|
+
}, [onDiagnostic]);
|
|
814
111
|
useEffect(() => {
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
if (!hasProjectedView(currentSnapshot)) {
|
|
112
|
+
const markReadyFromFrame = () => {
|
|
113
|
+
if (!hasProjectedView(runtime)) {
|
|
818
114
|
return false;
|
|
819
115
|
}
|
|
820
116
|
setError(null);
|
|
821
117
|
setIsReady(true);
|
|
822
118
|
return true;
|
|
823
119
|
};
|
|
824
|
-
if (
|
|
120
|
+
if (markReadyFromFrame()) {
|
|
825
121
|
return;
|
|
826
122
|
}
|
|
827
123
|
const timeoutId = setTimeout(() => {
|
|
828
|
-
if (!
|
|
124
|
+
if (!markReadyFromFrame()) {
|
|
829
125
|
setError(
|
|
830
|
-
`Timed out waiting for the initial projected view after ${timeout}ms. Ensure the host sends a
|
|
126
|
+
`Timed out waiting for the initial projected view after ${timeout}ms. Ensure the host sends a gameplay frame with a seat view.`
|
|
831
127
|
);
|
|
832
128
|
}
|
|
833
129
|
}, timeout);
|
|
834
130
|
const pollId = setInterval(() => {
|
|
835
|
-
if (
|
|
131
|
+
if (markReadyFromFrame()) {
|
|
836
132
|
clearInterval(pollId);
|
|
837
133
|
clearTimeout(timeoutId);
|
|
838
134
|
}
|
|
839
135
|
}, 100);
|
|
840
|
-
const unsubscribe = runtime.
|
|
841
|
-
if (!hasProjectedView(
|
|
136
|
+
const unsubscribe = runtime.subscribeFrame(() => {
|
|
137
|
+
if (!hasProjectedView(runtime)) {
|
|
842
138
|
setIsReady(false);
|
|
843
139
|
return;
|
|
844
140
|
}
|
|
@@ -894,19 +190,13 @@ function PluginRuntime({
|
|
|
894
190
|
}
|
|
895
191
|
);
|
|
896
192
|
}
|
|
897
|
-
return /* @__PURE__ */ jsx(
|
|
898
|
-
}
|
|
899
|
-
function SessionScopedInteractionUiProvider({
|
|
900
|
-
children
|
|
901
|
-
}) {
|
|
902
|
-
const { controllingPlayerId } = usePluginSession();
|
|
903
|
-
return /* @__PURE__ */ jsxs(InteractionUiProvider, { children: [
|
|
904
|
-
/* @__PURE__ */ jsx(RuntimeSemanticProjectionMarker, {}),
|
|
905
|
-
children
|
|
906
|
-
] }, controllingPlayerId ?? "__no_player__");
|
|
193
|
+
return /* @__PURE__ */ jsx(PluginRuntimeBoundary, { runtime, children });
|
|
907
194
|
}
|
|
908
195
|
export {
|
|
909
196
|
PluginRuntime,
|
|
197
|
+
PluginRuntimeBoundary,
|
|
198
|
+
createPluginRuntimeClient,
|
|
199
|
+
createPostMessagePluginTransport,
|
|
910
200
|
createWorkspaceUIContract
|
|
911
201
|
};
|
|
912
202
|
//# sourceMappingURL=runtime.js.map
|