@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
@@ -15,724 +15,70 @@ import {
15
15
  createHexBoardView,
16
16
  surfaceStyle,
17
17
  useChromeSuppression,
18
+ useOverlayInsets,
18
19
  useTheme,
19
20
  useThemeCssVars
20
- } from "./chunk-Q5O7GPVY.js";
21
+ } from "./chunk-45FI6XII.js";
21
22
  import {
22
23
  composeEventHandlers,
23
24
  renderPrimitive
24
25
  } from "./chunk-VDXOF4FW.js";
25
26
  import {
26
- BROWSER_INTERACTION_ATTRIBUTES,
27
- DREAMBOARD_BROWSER_INTERACTION_PROTOCOL_VERSION,
28
- GAMEPLAY_BROWSER_INTERACTION_SURFACE,
29
- createGameplayActuatorAttributes,
30
- createGameplayInteractionRootAttributes,
31
- gameplayAdjustResourceEffect,
32
- gameplayCommitEffect,
33
- gameplayInvokeEffect,
34
- gameplaySetCandidateEffect,
35
- gameplaySetScalarEffect
36
- } from "./chunk-QLG6VEMW.js";
37
-
38
- // src/runtime/primitives/ui.tsx
39
- import { Fragment, jsx } from "react/jsx-runtime";
40
- function UIRoot({
41
- theme,
42
- themeOverride,
43
- reducedMotion,
44
- className,
45
- style,
46
- children
47
- }) {
48
- if (theme === void 0 && themeOverride === void 0) {
49
- return /* @__PURE__ */ jsx(Fragment, { children });
50
- }
51
- return /* @__PURE__ */ jsx(
52
- ThemeProvider,
53
- {
54
- theme,
55
- override: themeOverride,
56
- reducedMotion,
57
- className,
58
- style,
59
- children
60
- }
61
- );
62
- }
63
- var UI = {
64
- Root: UIRoot
65
- };
66
-
67
- // src/runtime/primitives/hand-intent-adapter.ts
68
- import { useCallback } from "react";
69
-
70
- // src/runtime/context/InteractionDraftContext.tsx
71
- import { createContext, useContext, useMemo } from "react";
72
- import { useStore } from "zustand";
73
- import { createStore } from "zustand/vanilla";
74
- import { useShallow } from "zustand/shallow";
75
- import { jsx as jsx2 } from "react/jsx-runtime";
76
- var EMPTY_DRAFT = Object.freeze({});
77
- function createInteractionUiStore() {
78
- const store = createStore()(() => ({
79
- drafts: {},
80
- arms: {},
81
- submitting: {},
82
- pendingInteractionKey: null,
83
- pendingInteractionRevision: 0
84
- }));
85
- const api = {
86
- getDraft(interactionId) {
87
- return store.getState().drafts[interactionId] ?? EMPTY_DRAFT;
88
- },
89
- setInput(interactionId, key, value) {
90
- store.setState((prev) => {
91
- const current = prev.drafts[interactionId];
92
- if (current && current[key] === value) return prev;
93
- return {
94
- ...prev,
95
- drafts: {
96
- ...prev.drafts,
97
- [interactionId]: { ...current ?? {}, [key]: value }
98
- }
99
- };
100
- });
101
- },
102
- clearInput(interactionId, key) {
103
- store.setState((prev) => {
104
- const current = prev.drafts[interactionId];
105
- if (!current) return prev;
106
- if (key === void 0) {
107
- const { [interactionId]: _omit, ...rest } = prev.drafts;
108
- return { ...prev, drafts: rest };
109
- }
110
- if (!(key in current)) return prev;
111
- const { [key]: _omitKey, ...remainingKeys } = current;
112
- if (Object.keys(remainingKeys).length === 0) {
113
- const { [interactionId]: _omit, ...rest } = prev.drafts;
114
- return { ...prev, drafts: rest };
115
- }
116
- return {
117
- ...prev,
118
- drafts: { ...prev.drafts, [interactionId]: remainingKeys }
119
- };
120
- });
121
- },
122
- clearAll() {
123
- store.setState((prev) => {
124
- if (Object.keys(prev.drafts).length === 0 && Object.keys(prev.arms).length === 0 && Object.keys(prev.submitting).length === 0 && prev.pendingInteractionKey === null) {
125
- return prev;
126
- }
127
- return {
128
- drafts: {},
129
- arms: {},
130
- submitting: {},
131
- pendingInteractionKey: null,
132
- pendingInteractionRevision: prev.pendingInteractionRevision + 1
133
- };
134
- });
135
- },
136
- getArmed(surface) {
137
- return store.getState().arms[surface] ?? null;
138
- },
139
- arm(surface, interactionId) {
140
- store.setState((prev) => {
141
- const current = prev.arms[surface] ?? null;
142
- if (current === interactionId) return prev;
143
- if (interactionId === null) {
144
- const { [surface]: _omit, ...rest } = prev.arms;
145
- return { ...prev, arms: rest };
146
- }
147
- return { ...prev, arms: { ...prev.arms, [surface]: interactionId } };
148
- });
149
- },
150
- getPendingInteraction() {
151
- return store.getState().pendingInteractionKey;
152
- },
153
- setPendingInteraction(interactionId) {
154
- store.setState((prev) => {
155
- if (prev.pendingInteractionKey === interactionId) {
156
- return interactionId === null ? prev : {
157
- ...prev,
158
- pendingInteractionRevision: prev.pendingInteractionRevision + 1
159
- };
160
- }
161
- return {
162
- ...prev,
163
- pendingInteractionKey: interactionId,
164
- pendingInteractionRevision: prev.pendingInteractionRevision + 1
165
- };
166
- });
167
- },
168
- getPendingInteractionRevision() {
169
- return store.getState().pendingInteractionRevision;
170
- },
171
- isSubmitting(interactionId) {
172
- return store.getState().submitting[interactionId] === true;
173
- },
174
- claimSubmitting(interactionId) {
175
- let claimed = false;
176
- store.setState((prev) => {
177
- if (prev.submitting[interactionId] === true) return prev;
178
- claimed = true;
179
- return {
180
- ...prev,
181
- submitting: { ...prev.submitting, [interactionId]: true }
182
- };
183
- });
184
- return claimed;
185
- },
186
- setSubmitting(interactionId, submitting) {
187
- store.setState((prev) => {
188
- const current = prev.submitting[interactionId] === true;
189
- if (current === submitting) return prev;
190
- if (!submitting) {
191
- const { [interactionId]: _omit, ...rest } = prev.submitting;
192
- return { ...prev, submitting: rest };
193
- }
194
- return {
195
- ...prev,
196
- submitting: { ...prev.submitting, [interactionId]: true }
197
- };
198
- });
199
- }
200
- };
201
- return Object.assign(store, api);
202
- }
203
- var InteractionUiCtx = createContext(null);
204
- function InteractionUiProvider({
205
- children,
206
- store
207
- }) {
208
- const ownedStore = useMemo(() => createInteractionUiStore(), []);
209
- return /* @__PURE__ */ jsx2(InteractionUiCtx.Provider, { value: store ?? ownedStore, children });
210
- }
211
- function useInteractionUiStore() {
212
- const ctx = useContext(InteractionUiCtx);
213
- const fallback = useMemo(() => createInteractionUiStore(), []);
214
- return ctx ?? fallback;
215
- }
216
- function useInteractionDraft(interactionId) {
217
- const store = useInteractionUiStore();
218
- useStore(
219
- store,
220
- useShallow(
221
- (state) => state.drafts[interactionId] ?? EMPTY_DRAFT
222
- )
223
- );
224
- return store.getDraft(interactionId);
225
- }
226
- function useArmedInteraction(surface) {
227
- const store = useInteractionUiStore();
228
- return useStore(store, (state) => state.arms[surface] ?? null);
229
- }
230
- function usePendingInteractionKey() {
231
- const store = useInteractionUiStore();
232
- const subscribed = useStore(
233
- store,
234
- (state) => state.pendingInteractionKey ?? null
235
- );
236
- return store.getPendingInteraction() ?? subscribed;
237
- }
238
- function usePendingInteractionRevision() {
239
- const store = useInteractionUiStore();
240
- const subscribed = useStore(
241
- store,
242
- (state) => state.pendingInteractionRevision
243
- );
244
- return Math.max(store.getPendingInteractionRevision(), subscribed);
245
- }
246
- function useInteractionSubmitting(interactionId) {
247
- const store = useInteractionUiStore();
248
- return useStore(
249
- store,
250
- (state) => state.submitting[interactionId] === true
251
- );
252
- }
253
-
254
- // src/runtime/context/PluginSessionContext.tsx
255
- import { createContext as createContext2, useContext as useContext2 } from "react";
256
- var PluginSessionContext = createContext2(
257
- null
258
- );
259
- function usePluginSession() {
260
- const context = useContext2(PluginSessionContext);
261
- if (context === null) {
262
- throw new Error(
263
- "usePluginSession must be used within a PluginSessionContext.Provider (provided by RuntimeContext)"
264
- );
265
- }
266
- return context;
267
- }
268
-
269
- // src/runtime/context/PluginStateContext.tsx
270
- import {
271
- createContext as createContext4,
272
- useContext as useContext4,
273
- useState as useState2,
274
- useEffect as useEffect2,
275
- useMemo as useMemo2,
276
- useSyncExternalStore
277
- } from "react";
278
-
279
- // src/runtime/context/RuntimeContext.tsx
280
- import { createContext as createContext3, useContext as useContext3, useState, useEffect } from "react";
281
- import { jsx as jsx3 } from "react/jsx-runtime";
282
- var RuntimeContext = createContext3(null);
283
- function useRuntimeContext() {
284
- const context = useContext3(RuntimeContext);
285
- if (!context) {
286
- throw new Error(
287
- "useRuntimeContext must be used within a RuntimeContext.Provider"
288
- );
289
- }
290
- return context;
291
- }
292
- function RuntimeProvider({
293
- runtime,
294
- children
295
- }) {
296
- const [sessionState, setSessionState] = useState(
297
- () => runtime.getSessionState()
298
- );
299
- useEffect(() => {
300
- const runtimeWithInternal = runtime;
301
- if (runtimeWithInternal._subscribeToSessionState) {
302
- return runtimeWithInternal._subscribeToSessionState((state) => {
303
- setSessionState(state);
304
- });
305
- }
306
- return () => {
307
- };
308
- }, [runtime]);
309
- return /* @__PURE__ */ jsx3(RuntimeContext.Provider, { value: runtime, children: /* @__PURE__ */ jsx3(PluginSessionContext.Provider, { value: sessionState, children }) });
310
- }
311
-
312
- // src/runtime/utils/semantic-projection-digest.ts
313
- var AUTHORIZED_SEAT_PROJECTION_DIGEST_VERSION = "authorized-seat-projection@2";
314
- function semanticProjectionDigestForState(state) {
315
- const actorPlayerId = state.session.controllingPlayerId;
316
- if (!actorPlayerId) {
317
- return null;
318
- }
319
- const seatOrder = state.lobby?.seats.map((seat) => seat.playerId) ?? [];
320
- if (!seatOrder.includes(actorPlayerId)) {
321
- return null;
322
- }
323
- return hashJson(semanticSeatProjection(state, state.gameplay, seatOrder));
324
- }
325
- function semanticSeatProjection(state, gameplay, seatOrder) {
326
- const playerToSeat = new Map(
327
- seatOrder.map((playerId, index) => [playerId, index])
328
- );
329
- const actorPlayerId = state.session.controllingPlayerId;
330
- const actorSeat = actorPlayerId ? playerToSeat.get(actorPlayerId) : void 0;
331
- if (actorSeat === void 0) {
332
- throw new Error(
333
- `authorized projection player ${actorPlayerId ?? "__none__"} is not present in seat order`
334
- );
335
- }
336
- return {
337
- digestVersion: AUTHORIZED_SEAT_PROJECTION_DIGEST_VERSION,
338
- actorSeat,
339
- currentStage: gameplay.currentStage ?? null,
340
- stageSeats: gameplay.activePlayers.map(
341
- (playerId) => canonicalizeSeatReference(playerId, playerToSeat)
342
- ),
343
- view: canonicalizeSemanticProjectionValue(state.view, playerToSeat),
344
- zones: canonicalizeSemanticProjectionValue(
345
- gameplay.zones ?? {},
346
- playerToSeat
347
- ),
348
- availableInteractions: gameplay.availableInteractions.map(
349
- (descriptor) => semanticInteractionDescriptor(descriptor, playerToSeat)
350
- )
351
- };
352
- }
353
- function semanticInteractionDescriptor(descriptor, playerToSeat) {
354
- const inputs = descriptor.inputs.map(
355
- (input) => semanticInteractionInput(input, playerToSeat)
356
- );
357
- const { defaults, defaultProvenance } = collectDefaults(descriptor.inputs);
358
- return {
359
- interactionKey: descriptor.interactionKey,
360
- interactionId: descriptor.interactionId,
361
- stableIdentity: canonicalizeSemanticProjectionValue(
362
- `${descriptor.interactionKey}:${descriptor.interactionId}`,
363
- playerToSeat
364
- ),
365
- kind: descriptor.kind,
366
- surface: descriptor.zoneId ?? descriptor.zoneIds?.find((zoneId) => typeof zoneId === "string") ?? null,
367
- commitMode: descriptor.commit.mode === "autoWhenReady" ? "autoWhenReady" : "manual",
368
- status: descriptor.availability.status ?? null,
369
- available: descriptor.availability.status === "available",
370
- inputs,
371
- defaults: canonicalizeSemanticProjectionValue(defaults, playerToSeat),
372
- defaultProvenance
373
- };
374
- }
375
- function semanticInteractionInput(input, playerToSeat) {
376
- const domain = asRecord(input.domain);
377
- const selection = asRecord(domain.selection);
378
- return {
379
- key: input.key,
380
- kind: input.kind,
381
- domain: canonicalizeSemanticProjectionValue(input.domain, playerToSeat),
382
- defaultValue: input.defaultValue === void 0 ? null : canonicalizeSemanticProjectionValue(input.defaultValue, playerToSeat),
383
- defaultProvenance: input.defaultValue === void 0 ? null : "input",
384
- selectionMode: stringField(selection, "mode"),
385
- min: numberField(domain),
386
- max: numberField(domain, "max")
387
- };
388
- }
389
- function collectDefaults(inputs) {
390
- const defaults = {};
391
- const defaultProvenance = {};
392
- for (const input of inputs) {
393
- if (input.defaultValue !== void 0) {
394
- defaults[input.key] = toCanonicalJson(input.defaultValue);
395
- defaultProvenance[input.key] = "input";
396
- }
397
- }
398
- return { defaults, defaultProvenance };
399
- }
400
- function canonicalizeSemanticProjectionValue(value, playerToSeat) {
401
- if (value === null || typeof value === "boolean" || typeof value === "number") {
402
- return toCanonicalJson(value);
403
- }
404
- if (typeof value === "string") {
405
- return canonicalizeSeatReference(value, playerToSeat);
406
- }
407
- if (Array.isArray(value)) {
408
- return value.map(
409
- (item) => canonicalizeSemanticProjectionValue(item, playerToSeat)
410
- );
411
- }
412
- if (isRecord(value)) {
413
- return Object.fromEntries(
414
- Object.entries(value).filter(
415
- ([key, item]) => item !== void 0 && !SEMANTIC_PROJECTION_TRANSPORT_FIELDS.has(key)
416
- ).map(([key, item]) => [
417
- canonicalizeObjectKey(key, playerToSeat),
418
- canonicalizeSemanticProjectionProperty(key, item, playerToSeat)
419
- ])
420
- );
421
- }
422
- return null;
423
- }
424
- function canonicalizeSemanticProjectionProperty(key, value, playerToSeat) {
425
- const canonicalValue = canonicalizeSemanticProjectionValue(
426
- value,
427
- playerToSeat
428
- );
429
- if ((key === "eligibleTargets" || key === "dependentCases") && Array.isArray(canonicalValue)) {
430
- return [...canonicalValue].sort(
431
- (left, right) => compareJson(canonicalJson(left), canonicalJson(right))
432
- );
433
- }
434
- return canonicalValue;
435
- }
436
- function canonicalizeSeatReference(value, playerToSeat) {
437
- const seat = playerToSeat.get(value);
438
- return seat === void 0 ? value : { $seat: seat };
439
- }
440
- function canonicalizeObjectKey(key, playerToSeat) {
441
- const seat = playerToSeat.get(key);
442
- return seat === void 0 ? key : `$seat:${seat}`;
443
- }
444
- var SEMANTIC_PROJECTION_TRANSPORT_FIELDS = /* @__PURE__ */ new Set([
445
- "availableInteractionRefs",
446
- "board",
447
- "cursor",
448
- "etag",
449
- "hydratedAt",
450
- "hydrationCursor",
451
- "hydrationSequence",
452
- "interactionRef",
453
- "interactionRefs",
454
- "lastEventId",
455
- "receivedAt",
456
- "sequence",
457
- "serverTime",
458
- "snapshotVersion",
459
- "transportSequence",
460
- "transportVersion",
461
- "updatedAt"
462
- ]);
463
- function toCanonicalJson(value) {
464
- if (value === null || typeof value === "boolean" || typeof value === "string") {
465
- return value;
466
- }
467
- if (typeof value === "number") {
468
- return value;
469
- }
470
- if (Array.isArray(value)) {
471
- return value.map((item) => toCanonicalJson(item));
472
- }
473
- if (isRecord(value)) {
474
- return Object.fromEntries(
475
- Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => [key, toCanonicalJson(item)])
476
- );
477
- }
478
- return null;
479
- }
480
- function hashJson(value) {
481
- return `sha256:${sha256Hex(canonicalJson(value))}`;
482
- }
483
- function canonicalJson(value) {
484
- return JSON.stringify(canonicalizeJson(value));
485
- }
486
- function canonicalizeJson(value) {
487
- if (value === null || typeof value === "boolean" || typeof value === "string") {
488
- return value;
489
- }
490
- if (typeof value === "number") {
491
- if (!Number.isFinite(value)) {
492
- throw new Error("canonical JSON contains a non-finite number");
493
- }
494
- return value;
495
- }
496
- if (Array.isArray(value)) {
497
- return value.map((item) => canonicalizeJson(item));
498
- }
499
- return Object.fromEntries(
500
- Object.entries(value).sort(([left], [right]) => compareJson(left, right)).map(([key, item]) => [key, canonicalizeJson(item)])
501
- );
502
- }
503
- function compareJson(left, right) {
504
- return left < right ? -1 : left > right ? 1 : 0;
505
- }
506
- function isRecord(value) {
507
- return !!value && typeof value === "object" && !Array.isArray(value);
508
- }
509
- function asRecord(value) {
510
- return isRecord(value) ? value : {};
511
- }
512
- function stringField(record, key) {
513
- const value = record[key];
514
- return typeof value === "string" && value.trim() ? value : null;
515
- }
516
- function numberField(record, key = "min") {
517
- const value = record[key];
518
- return typeof value === "number" && Number.isFinite(value) ? value : null;
519
- }
520
- var SHA256_K = [
521
- 1116352408,
522
- 1899447441,
523
- 3049323471,
524
- 3921009573,
525
- 961987163,
526
- 1508970993,
527
- 2453635748,
528
- 2870763221,
529
- 3624381080,
530
- 310598401,
531
- 607225278,
532
- 1426881987,
533
- 1925078388,
534
- 2162078206,
535
- 2614888103,
536
- 3248222580,
537
- 3835390401,
538
- 4022224774,
539
- 264347078,
540
- 604807628,
541
- 770255983,
542
- 1249150122,
543
- 1555081692,
544
- 1996064986,
545
- 2554220882,
546
- 2821834349,
547
- 2952996808,
548
- 3210313671,
549
- 3336571891,
550
- 3584528711,
551
- 113926993,
552
- 338241895,
553
- 666307205,
554
- 773529912,
555
- 1294757372,
556
- 1396182291,
557
- 1695183700,
558
- 1986661051,
559
- 2177026350,
560
- 2456956037,
561
- 2730485921,
562
- 2820302411,
563
- 3259730800,
564
- 3345764771,
565
- 3516065817,
566
- 3600352804,
567
- 4094571909,
568
- 275423344,
569
- 430227734,
570
- 506948616,
571
- 659060556,
572
- 883997877,
573
- 958139571,
574
- 1322822218,
575
- 1537002063,
576
- 1747873779,
577
- 1955562222,
578
- 2024104815,
579
- 2227730452,
580
- 2361852424,
581
- 2428436474,
582
- 2756734187,
583
- 3204031479,
584
- 3329325298
585
- ];
586
- function sha256Hex(input) {
587
- const bytes = utf8Bytes(input);
588
- const bitLength = bytes.length * 8;
589
- bytes.push(128);
590
- while (bytes.length % 64 !== 56) {
591
- bytes.push(0);
592
- }
593
- for (let shift = 56; shift >= 0; shift -= 8) {
594
- bytes.push(Math.floor(bitLength / 2 ** shift) & 255);
595
- }
596
- let h0 = 1779033703;
597
- let h1 = 3144134277;
598
- let h2 = 1013904242;
599
- let h3 = 2773480762;
600
- let h4 = 1359893119;
601
- let h5 = 2600822924;
602
- let h6 = 528734635;
603
- let h7 = 1541459225;
604
- const words = new Array(64);
605
- for (let offset = 0; offset < bytes.length; offset += 64) {
606
- for (let index = 0; index < 16; index += 1) {
607
- const base = offset + index * 4;
608
- words[index] = (bytes[base] << 24 | bytes[base + 1] << 16 | bytes[base + 2] << 8 | bytes[base + 3]) >>> 0;
609
- }
610
- for (let index = 16; index < 64; index += 1) {
611
- const s0 = rotateRight(words[index - 15], 7) ^ rotateRight(words[index - 15], 18) ^ words[index - 15] >>> 3;
612
- const s1 = rotateRight(words[index - 2], 17) ^ rotateRight(words[index - 2], 19) ^ words[index - 2] >>> 10;
613
- words[index] = words[index - 16] + s0 + words[index - 7] + s1 >>> 0;
614
- }
615
- let a = h0;
616
- let b = h1;
617
- let c = h2;
618
- let d = h3;
619
- let e = h4;
620
- let f = h5;
621
- let g = h6;
622
- let h = h7;
623
- for (let index = 0; index < 64; index += 1) {
624
- const s1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
625
- const ch2 = e & f ^ ~e & g;
626
- const temp1 = h + s1 + ch2 + SHA256_K[index] + words[index] >>> 0;
627
- const s0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
628
- const maj2 = a & b ^ a & c ^ b & c;
629
- const temp2 = s0 + maj2 >>> 0;
630
- h = g;
631
- g = f;
632
- f = e;
633
- e = d + temp1 >>> 0;
634
- d = c;
635
- c = b;
636
- b = a;
637
- a = temp1 + temp2 >>> 0;
638
- }
639
- h0 = h0 + a >>> 0;
640
- h1 = h1 + b >>> 0;
641
- h2 = h2 + c >>> 0;
642
- h3 = h3 + d >>> 0;
643
- h4 = h4 + e >>> 0;
644
- h5 = h5 + f >>> 0;
645
- h6 = h6 + g >>> 0;
646
- h7 = h7 + h >>> 0;
647
- }
648
- return [h0, h1, h2, h3, h4, h5, h6, h7].map((value) => value.toString(16).padStart(8, "0")).join("");
649
- }
650
- function rotateRight(value, bits) {
651
- return value >>> bits | value << 32 - bits;
652
- }
653
- function utf8Bytes(input) {
654
- return Array.from(new TextEncoder().encode(input));
655
- }
27
+ defaultRuntimeSnapshotEquality,
28
+ useArmedInteraction,
29
+ useAuthoredPluginGameplayFrameSelector,
30
+ useInteractionDraft,
31
+ useInteractionSubmitting,
32
+ useInteractionUiStore,
33
+ usePendingInteractionKey,
34
+ usePendingInteractionRevision,
35
+ usePluginGameplayFrameSelector,
36
+ usePluginSession,
37
+ usePluginSessionDescriptor,
38
+ useRuntimeContext
39
+ } from "./chunk-O6M6PN4E.js";
40
+ import {
41
+ createGameplayActuatorAttributes,
42
+ createGameplayInteractionRootAttributes,
43
+ createGameplayPointerTargetAttributes,
44
+ gameplayAdjustResourceEffect,
45
+ gameplayCommitEffect,
46
+ gameplayInvokeEffect,
47
+ gameplaySetCandidateEffect,
48
+ gameplaySetScalarEffect
49
+ } from "./chunk-WUIVY2KE.js";
656
50
 
657
- // src/runtime/context/PluginStateContext.tsx
658
- import { Fragment as Fragment2, jsx as jsx4, jsxs } from "react/jsx-runtime";
659
- var PluginStateContext = createContext4(null);
660
- var GAMEPLAY_BROWSER_SCOPE_ID = "runtime";
661
- var BROWSER_PROJECTION_DIGEST_ATTRIBUTE = "data-dreamboard-projection-digest";
662
- function RuntimeSemanticProjectionMarker() {
663
- const state = usePluginState((snapshot) => snapshot);
664
- return /* @__PURE__ */ jsx4(SemanticProjectionMarker, { state });
665
- }
666
- function SemanticProjectionMarker({
667
- state
51
+ // src/runtime/primitives/ui.tsx
52
+ import { Fragment, jsx } from "react/jsx-runtime";
53
+ function UIRoot({
54
+ theme,
55
+ themeOverride,
56
+ reducedMotion,
57
+ className,
58
+ style,
59
+ children
668
60
  }) {
669
- const digest = semanticProjectionDigestForState(state);
670
- if (!digest) {
671
- return null;
61
+ if (theme === void 0 && themeOverride === void 0) {
62
+ return /* @__PURE__ */ jsx(Fragment, { children });
672
63
  }
673
- return /* @__PURE__ */ jsx4(
674
- "span",
64
+ return /* @__PURE__ */ jsx(
65
+ ThemeProvider,
675
66
  {
676
- "aria-hidden": "true",
677
- style: { display: "none" },
678
- ...{
679
- [BROWSER_INTERACTION_ATTRIBUTES.protocol]: DREAMBOARD_BROWSER_INTERACTION_PROTOCOL_VERSION,
680
- [BROWSER_INTERACTION_ATTRIBUTES.surface]: GAMEPLAY_BROWSER_INTERACTION_SURFACE,
681
- [BROWSER_INTERACTION_ATTRIBUTES.scope]: GAMEPLAY_BROWSER_SCOPE_ID,
682
- [BROWSER_INTERACTION_ATTRIBUTES.role]: "projection",
683
- [BROWSER_PROJECTION_DIGEST_ATTRIBUTE]: digest
684
- }
67
+ theme,
68
+ override: themeOverride,
69
+ reducedMotion,
70
+ className,
71
+ style,
72
+ children
685
73
  }
686
74
  );
687
75
  }
688
- function usePluginState(selector) {
689
- const runtime = useRuntimeContext();
690
- const subscribe = (onStoreChange) => {
691
- if (!runtime.subscribeToState) {
692
- return () => {
693
- };
694
- }
695
- return runtime.subscribeToState(() => {
696
- onStoreChange();
697
- });
698
- };
699
- const getSnapshot = () => {
700
- const state2 = runtime.getSnapshot?.();
701
- if (!state2) {
702
- throw new Error(
703
- "usePluginState: No state available. Make sure you have wrapped your app with <PluginStateProvider>."
704
- );
705
- }
706
- return state2;
707
- };
708
- const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
709
- return useMemo2(() => selector(state), [selector, state]);
710
- }
711
- function usePluginActions() {
712
- const runtime = useRuntimeContext();
713
- return {
714
- /**
715
- * Mark a notification as read.
716
- * Sends message to host which updates the notification in GameSessionStore.
717
- */
718
- markNotificationRead: (notificationId) => {
719
- window.parent.postMessage(
720
- { type: "mark-notification-read", notificationId },
721
- "*"
722
- );
723
- },
724
- /**
725
- * Switch to a different player (for users controlling multiple seats).
726
- */
727
- switchPlayer: (playerId) => {
728
- runtime.switchPlayer?.(playerId);
729
- },
730
- /**
731
- * Submit a player interaction (action or prompt response).
732
- */
733
- submitInteraction: runtime.submitInteraction
734
- };
735
- }
76
+ var UI = {
77
+ Root: UIRoot
78
+ };
79
+
80
+ // src/runtime/primitives/hand-intent-adapter.ts
81
+ import { useCallback } from "react";
736
82
 
737
83
  // src/runtime/utils/interaction-inputs.ts
738
84
  function interactionInputKeys(descriptor) {
@@ -1427,9 +773,9 @@ function projectDraftCardState(availableInteractions, drafts, validate) {
1427
773
  }
1428
774
  return entries;
1429
775
  }
1430
- function selectedCardIdsForZone(store, zone, state) {
776
+ function selectedCardIdsForZone(store, zone, availableInteractions) {
1431
777
  const result = /* @__PURE__ */ new Set();
1432
- for (const descriptor of state.gameplay.availableInteractions) {
778
+ for (const descriptor of availableInteractions) {
1433
779
  const cardInput = descriptor.inputs.find((input) => {
1434
780
  if (!isTargetDomain(input.domain)) return false;
1435
781
  if (input.domain.type !== "cardTarget") return false;
@@ -1470,11 +816,11 @@ function useCardIntentAdapter({
1470
816
  const store = useInteractionUiStore();
1471
817
  const { controllingPlayerId } = usePluginSession();
1472
818
  const runtime = useRuntimeContext();
1473
- const zoneSnapshot = usePluginState(
1474
- (state) => state.gameplay.zones[zone] ?? null
819
+ const zoneSnapshot = useAuthoredPluginGameplayFrameSelector(
820
+ (frame) => frame.zones[zone] ?? null
1475
821
  );
1476
- const availableInteractions = usePluginState(
1477
- (state) => state.gameplay.availableInteractions
822
+ const availableInteractions = useAuthoredPluginGameplayFrameSelector(
823
+ (frame) => frame.availableInteractions
1478
824
  );
1479
825
  return useCallback(
1480
826
  async (intent) => {
@@ -1502,7 +848,6 @@ function useCardIntentAdapter({
1502
848
  zoneSnapshot,
1503
849
  submit: async (descriptor, params) => {
1504
850
  await runtime.submitInteraction(
1505
- controllingPlayerId,
1506
851
  descriptor.interactionId,
1507
852
  params
1508
853
  );
@@ -1529,82 +874,38 @@ function useCardIntentAdapter({
1529
874
  }
1530
875
 
1531
876
  // src/runtime/primitives/game.tsx
1532
- import { createContext as createContext5, useContext as useContext5, useMemo as useMemo5 } from "react";
1533
- import { useStore as useStore2 } from "zustand";
877
+ import {
878
+ createContext,
879
+ useContext,
880
+ useMemo as useMemo3
881
+ } from "react";
882
+ import { useStore } from "zustand";
1534
883
 
1535
884
  // src/runtime/hooks/useActivePlayers.ts
1536
885
  function useActivePlayers() {
1537
- return usePluginState((state) => {
1538
- const simultaneous = state.gameplay.simultaneousPhase;
886
+ return usePluginGameplayFrameSelector((frame) => {
887
+ const simultaneous = frame.flow.simultaneousPhase;
1539
888
  if (simultaneous && simultaneous.pendingPlayerIds.length > 0) {
1540
889
  return simultaneous.pendingPlayerIds;
1541
890
  }
1542
- return state.gameplay.activePlayers;
891
+ return frame.flow.activePlayers;
1543
892
  });
1544
893
  }
1545
894
 
1546
895
  // src/runtime/hooks/useGameSelector.ts
1547
- import { useRef, useSyncExternalStore as useSyncExternalStore2 } from "react";
1548
- function defaultEquality(left, right) {
1549
- return Object.is(left, right);
1550
- }
1551
- function requireProjectedView(snapshot, message) {
1552
- const view = snapshot?.view;
896
+ function requireProjectedView(frame, message) {
897
+ const view = frame?.view;
1553
898
  if (view === null || typeof view === "undefined") {
1554
899
  throw new Error(message);
1555
900
  }
1556
901
  return view;
1557
902
  }
1558
- function useGameSelector(selector, equalityFn = defaultEquality) {
1559
- const runtime = useRuntimeContext();
1560
- const selectorRef = useRef(selector);
1561
- const equalityRef = useRef(equalityFn);
1562
- const cacheRef = useRef(null);
1563
- if (selectorRef.current !== selector || equalityRef.current !== equalityFn) {
1564
- selectorRef.current = selector;
1565
- equalityRef.current = equalityFn;
1566
- cacheRef.current = null;
1567
- }
903
+ function useGameSelector(selector, equalityFn = defaultRuntimeSnapshotEquality) {
1568
904
  const message = "useGameSelector: Projected view not available. Ensure the reducer-native host payload is initialized.";
1569
- const getSelectedFromSnapshot = (snapshot) => {
1570
- const view = requireProjectedView(snapshot, message);
1571
- const cached = cacheRef.current;
1572
- if (cached && cached.rawView === view) {
1573
- return cached.selected;
1574
- }
1575
- const nextSelected = selectorRef.current(view);
1576
- if (cached && equalityRef.current(cached.selected, nextSelected)) {
1577
- cacheRef.current = {
1578
- rawView: view,
1579
- selected: cached.selected
1580
- };
1581
- return cached.selected;
1582
- }
1583
- cacheRef.current = {
1584
- rawView: view,
1585
- selected: nextSelected
1586
- };
1587
- return nextSelected;
1588
- };
1589
- const subscribe = (onStoreChange) => {
1590
- if (!runtime.subscribeToState) {
1591
- return () => {
1592
- };
1593
- }
1594
- return runtime.subscribeToState((snapshot) => {
1595
- const previousCache = cacheRef.current;
1596
- const nextSelected = getSelectedFromSnapshot(
1597
- snapshot
1598
- );
1599
- if (!previousCache || !equalityRef.current(previousCache.selected, nextSelected)) {
1600
- onStoreChange();
1601
- }
1602
- });
1603
- };
1604
- const getSnapshot = () => getSelectedFromSnapshot(
1605
- runtime.getSnapshot?.() ?? null
905
+ return usePluginGameplayFrameSelector(
906
+ (frame) => selector(requireProjectedView(frame, message)),
907
+ equalityFn
1606
908
  );
1607
- return useSyncExternalStore2(subscribe, getSnapshot, getSnapshot);
1608
909
  }
1609
910
 
1610
911
  // src/runtime/hooks/useGameView.ts
@@ -1613,76 +914,34 @@ function useGameView() {
1613
914
  }
1614
915
 
1615
916
  // src/runtime/hooks/usePlayerInfo.ts
1616
- import { useMemo as useMemo3 } from "react";
1617
-
1618
- // src/runtime/hooks/useLobby.ts
1619
- import { useState as useState3, useEffect as useEffect3 } from "react";
1620
- function useLobbyState() {
1621
- const runtime = useRuntimeContext();
1622
- const getStateFromSnapshot = () => {
1623
- if (!runtime.getSnapshot) return null;
1624
- const snapshot = runtime.getSnapshot();
1625
- if (!snapshot?.lobby) return null;
1626
- return snapshot.lobby;
1627
- };
1628
- const [lobbyState, setLobbyState] = useState3(
1629
- getStateFromSnapshot
1630
- );
1631
- useEffect3(() => {
1632
- if (!runtime.subscribeToState) {
1633
- return;
1634
- }
1635
- const initialState = runtime.getSnapshot?.();
1636
- if (initialState?.lobby) {
1637
- setLobbyState(initialState.lobby);
1638
- }
1639
- return runtime.subscribeToState((snapshot) => {
1640
- if (snapshot.lobby) {
1641
- setLobbyState(snapshot.lobby);
1642
- }
1643
- });
1644
- }, [runtime]);
1645
- return lobbyState;
1646
- }
1647
- function useLobby() {
1648
- const lobbyState = useLobbyState();
1649
- if (lobbyState === null) {
1650
- throw new Error(
1651
- "useLobby: Lobby state not available. The host should only render the plugin when lobby state is ready."
1652
- );
1653
- }
1654
- return lobbyState;
1655
- }
1656
-
1657
- // src/runtime/hooks/usePlayerInfo.ts
917
+ import { useMemo } from "react";
1658
918
  function usePlayerInfo() {
1659
- const lobby = useLobbyState();
1660
- return useMemo3(() => {
1661
- if (!lobby) {
1662
- return /* @__PURE__ */ new Map();
1663
- }
919
+ const sessionDescriptor = usePluginSessionDescriptor();
920
+ return useMemo(() => {
1664
921
  const playerMap = /* @__PURE__ */ new Map();
1665
- for (const seat of lobby.seats) {
1666
- const playerId = seat.playerId;
922
+ for (const player of sessionDescriptor.players) {
923
+ const playerId = player.playerId;
1667
924
  playerMap.set(playerId, {
1668
925
  playerId,
1669
- name: seat.displayName,
1670
- isHost: seat.isHost,
1671
- color: seat.playerColor
926
+ name: player.displayName,
927
+ isHost: false,
928
+ color: player.color
1672
929
  });
1673
930
  }
1674
931
  return playerMap;
1675
- }, [lobby]);
932
+ }, [sessionDescriptor]);
1676
933
  }
1677
934
 
1678
935
  // src/runtime/hooks/usePlayerTurnOrder.ts
1679
- import { useMemo as useMemo4 } from "react";
936
+ import { useMemo as useMemo2 } from "react";
1680
937
  function usePlayerTurnOrder() {
1681
- const lobby = useLobby();
1682
- return useMemo4(() => {
1683
- if (!lobby) return [];
1684
- return lobby.seats.map((seat) => seat.playerId);
1685
- }, [lobby]);
938
+ const sessionDescriptor = usePluginSessionDescriptor();
939
+ return useMemo2(
940
+ () => sessionDescriptor.players.map(
941
+ (player) => player.playerId
942
+ ),
943
+ [sessionDescriptor]
944
+ );
1686
945
  }
1687
946
 
1688
947
  // src/runtime/utils/interaction-labels.ts
@@ -1699,12 +958,12 @@ function interactionLabel(descriptor) {
1699
958
  }
1700
959
 
1701
960
  // src/runtime/primitives/game.tsx
1702
- import { Fragment as Fragment3, jsx as jsx5 } from "react/jsx-runtime";
1703
- var GameActionErrorContext = createContext5(
961
+ import { Fragment as Fragment2, jsx as jsx2 } from "react/jsx-runtime";
962
+ var GameActionErrorContext = createContext(
1704
963
  null
1705
964
  );
1706
965
  function useGameActionError() {
1707
- return useContext5(GameActionErrorContext);
966
+ return useContext(GameActionErrorContext);
1708
967
  }
1709
968
  function fallbackPlayer(playerId) {
1710
969
  return {
@@ -1722,11 +981,13 @@ function useGameRenderState() {
1722
981
  const turnOrder = usePlayerTurnOrder().map(
1723
982
  (playerId) => playerId
1724
983
  );
1725
- const phase = usePluginState(
1726
- (state) => state.gameplay.currentPhase
984
+ const phase = useAuthoredPluginGameplayFrameSelector(
985
+ (frame) => frame.flow.currentPhase
986
+ );
987
+ const stage = useAuthoredPluginGameplayFrameSelector(
988
+ (frame) => frame.flow.currentStage
1727
989
  );
1728
- const stage = usePluginState((state) => state.gameplay.currentStage);
1729
- const playersById = useMemo5(() => {
990
+ const playersById = useMemo3(() => {
1730
991
  const next = /* @__PURE__ */ new Map();
1731
992
  playerInfo.forEach((player, key) => {
1732
993
  const playerId = key;
@@ -1738,30 +999,20 @@ function useGameRenderState() {
1738
999
  return next;
1739
1000
  }, [playerInfo]);
1740
1001
  const controllingPlayerId = session.controllingPlayerId == null ? null : session.controllingPlayerId;
1741
- const controllablePlayerIds = session.controllablePlayerIds.map(
1742
- (playerId) => playerId
1743
- );
1744
1002
  const currentPlayerId = activePlayers[0] ?? turnOrder[0] ?? null;
1745
1003
  const currentPlayer = currentPlayerId ? playersById.get(currentPlayerId) ?? fallbackPlayer(currentPlayerId) : null;
1746
1004
  const mePlayer = controllingPlayerId ? playersById.get(controllingPlayerId) ?? fallbackPlayer(controllingPlayerId) : null;
1747
- const entries = useMemo5(
1005
+ const entries = useMemo3(
1748
1006
  () => turnOrder.map((playerId, index) => {
1749
1007
  const player = playersById.get(playerId) ?? fallbackPlayer(playerId);
1750
1008
  return {
1751
1009
  ...player,
1752
1010
  index,
1753
1011
  isActive: activePlayers.includes(playerId),
1754
- isCurrentPlayer: playerId === controllingPlayerId,
1755
- isControllable: controllablePlayerIds.includes(playerId)
1012
+ isCurrentPlayer: playerId === controllingPlayerId
1756
1013
  };
1757
1014
  }),
1758
- [
1759
- activePlayers,
1760
- controllablePlayerIds,
1761
- controllingPlayerId,
1762
- playersById,
1763
- turnOrder
1764
- ]
1015
+ [activePlayers, controllingPlayerId, playersById, turnOrder]
1765
1016
  );
1766
1017
  return {
1767
1018
  view,
@@ -1771,7 +1022,6 @@ function useGameRenderState() {
1771
1022
  me: {
1772
1023
  playerId: controllingPlayerId,
1773
1024
  player: mePlayer,
1774
- controllablePlayerIds,
1775
1025
  canAct: controllingPlayerId != null && activePlayers.includes(controllingPlayerId)
1776
1026
  },
1777
1027
  turn: {
@@ -1796,9 +1046,9 @@ function GameRoot({
1796
1046
  onActionError
1797
1047
  }) {
1798
1048
  const state = useGameRenderState();
1799
- const rendered = /* @__PURE__ */ jsx5(Fragment3, { children: children(state) });
1049
+ const rendered = /* @__PURE__ */ jsx2(Fragment2, { children: children(state) });
1800
1050
  if (!onActionError) return rendered;
1801
- return /* @__PURE__ */ jsx5(GameActionErrorContext.Provider, { value: onActionError, children: rendered });
1051
+ return /* @__PURE__ */ jsx2(GameActionErrorContext.Provider, { value: onActionError, children: rendered });
1802
1052
  }
1803
1053
  function GameChrome({
1804
1054
  children
@@ -1806,16 +1056,15 @@ function GameChrome({
1806
1056
  const renderState = useGameRenderState();
1807
1057
  const store = useInteractionUiStore();
1808
1058
  const pendingInteractionKey = usePendingInteractionKey();
1809
- const draftSnapshot = useStore2(store, (state) => state.drafts);
1810
- const armSnapshot = useStore2(store, (state) => state.arms);
1811
- const descriptor = usePluginState(
1812
- (state) => pendingInteractionKey ? state.gameplay.availableInteractions.find(
1059
+ const draftSnapshot = useStore(store, (state) => state.drafts);
1060
+ const descriptor = useAuthoredPluginGameplayFrameSelector(
1061
+ (frame) => pendingInteractionKey ? frame.availableInteractions.find(
1813
1062
  (candidate) => candidate.interactionKey === pendingInteractionKey
1814
1063
  ) : void 0
1815
1064
  );
1816
- const activeAction = useMemo5(() => {
1065
+ const activeAction = useMemo3(() => {
1817
1066
  if (!descriptor) return null;
1818
- const draft = store.getDraft(descriptor.interactionKey);
1067
+ const draft = draftSnapshot[descriptor.interactionKey] ?? store.getDraft(descriptor.interactionKey);
1819
1068
  const readiness = getInteractionDraftReadiness(descriptor, draft);
1820
1069
  const pendingInputKey = readiness.readyFrontier[0] ?? readiness.missingInputs[0] ?? null;
1821
1070
  const pendingInput = pendingInputKey ? descriptor.inputs.find((input) => input.key === pendingInputKey) : void 0;
@@ -1830,20 +1079,31 @@ function GameChrome({
1830
1079
  readyFrontier: readiness.readyFrontier,
1831
1080
  pendingInput: pendingInput ? pendingInputState(pendingInput) : null
1832
1081
  };
1833
- }, [descriptor, draftSnapshot, armSnapshot, store]);
1834
- const cancel = useMemo5(
1082
+ }, [descriptor, draftSnapshot, store]);
1083
+ const cancel = useMemo3(
1835
1084
  () => descriptor ? () => {
1836
1085
  clearInteractionRoute(store, descriptor);
1837
1086
  } : null,
1838
1087
  [descriptor, store]
1839
1088
  );
1840
- return /* @__PURE__ */ jsx5(Fragment3, { children: children({
1089
+ return /* @__PURE__ */ jsx2(Fragment2, { children: children({
1841
1090
  ...renderState,
1842
1091
  activePlayers: renderState.turn.activePlayerIds,
1843
1092
  activeAction,
1844
1093
  cancel
1845
1094
  }) });
1846
1095
  }
1096
+ function GameViewport({ children, style, ...props }) {
1097
+ const { bottom } = useOverlayInsets();
1098
+ const viewportStyle = {
1099
+ "--dreamboard-bottom-overlay-inset": `${bottom}px`,
1100
+ "--dreamboard-safe-area-bottom": "env(safe-area-inset-bottom, 0px)",
1101
+ minHeight: "100dvh",
1102
+ paddingBottom: "calc(var(--dreamboard-bottom-overlay-inset) + var(--dreamboard-safe-area-bottom))",
1103
+ ...style
1104
+ };
1105
+ return /* @__PURE__ */ jsx2("div", { "data-dreamboard-game-viewport": "", ...props, style: viewportStyle, children });
1106
+ }
1847
1107
  function pendingInputState(input) {
1848
1108
  return {
1849
1109
  key: input.key,
@@ -1873,14 +1133,15 @@ function humanizeInputKey(key) {
1873
1133
  }
1874
1134
  var Game = {
1875
1135
  Root: GameRoot,
1876
- Chrome: GameChrome
1136
+ Chrome: GameChrome,
1137
+ Viewport: GameViewport
1877
1138
  };
1878
1139
 
1879
1140
  // src/runtime/primitives/zone.tsx
1880
1141
  import {
1881
- createContext as createContext6,
1882
- useContext as useContext6,
1883
- useMemo as useMemo6
1142
+ createContext as createContext2,
1143
+ useContext as useContext2,
1144
+ useMemo as useMemo4
1884
1145
  } from "react";
1885
1146
 
1886
1147
  // src/runtime/primitives/interaction-submit.ts
@@ -1934,25 +1195,25 @@ function submitInteractionParams(handle, params, callbacks = {}, options = {}) {
1934
1195
  }
1935
1196
 
1936
1197
  // src/runtime/primitives/zone.tsx
1937
- import { Fragment as Fragment4, jsx as jsx6 } from "react/jsx-runtime";
1938
- var ZoneContext = createContext6(null);
1939
- var ZoneCardContext = createContext6(null);
1940
- var ZonePileContext = createContext6(null);
1198
+ import { Fragment as Fragment3, jsx as jsx3 } from "react/jsx-runtime";
1199
+ var ZoneContext = createContext2(null);
1200
+ var ZoneCardContext = createContext2(null);
1201
+ var ZonePileContext = createContext2(null);
1941
1202
  function useZonePrimitiveContext() {
1942
- const value = useContext6(ZoneContext);
1203
+ const value = useContext2(ZoneContext);
1943
1204
  if (!value) {
1944
1205
  throw new Error("Zone primitives must be rendered inside <Zone.Root>.");
1945
1206
  }
1946
1207
  return value;
1947
1208
  }
1948
1209
  function useOptionalZonePrimitiveContext() {
1949
- return useContext6(ZoneContext);
1210
+ return useContext2(ZoneContext);
1950
1211
  }
1951
1212
  function useZoneCardContext() {
1952
- return useContext6(ZoneCardContext);
1213
+ return useContext2(ZoneCardContext);
1953
1214
  }
1954
1215
  function useZonePileContext() {
1955
- const value = useContext6(ZonePileContext);
1216
+ const value = useContext2(ZonePileContext);
1956
1217
  if (!value) {
1957
1218
  throw new Error(
1958
1219
  "Zone pile primitives must be rendered inside <Zone.PileRoot>."
@@ -1965,12 +1226,12 @@ function ZoneRoot({
1965
1226
  children,
1966
1227
  ...props
1967
1228
  }) {
1968
- const snapshot = usePluginState((state) => state.gameplay.zones[zone]) ?? null;
1969
- const value = useMemo6(
1229
+ const snapshot = useAuthoredPluginGameplayFrameSelector((frame) => frame.zones[zone]) ?? null;
1230
+ const value = useMemo4(
1970
1231
  () => ({ zone, snapshot }),
1971
1232
  [snapshot, zone]
1972
1233
  );
1973
- return /* @__PURE__ */ jsx6(ZoneContext.Provider, { value, children: renderPrimitive("div", {
1234
+ return /* @__PURE__ */ jsx3(ZoneContext.Provider, { value, children: renderPrimitive("div", {
1974
1235
  ...props,
1975
1236
  "data-dreamboard-zone-root": "",
1976
1237
  "data-zone": zone,
@@ -1980,7 +1241,7 @@ function ZoneRoot({
1980
1241
  }
1981
1242
  function ZoneList({ children, empty, sort, ...props }) {
1982
1243
  const { zone, items, isEmpty } = useZoneCards({ sort });
1983
- const renderedChildren = typeof children === "function" ? isEmpty ? empty : items.map((item) => /* @__PURE__ */ jsx6(ZoneItem, { card: item, children: children(item) }, item.id)) : isEmpty && empty !== void 0 ? empty : children;
1244
+ const renderedChildren = typeof children === "function" ? isEmpty ? empty : items.map((item) => /* @__PURE__ */ jsx3(ZoneItem, { card: item, children: children(item) }, item.id)) : isEmpty && empty !== void 0 ? empty : children;
1984
1245
  return renderPrimitive("div", {
1985
1246
  ...props,
1986
1247
  role: props.role ?? "list",
@@ -1994,7 +1255,7 @@ function useZoneCards({
1994
1255
  sort
1995
1256
  } = {}) {
1996
1257
  const { zone, snapshot } = useZonePrimitiveContext();
1997
- return useMemo6(() => {
1258
+ return useMemo4(() => {
1998
1259
  const cards = (snapshot?.cardIds ?? []).map(
1999
1260
  (cardId, index) => createZoneCardRenderItem(zone, snapshot, cardId, index)
2000
1261
  );
@@ -2016,11 +1277,11 @@ function ZoneItem({ card, children, ...props }) {
2016
1277
  card,
2017
1278
  indexOfCard(snapshot, card)
2018
1279
  ) : card;
2019
- const cardContext = useMemo6(
1280
+ const cardContext = useMemo4(
2020
1281
  () => ({ zone, cardId: item.id }),
2021
1282
  [item.id, zone]
2022
1283
  );
2023
- return /* @__PURE__ */ jsx6(ZoneCardContext.Provider, { value: cardContext, children: renderPrimitive("div", {
1284
+ return /* @__PURE__ */ jsx3(ZoneCardContext.Provider, { value: cardContext, children: renderPrimitive("div", {
2024
1285
  ...props,
2025
1286
  role: props.role ?? "listitem",
2026
1287
  "data-dreamboard-zone-item": "",
@@ -2041,23 +1302,23 @@ function ZoneCardAtContent({
2041
1302
  }) {
2042
1303
  const { zone, snapshot } = useZonePrimitiveContext();
2043
1304
  const cardIndex = resolveZoneCardIndex(snapshot, index);
2044
- if (cardIndex === null) return /* @__PURE__ */ jsx6(Fragment4, { children: empty });
1305
+ if (cardIndex === null) return /* @__PURE__ */ jsx3(Fragment3, { children: empty });
2045
1306
  const cardId = snapshot?.cardIds[cardIndex];
2046
- if (!cardId) return /* @__PURE__ */ jsx6(Fragment4, { children: empty });
1307
+ if (!cardId) return /* @__PURE__ */ jsx3(Fragment3, { children: empty });
2047
1308
  const card = createZoneCardRenderItem(zone, snapshot, cardId, cardIndex);
2048
- return /* @__PURE__ */ jsx6(ZoneItem, { card, ...props, children: typeof children === "function" ? children(card) : children });
1309
+ return /* @__PURE__ */ jsx3(ZoneItem, { card, ...props, children: typeof children === "function" ? children(card) : children });
2049
1310
  }
2050
1311
  function ZoneCardAt({
2051
1312
  zone,
2052
1313
  ...props
2053
1314
  }) {
2054
1315
  if (zone) {
2055
- return /* @__PURE__ */ jsx6(ZoneRoot, { zone, children: /* @__PURE__ */ jsx6(ZoneCardAtContent, { ...props }) });
1316
+ return /* @__PURE__ */ jsx3(ZoneRoot, { zone, children: /* @__PURE__ */ jsx3(ZoneCardAtContent, { ...props }) });
2056
1317
  }
2057
- return /* @__PURE__ */ jsx6(ZoneCardAtContent, { ...props });
1318
+ return /* @__PURE__ */ jsx3(ZoneCardAtContent, { ...props });
2058
1319
  }
2059
1320
  function ZoneTopCard(props) {
2060
- return /* @__PURE__ */ jsx6(ZoneCardAt, { ...props, index: 0 });
1321
+ return /* @__PURE__ */ jsx3(ZoneCardAt, { ...props, index: 0 });
2061
1322
  }
2062
1323
  function ZoneCardAction({
2063
1324
  card,
@@ -2129,7 +1390,6 @@ function ZoneCardAction({
2129
1390
  }
2130
1391
  try {
2131
1392
  await runtime.submitInteraction(
2132
- controllingPlayerId,
2133
1393
  descriptor.interactionId,
2134
1394
  params
2135
1395
  );
@@ -2160,7 +1420,7 @@ function ZonePileRoot({
2160
1420
  children,
2161
1421
  ...props
2162
1422
  }) {
2163
- return /* @__PURE__ */ jsx6(ZoneRoot, { zone, ...props, children: /* @__PURE__ */ jsx6(
1423
+ return /* @__PURE__ */ jsx3(ZoneRoot, { zone, ...props, children: /* @__PURE__ */ jsx3(
2164
1424
  ZonePileProvider,
2165
1425
  {
2166
1426
  emptyDescription,
@@ -2179,15 +1439,18 @@ function ZonePileProvider({
2179
1439
  children
2180
1440
  }) {
2181
1441
  const { zone, snapshot } = useZonePrimitiveContext();
2182
- const cards = snapshot?.cardIds ?? [];
2183
- const items = cards.map(
2184
- (cardId, index) => createZoneCardRenderItem(zone, snapshot, cardId, index)
1442
+ const cards = useMemo4(() => snapshot?.cardIds ?? [], [snapshot]);
1443
+ const items = useMemo4(
1444
+ () => cards.map(
1445
+ (cardId, index) => createZoneCardRenderItem(zone, snapshot, cardId, index)
1446
+ ),
1447
+ [cards, snapshot, zone]
2185
1448
  );
2186
1449
  const count = cards.length;
2187
1450
  const isHidden = snapshot === null;
2188
1451
  const hasVisibleCards = items.length > 0;
2189
1452
  const description = isHidden ? hiddenDescription : hasVisibleCards ? visibleDescription?.(count) ?? null : emptyDescription;
2190
- const value = useMemo6(
1453
+ const value = useMemo4(
2191
1454
  () => ({
2192
1455
  zone,
2193
1456
  label,
@@ -2200,7 +1463,7 @@ function ZonePileProvider({
2200
1463
  }),
2201
1464
  [cards, count, description, hasVisibleCards, isHidden, items, label, zone]
2202
1465
  );
2203
- return /* @__PURE__ */ jsx6(ZonePileContext.Provider, { value, children });
1466
+ return /* @__PURE__ */ jsx3(ZonePileContext.Provider, { value, children });
2204
1467
  }
2205
1468
  function ZonePileTrigger({ children, ...props }) {
2206
1469
  const pile = useZonePileContext();
@@ -2251,7 +1514,7 @@ function ZonePileDescription({
2251
1514
  function ZonePileCards({ renderCard, ...props }) {
2252
1515
  const pile = useZonePileContext();
2253
1516
  if (!pile.hasVisibleCards) return null;
2254
- return /* @__PURE__ */ jsx6(ZoneList, { ...props, children: pile.items.map((card) => /* @__PURE__ */ jsx6(ZoneItem, { card, children: renderCard(card) }, card.id)) });
1517
+ return /* @__PURE__ */ jsx3(ZoneList, { ...props, children: pile.items.map((card) => /* @__PURE__ */ jsx3(ZoneItem, { card, children: renderCard(card) }, card.id)) });
2255
1518
  }
2256
1519
  function indexOfCard(snapshot, cardId) {
2257
1520
  return snapshot?.cardIds.indexOf(cardId) ?? -1;
@@ -2278,7 +1541,7 @@ function createZoneCardRenderItem(zone, snapshot, cardId, index) {
2278
1541
  };
2279
1542
  }
2280
1543
  function useZoneCardActionRoute(cardId, snapshot, interaction, input) {
2281
- return useMemo6(() => {
1544
+ return useMemo4(() => {
2282
1545
  if (!cardId || !snapshot) {
2283
1546
  return { descriptor: null, inputKey: null, ambiguous: false };
2284
1547
  }
@@ -2368,15 +1631,15 @@ var Zone = {
2368
1631
 
2369
1632
  // src/runtime/primitives/hand-surface.tsx
2370
1633
  import {
2371
- Fragment as Fragment5,
1634
+ Fragment as Fragment4,
2372
1635
  useCallback as useCallback2,
2373
- useEffect as useEffect4,
2374
- useMemo as useMemo7,
2375
- useRef as useRef2
1636
+ useEffect,
1637
+ useMemo as useMemo5,
1638
+ useRef
2376
1639
  } from "react";
2377
- import { useStore as useStore3 } from "zustand";
2378
- import { useShallow as useShallow2 } from "zustand/shallow";
2379
- import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
1640
+ import { useStore as useStore2 } from "zustand";
1641
+ import { useShallow } from "zustand/shallow";
1642
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
2380
1643
  function HandSurfaceView({
2381
1644
  zone,
2382
1645
  cards,
@@ -2396,26 +1659,30 @@ function HandSurfaceView({
2396
1659
  }) {
2397
1660
  const route = useCardIntentAdapter({ zone, onResult: onIntentRouted });
2398
1661
  const interactionStore = useInteractionUiStore();
2399
- const drafts = useStore3(
1662
+ const drafts = useStore2(
2400
1663
  interactionStore,
2401
- useShallow2((state) => state.drafts)
1664
+ useShallow((state) => state.drafts)
2402
1665
  );
2403
- const availableInteractions = usePluginState(
2404
- (state) => state.gameplay.availableInteractions
1666
+ const availableInteractions = useAuthoredPluginGameplayFrameSelector(
1667
+ (frame) => frame.availableInteractions
2405
1668
  );
2406
- const selectedIds = usePluginState(
1669
+ const selectedIds = useAuthoredPluginGameplayFrameSelector(
2407
1670
  useCallback2(
2408
- (state) => selectedCardIdsForZone(interactionStore, zone, state),
1671
+ (frame) => selectedCardIdsForZone(
1672
+ interactionStore,
1673
+ zone,
1674
+ frame.availableInteractions
1675
+ ),
2409
1676
  // drafts is part of the store snapshot — useStore handles re-render.
2410
1677
  // eslint-disable-next-line react-hooks/exhaustive-deps
2411
1678
  [interactionStore, zone, drafts]
2412
1679
  )
2413
1680
  );
2414
- const visibleCards = useMemo7(
1681
+ const visibleCards = useMemo5(
2415
1682
  () => cards.filter((card) => !selectedIds.includes(card.id)),
2416
1683
  [cards, selectedIds]
2417
1684
  );
2418
- const viewCards = useMemo7(
1685
+ const viewCards = useMemo5(
2419
1686
  () => visibleCards.map(
2420
1687
  (card) => card.hidden ? {
2421
1688
  id: card.id,
@@ -2426,18 +1693,20 @@ function HandSurfaceView({
2426
1693
  ),
2427
1694
  [visibleCards]
2428
1695
  );
2429
- const cardByViewId = useMemo7(() => {
1696
+ const cardByViewId = useMemo5(() => {
2430
1697
  const index = /* @__PURE__ */ new Map();
2431
1698
  for (const card of visibleCards) {
2432
1699
  index.set(card.id, card);
2433
1700
  }
2434
1701
  return index;
2435
1702
  }, [visibleCards]);
2436
- const cardDescriptorIndex = usePluginState((state) => {
2437
- const snapshot = state.gameplay.zones[zone];
2438
- return snapshot?.playableByCardId ?? {};
2439
- });
2440
- const draftCardProjection = useMemo7(
1703
+ const cardDescriptorIndex = useAuthoredPluginGameplayFrameSelector(
1704
+ (frame) => {
1705
+ const snapshot = frame.zones[zone];
1706
+ return snapshot?.playableByCardId ?? {};
1707
+ }
1708
+ );
1709
+ const draftCardProjection = useMemo5(
2441
1710
  () => projectDraftCardState(
2442
1711
  availableInteractions,
2443
1712
  drafts,
@@ -2445,7 +1714,7 @@ function HandSurfaceView({
2445
1714
  ),
2446
1715
  [availableInteractions, drafts]
2447
1716
  );
2448
- const eligibleCardIds = useMemo7(() => {
1717
+ const eligibleCardIds = useMemo5(() => {
2449
1718
  const set = /* @__PURE__ */ new Set();
2450
1719
  for (const card of visibleCards) {
2451
1720
  const cardId = card.id;
@@ -2483,7 +1752,7 @@ function HandSurfaceView({
2483
1752
  },
2484
1753
  [allVisibleEligible, cardByViewId, draftCardProjection, eligibleCardIds]
2485
1754
  );
2486
- const selectionSummary = useMemo7(() => {
1755
+ const selectionSummary = useMemo5(() => {
2487
1756
  const ids = /* @__PURE__ */ new Set();
2488
1757
  let hasInvalidSelection = false;
2489
1758
  for (const entry of draftCardProjection) {
@@ -2496,14 +1765,14 @@ function HandSurfaceView({
2496
1765
  hasInvalidSelection
2497
1766
  };
2498
1767
  }, [draftCardProjection]);
2499
- const onSelectionSummaryRef = useRef2(onSelectionSummary);
1768
+ const onSelectionSummaryRef = useRef(onSelectionSummary);
2500
1769
  onSelectionSummaryRef.current = onSelectionSummary;
2501
- useEffect4(() => {
1770
+ useEffect(() => {
2502
1771
  onSelectionSummaryRef.current?.(selectionSummary);
2503
1772
  }, [selectionSummary]);
2504
1773
  const summaryContent = renderSummary ? renderSummary(selectionSummary) : null;
2505
1774
  const actionsNode = renderActions ? renderActions(selectionSummary) : null;
2506
- const actionsContent = actionsNode !== null && actionsNode !== void 0 ? /* @__PURE__ */ jsx7(
1775
+ const actionsContent = actionsNode !== null && actionsNode !== void 0 ? /* @__PURE__ */ jsx4(
2507
1776
  "div",
2508
1777
  {
2509
1778
  "data-dreamboard-hand-actions": "",
@@ -2522,7 +1791,21 @@ function HandSurfaceView({
2522
1791
  },
2523
1792
  [route]
2524
1793
  );
2525
- const handView = /* @__PURE__ */ jsx7(
1794
+ const pointerTargetAttributesById = useMemo5(() => {
1795
+ const map = /* @__PURE__ */ new Map();
1796
+ for (const target of dropTargets ?? []) {
1797
+ const attributes = pointerTargetAttributesForRuntimeDropTarget({
1798
+ target,
1799
+ availableInteractions,
1800
+ drafts
1801
+ });
1802
+ if (attributes) {
1803
+ map.set(target.targetId, attributes);
1804
+ }
1805
+ }
1806
+ return map;
1807
+ }, [availableInteractions, drafts, dropTargets]);
1808
+ const handView = /* @__PURE__ */ jsx4(
2526
1809
  HandView,
2527
1810
  {
2528
1811
  cards: viewCards,
@@ -2545,8 +1828,8 @@ function HandSurfaceView({
2545
1828
  if (summaryContent === null && actionsContent === null) {
2546
1829
  return handView;
2547
1830
  }
2548
- return /* @__PURE__ */ jsxs2(Fragment5, { children: [
2549
- summaryContent !== null ? /* @__PURE__ */ jsx7(
1831
+ return /* @__PURE__ */ jsxs(Fragment4, { children: [
1832
+ summaryContent !== null ? /* @__PURE__ */ jsx4(
2550
1833
  "div",
2551
1834
  {
2552
1835
  "data-dreamboard-runtime-hand-summary": "",
@@ -2560,7 +1843,7 @@ function HandSurfaceView({
2560
1843
  actionsContent
2561
1844
  ] });
2562
1845
  }
2563
- const targets = dropTargets.map((target) => /* @__PURE__ */ jsx7(
1846
+ const targets = dropTargets.map((target) => /* @__PURE__ */ jsx4(
2564
1847
  CardDropTargetView,
2565
1848
  {
2566
1849
  targetId: target.targetId,
@@ -2569,12 +1852,15 @@ function HandSurfaceView({
2569
1852
  role: target.role,
2570
1853
  order: target.order,
2571
1854
  className: target.className,
1855
+ browserInteractionAttributes: pointerTargetAttributesById.get(
1856
+ target.targetId
1857
+ ),
2572
1858
  renderTarget: target.render
2573
1859
  },
2574
1860
  target.targetId
2575
1861
  ));
2576
- return /* @__PURE__ */ jsxs2(CardDragSurface, { onCardIntent: handleIntent, children: [
2577
- summaryContent !== null ? /* @__PURE__ */ jsx7(
1862
+ return /* @__PURE__ */ jsxs(CardDragSurface, { onCardIntent: handleIntent, children: [
1863
+ summaryContent !== null ? /* @__PURE__ */ jsx4(
2578
1864
  "div",
2579
1865
  {
2580
1866
  "data-dreamboard-runtime-hand-summary": "",
@@ -2584,7 +1870,7 @@ function HandSurfaceView({
2584
1870
  children: summaryContent
2585
1871
  }
2586
1872
  ) : null,
2587
- renderDropTargets ? renderDropTargets(/* @__PURE__ */ jsx7(Fragment5, { children: targets })) : /* @__PURE__ */ jsx7("div", { "data-dreamboard-runtime-drop-row": "", className: "flex gap-2 mb-2", children: targets }),
1873
+ renderDropTargets ? renderDropTargets(/* @__PURE__ */ jsx4(Fragment4, { children: targets })) : /* @__PURE__ */ jsx4("div", { "data-dreamboard-runtime-drop-row": "", className: "flex gap-2 mb-2", children: targets }),
2588
1874
  handView,
2589
1875
  actionsContent
2590
1876
  ] });
@@ -2603,6 +1889,49 @@ function manyCardSelectionForZone(availableInteractions, zone) {
2603
1889
  }
2604
1890
  return null;
2605
1891
  }
1892
+ function pointerTargetAttributesForRuntimeDropTarget({
1893
+ target,
1894
+ availableInteractions,
1895
+ drafts
1896
+ }) {
1897
+ const decoded = decodeRuntimeDropTargetId(target.targetId);
1898
+ if (!decoded) return void 0;
1899
+ for (const descriptor of availableInteractions) {
1900
+ if (!isInteractionAvailable(descriptor)) continue;
1901
+ const draft = drafts[descriptor.interactionKey] ?? {};
1902
+ const acceptedEffectPatterns = [];
1903
+ for (const rawInput of descriptor.inputs) {
1904
+ const input = resolveInputDomain(rawInput, draft);
1905
+ if (decoded.mode === "input" && input.key !== decoded.inputKey) {
1906
+ continue;
1907
+ }
1908
+ if (decoded.mode === "kind") {
1909
+ if (!isTargetDomain(input.domain) || decoded.kind === "card" && input.domain.type !== "cardTarget" || decoded.kind !== "card" && (input.domain.type !== "boardTarget" || input.domain.targetKind !== decoded.kind)) {
1910
+ continue;
1911
+ }
1912
+ }
1913
+ if (isResolvedTargetDomain(input.domain) && !input.domain.eligibleTargets.includes(decoded.value)) {
1914
+ continue;
1915
+ }
1916
+ acceptedEffectPatterns.push({
1917
+ kind: "match",
1918
+ effectKind: "setCandidate",
1919
+ fields: { inputKey: input.key, candidateValue: decoded.value }
1920
+ });
1921
+ }
1922
+ if (acceptedEffectPatterns.length === 0) continue;
1923
+ return createGameplayPointerTargetAttributes({
1924
+ scopeId: "runtime",
1925
+ interactionKey: descriptor.interactionKey,
1926
+ interactionId: descriptor.interactionId,
1927
+ targetId: target.targetId,
1928
+ enabled: (target.visualState?.eligible ?? true) && !(target.visualState?.disabled ?? false),
1929
+ ...descriptor.descriptorDigest !== void 0 ? { descriptorDigest: descriptor.descriptorDigest } : {},
1930
+ acceptedEffectPatterns
1931
+ });
1932
+ }
1933
+ return void 0;
1934
+ }
2606
1935
  function HandStagingView({
2607
1936
  zone,
2608
1937
  renderCard,
@@ -2613,31 +1942,35 @@ function HandStagingView({
2613
1942
  className
2614
1943
  }) {
2615
1944
  const interactionStore = useInteractionUiStore();
2616
- const drafts = useStore3(
1945
+ const drafts = useStore2(
2617
1946
  interactionStore,
2618
- useShallow2((state) => state.drafts)
1947
+ useShallow((state) => state.drafts)
2619
1948
  );
2620
- const stagedIds = usePluginState(
1949
+ const stagedIds = useAuthoredPluginGameplayFrameSelector(
2621
1950
  useCallback2(
2622
- (state) => selectedCardIdsForZone(interactionStore, zone, state),
1951
+ (frame) => selectedCardIdsForZone(
1952
+ interactionStore,
1953
+ zone,
1954
+ frame.availableInteractions
1955
+ ),
2623
1956
  // drafts is part of the store snapshot — useStore handles re-render.
2624
1957
  // eslint-disable-next-line react-hooks/exhaustive-deps
2625
1958
  [interactionStore, zone, drafts]
2626
1959
  )
2627
1960
  );
2628
- const zoneSnapshot = usePluginState(
2629
- (state) => state.gameplay.zones[zone] ?? null
1961
+ const zoneSnapshot = useAuthoredPluginGameplayFrameSelector(
1962
+ (frame) => frame.zones[zone] ?? null
2630
1963
  );
2631
- const availableInteractions = usePluginState(
2632
- (state) => state.gameplay.availableInteractions
1964
+ const availableInteractions = useAuthoredPluginGameplayFrameSelector(
1965
+ (frame) => frame.availableInteractions
2633
1966
  );
2634
- const cards = useMemo7(
1967
+ const cards = useMemo5(
2635
1968
  () => stagedIds.map(
2636
1969
  (cardId, index) => createZoneCardRenderItem(zone, zoneSnapshot, cardId, index)
2637
1970
  ).filter((card) => !card.hidden),
2638
1971
  [stagedIds, zone, zoneSnapshot]
2639
1972
  );
2640
- const selection = useMemo7(
1973
+ const selection = useMemo5(
2641
1974
  () => manyCardSelectionForZone(availableInteractions, zone),
2642
1975
  [availableInteractions, zone]
2643
1976
  );
@@ -2650,7 +1983,7 @@ function HandStagingView({
2650
1983
  [route]
2651
1984
  );
2652
1985
  if (slotCount <= 0 && cards.length === 0) return null;
2653
- return /* @__PURE__ */ jsx7(
1986
+ return /* @__PURE__ */ jsx4(
2654
1987
  StagingZone,
2655
1988
  {
2656
1989
  cards,
@@ -2668,8 +2001,8 @@ function HandStagingView({
2668
2001
  function dropTargetIdFor(kind, value) {
2669
2002
  return encodeRuntimeDropTargetKind(kind, value);
2670
2003
  }
2671
- function descriptorsHaveDestinationInput(state) {
2672
- for (const descriptor of state.gameplay.availableInteractions) {
2004
+ function descriptorsHaveDestinationInput(availableInteractions) {
2005
+ for (const descriptor of availableInteractions) {
2673
2006
  const cardInputs = descriptor.inputs.filter(
2674
2007
  (input) => isTargetDomain(input.domain) && input.domain.type === "cardTarget"
2675
2008
  );
@@ -2683,15 +2016,15 @@ function descriptorsHaveDestinationInput(state) {
2683
2016
 
2684
2017
  // src/runtime/primitives/board.tsx
2685
2018
  import {
2686
- createContext as createContext7,
2687
- useContext as useContext7,
2688
- useMemo as useMemo9
2019
+ createContext as createContext3,
2020
+ useContext as useContext3,
2021
+ useMemo as useMemo7
2689
2022
  } from "react";
2690
- import { useStore as useStore5 } from "zustand";
2023
+ import { useStore as useStore4 } from "zustand";
2691
2024
 
2692
2025
  // src/runtime/hooks/useBoardInteractions.ts
2693
- import { useCallback as useCallback3, useMemo as useMemo8 } from "react";
2694
- import { useStore as useStore4 } from "zustand";
2026
+ import { useCallback as useCallback3, useMemo as useMemo6 } from "react";
2027
+ import { useStore as useStore3 } from "zustand";
2695
2028
 
2696
2029
  // src/ui/errors/ValidationError.ts
2697
2030
  var ValidationError = class extends Error {
@@ -2722,7 +2055,7 @@ function interactionDraftDigestForValues(descriptor, values) {
2722
2055
  interactionKey: descriptor.interactionKey,
2723
2056
  values: {
2724
2057
  ...defaults,
2725
- ...toCanonicalJson2(values)
2058
+ ...toCanonicalJson(values)
2726
2059
  }
2727
2060
  });
2728
2061
  }
@@ -2733,7 +2066,7 @@ function draftDigest({
2733
2066
  interactionKey,
2734
2067
  values
2735
2068
  }) {
2736
- return hashJson2({
2069
+ return hashJson({
2737
2070
  digestVersion: "interaction-draft@2",
2738
2071
  actorSeat,
2739
2072
  descriptorDigest,
@@ -2746,11 +2079,11 @@ function draftDigest({
2746
2079
  function defaultsForDescriptor(descriptor) {
2747
2080
  return Object.fromEntries(
2748
2081
  descriptor.inputs.flatMap(
2749
- (input) => input.defaultValue === void 0 ? [] : [[input.key, toCanonicalJson2(input.defaultValue)]]
2082
+ (input) => input.defaultValue === void 0 ? [] : [[input.key, toCanonicalJson(input.defaultValue)]]
2750
2083
  )
2751
2084
  );
2752
2085
  }
2753
- function toCanonicalJson2(value) {
2086
+ function toCanonicalJson(value) {
2754
2087
  if (value === null || typeof value === "boolean" || typeof value === "string") {
2755
2088
  return value;
2756
2089
  }
@@ -2758,22 +2091,22 @@ function toCanonicalJson2(value) {
2758
2091
  return value;
2759
2092
  }
2760
2093
  if (Array.isArray(value)) {
2761
- return value.map((item) => toCanonicalJson2(item));
2094
+ return value.map((item) => toCanonicalJson(item));
2762
2095
  }
2763
2096
  if (typeof value === "object") {
2764
2097
  return Object.fromEntries(
2765
- Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => [key, toCanonicalJson2(item)])
2098
+ Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => [key, toCanonicalJson(item)])
2766
2099
  );
2767
2100
  }
2768
2101
  return null;
2769
2102
  }
2770
- function hashJson2(value) {
2771
- return `sha256:${sha256Hex2(canonicalJson2(value))}`;
2103
+ function hashJson(value) {
2104
+ return `sha256:${sha256Hex(canonicalJson(value))}`;
2772
2105
  }
2773
- function canonicalJson2(value) {
2774
- return JSON.stringify(canonicalizeJson2(value));
2106
+ function canonicalJson(value) {
2107
+ return JSON.stringify(canonicalizeJson(value));
2775
2108
  }
2776
- function canonicalizeJson2(value) {
2109
+ function canonicalizeJson(value) {
2777
2110
  if (value === null || typeof value === "boolean" || typeof value === "string") {
2778
2111
  return value;
2779
2112
  }
@@ -2784,14 +2117,14 @@ function canonicalizeJson2(value) {
2784
2117
  return value;
2785
2118
  }
2786
2119
  if (Array.isArray(value)) {
2787
- return value.map((item) => canonicalizeJson2(item));
2120
+ return value.map((item) => canonicalizeJson(item));
2788
2121
  }
2789
2122
  return Object.fromEntries(
2790
- Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, canonicalizeJson2(item)])
2123
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, canonicalizeJson(item)])
2791
2124
  );
2792
2125
  }
2793
- function sha256Hex2(input) {
2794
- const bytes = utf8Bytes2(input);
2126
+ function sha256Hex(input) {
2127
+ const bytes = utf8Bytes(input);
2795
2128
  const bitLength = bytes.length * 8;
2796
2129
  bytes.push(128);
2797
2130
  while (bytes.length % 64 !== 56) {
@@ -2847,7 +2180,7 @@ function sha256Hex2(input) {
2847
2180
  }
2848
2181
  return [h0, h1, h2, h3, h4, h5, h6, h7].map((word) => word.toString(16).padStart(8, "0")).join("");
2849
2182
  }
2850
- function utf8Bytes2(input) {
2183
+ function utf8Bytes(input) {
2851
2184
  return Array.from(new TextEncoder().encode(input));
2852
2185
  }
2853
2186
  function rightRotate(value, bits) {
@@ -3102,26 +2435,26 @@ function useBoardInteractions(options = {}) {
3102
2435
  const runtime = useRuntimeContext();
3103
2436
  const { controllingPlayerId } = usePluginSession();
3104
2437
  const store = useInteractionUiStore();
3105
- const subscribedArmedBySurface = useStore4(store, (state) => state.arms);
3106
- const subscribedDrafts = useStore4(store, (state) => state.drafts);
3107
- const pendingInteractionKey = useStore4(
2438
+ const subscribedArmedBySurface = useStore3(store, (state) => state.arms);
2439
+ const subscribedDrafts = useStore3(store, (state) => state.drafts);
2440
+ const pendingInteractionKey = useStore3(
3108
2441
  store,
3109
2442
  (state) => state.pendingInteractionKey
3110
2443
  );
3111
2444
  const armedBySurface = store.getState().arms ?? subscribedArmedBySurface;
3112
2445
  const drafts = store.getState().drafts ?? subscribedDrafts;
3113
- const descriptors = usePluginState(
3114
- (state) => state.gameplay.availableInteractions ?? []
2446
+ const descriptors = usePluginGameplayFrameSelector(
2447
+ (frame) => frame.availableInteractions ?? []
3115
2448
  );
3116
- const targetKindSet = useMemo8(
2449
+ const targetKindSet = useMemo6(
3117
2450
  () => new Set(targetKinds),
3118
2451
  [targetKinds]
3119
2452
  );
3120
- const armedIds = useMemo8(
2453
+ const armedIds = useMemo6(
3121
2454
  () => new Set(Object.values(armedBySurface)),
3122
2455
  [armedBySurface]
3123
2456
  );
3124
- const interactions = useMemo8(() => {
2457
+ const interactions = useMemo6(() => {
3125
2458
  return descriptors.flatMap(
3126
2459
  (descriptor) => {
3127
2460
  if (armedIds.has(descriptor.interactionKey)) {
@@ -3138,7 +2471,7 @@ function useBoardInteractions(options = {}) {
3138
2471
  }
3139
2472
  );
3140
2473
  }, [armedIds, descriptors, targetKindSet, targetKinds]);
3141
- const eligible = useMemo8(() => {
2474
+ const eligible = useMemo6(() => {
3142
2475
  const acc = {
3143
2476
  edge: /* @__PURE__ */ new Set(),
3144
2477
  vertex: /* @__PURE__ */ new Set(),
@@ -3204,7 +2537,6 @@ function useBoardInteractions(options = {}) {
3204
2537
  }
3205
2538
  try {
3206
2539
  await runtime.submitInteraction(
3207
- controllingPlayerId,
3208
2540
  descriptor.interactionId,
3209
2541
  submitParams
3210
2542
  );
@@ -3273,7 +2605,7 @@ function useBoardInteractions(options = {}) {
3273
2605
  },
3274
2606
  [controllingPlayerId, resolveSelection, resolveTargetMatches]
3275
2607
  );
3276
- const select = useMemo8(
2608
+ const select = useMemo6(
3277
2609
  () => ({
3278
2610
  edge: (targetId, extraInputs) => selectByKind("edge", targetId, extraInputs),
3279
2611
  vertex: (targetId, extraInputs) => selectByKind("vertex", targetId, extraInputs),
@@ -3317,7 +2649,7 @@ function useBoardInteractions(options = {}) {
3317
2649
  },
3318
2650
  [controllingPlayerId, drafts, pendingInteractionKey, resolveTargetMatches]
3319
2651
  );
3320
- const targetLayers = useMemo8(() => {
2652
+ const targetLayers = useMemo6(() => {
3321
2653
  const createLayer = (targetKind) => (layerOptions = {}) => {
3322
2654
  const {
3323
2655
  enabled,
@@ -3374,7 +2706,7 @@ function useBoardInteractions(options = {}) {
3374
2706
  tile: createLayer("tile")
3375
2707
  };
3376
2708
  }, [eligible, selectByKind, targetState]);
3377
- const pendingInteraction = useMemo8(() => {
2709
+ const pendingInteraction = useMemo6(() => {
3378
2710
  if (!pendingInteractionKey) return null;
3379
2711
  const descriptor = interactions.find(
3380
2712
  (candidate) => candidate.interactionKey === pendingInteractionKey
@@ -3394,7 +2726,7 @@ function useBoardInteractions(options = {}) {
3394
2726
  (descriptor, _targetKind, targetId, inputKey, extraInputs) => resolveSelection(descriptor, inputKey, targetId, extraInputs),
3395
2727
  [resolveSelection]
3396
2728
  );
3397
- return useMemo8(
2729
+ return useMemo6(
3398
2730
  () => ({
3399
2731
  interactions,
3400
2732
  eligible,
@@ -3428,7 +2760,7 @@ function isTargetSelectable(input, draft, targetId) {
3428
2760
  function missingInputsForDraft(descriptor, draft) {
3429
2761
  return [...getInteractionDraftReadiness(descriptor, draft).missingInputs];
3430
2762
  }
3431
- var GAMEPLAY_BROWSER_SCOPE_ID2 = "runtime";
2763
+ var GAMEPLAY_BROWSER_SCOPE_ID = "runtime";
3432
2764
  function boardTargetBrowserAttributes({
3433
2765
  descriptor,
3434
2766
  inputKey,
@@ -3438,7 +2770,7 @@ function boardTargetBrowserAttributes({
3438
2770
  draft
3439
2771
  }) {
3440
2772
  return createGameplayActuatorAttributes({
3441
- scopeId: GAMEPLAY_BROWSER_SCOPE_ID2,
2773
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID,
3442
2774
  interactionKey: descriptor.interactionKey,
3443
2775
  interactionId: descriptor.interactionId,
3444
2776
  intent: "select",
@@ -3488,8 +2820,8 @@ function candidateUnavailableReason(match, conflict) {
3488
2820
  }
3489
2821
 
3490
2822
  // src/runtime/primitives/board.tsx
3491
- import { Fragment as Fragment6, jsx as jsx8 } from "react/jsx-runtime";
3492
- var BoardContext = createContext7(null);
2823
+ import { Fragment as Fragment5, jsx as jsx5 } from "react/jsx-runtime";
2824
+ var BoardContext = createContext3(null);
3493
2825
  var warnedAmbiguousBoardTargets = /* @__PURE__ */ new Set();
3494
2826
  function warnAmbiguousBoardTarget({
3495
2827
  kind,
@@ -3510,7 +2842,7 @@ function warnAmbiguousBoardTarget({
3510
2842
  }
3511
2843
  }
3512
2844
  function useBoardPrimitiveContext() {
3513
- const value = useContext7(BoardContext);
2845
+ const value = useContext3(BoardContext);
3514
2846
  if (!value) {
3515
2847
  throw new Error("Board primitives must be rendered inside <Board.Root>.");
3516
2848
  }
@@ -3518,21 +2850,21 @@ function useBoardPrimitiveContext() {
3518
2850
  }
3519
2851
  function BoardRoot({ children, targetKinds, ...props }) {
3520
2852
  const board = useBoardInteractions({ targetKinds });
3521
- return /* @__PURE__ */ jsx8(BoardContext.Provider, { value: board, children: renderPrimitive("div", {
2853
+ return /* @__PURE__ */ jsx5(BoardContext.Provider, { value: board, children: renderPrimitive("div", {
3522
2854
  ...props,
3523
2855
  "data-dreamboard-board-root": "",
3524
2856
  children
3525
2857
  }) });
3526
2858
  }
3527
2859
  function BoardState({ children }) {
3528
- return /* @__PURE__ */ jsx8(Fragment6, { children: children(useBoardPrimitiveContext()) });
2860
+ return /* @__PURE__ */ jsx5(Fragment5, { children: children(useBoardPrimitiveContext()) });
3529
2861
  }
3530
2862
  function BoardHexView({ board, spaces, children }) {
3531
- const view = useMemo9(
2863
+ const view = useMemo7(
3532
2864
  () => createHexBoardView(board, { spaces }),
3533
2865
  [board, spaces]
3534
2866
  );
3535
- return /* @__PURE__ */ jsx8(Fragment6, { children: children(view) });
2867
+ return /* @__PURE__ */ jsx5(Fragment5, { children: children(view) });
3536
2868
  }
3537
2869
  function BoardHexGrid({
3538
2870
  board,
@@ -3557,7 +2889,7 @@ function BoardHexGrid({
3557
2889
  interactionKeys: interactions === "auto" ? void 0 : interactions.space,
3558
2890
  onError: gameActionError ?? void 0
3559
2891
  });
3560
- return /* @__PURE__ */ jsx8(BoardHexView, { board, spaces, children: (view) => /* @__PURE__ */ jsx8(
2892
+ return /* @__PURE__ */ jsx5(BoardHexView, { board, spaces, children: (view) => /* @__PURE__ */ jsx5(
3561
2893
  HexGrid,
3562
2894
  {
3563
2895
  ...props,
@@ -3573,13 +2905,13 @@ function BoardTarget({
3573
2905
  input,
3574
2906
  ...props
3575
2907
  }) {
3576
- const descriptor = usePluginState(
3577
- (state) => interaction ? state.gameplay.availableInteractions.find(
2908
+ const descriptor = useAuthoredPluginGameplayFrameSelector(
2909
+ (frame) => interaction ? frame.availableInteractions.find(
3578
2910
  (candidate) => candidate.interactionKey === interaction || candidate.interactionId === interaction
3579
2911
  ) : void 0
3580
2912
  );
3581
2913
  if (interaction) {
3582
- return descriptor ? /* @__PURE__ */ jsx8(ExplicitBoardTarget, { descriptor, input, ...props }) : /* @__PURE__ */ jsx8(
2914
+ return descriptor ? /* @__PURE__ */ jsx5(ExplicitBoardTarget, { descriptor, input, ...props }) : /* @__PURE__ */ jsx5(
3583
2915
  UnavailableBoardTarget,
3584
2916
  {
3585
2917
  interaction,
@@ -3588,16 +2920,16 @@ function BoardTarget({
3588
2920
  }
3589
2921
  );
3590
2922
  }
3591
- return /* @__PURE__ */ jsx8(UnambiguousBoardTarget, { input, ...props });
2923
+ return /* @__PURE__ */ jsx5(UnambiguousBoardTarget, { input, ...props });
3592
2924
  }
3593
2925
  function BoardSpaceTarget(props) {
3594
- return /* @__PURE__ */ jsx8(BoardTarget, { kind: "space", ...props });
2926
+ return /* @__PURE__ */ jsx5(BoardTarget, { kind: "space", ...props });
3595
2927
  }
3596
2928
  function BoardEdgeTarget(props) {
3597
- return /* @__PURE__ */ jsx8(BoardTarget, { kind: "edge", ...props });
2929
+ return /* @__PURE__ */ jsx5(BoardTarget, { kind: "edge", ...props });
3598
2930
  }
3599
2931
  function BoardVertexTarget(props) {
3600
- return /* @__PURE__ */ jsx8(BoardTarget, { kind: "vertex", ...props });
2932
+ return /* @__PURE__ */ jsx5(BoardTarget, { kind: "vertex", ...props });
3601
2933
  }
3602
2934
  function UnambiguousBoardTarget({
3603
2935
  kind,
@@ -3672,7 +3004,7 @@ function ExplicitBoardTarget({
3672
3004
  const board = useBoardPrimitiveContext();
3673
3005
  const gameActionError = useGameActionError();
3674
3006
  const store = useInteractionUiStore();
3675
- useStore5(store, (state) => state.drafts[descriptor.interactionKey] ?? {});
3007
+ useStore4(store, (state) => state.drafts[descriptor.interactionKey] ?? {});
3676
3008
  const draft = store.getDraft(descriptor.interactionKey);
3677
3009
  const inputKey = input ?? inputKeyForTarget(descriptor, kind, value, draft);
3678
3010
  const rawInputDescriptor = inputKey ? inputByKey(descriptor, inputKey) : void 0;
@@ -3750,7 +3082,7 @@ function UnavailableBoardTarget({
3750
3082
  function resolveExtraInputs(extraInputs, targetId) {
3751
3083
  return typeof extraInputs === "function" ? extraInputs(targetId) : extraInputs ?? {};
3752
3084
  }
3753
- var GAMEPLAY_BROWSER_SCOPE_ID3 = "runtime";
3085
+ var GAMEPLAY_BROWSER_SCOPE_ID2 = "runtime";
3754
3086
  function boardTargetBrowserAttributes2({
3755
3087
  descriptor,
3756
3088
  inputKey,
@@ -3760,7 +3092,7 @@ function boardTargetBrowserAttributes2({
3760
3092
  draft
3761
3093
  }) {
3762
3094
  return createGameplayActuatorAttributes({
3763
- scopeId: GAMEPLAY_BROWSER_SCOPE_ID3,
3095
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID2,
3764
3096
  interactionKey: descriptor.interactionKey,
3765
3097
  interactionId: descriptor.interactionId,
3766
3098
  intent: "select",
@@ -3799,133 +3131,134 @@ var Board = {
3799
3131
  };
3800
3132
 
3801
3133
  // src/runtime/primitives/interaction/context.tsx
3802
- import { createContext as createContext9, useContext as useContext9, useMemo as useMemo11 } from "react";
3134
+ import { createContext as createContext5, useContext as useContext5, useMemo as useMemo9 } from "react";
3803
3135
 
3804
- // src/runtime/hooks/useInteractionHandle.ts
3805
- import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo10, useRef as useRef3 } from "react";
3136
+ // src/runtime/hooks/useBoundInteractionHandle.ts
3137
+ import { useCallback as useCallback4, useEffect as useEffect2, useMemo as useMemo8, useRef as useRef2 } from "react";
3806
3138
 
3807
3139
  // src/runtime/context/ClientParamSchemaContext.tsx
3808
- import { createContext as createContext8, useContext as useContext8 } from "react";
3809
- import { jsx as jsx9 } from "react/jsx-runtime";
3810
- var ClientParamSchemaContext = createContext8({});
3140
+ import { createContext as createContext4, useContext as useContext4 } from "react";
3141
+ import { jsx as jsx6 } from "react/jsx-runtime";
3142
+ var ClientParamSchemaContext = createContext4({});
3811
3143
  function ClientParamSchemaProvider({
3812
3144
  schemas,
3813
3145
  children
3814
3146
  }) {
3815
- return /* @__PURE__ */ jsx9(ClientParamSchemaContext.Provider, { value: schemas ?? {}, children });
3147
+ return /* @__PURE__ */ jsx6(ClientParamSchemaContext.Provider, { value: schemas ?? {}, children });
3816
3148
  }
3817
3149
  function useClientParamSchema(phaseName, interactionId) {
3818
- const schemas = useContext8(ClientParamSchemaContext);
3150
+ const schemas = useContext4(ClientParamSchemaContext);
3819
3151
  if (!phaseName) return void 0;
3820
3152
  return schemas[phaseName]?.[interactionId];
3821
3153
  }
3822
3154
 
3823
- // src/runtime/hooks/useInteractionHandle.ts
3824
- function useInteractionHandle(descriptor) {
3155
+ // src/runtime/hooks/useBoundInteractionHandle.ts
3156
+ var MISSING_INTERACTION_KEY = "__dreamboard_missing_interaction__";
3157
+ var MISSING_INTERACTION_SCOPE = "interaction:missing";
3158
+ function useBoundInteractionHandle(descriptor) {
3825
3159
  const runtime = useRuntimeContext();
3826
3160
  const { controllingPlayerId } = usePluginSession();
3827
3161
  const store = useInteractionUiStore();
3828
- const submittingRef = useRef3(false);
3829
- const autoSubmitSignatureRef = useRef3(null);
3830
- const simultaneousPhase = usePluginState(
3831
- (state) => state.gameplay.simultaneousPhase
3162
+ const autoSubmitSignatureRef = useRef2(null);
3163
+ const simultaneousPhase = usePluginGameplayFrameSelector(
3164
+ (frame) => frame.flow.simultaneousPhase
3832
3165
  );
3833
- const { interactionId, interactionKey, phaseName } = descriptor;
3834
- const armScope = interactionArmScope(descriptor);
3835
- const inputKeys = useMemo10(
3836
- () => interactionInputKeys(descriptor),
3166
+ const interactionId = descriptor?.interactionId ?? "";
3167
+ const interactionKey = descriptor?.interactionKey ?? MISSING_INTERACTION_KEY;
3168
+ const phaseName = descriptor?.phaseName;
3169
+ const armScope = descriptor ? interactionArmScope(descriptor) : MISSING_INTERACTION_SCOPE;
3170
+ const inputKeys = useMemo8(
3171
+ () => descriptor ? interactionInputKeys(descriptor) : [],
3837
3172
  [descriptor]
3838
3173
  );
3839
3174
  const paramsSchema = useClientParamSchema(phaseName, interactionId);
3840
3175
  const draft = useInteractionDraft(interactionKey);
3841
- const values = useMemo10(
3842
- () => applyInteractionInputDefaults(descriptor, draft),
3843
- [descriptor, draft]
3844
- );
3176
+ const values = useMemo8(() => {
3177
+ if (!descriptor) {
3178
+ return {};
3179
+ }
3180
+ return applyInteractionInputDefaults(descriptor, draft);
3181
+ }, [descriptor, draft]);
3845
3182
  const armedId = useArmedInteraction(armScope);
3846
- const isArmed = armedId === interactionKey;
3183
+ const isArmed = descriptor ? armedId === interactionKey : false;
3847
3184
  const submitting = useInteractionSubmitting(interactionKey);
3848
- const submitted = controllingPlayerId !== null && simultaneousPhase?.phaseName === phaseName && simultaneousPhase.interactionId === interactionId && simultaneousPhase.sealedPlayerIds.includes(controllingPlayerId);
3185
+ const submitted = descriptor !== null && controllingPlayerId !== null && simultaneousPhase?.phaseName === descriptor.phaseName && simultaneousPhase.interactionId === descriptor.interactionId && simultaneousPhase.sealedPlayerIds.includes(controllingPlayerId);
3849
3186
  const status = submitted ? "submitted" : submitting ? "submitting" : "open";
3850
- const isReady = useMemo10(() => {
3187
+ const readiness = useMemo8(() => {
3188
+ if (!descriptor) {
3189
+ return null;
3190
+ }
3851
3191
  return getInteractionDraftReadiness(
3852
3192
  descriptor,
3853
3193
  values
3854
- ).ready;
3194
+ );
3855
3195
  }, [descriptor, values]);
3856
- const requirePlayer = useCallback4(() => {
3857
- if (!controllingPlayerId) {
3858
- throw new Error("useInteractionHandle: no controlling player available");
3196
+ const isReady = readiness?.ready ?? false;
3197
+ const requireDescriptor = useCallback4(() => {
3198
+ if (!descriptor) {
3199
+ throw new Error(
3200
+ "useInteractionHandle: interaction descriptor unavailable"
3201
+ );
3859
3202
  }
3860
- return controllingPlayerId;
3861
- }, [controllingPlayerId]);
3203
+ return descriptor;
3204
+ }, [descriptor]);
3862
3205
  const submit = useCallback4(
3863
3206
  async (params) => {
3864
- if (status !== "open" || submittingRef.current) {
3207
+ const activeDescriptor = requireDescriptor();
3208
+ if (status !== "open") {
3865
3209
  throw new ValidationError(
3866
3210
  status === "submitted" ? "ALREADY_SUBMITTED" : "SUBMITTING",
3867
3211
  status === "submitted" ? "Interaction has already been submitted." : "Interaction submission is already in progress."
3868
3212
  );
3869
3213
  }
3870
- if (!claimInteractionSubmit(store, descriptor)) {
3214
+ if (!claimInteractionSubmit(store, activeDescriptor)) {
3871
3215
  throw new ValidationError(
3872
3216
  "SUBMITTING",
3873
3217
  "Interaction submission is already in progress."
3874
3218
  );
3875
3219
  }
3876
- submittingRef.current = true;
3877
3220
  const finalParams = applyInteractionInputDefaults(
3878
- descriptor,
3221
+ activeDescriptor,
3879
3222
  params ?? values
3880
3223
  );
3881
3224
  try {
3882
3225
  await runtime.submitInteraction(
3883
- requirePlayer(),
3884
- interactionId,
3226
+ activeDescriptor.interactionId,
3885
3227
  finalParams
3886
3228
  );
3887
- clearInteractionRoute(store, descriptor);
3229
+ clearInteractionRoute(store, activeDescriptor);
3888
3230
  } catch (error) {
3889
3231
  throw validationErrorFromUnknown(error);
3890
3232
  } finally {
3891
- submittingRef.current = false;
3892
- store.setSubmitting(interactionKey, false);
3233
+ store.setSubmitting(activeDescriptor.interactionKey, false);
3893
3234
  }
3894
3235
  },
3895
- [
3896
- descriptor,
3897
- values,
3898
- runtime,
3899
- requirePlayer,
3900
- interactionId,
3901
- interactionKey,
3902
- store,
3903
- status
3904
- ]
3236
+ [requireDescriptor, status, store, values, runtime]
3905
3237
  );
3906
3238
  const validate = useCallback4(
3907
3239
  async (params) => {
3240
+ const activeDescriptor = requireDescriptor();
3908
3241
  const finalParams = applyInteractionInputDefaults(
3909
- descriptor,
3242
+ activeDescriptor,
3910
3243
  params ?? values
3911
3244
  );
3912
3245
  const result = await runtime.validateInteraction(
3913
- requirePlayer(),
3914
- interactionId,
3246
+ activeDescriptor.interactionId,
3915
3247
  finalParams
3916
3248
  );
3917
3249
  if (!result.valid) {
3918
3250
  throw new ValidationError(result.errorCode, result.message);
3919
3251
  }
3920
3252
  },
3921
- [descriptor, values, runtime, requirePlayer, interactionId]
3253
+ [requireDescriptor, values, runtime]
3922
3254
  );
3923
3255
  const validateDraft = useCallback4(() => {
3256
+ const activeDescriptor = requireDescriptor();
3924
3257
  const rawDraft = { ...values };
3925
3258
  const required = inputKeys;
3926
- const missing = getInteractionDraftReadiness(descriptor, rawDraft).missingInputs;
3259
+ const missing = getInteractionDraftReadiness(activeDescriptor, rawDraft).missingInputs;
3927
3260
  const domainFieldErrors = validateInteractionInputDomains(
3928
- descriptor,
3261
+ activeDescriptor,
3929
3262
  rawDraft
3930
3263
  );
3931
3264
  if (!paramsSchema) {
@@ -3985,7 +3318,7 @@ function useInteractionHandle(descriptor) {
3985
3318
  formErrors,
3986
3319
  missing
3987
3320
  };
3988
- }, [descriptor, values, inputKeys, paramsSchema]);
3321
+ }, [requireDescriptor, values, inputKeys, paramsSchema]);
3989
3322
  const validateDraftServer = useCallback4(async () => {
3990
3323
  await validate({ ...values });
3991
3324
  }, [values, validate]);
@@ -3997,7 +3330,11 @@ function useInteractionHandle(descriptor) {
3997
3330
  }
3998
3331
  await submit(validation.params);
3999
3332
  }, [submit, validateDraft]);
4000
- useEffect5(() => {
3333
+ useEffect2(() => {
3334
+ if (!descriptor) {
3335
+ autoSubmitSignatureRef.current = null;
3336
+ return;
3337
+ }
4001
3338
  if (!shouldAutoSubmitInteraction(descriptor)) {
4002
3339
  autoSubmitSignatureRef.current = null;
4003
3340
  return;
@@ -4008,16 +3345,19 @@ function useInteractionHandle(descriptor) {
4008
3345
  }
4009
3346
  const validation = validateDraft();
4010
3347
  if (!validation.ok) return;
4011
- const signature = `${interactionKey}:${JSON.stringify(validation.params)}`;
3348
+ const signature = `${descriptor.interactionKey}:${JSON.stringify(
3349
+ validation.params
3350
+ )}`;
4012
3351
  if (autoSubmitSignatureRef.current === signature) return;
4013
3352
  autoSubmitSignatureRef.current = signature;
4014
3353
  void submit(validation.params).catch(() => {
4015
3354
  });
4016
3355
  }, [
4017
- descriptor.availability,
4018
- descriptor.commit.mode,
4019
- descriptor.inputs,
4020
- interactionKey,
3356
+ descriptor,
3357
+ descriptor?.availability,
3358
+ descriptor?.commit.mode,
3359
+ descriptor?.inputs,
3360
+ descriptor?.interactionKey,
4021
3361
  isReady,
4022
3362
  status,
4023
3363
  submit,
@@ -4025,24 +3365,35 @@ function useInteractionHandle(descriptor) {
4025
3365
  ]);
4026
3366
  const setInput = useCallback4(
4027
3367
  (key, value) => {
4028
- applyInteractionDraftMutation(store, descriptor, [{ key, value }]);
3368
+ const activeDescriptor = requireDescriptor();
3369
+ applyInteractionDraftMutation(store, activeDescriptor, [{ key, value }]);
4029
3370
  },
4030
- [store, descriptor]
3371
+ [store, requireDescriptor]
4031
3372
  );
4032
3373
  const clearInput = useCallback4(
4033
3374
  (key) => {
4034
- store.clearInput(interactionKey, key);
3375
+ const activeDescriptor = requireDescriptor();
3376
+ store.clearInput(activeDescriptor.interactionKey, key);
4035
3377
  },
4036
- [store, interactionKey]
3378
+ [store, requireDescriptor]
4037
3379
  );
4038
3380
  const arm = useCallback4(() => {
4039
- store.arm(armScope, interactionKey);
4040
- }, [store, armScope, interactionKey]);
3381
+ const activeDescriptor = requireDescriptor();
3382
+ store.arm(
3383
+ interactionArmScope(activeDescriptor),
3384
+ activeDescriptor.interactionKey
3385
+ );
3386
+ }, [store, requireDescriptor]);
4041
3387
  const disarm = useCallback4(() => {
4042
- if (store.getArmed(armScope) === interactionKey) {
4043
- store.arm(armScope, null);
3388
+ const activeDescriptor = requireDescriptor();
3389
+ const activeArmScope = interactionArmScope(activeDescriptor);
3390
+ if (store.getArmed(activeArmScope) === activeDescriptor.interactionKey) {
3391
+ store.arm(activeArmScope, null);
4044
3392
  }
4045
- }, [store, armScope, interactionKey]);
3393
+ }, [store, requireDescriptor]);
3394
+ if (!descriptor) {
3395
+ return null;
3396
+ }
4046
3397
  return {
4047
3398
  descriptor,
4048
3399
  commit: descriptor.commit,
@@ -4065,8 +3416,13 @@ function useInteractionHandle(descriptor) {
4065
3416
  };
4066
3417
  }
4067
3418
 
3419
+ // src/runtime/hooks/useInteractionHandle.ts
3420
+ function useInteractionHandle(descriptor) {
3421
+ return useBoundInteractionHandle(descriptor);
3422
+ }
3423
+
4068
3424
  // src/runtime/interactions/gameplay-attributes.ts
4069
- var GAMEPLAY_BROWSER_SCOPE_ID4 = "runtime";
3425
+ var GAMEPLAY_BROWSER_SCOPE_ID3 = "runtime";
4070
3426
  function gameplayInteractionRootAttributes({
4071
3427
  descriptor,
4072
3428
  draftDigest: draftDigest2,
@@ -4074,7 +3430,7 @@ function gameplayInteractionRootAttributes({
4074
3430
  available
4075
3431
  }) {
4076
3432
  return createGameplayInteractionRootAttributes({
4077
- scopeId: GAMEPLAY_BROWSER_SCOPE_ID4,
3433
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID3,
4078
3434
  interactionKey: descriptor.interactionKey,
4079
3435
  interactionId: descriptor.interactionId,
4080
3436
  ...descriptor.descriptorDigest !== void 0 ? { descriptorDigest: descriptor.descriptorDigest } : {},
@@ -4097,7 +3453,7 @@ function gameplayActuatorAttributes({
4097
3453
  actuatorId
4098
3454
  }) {
4099
3455
  return createGameplayActuatorAttributes({
4100
- scopeId: GAMEPLAY_BROWSER_SCOPE_ID4,
3456
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID3,
4101
3457
  interactionKey: descriptor.interactionKey,
4102
3458
  interactionId: descriptor.interactionId,
4103
3459
  intent,
@@ -4116,15 +3472,15 @@ function gameplayActuatorAttributes({
4116
3472
  }
4117
3473
 
4118
3474
  // src/runtime/primitives/interaction/context.tsx
4119
- import { jsx as jsx10 } from "react/jsx-runtime";
4120
- var InteractionContext = createContext9(null);
3475
+ import { jsx as jsx7 } from "react/jsx-runtime";
3476
+ var InteractionContext = createContext5(null);
4121
3477
  function humanizeInteraction(value) {
4122
3478
  const parts = value.split(".");
4123
3479
  const leaf = parts[parts.length - 1] ?? value;
4124
3480
  return leaf.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (first) => first.toUpperCase());
4125
3481
  }
4126
3482
  function useInteractionPrimitiveContext() {
4127
- const value = useContext9(InteractionContext);
3483
+ const value = useContext5(InteractionContext);
4128
3484
  if (!value) {
4129
3485
  throw new Error(
4130
3486
  "Interaction primitives must be rendered inside <Interaction.Root>."
@@ -4133,7 +3489,7 @@ function useInteractionPrimitiveContext() {
4133
3489
  return value;
4134
3490
  }
4135
3491
  function useResolvedCardTargetValue() {
4136
- const context = useContext9(InteractionContext);
3492
+ const context = useContext5(InteractionContext);
4137
3493
  const descriptor = context?.descriptor;
4138
3494
  const handle = context?.handle;
4139
3495
  if (!descriptor || !handle) return void 0;
@@ -4144,8 +3500,8 @@ function useResolvedCardTargetValue() {
4144
3500
  return handle.values[cardInput.key];
4145
3501
  }
4146
3502
  function useInteractionDescriptor(interaction) {
4147
- return usePluginState(
4148
- (state) => state.gameplay.availableInteractions.find(
3503
+ return useAuthoredPluginGameplayFrameSelector(
3504
+ (frame) => frame.availableInteractions.find(
4149
3505
  (descriptor) => descriptor.interactionKey === interaction || descriptor.interactionId === interaction
4150
3506
  )
4151
3507
  );
@@ -4156,20 +3512,20 @@ function ResolvedInteractionRoot({
4156
3512
  children
4157
3513
  }) {
4158
3514
  const handle = useInteractionHandle(descriptor);
4159
- const value = useMemo11(
3515
+ const value = useMemo9(
4160
3516
  () => ({ interaction, descriptor, handle }),
4161
3517
  [descriptor, handle, interaction]
4162
3518
  );
4163
3519
  const available = isInteractionAvailable(descriptor);
4164
3520
  const rootAttributes = createGameplayInteractionRootAttributes({
4165
- scopeId: GAMEPLAY_BROWSER_SCOPE_ID4,
3521
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID3,
4166
3522
  interactionKey: descriptor.interactionKey,
4167
3523
  interactionId: descriptor.interactionId,
4168
3524
  ...descriptor.descriptorDigest !== void 0 ? { descriptorDigest: descriptor.descriptorDigest } : {},
4169
3525
  ...descriptor.draftDigest !== void 0 ? { draftDigest: descriptor.draftDigest } : {},
4170
3526
  readiness: available ? handle.isReady ? "ready" : "blocked" : "unavailable"
4171
3527
  });
4172
- return /* @__PURE__ */ jsx10(InteractionContext.Provider, { value, children: renderPrimitive("span", {
3528
+ return /* @__PURE__ */ jsx7(InteractionContext.Provider, { value, children: renderPrimitive("span", {
4173
3529
  ...rootAttributes,
4174
3530
  style: { display: "contents" },
4175
3531
  children
@@ -4183,7 +3539,7 @@ function InteractionRoot({
4183
3539
  const descriptor = useInteractionDescriptor(interaction);
4184
3540
  if (!descriptor) {
4185
3541
  if (unavailable === "hide") return null;
4186
- return /* @__PURE__ */ jsx10(
3542
+ return /* @__PURE__ */ jsx7(
4187
3543
  InteractionContext.Provider,
4188
3544
  {
4189
3545
  value: {
@@ -4198,12 +3554,12 @@ function InteractionRoot({
4198
3554
  if (!isInteractionAvailable(descriptor) && unavailable === "hide") {
4199
3555
  return null;
4200
3556
  }
4201
- return /* @__PURE__ */ jsx10(ResolvedInteractionRoot, { interaction, descriptor, children });
3557
+ return /* @__PURE__ */ jsx7(ResolvedInteractionRoot, { interaction, descriptor, children });
4202
3558
  }
4203
3559
 
4204
3560
  // src/runtime/components/interaction-form/fields.tsx
4205
3561
  import { useId } from "react";
4206
- import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
3562
+ import { Fragment as Fragment6, jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
4207
3563
  var EMPTY_FIELD_ERRORS = [];
4208
3564
  function InteractionField({
4209
3565
  descriptor,
@@ -4234,8 +3590,8 @@ function InteractionField({
4234
3590
  missing,
4235
3591
  disabled
4236
3592
  };
4237
- if (render) return /* @__PURE__ */ jsx11(Fragment7, { children: render(props) });
4238
- return /* @__PURE__ */ jsx11(DefaultInteractionField, { ...props });
3593
+ if (render) return /* @__PURE__ */ jsx8(Fragment6, { children: render(props) });
3594
+ return /* @__PURE__ */ jsx8(DefaultInteractionField, { ...props });
4239
3595
  }
4240
3596
  function defaultFormInputs(descriptor, values = {}) {
4241
3597
  return resolveInteractionInputs(descriptor, values).filter((input) => {
@@ -4256,7 +3612,7 @@ function DefaultInteractionField(props) {
4256
3612
  switch (input.domain.type) {
4257
3613
  case "choice":
4258
3614
  if (input.domain.selection?.mode === "many") {
4259
- return /* @__PURE__ */ jsx11(
3615
+ return /* @__PURE__ */ jsx8(
4260
3616
  ChoiceListField,
4261
3617
  {
4262
3618
  ...props,
@@ -4270,16 +3626,16 @@ function DefaultInteractionField(props) {
4270
3626
  }
4271
3627
  );
4272
3628
  }
4273
- return /* @__PURE__ */ jsx11(ChoiceField, { ...props, domain: input.domain });
3629
+ return /* @__PURE__ */ jsx8(ChoiceField, { ...props, domain: input.domain });
4274
3630
  case "choiceList":
4275
- return /* @__PURE__ */ jsx11(ChoiceListField, { ...props, domain: input.domain });
3631
+ return /* @__PURE__ */ jsx8(ChoiceListField, { ...props, domain: input.domain });
4276
3632
  case "resourceMap":
4277
- return /* @__PURE__ */ jsx11(ResourceMapField, { ...props, domain: input.domain });
3633
+ return /* @__PURE__ */ jsx8(ResourceMapField, { ...props, domain: input.domain });
4278
3634
  case "boundedNumber":
4279
- return /* @__PURE__ */ jsx11(BoundedNumberField, { ...props, domain: input.domain });
3635
+ return /* @__PURE__ */ jsx8(BoundedNumberField, { ...props, domain: input.domain });
4280
3636
  case "cardTarget":
4281
3637
  case "boardTarget":
4282
- return /* @__PURE__ */ jsx11(TargetSummaryField, { ...props, domain: input.domain });
3638
+ return /* @__PURE__ */ jsx8(TargetSummaryField, { ...props, domain: input.domain });
4283
3639
  }
4284
3640
  }
4285
3641
  function FieldFrame({
@@ -4291,7 +3647,7 @@ function FieldFrame({
4291
3647
  }) {
4292
3648
  const theme = useTheme();
4293
3649
  const messages = errors.length > 0 ? errors : missing ? ["Required"] : [];
4294
- return /* @__PURE__ */ jsxs3(
3650
+ return /* @__PURE__ */ jsxs2(
4295
3651
  "div",
4296
3652
  {
4297
3653
  style: {
@@ -4302,7 +3658,7 @@ function FieldFrame({
4302
3658
  color: theme.semantic.text.primary
4303
3659
  },
4304
3660
  children: [
4305
- /* @__PURE__ */ jsx11(
3661
+ /* @__PURE__ */ jsx8(
4306
3662
  Label,
4307
3663
  {
4308
3664
  htmlFor: controlId,
@@ -4314,7 +3670,7 @@ function FieldFrame({
4314
3670
  }
4315
3671
  ),
4316
3672
  children,
4317
- messages.length > 0 ? /* @__PURE__ */ jsx11(
3673
+ messages.length > 0 ? /* @__PURE__ */ jsx8(
4318
3674
  "span",
4319
3675
  {
4320
3676
  role: "alert",
@@ -4325,7 +3681,7 @@ function FieldFrame({
4325
3681
  color: theme.semantic.intent.danger.solid,
4326
3682
  fontSize: theme.typography.fontSize.xs
4327
3683
  },
4328
- children: messages.map((message) => /* @__PURE__ */ jsx11("span", { children: message }, message))
3684
+ children: messages.map((message) => /* @__PURE__ */ jsx8("span", { children: message }, message))
4329
3685
  }
4330
3686
  ) : null
4331
3687
  ]
@@ -4334,7 +3690,7 @@ function FieldFrame({
4334
3690
  }
4335
3691
  function ChoiceOptionLabel({ choice }) {
4336
3692
  const theme = useTheme();
4337
- return /* @__PURE__ */ jsxs3(
3693
+ return /* @__PURE__ */ jsxs2(
4338
3694
  "span",
4339
3695
  {
4340
3696
  style: {
@@ -4344,7 +3700,7 @@ function ChoiceOptionLabel({ choice }) {
4344
3700
  minWidth: 0
4345
3701
  },
4346
3702
  children: [
4347
- /* @__PURE__ */ jsxs3(
3703
+ /* @__PURE__ */ jsxs2(
4348
3704
  "span",
4349
3705
  {
4350
3706
  style: {
@@ -4354,12 +3710,12 @@ function ChoiceOptionLabel({ choice }) {
4354
3710
  minWidth: 0
4355
3711
  },
4356
3712
  children: [
4357
- choice.icon ? /* @__PURE__ */ jsx11("span", { "aria-hidden": true, style: { fontSize: "1.1em", lineHeight: 1 }, children: choice.icon }) : null,
4358
- /* @__PURE__ */ jsx11("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: choice.label })
3713
+ choice.icon ? /* @__PURE__ */ jsx8("span", { "aria-hidden": true, style: { fontSize: "1.1em", lineHeight: 1 }, children: choice.icon }) : null,
3714
+ /* @__PURE__ */ jsx8("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: choice.label })
4359
3715
  ]
4360
3716
  }
4361
3717
  ),
4362
- choice.badge ? /* @__PURE__ */ jsx11(
3718
+ choice.badge ? /* @__PURE__ */ jsx8(
4363
3719
  "span",
4364
3720
  {
4365
3721
  style: {
@@ -4383,7 +3739,7 @@ function ChoiceDescription({ choice }) {
4383
3739
  const theme = useTheme();
4384
3740
  const message = choice?.disabledReason ?? choice?.description;
4385
3741
  if (!message) return null;
4386
- return /* @__PURE__ */ jsx11(
3742
+ return /* @__PURE__ */ jsx8(
4387
3743
  "span",
4388
3744
  {
4389
3745
  style: {
@@ -4422,13 +3778,13 @@ function ChoiceField({
4422
3778
  const controlId = useId();
4423
3779
  const selectedChoice = typeof value === "string" || value === null ? choices.find((choice) => choice.value === value) : void 0;
4424
3780
  if (choices.length > 0 && choices.length <= 3) {
4425
- return /* @__PURE__ */ jsx11(
3781
+ return /* @__PURE__ */ jsx8(
4426
3782
  FieldFrame,
4427
3783
  {
4428
3784
  label: labelForInput(input),
4429
3785
  errors,
4430
3786
  missing,
4431
- children: /* @__PURE__ */ jsx11(
3787
+ children: /* @__PURE__ */ jsx8(
4432
3788
  "span",
4433
3789
  {
4434
3790
  style: {
@@ -4439,7 +3795,7 @@ function ChoiceField({
4439
3795
  children: choices.map((choice) => {
4440
3796
  const selected = value === choice.value;
4441
3797
  const isDisabled = disabled || choice.disabled;
4442
- return /* @__PURE__ */ jsx11(
3798
+ return /* @__PURE__ */ jsx8(
4443
3799
  ThemedButton,
4444
3800
  {
4445
3801
  type: "button",
@@ -4471,7 +3827,7 @@ function ChoiceField({
4471
3827
  }),
4472
3828
  onClick: () => setValue(choice.value),
4473
3829
  className: "h-8 px-3 text-sm",
4474
- children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
3830
+ children: /* @__PURE__ */ jsx8(ChoiceOptionLabel, { choice })
4475
3831
  },
4476
3832
  choiceRenderKey(choice)
4477
3833
  );
@@ -4481,7 +3837,7 @@ function ChoiceField({
4481
3837
  }
4482
3838
  );
4483
3839
  }
4484
- return /* @__PURE__ */ jsxs3(
3840
+ return /* @__PURE__ */ jsxs2(
4485
3841
  FieldFrame,
4486
3842
  {
4487
3843
  label: labelForInput(input),
@@ -4489,14 +3845,14 @@ function ChoiceField({
4489
3845
  errors,
4490
3846
  missing,
4491
3847
  children: [
4492
- /* @__PURE__ */ jsxs3(
3848
+ /* @__PURE__ */ jsxs2(
4493
3849
  Select,
4494
3850
  {
4495
3851
  disabled,
4496
3852
  value: encodeChoiceSelectValue(value),
4497
3853
  onValueChange: (next) => setValue(decodeChoiceSelectValue(next)),
4498
3854
  children: [
4499
- /* @__PURE__ */ jsx11(
3855
+ /* @__PURE__ */ jsx8(
4500
3856
  SelectTrigger,
4501
3857
  {
4502
3858
  id: controlId,
@@ -4518,17 +3874,17 @@ function ChoiceField({
4518
3874
  handle.values
4519
3875
  )
4520
3876
  }),
4521
- children: /* @__PURE__ */ jsx11("span", { "data-slot": "select-value", children: selectedChoice ? /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice: selectedChoice }) : /* @__PURE__ */ jsx11("span", { style: { color: theme.semantic.text.muted }, children: "Choose..." }) })
3877
+ children: /* @__PURE__ */ jsx8("span", { "data-slot": "select-value", children: selectedChoice ? /* @__PURE__ */ jsx8(ChoiceOptionLabel, { choice: selectedChoice }) : /* @__PURE__ */ jsx8("span", { style: { color: theme.semantic.text.muted }, children: "Choose..." }) })
4522
3878
  }
4523
3879
  ),
4524
- /* @__PURE__ */ jsx11(
3880
+ /* @__PURE__ */ jsx8(
4525
3881
  SelectContent,
4526
3882
  {
4527
3883
  style: {
4528
3884
  ...themeCssVars,
4529
3885
  fontFamily: theme.typography.fontFamily.body
4530
3886
  },
4531
- children: choices.map((choice) => /* @__PURE__ */ jsx11(
3887
+ children: choices.map((choice) => /* @__PURE__ */ jsx8(
4532
3888
  SelectItem,
4533
3889
  {
4534
3890
  value: choiceRenderKey(choice),
@@ -4555,7 +3911,7 @@ function ChoiceField({
4555
3911
  intent: "select"
4556
3912
  }).semanticEffects
4557
3913
  }),
4558
- children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
3914
+ children: /* @__PURE__ */ jsx8(ChoiceOptionLabel, { choice })
4559
3915
  },
4560
3916
  choiceRenderKey(choice)
4561
3917
  ))
@@ -4564,7 +3920,7 @@ function ChoiceField({
4564
3920
  ]
4565
3921
  }
4566
3922
  ),
4567
- /* @__PURE__ */ jsx11(ChoiceDescription, { choice: selectedChoice })
3923
+ /* @__PURE__ */ jsx8(ChoiceDescription, { choice: selectedChoice })
4568
3924
  ]
4569
3925
  }
4570
3926
  );
@@ -4591,10 +3947,10 @@ function ChoiceListField({
4591
3947
  setValue([...next]);
4592
3948
  };
4593
3949
  const meta = min || Number.isFinite(max) ? `Pick ${min ?? 0}${Number.isFinite(max) ? `-${max}` : "+"}` : void 0;
4594
- return /* @__PURE__ */ jsx11(
3950
+ return /* @__PURE__ */ jsx8(
4595
3951
  FieldFrame,
4596
3952
  {
4597
- label: /* @__PURE__ */ jsxs3(
3953
+ label: /* @__PURE__ */ jsxs2(
4598
3954
  "span",
4599
3955
  {
4600
3956
  style: {
@@ -4603,18 +3959,18 @@ function ChoiceListField({
4603
3959
  gap: theme.space[2]
4604
3960
  },
4605
3961
  children: [
4606
- /* @__PURE__ */ jsx11("span", { children: labelForInput(input) }),
4607
- meta ? /* @__PURE__ */ jsx11("span", { style: { color: theme.semantic.text.muted }, children: meta }) : null
3962
+ /* @__PURE__ */ jsx8("span", { children: labelForInput(input) }),
3963
+ meta ? /* @__PURE__ */ jsx8("span", { style: { color: theme.semantic.text.muted }, children: meta }) : null
4608
3964
  ]
4609
3965
  }
4610
3966
  ),
4611
3967
  errors,
4612
3968
  missing,
4613
- children: /* @__PURE__ */ jsx11("span", { style: { display: "flex", flexWrap: "wrap", gap: theme.space[1] }, children: (domain.choices ?? []).map((choice) => {
3969
+ children: /* @__PURE__ */ jsx8("span", { style: { display: "flex", flexWrap: "wrap", gap: theme.space[1] }, children: (domain.choices ?? []).map((choice) => {
4614
3970
  const value2 = choice.value;
4615
3971
  const checked = selected.has(value2);
4616
3972
  const isDisabled = disabled || choice.disabled || !checked && selected.size >= max;
4617
- return /* @__PURE__ */ jsx11(
3973
+ return /* @__PURE__ */ jsx8(
4618
3974
  ThemedButton,
4619
3975
  {
4620
3976
  type: "button",
@@ -4646,7 +4002,7 @@ function ChoiceListField({
4646
4002
  }),
4647
4003
  onClick: () => toggle(value2),
4648
4004
  className: "h-8 px-3 text-sm",
4649
- children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
4005
+ children: /* @__PURE__ */ jsx8(ChoiceOptionLabel, { choice })
4650
4006
  },
4651
4007
  value2
4652
4008
  );
@@ -4666,13 +4022,13 @@ function ResourceMapField({
4666
4022
  domain
4667
4023
  }) {
4668
4024
  const theme = useTheme();
4669
- const current = isRecord2(value) ? value : {};
4025
+ const current = isRecord(value) ? value : {};
4670
4026
  const update = (resourceId, delta, min, max) => {
4671
4027
  const previous = numberOrZero(current[resourceId]);
4672
4028
  const next = Math.max(min, Math.min(max, previous + delta));
4673
4029
  setValue({ ...current, [resourceId]: next });
4674
4030
  };
4675
- return /* @__PURE__ */ jsx11(FieldFrame, { label: labelForInput(input), errors, missing, children: /* @__PURE__ */ jsx11(
4031
+ return /* @__PURE__ */ jsx8(FieldFrame, { label: labelForInput(input), errors, missing, children: /* @__PURE__ */ jsx8(
4676
4032
  "span",
4677
4033
  {
4678
4034
  style: {
@@ -4684,7 +4040,7 @@ function ResourceMapField({
4684
4040
  const min = resource.min ?? 0;
4685
4041
  const max = resource.max ?? 0;
4686
4042
  const amount = numberOrZero(current[resource.resourceId]);
4687
- return /* @__PURE__ */ jsxs3(
4043
+ return /* @__PURE__ */ jsxs2(
4688
4044
  "span",
4689
4045
  {
4690
4046
  style: {
@@ -4697,7 +4053,7 @@ function ResourceMapField({
4697
4053
  background: theme.semantic.surface.inset
4698
4054
  },
4699
4055
  children: [
4700
- /* @__PURE__ */ jsxs3(
4056
+ /* @__PURE__ */ jsxs2(
4701
4057
  "span",
4702
4058
  {
4703
4059
  style: {
@@ -4707,12 +4063,12 @@ function ResourceMapField({
4707
4063
  gap: theme.space[1]
4708
4064
  },
4709
4065
  children: [
4710
- resource.icon ? /* @__PURE__ */ jsx11("span", { "aria-hidden": true, style: { fontSize: "1.1em" }, children: resource.icon }) : null,
4066
+ resource.icon ? /* @__PURE__ */ jsx8("span", { "aria-hidden": true, style: { fontSize: "1.1em" }, children: resource.icon }) : null,
4711
4067
  resource.label ?? humanize(input.key)
4712
4068
  ]
4713
4069
  }
4714
4070
  ),
4715
- /* @__PURE__ */ jsx11(
4071
+ /* @__PURE__ */ jsx8(
4716
4072
  StepperButton,
4717
4073
  {
4718
4074
  label: `Decrease ${resource.label ?? resource.resourceId}`,
@@ -4739,7 +4095,7 @@ function ResourceMapField({
4739
4095
  children: "-"
4740
4096
  }
4741
4097
  ),
4742
- /* @__PURE__ */ jsx11(
4098
+ /* @__PURE__ */ jsx8(
4743
4099
  "span",
4744
4100
  {
4745
4101
  style: {
@@ -4750,7 +4106,7 @@ function ResourceMapField({
4750
4106
  children: amount
4751
4107
  }
4752
4108
  ),
4753
- /* @__PURE__ */ jsx11(
4109
+ /* @__PURE__ */ jsx8(
4754
4110
  StepperButton,
4755
4111
  {
4756
4112
  label: `Increase ${resource.label ?? resource.resourceId}`,
@@ -4803,14 +4159,14 @@ function BoundedNumberField({
4803
4159
  const current = typeof value === "number" ? value : min;
4804
4160
  const controlId = useId();
4805
4161
  const update = (next) => setValue(Math.max(min, Math.min(max, next)));
4806
- return /* @__PURE__ */ jsx11(
4162
+ return /* @__PURE__ */ jsx8(
4807
4163
  FieldFrame,
4808
4164
  {
4809
4165
  label: labelForInput(input),
4810
4166
  controlId,
4811
4167
  errors,
4812
4168
  missing,
4813
- children: /* @__PURE__ */ jsxs3(
4169
+ children: /* @__PURE__ */ jsxs2(
4814
4170
  "span",
4815
4171
  {
4816
4172
  style: {
@@ -4819,7 +4175,7 @@ function BoundedNumberField({
4819
4175
  gap: theme.space[1]
4820
4176
  },
4821
4177
  children: [
4822
- /* @__PURE__ */ jsx11(
4178
+ /* @__PURE__ */ jsx8(
4823
4179
  StepperButton,
4824
4180
  {
4825
4181
  label: `Decrease ${input.key}`,
@@ -4844,7 +4200,7 @@ function BoundedNumberField({
4844
4200
  children: "-"
4845
4201
  }
4846
4202
  ),
4847
- /* @__PURE__ */ jsx11(
4203
+ /* @__PURE__ */ jsx8(
4848
4204
  Input,
4849
4205
  {
4850
4206
  id: controlId,
@@ -4874,7 +4230,7 @@ function BoundedNumberField({
4874
4230
  className: "h-9 w-[8ch] px-2 text-center text-sm md:text-sm"
4875
4231
  }
4876
4232
  ),
4877
- /* @__PURE__ */ jsx11(
4233
+ /* @__PURE__ */ jsx8(
4878
4234
  StepperButton,
4879
4235
  {
4880
4236
  label: `Increase ${input.key}`,
@@ -4913,7 +4269,7 @@ function TargetSummaryField({
4913
4269
  domain
4914
4270
  }) {
4915
4271
  const target = inputTargetKind(domain) ?? "target";
4916
- return /* @__PURE__ */ jsx11(FieldFrame, { label: labelForInput(input), errors, missing, children: /* @__PURE__ */ jsx11("span", { children: Array.isArray(value) ? value.length > 0 ? `${value.length} selected: ${value.join(", ")}` : `Select ${targetSelectionLabel(domain)}.` : typeof value === "string" ? value : `Select a ${target} on the board.` }) });
4272
+ return /* @__PURE__ */ jsx8(FieldFrame, { label: labelForInput(input), errors, missing, children: /* @__PURE__ */ jsx8("span", { children: Array.isArray(value) ? value.length > 0 ? `${value.length} selected: ${value.join(", ")}` : `Select ${targetSelectionLabel(domain)}.` : typeof value === "string" ? value : `Select a ${target} on the board.` }) });
4917
4273
  }
4918
4274
  function targetSelectionLabel(domain) {
4919
4275
  const target = inputTargetKind(domain) ?? "target";
@@ -4932,7 +4288,7 @@ function StepperButton({
4932
4288
  onClick,
4933
4289
  children
4934
4290
  }) {
4935
- return /* @__PURE__ */ jsx11(
4291
+ return /* @__PURE__ */ jsx8(
4936
4292
  ThemedButton,
4937
4293
  {
4938
4294
  type: "button",
@@ -4959,7 +4315,7 @@ function labelForInput(input) {
4959
4315
  function humanize(key) {
4960
4316
  return key.replace(/Id$/, "").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
4961
4317
  }
4962
- function isRecord2(value) {
4318
+ function isRecord(value) {
4963
4319
  return typeof value === "object" && value !== null && !Array.isArray(value);
4964
4320
  }
4965
4321
  function numberOrZero(value) {
@@ -4968,15 +4324,15 @@ function numberOrZero(value) {
4968
4324
 
4969
4325
  // src/runtime/components/interaction-form/InteractionForm.tsx
4970
4326
  import {
4971
- useEffect as useEffect6,
4327
+ useEffect as useEffect3,
4972
4328
  useId as useId2,
4973
- useMemo as useMemo12,
4974
- useState as useState4
4329
+ useMemo as useMemo10,
4330
+ useState
4975
4331
  } from "react";
4976
4332
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
4977
4333
 
4978
4334
  // src/runtime/components/interaction-form/input-slot.tsx
4979
- import { Fragment as Fragment8, jsx as jsx12 } from "react/jsx-runtime";
4335
+ import { Fragment as Fragment7, jsx as jsx9 } from "react/jsx-runtime";
4980
4336
  function createInteractionInputSlot({
4981
4337
  descriptor,
4982
4338
  input,
@@ -5024,7 +4380,7 @@ function createInteractionInputSlot({
5024
4380
  intent: selection?.mode === "many" ? "toggle" : "select"
5025
4381
  }).semanticEffects
5026
4382
  });
5027
- return /* @__PURE__ */ jsx12(
4383
+ return /* @__PURE__ */ jsx9(
5028
4384
  "button",
5029
4385
  {
5030
4386
  type: "button",
@@ -5050,7 +4406,7 @@ function createInteractionInputSlot({
5050
4406
  );
5051
4407
  };
5052
4408
  return {
5053
- Field: () => /* @__PURE__ */ jsx12(
4409
+ Field: () => /* @__PURE__ */ jsx9(
5054
4410
  DefaultInteractionField,
5055
4411
  {
5056
4412
  descriptor,
@@ -5088,7 +4444,7 @@ function createInteractionInputSlot({
5088
4444
  intent: "select"
5089
4445
  }).semanticEffects : void 0
5090
4446
  });
5091
- return /* @__PURE__ */ jsx12(
4447
+ return /* @__PURE__ */ jsx9(
5092
4448
  "button",
5093
4449
  {
5094
4450
  type: "button",
@@ -5111,24 +4467,24 @@ function createInteractionInputSlot({
5111
4467
  Cards: ({ children }) => {
5112
4468
  const domain = resolvedInput.domain;
5113
4469
  const targets = isResolvedTargetDomain(domain) ? domain.eligibleTargets : [];
5114
- return /* @__PURE__ */ jsx12(Fragment8, { children: targets.map((id) => children({ id })) });
4470
+ return /* @__PURE__ */ jsx9(Fragment7, { children: targets.map((id) => children({ id })) });
5115
4471
  },
5116
4472
  Options: ({ children }) => {
5117
4473
  const domain = resolvedInput.domain;
5118
4474
  const choices = domain.type === "choice" || domain.type === "choiceList" ? domain.choices ?? [] : [];
5119
- return /* @__PURE__ */ jsx12(Fragment8, { children: choices.map((choice) => children(choice)) });
4475
+ return /* @__PURE__ */ jsx9(Fragment7, { children: choices.map((choice) => children(choice)) });
5120
4476
  },
5121
- Value: ({ children }) => /* @__PURE__ */ jsx12(Fragment8, { children: children(value) }),
5122
- Label: ({ children }) => /* @__PURE__ */ jsx12(Fragment8, { children: children ?? labelForInput(resolvedInput) }),
4477
+ Value: ({ children }) => /* @__PURE__ */ jsx9(Fragment7, { children: children(value) }),
4478
+ Label: ({ children }) => /* @__PURE__ */ jsx9(Fragment7, { children: children ?? labelForInput(resolvedInput) }),
5123
4479
  Message: ({ children }) => {
5124
4480
  const message = children ?? errors[0] ?? (missing ? "Required" : null);
5125
- return message ? /* @__PURE__ */ jsx12("span", { role: "alert", "data-dreamboard-interaction-message-slot": "", children: message }) : null;
4481
+ return message ? /* @__PURE__ */ jsx9("span", { role: "alert", "data-dreamboard-interaction-message-slot": "", children: message }) : null;
5126
4482
  }
5127
4483
  };
5128
4484
  }
5129
4485
 
5130
4486
  // src/runtime/components/interaction-form/InteractionForm.tsx
5131
- import { Fragment as Fragment9, jsx as jsx13, jsxs as jsxs4 } from "react/jsx-runtime";
4487
+ import { Fragment as Fragment8, jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
5132
4488
  function InteractionForm({
5133
4489
  descriptor,
5134
4490
  handle,
@@ -5152,14 +4508,14 @@ function InteractionForm({
5152
4508
  const fallbackLabel = interactionLabel(descriptor);
5153
4509
  const formId = useId2();
5154
4510
  useChromeSuppression(formId, true);
5155
- const [pending, setPending] = useState4(false);
5156
- const [validation, setValidation] = useState4(
4511
+ const [pending, setPending] = useState(false);
4512
+ const [validation, setValidation] = useState(
5157
4513
  null
5158
4514
  );
5159
- const [formError, setFormError] = useState4(null);
5160
- const [accordionOpen, setAccordionOpen] = useState4(defaultOpen);
5161
- const hidden = useMemo12(() => new Set(hiddenFields ?? []), [hiddenFields]);
5162
- const visibleInputs = useMemo12(() => {
4515
+ const [formError, setFormError] = useState(null);
4516
+ const [accordionOpen, setAccordionOpen] = useState(defaultOpen);
4517
+ const hidden = useMemo10(() => new Set(hiddenFields ?? []), [hiddenFields]);
4518
+ const visibleInputs = useMemo10(() => {
5163
4519
  if (inputs) {
5164
4520
  const rendered = new Set(Object.keys(inputs));
5165
4521
  return resolveInteractionInputs(
@@ -5223,7 +4579,7 @@ function InteractionForm({
5223
4579
  actuatorId: "submit",
5224
4580
  semanticEffects: submitMetadata.semanticEffects
5225
4581
  });
5226
- useEffect6(() => {
4582
+ useEffect3(() => {
5227
4583
  setAccordionOpen(defaultOpen);
5228
4584
  }, [defaultOpen, descriptor.interactionId]);
5229
4585
  const containerStyle = {
@@ -5261,8 +4617,8 @@ function InteractionForm({
5261
4617
  setPending(false);
5262
4618
  }
5263
4619
  };
5264
- const header = /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
5265
- /* @__PURE__ */ jsx13(
4620
+ const header = /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
4621
+ /* @__PURE__ */ jsx10(
5266
4622
  "strong",
5267
4623
  {
5268
4624
  style: {
@@ -5273,7 +4629,7 @@ function InteractionForm({
5273
4629
  children: title ?? fallbackLabel
5274
4630
  }
5275
4631
  ),
5276
- description ? /* @__PURE__ */ jsx13(
4632
+ description ? /* @__PURE__ */ jsx10(
5277
4633
  "span",
5278
4634
  {
5279
4635
  style: {
@@ -5284,7 +4640,7 @@ function InteractionForm({
5284
4640
  }
5285
4641
  ) : null
5286
4642
  ] });
5287
- const fieldsContent = visibleInputs.length > 0 ? /* @__PURE__ */ jsx13(
4643
+ const fieldsContent = visibleInputs.length > 0 ? /* @__PURE__ */ jsx10(
5288
4644
  "div",
5289
4645
  {
5290
4646
  style: {
@@ -5295,7 +4651,7 @@ function InteractionForm({
5295
4651
  children: visibleInputs.map((input) => {
5296
4652
  const key = input.key;
5297
4653
  const inputRenderer = inputs?.[key];
5298
- return /* @__PURE__ */ jsx13(
4654
+ return /* @__PURE__ */ jsx10(
5299
4655
  InteractionField,
5300
4656
  {
5301
4657
  descriptor,
@@ -5325,7 +4681,7 @@ function InteractionForm({
5325
4681
  `InteractionForm '${descriptor.interactionKey}' has required inputs that cannot be rendered by the default form. Provide renderFields, select on a surface, or use a default-renderable input domain.`
5326
4682
  );
5327
4683
  }
5328
- const formErrorContent = formErrors.length > 0 ? /* @__PURE__ */ jsx13(
4684
+ const formErrorContent = formErrors.length > 0 ? /* @__PURE__ */ jsx10(
5329
4685
  "div",
5330
4686
  {
5331
4687
  role: "alert",
@@ -5336,10 +4692,10 @@ function InteractionForm({
5336
4692
  color: theme.semantic.intent.danger.solid,
5337
4693
  fontSize: theme.typography.fontSize.sm
5338
4694
  },
5339
- children: formErrors.map((error) => /* @__PURE__ */ jsx13("span", { children: error }, error))
4695
+ children: formErrors.map((error) => /* @__PURE__ */ jsx10("span", { children: error }, error))
5340
4696
  }
5341
4697
  ) : null;
5342
- const actions = /* @__PURE__ */ jsxs4(
4698
+ const actions = /* @__PURE__ */ jsxs3(
5343
4699
  "div",
5344
4700
  {
5345
4701
  style: {
@@ -5348,7 +4704,7 @@ function InteractionForm({
5348
4704
  justifyContent: "flex-end"
5349
4705
  },
5350
4706
  children: [
5351
- onCancel ? /* @__PURE__ */ jsx13(
4707
+ onCancel ? /* @__PURE__ */ jsx10(
5352
4708
  ThemedButton,
5353
4709
  {
5354
4710
  type: "button",
@@ -5362,7 +4718,7 @@ function InteractionForm({
5362
4718
  ) : null,
5363
4719
  renderSubmit ? renderSubmit(
5364
4720
  {
5365
- Button: ({ children, ...buttonProps }) => /* @__PURE__ */ jsx13(
4721
+ Button: ({ children, ...buttonProps }) => /* @__PURE__ */ jsx10(
5366
4722
  ThemedButton,
5367
4723
  {
5368
4724
  type: "submit",
@@ -5377,7 +4733,7 @@ function InteractionForm({
5377
4733
  )
5378
4734
  },
5379
4735
  descriptor
5380
- ) : /* @__PURE__ */ jsx13(
4736
+ ) : /* @__PURE__ */ jsx10(
5381
4737
  ThemedButton,
5382
4738
  {
5383
4739
  type: "submit",
@@ -5392,12 +4748,12 @@ function InteractionForm({
5392
4748
  ]
5393
4749
  }
5394
4750
  );
5395
- const body = /* @__PURE__ */ jsxs4(Fragment9, { children: [
4751
+ const body = /* @__PURE__ */ jsxs3(Fragment8, { children: [
5396
4752
  fieldsContent,
5397
4753
  formErrorContent,
5398
4754
  actions
5399
4755
  ] });
5400
- return /* @__PURE__ */ jsx13(
4756
+ return /* @__PURE__ */ jsx10(
5401
4757
  "form",
5402
4758
  {
5403
4759
  "data-interaction-form": true,
@@ -5405,15 +4761,15 @@ function InteractionForm({
5405
4761
  onSubmit: (event) => void submit(event),
5406
4762
  style: containerStyle,
5407
4763
  ...rootBrowserAttributes,
5408
- children: useAccordion ? /* @__PURE__ */ jsx13(
4764
+ children: useAccordion ? /* @__PURE__ */ jsx10(
5409
4765
  AccordionPrimitive.Root,
5410
4766
  {
5411
4767
  type: "single",
5412
4768
  collapsible: true,
5413
4769
  value: accordionOpen ? "fields" : void 0,
5414
4770
  onValueChange: (value) => setAccordionOpen(value === "fields"),
5415
- children: /* @__PURE__ */ jsxs4(AccordionPrimitive.Item, { value: "fields", children: [
5416
- /* @__PURE__ */ jsx13(AccordionPrimitive.Header, { style: { margin: 0 }, children: /* @__PURE__ */ jsxs4(
4771
+ children: /* @__PURE__ */ jsxs3(AccordionPrimitive.Item, { value: "fields", children: [
4772
+ /* @__PURE__ */ jsx10(AccordionPrimitive.Header, { style: { margin: 0 }, children: /* @__PURE__ */ jsxs3(
5417
4773
  AccordionPrimitive.Trigger,
5418
4774
  {
5419
4775
  ...armBrowserAttributes,
@@ -5434,12 +4790,12 @@ function InteractionForm({
5434
4790
  width: "100%"
5435
4791
  },
5436
4792
  children: [
5437
- /* @__PURE__ */ jsx13("span", { children: title ?? fallbackLabel }),
5438
- /* @__PURE__ */ jsx13("span", { "aria-hidden": true, children: accordionOpen ? "\u2212" : "+" })
4793
+ /* @__PURE__ */ jsx10("span", { children: title ?? fallbackLabel }),
4794
+ /* @__PURE__ */ jsx10("span", { "aria-hidden": true, children: accordionOpen ? "\u2212" : "+" })
5439
4795
  ]
5440
4796
  }
5441
4797
  ) }),
5442
- /* @__PURE__ */ jsx13(AccordionPrimitive.Content, { children: /* @__PURE__ */ jsxs4(
4798
+ /* @__PURE__ */ jsx10(AccordionPrimitive.Content, { children: /* @__PURE__ */ jsxs3(
5443
4799
  "div",
5444
4800
  {
5445
4801
  style: {
@@ -5449,7 +4805,7 @@ function InteractionForm({
5449
4805
  marginTop: theme.space[2]
5450
4806
  },
5451
4807
  children: [
5452
- description ? /* @__PURE__ */ jsx13(
4808
+ description ? /* @__PURE__ */ jsx10(
5453
4809
  "span",
5454
4810
  {
5455
4811
  style: {
@@ -5465,7 +4821,7 @@ function InteractionForm({
5465
4821
  ) })
5466
4822
  ] })
5467
4823
  }
5468
- ) : /* @__PURE__ */ jsxs4(Fragment9, { children: [
4824
+ ) : /* @__PURE__ */ jsxs3(Fragment8, { children: [
5469
4825
  header,
5470
4826
  body
5471
4827
  ] })
@@ -5474,7 +4830,7 @@ function InteractionForm({
5474
4830
  }
5475
4831
 
5476
4832
  // src/runtime/primitives/interaction/form.tsx
5477
- import { jsx as jsx14 } from "react/jsx-runtime";
4833
+ import { jsx as jsx11 } from "react/jsx-runtime";
5478
4834
  function castInteractionHandle(handle) {
5479
4835
  return handle;
5480
4836
  }
@@ -5486,7 +4842,7 @@ function BoundInteractionForm({
5486
4842
  handle,
5487
4843
  ...props
5488
4844
  }) {
5489
- return /* @__PURE__ */ jsx14(
4845
+ return /* @__PURE__ */ jsx11(
5490
4846
  InteractionForm,
5491
4847
  {
5492
4848
  descriptor,
@@ -5498,7 +4854,7 @@ function BoundInteractionForm({
5498
4854
  function InteractionFormPrimitive(props) {
5499
4855
  const { descriptor, handle } = useInteractionPrimitiveContext();
5500
4856
  if (!descriptor || !handle) return null;
5501
- return /* @__PURE__ */ jsx14(
4857
+ return /* @__PURE__ */ jsx11(
5502
4858
  BoundInteractionForm,
5503
4859
  {
5504
4860
  descriptor,
@@ -5510,7 +4866,7 @@ function InteractionFormPrimitive(props) {
5510
4866
  function InteractionFieldPrimitive({ input, ...props }) {
5511
4867
  const { descriptor, handle } = useInteractionPrimitiveContext();
5512
4868
  if (!descriptor || !handle) return null;
5513
- return /* @__PURE__ */ jsx14(
4869
+ return /* @__PURE__ */ jsx11(
5514
4870
  InteractionField,
5515
4871
  {
5516
4872
  descriptor,
@@ -5522,12 +4878,12 @@ function InteractionFieldPrimitive({ input, ...props }) {
5522
4878
  }
5523
4879
 
5524
4880
  // src/runtime/primitives/interaction/state.tsx
5525
- import { Fragment as Fragment10, jsx as jsx15 } from "react/jsx-runtime";
4881
+ import { Fragment as Fragment9, jsx as jsx12 } from "react/jsx-runtime";
5526
4882
  function InteractionState({ children, unavailable }) {
5527
4883
  const { interaction, descriptor, handle } = useInteractionPrimitiveContext();
5528
4884
  const store = useInteractionUiStore();
5529
4885
  if (!descriptor || !handle) {
5530
- return /* @__PURE__ */ jsx15(Fragment10, { children: unavailable });
4886
+ return /* @__PURE__ */ jsx12(Fragment9, { children: unavailable });
5531
4887
  }
5532
4888
  const typedHandle = castInteractionHandle(handle);
5533
4889
  const liveDraft = castInteractionDraft(
@@ -5535,7 +4891,7 @@ function InteractionState({ children, unavailable }) {
5535
4891
  );
5536
4892
  const inputKeys = descriptor.inputs.map((input) => input.key);
5537
4893
  const readiness = getInteractionDraftReadiness(descriptor, liveDraft);
5538
- return /* @__PURE__ */ jsx15(Fragment10, { children: children({
4894
+ return /* @__PURE__ */ jsx12(Fragment9, { children: children({
5539
4895
  interaction,
5540
4896
  descriptor,
5541
4897
  handle: typedHandle,
@@ -5554,25 +4910,25 @@ function InteractionState({ children, unavailable }) {
5554
4910
  }
5555
4911
 
5556
4912
  // src/runtime/primitives/interaction/routes.tsx
5557
- import { Fragment as Fragment11, jsx as jsx16 } from "react/jsx-runtime";
4913
+ import { Fragment as Fragment10, jsx as jsx13 } from "react/jsx-runtime";
5558
4914
  function InteractionSwitch({
5559
4915
  interaction,
5560
4916
  routes,
5561
4917
  fallback = null
5562
4918
  }) {
5563
4919
  const pendingInteractionKey = usePendingInteractionKey();
5564
- const descriptors = usePluginState(
5565
- (state) => state.gameplay.availableInteractions
4920
+ const descriptors = useAuthoredPluginGameplayFrameSelector(
4921
+ (frame) => frame.availableInteractions
5566
4922
  );
5567
4923
  const routedInteraction = interaction ?? pendingInteractionKey;
5568
4924
  const descriptor = routedInteraction ? descriptors.find(
5569
4925
  (candidate) => candidate.interactionKey === routedInteraction
5570
4926
  ) : void 0;
5571
- if (!descriptor) return /* @__PURE__ */ jsx16(Fragment11, { children: fallback });
4927
+ if (!descriptor) return /* @__PURE__ */ jsx13(Fragment10, { children: fallback });
5572
4928
  const route = routes[descriptor.interactionKey] ?? null;
5573
- if (!route) return /* @__PURE__ */ jsx16(Fragment11, { children: fallback });
4929
+ if (!route) return /* @__PURE__ */ jsx13(Fragment10, { children: fallback });
5574
4930
  const typedInteraction = descriptor.interactionKey;
5575
- return /* @__PURE__ */ jsx16(InteractionRoot, { interaction: typedInteraction, children: route({
4931
+ return /* @__PURE__ */ jsx13(InteractionRoot, { interaction: typedInteraction, children: route({
5576
4932
  interaction: typedInteraction,
5577
4933
  descriptor
5578
4934
  }) });
@@ -5593,10 +4949,10 @@ function InteractionRoutes({
5593
4949
  includeUnavailable = false
5594
4950
  }) {
5595
4951
  const runtime = useRuntimeContext();
5596
- const descriptors = usePluginState(
5597
- (state) => state.gameplay.availableInteractions
4952
+ const descriptors = useAuthoredPluginGameplayFrameSelector(
4953
+ (frame) => frame.availableInteractions
5598
4954
  );
5599
- if (descriptors.length === 0) return /* @__PURE__ */ jsx16(Fragment11, { children: fallback });
4955
+ if (descriptors.length === 0) return /* @__PURE__ */ jsx13(Fragment10, { children: fallback });
5600
4956
  const routedDescriptors = descriptors.filter(
5601
4957
  (descriptor) => includeUnavailable || isInteractionAvailable(descriptor)
5602
4958
  ).map((descriptor) => {
@@ -5620,20 +4976,20 @@ function InteractionRoutes({
5620
4976
  }
5621
4977
  return descriptor;
5622
4978
  });
5623
- if (routedDescriptors.length === 0) return /* @__PURE__ */ jsx16(Fragment11, { children: fallback });
4979
+ if (routedDescriptors.length === 0) return /* @__PURE__ */ jsx13(Fragment10, { children: fallback });
5624
4980
  return null;
5625
4981
  }
5626
4982
 
5627
4983
  // src/runtime/primitives/interaction/dialog.tsx
5628
- import { useEffect as useEffect7, useMemo as useMemo14, useRef as useRef4 } from "react";
4984
+ import { useEffect as useEffect4, useMemo as useMemo12, useRef as useRef3 } from "react";
5629
4985
 
5630
4986
  // src/ui/primitives/dialog-lifecycle.ts
5631
- import { useCallback as useCallback5, useMemo as useMemo13, useState as useState5 } from "react";
4987
+ import { useCallback as useCallback5, useMemo as useMemo11, useState as useState2 } from "react";
5632
4988
  function useDialogLifecycle({
5633
4989
  defaultOpen = true,
5634
4990
  onStateChange
5635
4991
  }) {
5636
- const [state, setState] = useState5(
4992
+ const [state, setState] = useState2(
5637
4993
  defaultOpen ? "open" : "minimized"
5638
4994
  );
5639
4995
  const updateState = useCallback5(
@@ -5652,7 +5008,7 @@ function useDialogLifecycle({
5652
5008
  },
5653
5009
  [updateState]
5654
5010
  );
5655
- return useMemo13(
5011
+ return useMemo11(
5656
5012
  () => ({
5657
5013
  state,
5658
5014
  open: state === "open",
@@ -5668,7 +5024,7 @@ function useDialogLifecycle({
5668
5024
  }
5669
5025
 
5670
5026
  // src/runtime/primitives/interaction/dialog.tsx
5671
- import { Fragment as Fragment12, jsx as jsx17 } from "react/jsx-runtime";
5027
+ import { Fragment as Fragment11, jsx as jsx14 } from "react/jsx-runtime";
5672
5028
  function InteractionDialog({
5673
5029
  defaultOpen = false,
5674
5030
  onStateChange,
@@ -5678,8 +5034,8 @@ function InteractionDialog({
5678
5034
  const pendingInteractionKey = usePendingInteractionKey();
5679
5035
  const pendingInteractionRevision = usePendingInteractionRevision();
5680
5036
  const lifecycle = useDialogLifecycle({ defaultOpen, onStateChange });
5681
- const restoredRevisionRef = useRef4(null);
5682
- useEffect7(() => {
5037
+ const restoredRevisionRef = useRef3(null);
5038
+ useEffect4(() => {
5683
5039
  if (pendingInteractionKey === interaction && restoredRevisionRef.current !== pendingInteractionRevision) {
5684
5040
  restoredRevisionRef.current = pendingInteractionRevision;
5685
5041
  lifecycle.restore();
@@ -5690,14 +5046,14 @@ function InteractionDialog({
5690
5046
  pendingInteractionKey,
5691
5047
  pendingInteractionRevision
5692
5048
  ]);
5693
- const renderState = useMemo14(
5049
+ const renderState = useMemo12(
5694
5050
  () => ({
5695
5051
  interaction,
5696
5052
  ...lifecycle
5697
5053
  }),
5698
5054
  [interaction, lifecycle]
5699
5055
  );
5700
- return /* @__PURE__ */ jsx17(Fragment12, { children: children(renderState) });
5056
+ return /* @__PURE__ */ jsx14(Fragment11, { children: children(renderState) });
5701
5057
  }
5702
5058
 
5703
5059
  // src/runtime/primitives/interaction/controls.tsx
@@ -5905,12 +5261,12 @@ function InteractionCardInput({
5905
5261
  const zoneContext = useOptionalZonePrimitiveContext();
5906
5262
  const cardId = zoneCard?.cardId ?? unsafeCardId;
5907
5263
  const validationZone = zoneCard?.zone ?? zoneContext?.zone;
5908
- const zoneSnapshot = usePluginState(
5909
- (state) => validationZone ? state.gameplay.zones[validationZone] : void 0
5264
+ const zoneSnapshot = useAuthoredPluginGameplayFrameSelector(
5265
+ (frame) => validationZone ? frame.zones[validationZone] : void 0
5910
5266
  );
5911
- const cardDescriptor = usePluginState((state) => {
5267
+ const cardDescriptor = useAuthoredPluginGameplayFrameSelector((frame) => {
5912
5268
  if (!cardId || !validationZone) return void 0;
5913
- return state.gameplay.zones[validationZone]?.playableByCardId[cardId]?.find(
5269
+ return frame.zones[validationZone]?.playableByCardId[cardId]?.find(
5914
5270
  (candidate) => candidate.interactionKey === descriptor?.interactionKey && candidate.inputs.some((candidateInput) => candidateInput.key === input)
5915
5271
  );
5916
5272
  });
@@ -6113,7 +5469,7 @@ var Interaction = {
6113
5469
  };
6114
5470
 
6115
5471
  // src/runtime/primitives/phase.tsx
6116
- import { Fragment as Fragment13, jsx as jsx18 } from "react/jsx-runtime";
5472
+ import { Fragment as Fragment12, jsx as jsx15 } from "react/jsx-runtime";
6117
5473
  function hasRoute(routes, phase) {
6118
5474
  return Object.prototype.hasOwnProperty.call(routes, phase);
6119
5475
  }
@@ -6124,11 +5480,13 @@ function PhaseSwitch({
6124
5480
  routes,
6125
5481
  fallback
6126
5482
  }) {
6127
- const phase = usePluginState((state) => state.gameplay.currentPhase);
5483
+ const phase = useAuthoredPluginGameplayFrameSelector(
5484
+ (frame) => frame.flow.currentPhase
5485
+ );
6128
5486
  if (phase && hasRoute(routes, phase)) {
6129
- return /* @__PURE__ */ jsx18(Fragment13, { children: routes[phase]() });
5487
+ return /* @__PURE__ */ jsx15(Fragment12, { children: routes[phase]() });
6130
5488
  }
6131
- return /* @__PURE__ */ jsx18(Fragment13, { children: renderFallback(fallback, phase) });
5489
+ return /* @__PURE__ */ jsx15(Fragment12, { children: renderFallback(fallback, phase) });
6132
5490
  }
6133
5491
  var Phase = {
6134
5492
  Switch: PhaseSwitch
@@ -6136,17 +5494,17 @@ var Phase = {
6136
5494
 
6137
5495
  // src/runtime/primitives/player-roster.tsx
6138
5496
  import {
6139
- createContext as createContext10,
6140
- Fragment as Fragment14,
6141
- useContext as useContext10,
6142
- useMemo as useMemo15
5497
+ createContext as createContext6,
5498
+ Fragment as Fragment13,
5499
+ useContext as useContext6,
5500
+ useMemo as useMemo13
6143
5501
  } from "react";
6144
- import { Fragment as Fragment15, jsx as jsx19, jsxs as jsxs5 } from "react/jsx-runtime";
6145
- var PlayerRosterContext = createContext10(
5502
+ import { Fragment as Fragment14, jsx as jsx16, jsxs as jsxs4 } from "react/jsx-runtime";
5503
+ var PlayerRosterContext = createContext6(
6146
5504
  null
6147
5505
  );
6148
5506
  function usePlayerRosterContext() {
6149
- const value = useContext10(PlayerRosterContext);
5507
+ const value = useContext6(PlayerRosterContext);
6150
5508
  if (!value) {
6151
5509
  throw new Error(
6152
5510
  "PlayerRoster primitives must be rendered inside <PlayerRoster.Root>."
@@ -6171,8 +5529,8 @@ function PlayerRosterRoot({
6171
5529
  const playerInfo = usePlayerInfo();
6172
5530
  const activePlayers = useActivePlayers();
6173
5531
  const turnOrder = usePlayerTurnOrder();
6174
- const { controllingPlayerId, controllablePlayerIds } = usePluginSession();
6175
- const players = useMemo15(() => {
5532
+ const { controllingPlayerId } = usePluginSession();
5533
+ const players = useMemo13(() => {
6176
5534
  const orderedPlayerIds = order === "self-first" && controllingPlayerId ? [
6177
5535
  ...turnOrder.filter((pid) => pid === controllingPlayerId),
6178
5536
  ...turnOrder.filter((pid) => pid !== controllingPlayerId)
@@ -6180,7 +5538,6 @@ function PlayerRosterRoot({
6180
5538
  return orderedPlayerIds.map((playerId, index) => {
6181
5539
  const player = playerInfo.get(playerId);
6182
5540
  const isCurrentPlayer = playerId === controllingPlayerId;
6183
- const isControllable = controllablePlayerIds.includes(playerId);
6184
5541
  const resolvedScoreLabel = typeof scoreLabel === "function" ? scoreLabel(playerId) : scoreLabel;
6185
5542
  return {
6186
5543
  playerId,
@@ -6189,8 +5546,6 @@ function PlayerRosterRoot({
6189
5546
  index,
6190
5547
  isActive: activePlayers.includes(playerId),
6191
5548
  isCurrentPlayer,
6192
- isControllable,
6193
- canSwitchToPlayer: controllablePlayerIds.length > 1 && isControllable && !isCurrentPlayer,
6194
5549
  score: score?.(playerId),
6195
5550
  scoreLabel: resolvedScoreLabel,
6196
5551
  badges: projectBadges(badges, playerId),
@@ -6204,7 +5559,6 @@ function PlayerRosterRoot({
6204
5559
  }, [
6205
5560
  activePlayers,
6206
5561
  badges,
6207
- controllablePlayerIds,
6208
5562
  controllingPlayerId,
6209
5563
  include,
6210
5564
  metadata,
@@ -6214,11 +5568,11 @@ function PlayerRosterRoot({
6214
5568
  scoreLabel,
6215
5569
  turnOrder
6216
5570
  ]);
6217
- const value = useMemo15(
5571
+ const value = useMemo13(
6218
5572
  () => ({ players }),
6219
5573
  [players]
6220
5574
  );
6221
- return /* @__PURE__ */ jsx19(PlayerRosterContext.Provider, { value, children });
5575
+ return /* @__PURE__ */ jsx16(PlayerRosterContext.Provider, { value, children });
6222
5576
  }
6223
5577
  function PlayerRosterList({
6224
5578
  children,
@@ -6228,39 +5582,13 @@ function PlayerRosterList({
6228
5582
  return renderPrimitive("div", {
6229
5583
  ...props,
6230
5584
  "data-dreamboard-player-roster-list": "",
6231
- children: players.map((player) => /* @__PURE__ */ jsx19(Fragment14, { children: children ? children(player) : /* @__PURE__ */ jsx19(PlayerRosterName, { player }) }, player.playerId))
5585
+ children: players.map((player) => /* @__PURE__ */ jsx16(Fragment13, { children: children ? children(player) : /* @__PURE__ */ jsx16(PlayerRosterName, { player }) }, player.playerId))
6232
5586
  });
6233
5587
  }
6234
5588
  function PlayerRosterEmpty({ children }) {
6235
5589
  const { players } = usePlayerRosterContext();
6236
5590
  if (players.length > 0) return null;
6237
- return /* @__PURE__ */ jsx19(Fragment15, { children });
6238
- }
6239
- function PlayerRosterSwitchButton({
6240
- player,
6241
- disabled,
6242
- onClick,
6243
- ...props
6244
- }) {
6245
- const { switchPlayer } = usePluginActions();
6246
- const isDisabled = disabled === true || !player.canSwitchToPlayer;
6247
- return renderPrimitive("button", {
6248
- type: "button",
6249
- ...props,
6250
- disabled: isDisabled,
6251
- "aria-current": player.isCurrentPlayer ? "true" : void 0,
6252
- "aria-disabled": isDisabled,
6253
- "data-dreamboard-player-roster-switch": "",
6254
- "data-player-id": player.playerId,
6255
- "data-active": player.isActive || void 0,
6256
- "data-current": player.isCurrentPlayer || void 0,
6257
- "data-controllable": player.isControllable || void 0,
6258
- "data-switchable": player.canSwitchToPlayer || void 0,
6259
- "data-disabled": isDisabled || void 0,
6260
- onClick: composeEventHandlers(onClick, () => {
6261
- if (!isDisabled) switchPlayer(player.playerId);
6262
- })
6263
- });
5591
+ return /* @__PURE__ */ jsx16(Fragment14, { children });
6264
5592
  }
6265
5593
  function PlayerRosterName({
6266
5594
  player,
@@ -6295,7 +5623,7 @@ function PlayerRosterBadges({
6295
5623
  return renderPrimitive("span", {
6296
5624
  ...props,
6297
5625
  "data-dreamboard-player-roster-badges": "",
6298
- children: children ?? player.badges.map((badge) => /* @__PURE__ */ jsxs5(
5626
+ children: children ?? player.badges.map((badge) => /* @__PURE__ */ jsxs4(
6299
5627
  "span",
6300
5628
  {
6301
5629
  "data-dreamboard-player-roster-badge": "",
@@ -6314,7 +5642,6 @@ var PlayerRoster = {
6314
5642
  Root: PlayerRosterRoot,
6315
5643
  List: PlayerRosterList,
6316
5644
  Empty: PlayerRosterEmpty,
6317
- SwitchButton: PlayerRosterSwitchButton,
6318
5645
  Name: PlayerRosterName,
6319
5646
  Score: PlayerRosterScore,
6320
5647
  Badges: PlayerRosterBadges
@@ -6322,16 +5649,16 @@ var PlayerRoster = {
6322
5649
 
6323
5650
  // src/runtime/primitives/prompt.tsx
6324
5651
  import {
6325
- Fragment as Fragment16,
6326
- createContext as createContext11,
6327
- useContext as useContext11,
6328
- useMemo as useMemo16
5652
+ Fragment as Fragment15,
5653
+ createContext as createContext7,
5654
+ useContext as useContext7,
5655
+ useMemo as useMemo14
6329
5656
  } from "react";
6330
5657
 
6331
5658
  // src/runtime/hooks/useSeatInbox.ts
6332
5659
  function useSeatInbox() {
6333
- const interactions = usePluginState(
6334
- (s) => s.gameplay.availableInteractions ?? []
5660
+ const interactions = usePluginGameplayFrameSelector(
5661
+ (frame) => frame.availableInteractions ?? []
6335
5662
  );
6336
5663
  const bySurface = {};
6337
5664
  const prompts = [];
@@ -6362,21 +5689,21 @@ function bucketForDescriptor(descriptor) {
6362
5689
  }
6363
5690
 
6364
5691
  // src/runtime/primitives/prompt.tsx
6365
- import { Fragment as Fragment17, jsx as jsx20 } from "react/jsx-runtime";
5692
+ import { Fragment as Fragment16, jsx as jsx17 } from "react/jsx-runtime";
6366
5693
  function PromptRoot(props) {
6367
- return /* @__PURE__ */ jsx20(InteractionRoot, { ...props });
5694
+ return /* @__PURE__ */ jsx17(InteractionRoot, { ...props });
6368
5695
  }
6369
5696
  function PromptTitle(props) {
6370
5697
  const { descriptor } = useInteractionPrimitiveContext();
6371
5698
  const context = descriptor?.kind === "prompt" ? descriptor.context : void 0;
6372
- return /* @__PURE__ */ jsx20(InteractionLabel, { ...props, children: props.children ?? context?.title ?? (descriptor ? interactionLabel(descriptor) : void 0) });
5699
+ return /* @__PURE__ */ jsx17(InteractionLabel, { ...props, children: props.children ?? context?.title ?? (descriptor ? interactionLabel(descriptor) : void 0) });
6373
5700
  }
6374
5701
  function PromptMessage(props) {
6375
5702
  const { descriptor } = useInteractionPrimitiveContext();
6376
5703
  const context = descriptor?.kind === "prompt" ? descriptor.context : void 0;
6377
5704
  const message = props.children ?? (typeof context?.payload?.message === "string" ? context.payload.message : void 0);
6378
5705
  if (!message) return null;
6379
- return /* @__PURE__ */ jsx20(InteractionDescription, { ...props, children: message });
5706
+ return /* @__PURE__ */ jsx17(InteractionDescription, { ...props, children: message });
6380
5707
  }
6381
5708
  function PromptOption({
6382
5709
  value,
@@ -6427,7 +5754,7 @@ function PromptOption({
6427
5754
  function PromptOptions({ children }) {
6428
5755
  const { descriptor } = useInteractionPrimitiveContext();
6429
5756
  const options = descriptor?.kind === "prompt" ? descriptor.context.options ?? [] : [];
6430
- return /* @__PURE__ */ jsx20(Fragment17, { children: options.map((option) => /* @__PURE__ */ jsx20(Fragment16, { children: children(option) }, option.id)) });
5757
+ return /* @__PURE__ */ jsx17(Fragment16, { children: options.map((option) => /* @__PURE__ */ jsx17(Fragment15, { children: children(option) }, option.id)) });
6431
5758
  }
6432
5759
  function PromptDialog({
6433
5760
  prompt,
@@ -6436,18 +5763,18 @@ function PromptDialog({
6436
5763
  children
6437
5764
  }) {
6438
5765
  const lifecycle = useDialogLifecycle({ defaultOpen, onStateChange });
6439
- const renderState = useMemo16(
5766
+ const renderState = useMemo14(
6440
5767
  () => ({
6441
5768
  prompt,
6442
5769
  ...lifecycle
6443
5770
  }),
6444
5771
  [lifecycle, prompt]
6445
5772
  );
6446
- return /* @__PURE__ */ jsx20(Fragment17, { children: children(renderState) });
5773
+ return /* @__PURE__ */ jsx17(Fragment16, { children: children(renderState) });
6447
5774
  }
6448
- var PromptInboxContext = createContext11(null);
5775
+ var PromptInboxContext = createContext7(null);
6449
5776
  function usePromptInboxContext() {
6450
- const value = useContext11(PromptInboxContext);
5777
+ const value = useContext7(PromptInboxContext);
6451
5778
  if (!value) {
6452
5779
  throw new Error(
6453
5780
  "PromptInbox primitives must be rendered inside <PromptInbox.Root>."
@@ -6457,16 +5784,16 @@ function usePromptInboxContext() {
6457
5784
  }
6458
5785
  function PromptInboxRoot({ children }) {
6459
5786
  const inbox = useSeatInbox();
6460
- return /* @__PURE__ */ jsx20(PromptInboxContext.Provider, { value: { prompts: inbox.prompts }, children });
5787
+ return /* @__PURE__ */ jsx17(PromptInboxContext.Provider, { value: { prompts: inbox.prompts }, children });
6461
5788
  }
6462
5789
  function PromptInboxEmpty({ children }) {
6463
5790
  const { prompts } = usePromptInboxContext();
6464
5791
  if (prompts.length > 0) return null;
6465
- return /* @__PURE__ */ jsx20(Fragment17, { children });
5792
+ return /* @__PURE__ */ jsx17(Fragment16, { children });
6466
5793
  }
6467
5794
  function PromptInboxItems({ children }) {
6468
5795
  const { prompts } = usePromptInboxContext();
6469
- return /* @__PURE__ */ jsx20(Fragment17, { children: prompts.map((prompt) => children(prompt)) });
5796
+ return /* @__PURE__ */ jsx17(Fragment16, { children: prompts.map((prompt) => children(prompt)) });
6470
5797
  }
6471
5798
  var Prompt = {
6472
5799
  Root: PromptRoot,
@@ -6483,9 +5810,9 @@ var PromptInbox = {
6483
5810
  };
6484
5811
 
6485
5812
  // src/runtime/primitives/dice.tsx
6486
- import { createContext as createContext12, useContext as useContext12 } from "react";
6487
- import { jsx as jsx21 } from "react/jsx-runtime";
6488
- var DiceContext = createContext12(null);
5813
+ import { createContext as createContext8, useContext as useContext8 } from "react";
5814
+ import { jsx as jsx18 } from "react/jsx-runtime";
5815
+ var DiceContext = createContext8(null);
6489
5816
  function normalizeDiceState({
6490
5817
  values,
6491
5818
  count = 2
@@ -6504,10 +5831,10 @@ function normalizeDiceState({
6504
5831
  };
6505
5832
  }
6506
5833
  function DiceRoot({ values, count, children }) {
6507
- return /* @__PURE__ */ jsx21(DiceContext.Provider, { value: normalizeDiceState({ values, count }), children });
5834
+ return /* @__PURE__ */ jsx18(DiceContext.Provider, { value: normalizeDiceState({ values, count }), children });
6508
5835
  }
6509
5836
  function useDicePrimitiveContext() {
6510
- const value = useContext12(DiceContext);
5837
+ const value = useContext8(DiceContext);
6511
5838
  if (!value) {
6512
5839
  throw new Error("Dice primitives must be rendered inside <Dice.Root>.");
6513
5840
  }
@@ -6524,17 +5851,13 @@ var Dice = {
6524
5851
  export {
6525
5852
  UIRoot,
6526
5853
  UI,
6527
- usePluginSession,
6528
- RuntimeProvider,
6529
- RuntimeSemanticProjectionMarker,
6530
- usePluginState,
6531
- InteractionUiProvider,
6532
5854
  isInteractionAvailable,
6533
5855
  decodeAuthoredCardIntent,
6534
5856
  useCardIntentAdapter,
6535
5857
  useGameActionError,
6536
5858
  GameRoot,
6537
5859
  GameChrome,
5860
+ GameViewport,
6538
5861
  Game,
6539
5862
  useZonePrimitiveContext,
6540
5863
  useOptionalZonePrimitiveContext,
@@ -6592,7 +5915,6 @@ export {
6592
5915
  PlayerRosterRoot,
6593
5916
  PlayerRosterList,
6594
5917
  PlayerRosterEmpty,
6595
- PlayerRosterSwitchButton,
6596
5918
  PlayerRosterName,
6597
5919
  PlayerRosterScore,
6598
5920
  PlayerRosterBadges,
@@ -6614,4 +5936,4 @@ export {
6614
5936
  DiceValues,
6615
5937
  Dice
6616
5938
  };
6617
- //# sourceMappingURL=chunk-P7F4L2FF.js.map
5939
+ //# sourceMappingURL=chunk-WOWFONLZ.js.map