@dreamboard-games/sdk 0.4.0-alpha.6 → 0.4.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/REFERENCE.md +408 -8
- package/dist/authoring/index.d.ts +5 -4
- package/dist/authoring/index.js +3 -3
- package/dist/authoring/index.js.map +1 -1
- package/dist/{chunk-PAPIAMYX.js → chunk-3QIZKXJ2.js} +6 -4
- package/dist/{chunk-PAPIAMYX.js.map → chunk-3QIZKXJ2.js.map} +1 -1
- package/dist/chunk-5IHU5CUK.js +575 -0
- package/dist/chunk-5IHU5CUK.js.map +1 -0
- package/dist/chunk-IU6KGPY7.js +659 -0
- package/dist/chunk-IU6KGPY7.js.map +1 -0
- package/dist/{chunk-HK3WN4U7.js → chunk-KYEWGZ2Y.js} +2 -2
- package/dist/{chunk-HK3WN4U7.js.map → chunk-KYEWGZ2Y.js.map} +1 -1
- package/dist/{chunk-DDST4U2P.js → chunk-NO537WSS.js} +2 -2
- package/dist/{chunk-SOBNI363.js → chunk-Q322XCY2.js} +11 -6
- package/dist/{chunk-SOBNI363.js.map → chunk-Q322XCY2.js.map} +1 -1
- package/dist/{chunk-OV6JC2BM.js → chunk-RKGJ64UN.js} +19 -15
- package/dist/chunk-RKGJ64UN.js.map +1 -0
- package/dist/chunk-VLG4YST5.js +564 -0
- package/dist/chunk-VLG4YST5.js.map +1 -0
- package/dist/{stale-contract-artifact-error-BelRiIDR.d.ts → diagnostics-1BWjRo6-.d.ts} +1 -18
- package/dist/index.js +2 -2
- package/dist/package-set.d.ts +2 -2
- package/dist/package-set.js +2 -2
- package/dist/reducer.d.ts +3 -2
- package/dist/reducer.js +5 -5
- package/dist/reducer.js.map +1 -1
- package/dist/reference-games/index.d.ts +223 -0
- package/dist/reference-games/index.js +230 -0
- package/dist/reference-games/index.js.map +1 -0
- package/dist/runtime/primitives.js +4 -3
- package/dist/runtime/workspace-contract.js +5 -4
- package/dist/runtime.js +15 -205
- package/dist/runtime.js.map +1 -1
- package/dist/stale-contract-artifact-error-C5AaZPJ8.d.ts +18 -0
- package/dist/testing-runtime.d.ts +42 -0
- package/dist/testing-runtime.js +153 -0
- package/dist/testing-runtime.js.map +1 -0
- package/dist/testing.d.ts +5 -191
- package/dist/testing.js +22 -640
- package/dist/testing.js.map +1 -1
- package/dist/types-DcADVHe9.d.ts +192 -0
- package/package.json +13 -2
- package/dist/chunk-OV6JC2BM.js.map +0 -1
- package/dist/chunk-UUQNOGZV.js +0 -1266
- package/dist/chunk-UUQNOGZV.js.map +0 -1
- /package/dist/{chunk-DDST4U2P.js.map → chunk-NO537WSS.js.map} +0 -0
package/dist/runtime.js
CHANGED
|
@@ -1,224 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PluginRuntimeBoundary,
|
|
3
|
+
createPluginRuntimeClient
|
|
4
|
+
} from "./chunk-3QIZKXJ2.js";
|
|
1
5
|
import {
|
|
2
6
|
createWorkspaceUIContract
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-UC2UXAC6.js";
|
|
7
|
+
} from "./chunk-Q322XCY2.js";
|
|
8
|
+
import "./chunk-RKGJ64UN.js";
|
|
6
9
|
import "./chunk-T3ZKNUZ7.js";
|
|
10
|
+
import "./chunk-VLG4YST5.js";
|
|
11
|
+
import "./chunk-UC2UXAC6.js";
|
|
7
12
|
import {
|
|
8
13
|
GameSkeleton
|
|
9
14
|
} from "./chunk-2TRZSZGD.js";
|
|
10
15
|
import "./chunk-VDXOF4FW.js";
|
|
16
|
+
import "./chunk-WHR5UW3F.js";
|
|
11
17
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
DREAMBOARD_SDK_VERSION
|
|
19
|
+
} from "./chunk-NO537WSS.js";
|
|
20
|
+
import "./chunk-KYEWGZ2Y.js";
|
|
21
|
+
import "./chunk-PF7L4BMG.js";
|
|
15
22
|
import {
|
|
16
23
|
DREAMBOARD_PLUGIN_PROTOCOL,
|
|
17
24
|
DREAMBOARD_PLUGIN_PROTOCOL_VERSION,
|
|
18
25
|
HostToPluginEnvelopeSchema
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-WHR5UW3F.js";
|
|
21
|
-
import "./chunk-PF7L4BMG.js";
|
|
26
|
+
} from "./chunk-5IHU5CUK.js";
|
|
22
27
|
import "./chunk-PZ5AY32C.js";
|
|
23
28
|
|
|
24
29
|
// src/runtime/hooks/usePluginRuntime.ts
|
|
25
30
|
import { useState, useEffect, useRef } from "react";
|
|
26
31
|
|
|
27
|
-
// package.json
|
|
28
|
-
var package_default = {
|
|
29
|
-
name: "@dreamboard-games/sdk",
|
|
30
|
-
version: "0.4.0-alpha.6",
|
|
31
|
-
description: "Dreamboard SDK package set metadata and public facade",
|
|
32
|
-
type: "module",
|
|
33
|
-
main: "./dist/index.js",
|
|
34
|
-
types: "./dist/index.d.ts",
|
|
35
|
-
exports: {
|
|
36
|
-
".": {
|
|
37
|
-
types: "./dist/index.d.ts",
|
|
38
|
-
import: "./dist/index.js",
|
|
39
|
-
default: "./dist/index.js"
|
|
40
|
-
},
|
|
41
|
-
"./package-set": {
|
|
42
|
-
types: "./dist/package-set.d.ts",
|
|
43
|
-
import: "./dist/package-set.js",
|
|
44
|
-
default: "./dist/package-set.js"
|
|
45
|
-
},
|
|
46
|
-
"./types": {
|
|
47
|
-
types: "./dist/types.d.ts",
|
|
48
|
-
import: "./dist/types.js",
|
|
49
|
-
default: "./dist/types.js"
|
|
50
|
-
},
|
|
51
|
-
"./reducer": {
|
|
52
|
-
types: "./dist/reducer.d.ts",
|
|
53
|
-
import: "./dist/reducer.js",
|
|
54
|
-
default: "./dist/reducer.js"
|
|
55
|
-
},
|
|
56
|
-
"./reducer/advanced": {
|
|
57
|
-
types: "./dist/reducer/advanced.d.ts",
|
|
58
|
-
import: "./dist/reducer/advanced.js",
|
|
59
|
-
default: "./dist/reducer/advanced.js"
|
|
60
|
-
},
|
|
61
|
-
"./ui": {
|
|
62
|
-
types: "./dist/ui.d.ts",
|
|
63
|
-
import: "./dist/ui.js",
|
|
64
|
-
default: "./dist/ui.js"
|
|
65
|
-
},
|
|
66
|
-
"./ui/components": {
|
|
67
|
-
types: "./dist/ui/components.d.ts",
|
|
68
|
-
import: "./dist/ui/components.js",
|
|
69
|
-
default: "./dist/ui/components.js"
|
|
70
|
-
},
|
|
71
|
-
"./ui/defaults": {
|
|
72
|
-
types: "./dist/ui/defaults.d.ts",
|
|
73
|
-
import: "./dist/ui/defaults.js",
|
|
74
|
-
default: "./dist/ui/defaults.js"
|
|
75
|
-
},
|
|
76
|
-
"./ui/player-state": {
|
|
77
|
-
types: "./dist/ui/player-state.d.ts",
|
|
78
|
-
import: "./dist/ui/player-state.js",
|
|
79
|
-
default: "./dist/ui/player-state.js"
|
|
80
|
-
},
|
|
81
|
-
"./ui/plugin-styles.css": {
|
|
82
|
-
default: "./dist/ui/plugin-styles.css"
|
|
83
|
-
},
|
|
84
|
-
"./runtime": {
|
|
85
|
-
types: "./dist/runtime.d.ts",
|
|
86
|
-
import: "./dist/runtime.js",
|
|
87
|
-
default: "./dist/runtime.js"
|
|
88
|
-
},
|
|
89
|
-
"./runtime/primitives": {
|
|
90
|
-
types: "./dist/runtime/primitives.d.ts",
|
|
91
|
-
import: "./dist/runtime/primitives.js",
|
|
92
|
-
default: "./dist/runtime/primitives.js"
|
|
93
|
-
},
|
|
94
|
-
"./runtime/workspace-contract": {
|
|
95
|
-
types: "./dist/runtime/workspace-contract.d.ts",
|
|
96
|
-
import: "./dist/runtime/workspace-contract.js",
|
|
97
|
-
default: "./dist/runtime/workspace-contract.js"
|
|
98
|
-
},
|
|
99
|
-
"./runtime/runtime-api": {
|
|
100
|
-
types: "./dist/runtime/runtime-api.d.ts",
|
|
101
|
-
import: "./dist/runtime/runtime-api.js",
|
|
102
|
-
default: "./dist/runtime/runtime-api.js"
|
|
103
|
-
},
|
|
104
|
-
"./codegen": {
|
|
105
|
-
types: "./dist/codegen.d.ts",
|
|
106
|
-
import: "./dist/codegen.js",
|
|
107
|
-
default: "./dist/codegen.js"
|
|
108
|
-
},
|
|
109
|
-
"./authoring": {
|
|
110
|
-
types: "./dist/authoring/index.d.ts",
|
|
111
|
-
import: "./dist/authoring/index.js",
|
|
112
|
-
default: "./dist/authoring/index.js"
|
|
113
|
-
},
|
|
114
|
-
"./reducer-contract": {
|
|
115
|
-
types: "./dist/reducer-contract.d.ts",
|
|
116
|
-
import: "./dist/reducer-contract.js",
|
|
117
|
-
default: "./dist/reducer-contract.js"
|
|
118
|
-
},
|
|
119
|
-
"./testing": {
|
|
120
|
-
types: "./dist/testing.d.ts",
|
|
121
|
-
import: "./dist/testing.js",
|
|
122
|
-
default: "./dist/testing.js"
|
|
123
|
-
},
|
|
124
|
-
"./browser-interaction": {
|
|
125
|
-
bun: "./src/browser-interaction.ts",
|
|
126
|
-
types: "./dist/browser-interaction.d.ts",
|
|
127
|
-
import: "./dist/browser-interaction.js",
|
|
128
|
-
default: "./dist/browser-interaction.js"
|
|
129
|
-
},
|
|
130
|
-
"./package.json": "./package.json"
|
|
131
|
-
},
|
|
132
|
-
files: [
|
|
133
|
-
"LICENSE.md",
|
|
134
|
-
"dist",
|
|
135
|
-
"README.md",
|
|
136
|
-
"REFERENCE.md",
|
|
137
|
-
"!.turbo/**",
|
|
138
|
-
"!tsconfig.tsbuildinfo"
|
|
139
|
-
],
|
|
140
|
-
scripts: {
|
|
141
|
-
build: "pnpm --dir ../.. --filter @dreamboard-games/plugin-runtime-contract build && pnpm --dir ../.. authoring-metadata:generate && tsup && node ../../scripts/copy-sdk-private-dts.mjs && mkdir -p dist/ui && tailwindcss -i src/ui/plugin-styles.css -o dist/ui/plugin-styles.css --minify",
|
|
142
|
-
typecheck: "tsc --noEmit",
|
|
143
|
-
lint: "eslint 'src/**/*.{ts,tsx}'",
|
|
144
|
-
storybook: "storybook dev -p 6006 --host 127.0.0.1 --no-open",
|
|
145
|
-
"storybook:build": "storybook build -o storybook-static",
|
|
146
|
-
"storybook:test": 'concurrently -k -s first -n storybook,test "http-server storybook-static -p 6006 -s --silent" "wait-on tcp:6006 && test-storybook --url http://127.0.0.1:6006"',
|
|
147
|
-
"storybook:test:visual": "playwright test --config .storybook/visual-runner.config.ts",
|
|
148
|
-
"storybook:test:visual:update": "playwright test --config .storybook/visual-runner.config.ts --update-snapshots",
|
|
149
|
-
test: "bun test src"
|
|
150
|
-
},
|
|
151
|
-
dependencies: {
|
|
152
|
-
"@radix-ui/react-accordion": "^1.2.14",
|
|
153
|
-
"@radix-ui/react-dialog": "^1.1.17",
|
|
154
|
-
"@radix-ui/react-label": "^2.1.10",
|
|
155
|
-
"@radix-ui/react-select": "^2.3.1",
|
|
156
|
-
"@radix-ui/react-slot": "^1.3.0",
|
|
157
|
-
"@radix-ui/react-tooltip": "^1.2.10",
|
|
158
|
-
"@use-gesture/react": "^10.3.1",
|
|
159
|
-
clsx: "^2.1.1",
|
|
160
|
-
"lucide-react": "^1.20.0",
|
|
161
|
-
vaul: "^1.1.2",
|
|
162
|
-
zustand: "^5.0.14"
|
|
163
|
-
},
|
|
164
|
-
devDependencies: {
|
|
165
|
-
"@dreamboard-games/plugin-runtime-contract": "workspace:*",
|
|
166
|
-
"@dreamboard-games/reducer-contract": "workspace:*",
|
|
167
|
-
"@dreamboard-games/sdk-types": "workspace:*",
|
|
168
|
-
"@dreamboard-games/workspace-codegen": "workspace:*",
|
|
169
|
-
"@happy-dom/global-registrator": "^20.9.0",
|
|
170
|
-
"@playwright/test": "1.60.0",
|
|
171
|
-
"@storybook/addon-a11y": "^10.4.6",
|
|
172
|
-
"@storybook/addon-themes": "^10.4.6",
|
|
173
|
-
"@storybook/react-vite": "^10.4.6",
|
|
174
|
-
"@storybook/test-runner": "^0.24.4",
|
|
175
|
-
"@tailwindcss/cli": "^4.3.1",
|
|
176
|
-
"@tailwindcss/vite": "^4.3.1",
|
|
177
|
-
"@types/node": "^24.5.2",
|
|
178
|
-
"@types/react": "^19.0.0",
|
|
179
|
-
"@types/react-dom": "^19.0.0",
|
|
180
|
-
"axe-playwright": "2.2.2",
|
|
181
|
-
concurrently: "^9.1.0",
|
|
182
|
-
eslint: "^9.39.0",
|
|
183
|
-
"framer-motion": "^12.40.0",
|
|
184
|
-
"http-server": "^14.1.1",
|
|
185
|
-
playwright: "1.60.0",
|
|
186
|
-
react: "^19.2.0",
|
|
187
|
-
"react-dom": "^19.2.0",
|
|
188
|
-
storybook: "^10.4.6",
|
|
189
|
-
tailwindcss: "^4.3.1",
|
|
190
|
-
tsup: "^8.5.0",
|
|
191
|
-
typescript: "^5.9.2",
|
|
192
|
-
vite: "8.0.16",
|
|
193
|
-
"wait-on": "^8.0.1",
|
|
194
|
-
zod: "4.4.3"
|
|
195
|
-
},
|
|
196
|
-
peerDependencies: {
|
|
197
|
-
"framer-motion": "^11.0.0 || ^12.0.0",
|
|
198
|
-
react: "^19.0.0",
|
|
199
|
-
"react-dom": "^19.0.0",
|
|
200
|
-
zod: "^4.4.3"
|
|
201
|
-
},
|
|
202
|
-
publishConfig: {
|
|
203
|
-
access: "public"
|
|
204
|
-
},
|
|
205
|
-
repository: {
|
|
206
|
-
type: "git",
|
|
207
|
-
url: "git+https://github.com/dreamboard-games/dreamboard-sdk.git",
|
|
208
|
-
directory: "packages/sdk"
|
|
209
|
-
},
|
|
210
|
-
bugs: {
|
|
211
|
-
url: "https://github.com/dreamboard-games/dreamboard-sdk/issues"
|
|
212
|
-
},
|
|
213
|
-
homepage: "https://github.com/dreamboard-games/dreamboard-sdk#readme",
|
|
214
|
-
keywords: [
|
|
215
|
-
"dreamboard",
|
|
216
|
-
"sdk",
|
|
217
|
-
"package-set"
|
|
218
|
-
],
|
|
219
|
-
license: "SEE LICENSE IN LICENSE.md"
|
|
220
|
-
};
|
|
221
|
-
|
|
222
32
|
// src/runtime/browser/post-message-transport.ts
|
|
223
33
|
function createPostMessagePluginTransport(options = {}) {
|
|
224
34
|
const targetWindow = options.targetWindow ?? window;
|
|
@@ -301,7 +111,7 @@ function createPostMessagePluginTransport(options = {}) {
|
|
|
301
111
|
}
|
|
302
112
|
|
|
303
113
|
// src/runtime/hooks/usePluginRuntime.ts
|
|
304
|
-
var BUNDLED_SDK_VERSION =
|
|
114
|
+
var BUNDLED_SDK_VERSION = DREAMBOARD_SDK_VERSION;
|
|
305
115
|
function hasProjectedView(runtime) {
|
|
306
116
|
const frame = runtime.getFrame();
|
|
307
117
|
return frame !== null && frame.view !== null && typeof frame.view !== "undefined";
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/hooks/usePluginRuntime.ts","../package.json","../src/runtime/browser/post-message-transport.ts","../src/runtime/components/PluginRuntime.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport packageJson from \"../../../package.json\";\nimport { createPostMessagePluginTransport } from \"../browser/post-message-transport.js\";\nimport { createPluginRuntimeClient } from \"../core/create-plugin-runtime-client.js\";\nimport type { PluginRuntimeClient } from \"../core/types.js\";\nimport type { RuntimeDiagnosticHandler } from \"../types/runtime-api.js\";\n\nconst BUNDLED_SDK_VERSION =\n typeof packageJson.version === \"string\" ? packageJson.version : \"unknown\";\n\nexport interface UsePluginRuntimeOptions {\n /**\n * Timeout in milliseconds to wait for the first gameplay frame.\n * @default 10000 (10 seconds)\n */\n timeout?: number;\n onDiagnostic?: RuntimeDiagnosticHandler;\n}\n\nexport interface UsePluginRuntimeResult {\n /** The transport-agnostic plugin runtime client. */\n runtime: PluginRuntimeClient;\n /** Whether the initial reducer-native snapshot is available and ready */\n isReady: boolean;\n /**\n * True when the plugin was ready before but the current snapshot has no\n * projected view — e.g. you've acted and are waiting on the rest of the\n * table in a simultaneous phase. Lets the loading affordance read as a\n * mid-game wait rather than a cold \"still loading\" stall.\n */\n waiting: boolean;\n /** Error message if initialization failed */\n error: string | null;\n}\n\nfunction hasProjectedView(runtime: PluginRuntimeClient): boolean {\n const frame = runtime.getFrame();\n return (\n frame !== null && frame.view !== null && typeof frame.view !== \"undefined\"\n );\n}\n\n/**\n * Hook that creates and manages a PluginRuntimeClient instance.\n *\n * This hook handles:\n * 1. Creating the runtime client\n * 2. Waiting for the first gameplay frame before setting isReady\n *\n * In the new architecture, the host only renders the plugin when a reducer-native\n * snapshot is available, so isReady should become true quickly after init.\n *\n * @example\n * ```tsx\n * function PluginRuntime({ children }: { children: React.ReactNode }) {\n * const { runtime, isReady, error } = usePluginRuntime();\n *\n * if (error) {\n * return <div>Error: {error}</div>;\n * }\n *\n * if (!isReady) {\n * return <GameSkeleton message=\"Waiting for game state...\" />;\n * }\n *\n * return <RuntimeProvider runtime={runtime}>{children}</RuntimeProvider>;\n * }\n * ```\n */\nexport function usePluginRuntime(\n options: UsePluginRuntimeOptions = {},\n): UsePluginRuntimeResult {\n const { timeout = 10000, onDiagnostic } = options;\n const [error, setError] = useState<string | null>(null);\n\n // Create runtime once and keep stable reference\n const [runtime] = useState<PluginRuntimeClient>(() =>\n createPluginRuntimeClient({\n transport: createPostMessagePluginTransport({\n bundledSdkVersion: BUNDLED_SDK_VERSION,\n onInvalidMessage: (reason, value) => {\n const message =\n `Plugin runtime rejected a host message (${reason}). ` +\n `Bundled @dreamboard-games/sdk version: ${BUNDLED_SDK_VERSION}. ` +\n \"The host and plugin bundle may have incompatible SDK/runtime contract versions.\";\n setError(message);\n onDiagnostic?.({\n type: \"runtimeLog\",\n level: \"warn\",\n message,\n details: [value],\n });\n },\n }),\n }),\n );\n const [isReady, setIsReady] = useState(() => hasProjectedView(runtime));\n // Latches once we've shown a view, so a later view-less snapshot reads as a\n // mid-game wait rather than a fresh load. (A ref, so it never re-triggers a\n // render on its own.)\n const hasBeenReadyRef = useRef(false);\n if (isReady) hasBeenReadyRef.current = true;\n\n useEffect(() => {\n void onDiagnostic;\n }, [onDiagnostic]);\n\n // Subscribe to gameplay frames and set isReady when the first projected view arrives.\n useEffect(() => {\n const markReadyFromFrame = () => {\n if (!hasProjectedView(runtime)) {\n return false;\n }\n setError(null);\n setIsReady(true);\n return true;\n };\n\n if (markReadyFromFrame()) {\n return;\n }\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n if (!markReadyFromFrame()) {\n setError(\n `Timed out waiting for the initial projected view after ${timeout}ms. ` +\n \"Ensure the host sends a gameplay frame with a seat view.\",\n );\n }\n }, timeout);\n\n // Fallback poll for dev/HMR flows where the runtime frame may already\n // exist but the first subscribe callback is missed.\n const pollId = setInterval(() => {\n if (markReadyFromFrame()) {\n clearInterval(pollId);\n clearTimeout(timeoutId);\n }\n }, 100);\n\n const unsubscribe = runtime.subscribeFrame(() => {\n if (!hasProjectedView(runtime)) {\n setIsReady(false);\n return;\n }\n clearInterval(pollId);\n clearTimeout(timeoutId);\n setError(null);\n setIsReady(true);\n });\n\n return () => {\n clearInterval(pollId);\n clearTimeout(timeoutId);\n unsubscribe?.();\n };\n }, [runtime, timeout]);\n\n return {\n runtime,\n isReady,\n waiting: hasBeenReadyRef.current && !isReady,\n error,\n };\n}\n","{\n \"name\": \"@dreamboard-games/sdk\",\n \"version\": \"0.4.0-alpha.6\",\n \"description\": \"Dreamboard SDK package set metadata and public facade\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n },\n \"./package-set\": {\n \"types\": \"./dist/package-set.d.ts\",\n \"import\": \"./dist/package-set.js\",\n \"default\": \"./dist/package-set.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"import\": \"./dist/types.js\",\n \"default\": \"./dist/types.js\"\n },\n \"./reducer\": {\n \"types\": \"./dist/reducer.d.ts\",\n \"import\": \"./dist/reducer.js\",\n \"default\": \"./dist/reducer.js\"\n },\n \"./reducer/advanced\": {\n \"types\": \"./dist/reducer/advanced.d.ts\",\n \"import\": \"./dist/reducer/advanced.js\",\n \"default\": \"./dist/reducer/advanced.js\"\n },\n \"./ui\": {\n \"types\": \"./dist/ui.d.ts\",\n \"import\": \"./dist/ui.js\",\n \"default\": \"./dist/ui.js\"\n },\n \"./ui/components\": {\n \"types\": \"./dist/ui/components.d.ts\",\n \"import\": \"./dist/ui/components.js\",\n \"default\": \"./dist/ui/components.js\"\n },\n \"./ui/defaults\": {\n \"types\": \"./dist/ui/defaults.d.ts\",\n \"import\": \"./dist/ui/defaults.js\",\n \"default\": \"./dist/ui/defaults.js\"\n },\n \"./ui/player-state\": {\n \"types\": \"./dist/ui/player-state.d.ts\",\n \"import\": \"./dist/ui/player-state.js\",\n \"default\": \"./dist/ui/player-state.js\"\n },\n \"./ui/plugin-styles.css\": {\n \"default\": \"./dist/ui/plugin-styles.css\"\n },\n \"./runtime\": {\n \"types\": \"./dist/runtime.d.ts\",\n \"import\": \"./dist/runtime.js\",\n \"default\": \"./dist/runtime.js\"\n },\n \"./runtime/primitives\": {\n \"types\": \"./dist/runtime/primitives.d.ts\",\n \"import\": \"./dist/runtime/primitives.js\",\n \"default\": \"./dist/runtime/primitives.js\"\n },\n \"./runtime/workspace-contract\": {\n \"types\": \"./dist/runtime/workspace-contract.d.ts\",\n \"import\": \"./dist/runtime/workspace-contract.js\",\n \"default\": \"./dist/runtime/workspace-contract.js\"\n },\n \"./runtime/runtime-api\": {\n \"types\": \"./dist/runtime/runtime-api.d.ts\",\n \"import\": \"./dist/runtime/runtime-api.js\",\n \"default\": \"./dist/runtime/runtime-api.js\"\n },\n \"./codegen\": {\n \"types\": \"./dist/codegen.d.ts\",\n \"import\": \"./dist/codegen.js\",\n \"default\": \"./dist/codegen.js\"\n },\n \"./authoring\": {\n \"types\": \"./dist/authoring/index.d.ts\",\n \"import\": \"./dist/authoring/index.js\",\n \"default\": \"./dist/authoring/index.js\"\n },\n \"./reducer-contract\": {\n \"types\": \"./dist/reducer-contract.d.ts\",\n \"import\": \"./dist/reducer-contract.js\",\n \"default\": \"./dist/reducer-contract.js\"\n },\n \"./testing\": {\n \"types\": \"./dist/testing.d.ts\",\n \"import\": \"./dist/testing.js\",\n \"default\": \"./dist/testing.js\"\n },\n \"./browser-interaction\": {\n \"bun\": \"./src/browser-interaction.ts\",\n \"types\": \"./dist/browser-interaction.d.ts\",\n \"import\": \"./dist/browser-interaction.js\",\n \"default\": \"./dist/browser-interaction.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"LICENSE.md\",\n \"dist\",\n \"README.md\",\n \"REFERENCE.md\",\n \"!.turbo/**\",\n \"!tsconfig.tsbuildinfo\"\n ],\n \"scripts\": {\n \"build\": \"pnpm --dir ../.. --filter @dreamboard-games/plugin-runtime-contract build && pnpm --dir ../.. authoring-metadata:generate && tsup && node ../../scripts/copy-sdk-private-dts.mjs && mkdir -p dist/ui && tailwindcss -i src/ui/plugin-styles.css -o dist/ui/plugin-styles.css --minify\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint 'src/**/*.{ts,tsx}'\",\n \"storybook\": \"storybook dev -p 6006 --host 127.0.0.1 --no-open\",\n \"storybook:build\": \"storybook build -o storybook-static\",\n \"storybook:test\": \"concurrently -k -s first -n storybook,test \\\"http-server storybook-static -p 6006 -s --silent\\\" \\\"wait-on tcp:6006 && test-storybook --url http://127.0.0.1:6006\\\"\",\n \"storybook:test:visual\": \"playwright test --config .storybook/visual-runner.config.ts\",\n \"storybook:test:visual:update\": \"playwright test --config .storybook/visual-runner.config.ts --update-snapshots\",\n \"test\": \"bun test src\"\n },\n \"dependencies\": {\n \"@radix-ui/react-accordion\": \"^1.2.14\",\n \"@radix-ui/react-dialog\": \"^1.1.17\",\n \"@radix-ui/react-label\": \"^2.1.10\",\n \"@radix-ui/react-select\": \"^2.3.1\",\n \"@radix-ui/react-slot\": \"^1.3.0\",\n \"@radix-ui/react-tooltip\": \"^1.2.10\",\n \"@use-gesture/react\": \"^10.3.1\",\n \"clsx\": \"^2.1.1\",\n \"lucide-react\": \"^1.20.0\",\n \"vaul\": \"^1.1.2\",\n \"zustand\": \"^5.0.14\"\n },\n \"devDependencies\": {\n \"@dreamboard-games/plugin-runtime-contract\": \"workspace:*\",\n \"@dreamboard-games/reducer-contract\": \"workspace:*\",\n \"@dreamboard-games/sdk-types\": \"workspace:*\",\n \"@dreamboard-games/workspace-codegen\": \"workspace:*\",\n \"@happy-dom/global-registrator\": \"^20.9.0\",\n \"@playwright/test\": \"1.60.0\",\n \"@storybook/addon-a11y\": \"^10.4.6\",\n \"@storybook/addon-themes\": \"^10.4.6\",\n \"@storybook/react-vite\": \"^10.4.6\",\n \"@storybook/test-runner\": \"^0.24.4\",\n \"@tailwindcss/cli\": \"^4.3.1\",\n \"@tailwindcss/vite\": \"^4.3.1\",\n \"@types/node\": \"^24.5.2\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"axe-playwright\": \"2.2.2\",\n \"concurrently\": \"^9.1.0\",\n \"eslint\": \"^9.39.0\",\n \"framer-motion\": \"^12.40.0\",\n \"http-server\": \"^14.1.1\",\n \"playwright\": \"1.60.0\",\n \"react\": \"^19.2.0\",\n \"react-dom\": \"^19.2.0\",\n \"storybook\": \"^10.4.6\",\n \"tailwindcss\": \"^4.3.1\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.2\",\n \"vite\": \"8.0.16\",\n \"wait-on\": \"^8.0.1\",\n \"zod\": \"4.4.3\"\n },\n \"peerDependencies\": {\n \"framer-motion\": \"^11.0.0 || ^12.0.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"zod\": \"^4.4.3\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/dreamboard-games/dreamboard-sdk.git\",\n \"directory\": \"packages/sdk\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/dreamboard-games/dreamboard-sdk/issues\"\n },\n \"homepage\": \"https://github.com/dreamboard-games/dreamboard-sdk#readme\",\n \"keywords\": [\n \"dreamboard\",\n \"sdk\",\n \"package-set\"\n ],\n \"license\": \"SEE LICENSE IN LICENSE.md\"\n}\n","import {\n DREAMBOARD_PLUGIN_PROTOCOL,\n DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n HostToPluginEnvelopeSchema,\n type HostToPluginEnvelope,\n type PluginToHostPayload,\n} from \"@dreamboard-games/plugin-runtime-contract\";\nimport type { PluginTransport } from \"../core/types.js\";\n\nexport interface PostMessagePluginTransportOptions {\n readonly targetWindow?: Window;\n readonly parentWindow?: Window;\n readonly bundledSdkVersion?: string;\n readonly onInvalidMessage?: (reason: string, value: unknown) => void;\n}\n\nexport function createPostMessagePluginTransport(\n options: PostMessagePluginTransportOptions = {},\n): PluginTransport {\n const targetWindow = options.targetWindow ?? window;\n const parentWindow = options.parentWindow ?? targetWindow.parent;\n const bundledSdkVersion = options.bundledSdkVersion?.trim() || \"unknown\";\n let channel: {\n readonly channelId: string;\n readonly hostOrigin: string;\n readonly hostWindow: Window;\n } | null = null;\n let outboundSequence = 0;\n let invalidEnvelopeReported = false;\n\n const reportInvalidEnvelope = (reason: string, value: unknown) => {\n options.onInvalidMessage?.(reason, value);\n\n if (!channel || invalidEnvelopeReported) {\n return;\n }\n\n invalidEnvelopeReported = true;\n channel.hostWindow.postMessage(\n {\n protocol: DREAMBOARD_PLUGIN_PROTOCOL,\n version: DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n channelId: channel.channelId,\n sequence: ++outboundSequence,\n payload: {\n type: \"runtime.error\",\n code: \"host-runtime-protocol-mismatch\",\n message:\n `Plugin runtime rejected a host message (${reason}). ` +\n `Bundled @dreamboard-games/sdk version: ${bundledSdkVersion}. ` +\n \"The host and plugin bundle may have incompatible SDK/runtime contract versions.\",\n },\n },\n channel.hostOrigin,\n );\n };\n\n return {\n start(onMessage) {\n const handleMessage = (event: MessageEvent) => {\n if (event.source !== parentWindow) {\n return;\n }\n const parseResult = HostToPluginEnvelopeSchema.safeParse(event.data);\n if (!parseResult.success) {\n reportInvalidEnvelope(\"invalid-envelope\", event.data);\n return;\n }\n const envelope = parseResult.data;\n if (!channel) {\n if (envelope.payload.type !== \"runtime.init\") {\n return;\n }\n channel = {\n channelId: envelope.channelId,\n hostOrigin: event.origin,\n hostWindow: event.source as Window,\n };\n }\n if (\n envelope.channelId !== channel.channelId ||\n event.origin !== channel.hostOrigin ||\n event.source !== channel.hostWindow\n ) {\n reportInvalidEnvelope(\"channel-mismatch\", event.data);\n return;\n }\n onMessage(envelope as HostToPluginEnvelope);\n };\n\n targetWindow.addEventListener(\"message\", handleMessage);\n return () => {\n targetWindow.removeEventListener(\"message\", handleMessage);\n channel = null;\n };\n },\n send(payload: PluginToHostPayload) {\n if (!channel) {\n throw new Error(\"Plugin transport is not initialized.\");\n }\n channel.hostWindow.postMessage(\n {\n protocol: DREAMBOARD_PLUGIN_PROTOCOL,\n version: DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n channelId: channel.channelId,\n sequence: ++outboundSequence,\n payload,\n },\n channel.hostOrigin,\n );\n },\n };\n}\n","import React from \"react\";\nimport { usePluginRuntime } from \"../hooks/usePluginRuntime.js\";\nimport { GameSkeleton } from \"../../ui.js\";\nimport type { RuntimeDiagnosticHandler } from \"../types/runtime-api.js\";\nimport { PluginRuntimeBoundary } from \"./PluginRuntimeBoundary.js\";\n\nexport interface PluginRuntimeProps {\n /** Child components to render after gameplay frame has started */\n children: React.ReactNode;\n /**\n * Timeout in milliseconds to wait for the first gameplay-frame snapshot.\n * @default 10000 (10 seconds)\n */\n timeout?: number;\n /** Custom loading component to show while waiting for gameplay frame */\n loadingComponent?: React.ReactNode;\n /** Custom error component to show when initialization fails */\n errorComponent?: (error: string) => React.ReactNode;\n onDiagnostic?: RuntimeDiagnosticHandler;\n}\n\n/**\n * PluginRuntime provides the RuntimeContext for plugin components.\n *\n * This component:\n * - Creates a transport-backed runtime client\n * - Waits for the first projected gameplay frame before rendering children\n * - Provides runtime commands plus session/frame state to all child components\n *\n * @example\n * ```tsx\n * // In your plugin's index.tsx\n * import { PluginRuntime } from \"./components/dreamboard\";\n * import App from './App';\n *\n * ReactDOM.createRoot(document.getElementById('root')!).render(\n * <PluginRuntime>\n * <App />\n * </PluginRuntime>\n * );\n * ```\n */\nexport function PluginRuntime({\n children,\n timeout = 10000,\n loadingComponent,\n errorComponent,\n onDiagnostic,\n}: PluginRuntimeProps) {\n const { runtime, isReady, waiting, error } = usePluginRuntime({\n timeout,\n onDiagnostic,\n });\n\n if (error) {\n if (errorComponent) {\n return <>{errorComponent(error)}</>;\n }\n return (\n <div className=\"flex h-full w-full items-center justify-center bg-gray-50\">\n <div className=\"text-center p-6\">\n <p className=\"text-red-600 font-medium mb-2\">Failed to load game</p>\n <p className=\"text-gray-600 text-sm\">{error}</p>\n </div>\n </div>\n );\n }\n\n if (!isReady) {\n if (loadingComponent) {\n return <>{loadingComponent}</>;\n }\n // Once the game has rendered, a view-less snapshot is a mid-game wait (you\n // acted and are waiting on the table), not a cold load — say so rather than\n // reading as a stalled \"Waiting for game state\".\n return (\n <GameSkeleton\n message={\n waiting\n ? \"Waiting for the other players…\"\n : \"Waiting for game state...\"\n }\n />\n );\n }\n\n return (\n <PluginRuntimeBoundary runtime={runtime}>{children}</PluginRuntimeBoundary>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/runtime/hooks/usePluginRuntime.ts","../src/runtime/browser/post-message-transport.ts","../src/runtime/components/PluginRuntime.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { DREAMBOARD_SDK_VERSION } from \"../../package-set.js\";\nimport { createPostMessagePluginTransport } from \"../browser/post-message-transport.js\";\nimport { createPluginRuntimeClient } from \"../core/create-plugin-runtime-client.js\";\nimport type { PluginRuntimeClient } from \"../core/types.js\";\nimport type { RuntimeDiagnosticHandler } from \"../types/runtime-api.js\";\n\nconst BUNDLED_SDK_VERSION = DREAMBOARD_SDK_VERSION;\n\nexport interface UsePluginRuntimeOptions {\n /**\n * Timeout in milliseconds to wait for the first gameplay frame.\n * @default 10000 (10 seconds)\n */\n timeout?: number;\n onDiagnostic?: RuntimeDiagnosticHandler;\n}\n\nexport interface UsePluginRuntimeResult {\n /** The transport-agnostic plugin runtime client. */\n runtime: PluginRuntimeClient;\n /** Whether the initial reducer-native snapshot is available and ready */\n isReady: boolean;\n /**\n * True when the plugin was ready before but the current snapshot has no\n * projected view — e.g. you've acted and are waiting on the rest of the\n * table in a simultaneous phase. Lets the loading affordance read as a\n * mid-game wait rather than a cold \"still loading\" stall.\n */\n waiting: boolean;\n /** Error message if initialization failed */\n error: string | null;\n}\n\nfunction hasProjectedView(runtime: PluginRuntimeClient): boolean {\n const frame = runtime.getFrame();\n return (\n frame !== null && frame.view !== null && typeof frame.view !== \"undefined\"\n );\n}\n\n/**\n * Hook that creates and manages a PluginRuntimeClient instance.\n *\n * This hook handles:\n * 1. Creating the runtime client\n * 2. Waiting for the first gameplay frame before setting isReady\n *\n * In the new architecture, the host only renders the plugin when a reducer-native\n * snapshot is available, so isReady should become true quickly after init.\n *\n * @example\n * ```tsx\n * function PluginRuntime({ children }: { children: React.ReactNode }) {\n * const { runtime, isReady, error } = usePluginRuntime();\n *\n * if (error) {\n * return <div>Error: {error}</div>;\n * }\n *\n * if (!isReady) {\n * return <GameSkeleton message=\"Waiting for game state...\" />;\n * }\n *\n * return <RuntimeProvider runtime={runtime}>{children}</RuntimeProvider>;\n * }\n * ```\n */\nexport function usePluginRuntime(\n options: UsePluginRuntimeOptions = {},\n): UsePluginRuntimeResult {\n const { timeout = 10000, onDiagnostic } = options;\n const [error, setError] = useState<string | null>(null);\n\n // Create runtime once and keep stable reference\n const [runtime] = useState<PluginRuntimeClient>(() =>\n createPluginRuntimeClient({\n transport: createPostMessagePluginTransport({\n bundledSdkVersion: BUNDLED_SDK_VERSION,\n onInvalidMessage: (reason, value) => {\n const message =\n `Plugin runtime rejected a host message (${reason}). ` +\n `Bundled @dreamboard-games/sdk version: ${BUNDLED_SDK_VERSION}. ` +\n \"The host and plugin bundle may have incompatible SDK/runtime contract versions.\";\n setError(message);\n onDiagnostic?.({\n type: \"runtimeLog\",\n level: \"warn\",\n message,\n details: [value],\n });\n },\n }),\n }),\n );\n const [isReady, setIsReady] = useState(() => hasProjectedView(runtime));\n // Latches once we've shown a view, so a later view-less snapshot reads as a\n // mid-game wait rather than a fresh load. (A ref, so it never re-triggers a\n // render on its own.)\n const hasBeenReadyRef = useRef(false);\n if (isReady) hasBeenReadyRef.current = true;\n\n useEffect(() => {\n void onDiagnostic;\n }, [onDiagnostic]);\n\n // Subscribe to gameplay frames and set isReady when the first projected view arrives.\n useEffect(() => {\n const markReadyFromFrame = () => {\n if (!hasProjectedView(runtime)) {\n return false;\n }\n setError(null);\n setIsReady(true);\n return true;\n };\n\n if (markReadyFromFrame()) {\n return;\n }\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n if (!markReadyFromFrame()) {\n setError(\n `Timed out waiting for the initial projected view after ${timeout}ms. ` +\n \"Ensure the host sends a gameplay frame with a seat view.\",\n );\n }\n }, timeout);\n\n // Fallback poll for dev/HMR flows where the runtime frame may already\n // exist but the first subscribe callback is missed.\n const pollId = setInterval(() => {\n if (markReadyFromFrame()) {\n clearInterval(pollId);\n clearTimeout(timeoutId);\n }\n }, 100);\n\n const unsubscribe = runtime.subscribeFrame(() => {\n if (!hasProjectedView(runtime)) {\n setIsReady(false);\n return;\n }\n clearInterval(pollId);\n clearTimeout(timeoutId);\n setError(null);\n setIsReady(true);\n });\n\n return () => {\n clearInterval(pollId);\n clearTimeout(timeoutId);\n unsubscribe?.();\n };\n }, [runtime, timeout]);\n\n return {\n runtime,\n isReady,\n waiting: hasBeenReadyRef.current && !isReady,\n error,\n };\n}\n","import {\n DREAMBOARD_PLUGIN_PROTOCOL,\n DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n HostToPluginEnvelopeSchema,\n type HostToPluginEnvelope,\n type PluginToHostPayload,\n} from \"@dreamboard-games/plugin-runtime-contract\";\nimport type { PluginTransport } from \"../core/types.js\";\n\nexport interface PostMessagePluginTransportOptions {\n readonly targetWindow?: Window;\n readonly parentWindow?: Window;\n readonly bundledSdkVersion?: string;\n readonly onInvalidMessage?: (reason: string, value: unknown) => void;\n}\n\nexport function createPostMessagePluginTransport(\n options: PostMessagePluginTransportOptions = {},\n): PluginTransport {\n const targetWindow = options.targetWindow ?? window;\n const parentWindow = options.parentWindow ?? targetWindow.parent;\n const bundledSdkVersion = options.bundledSdkVersion?.trim() || \"unknown\";\n let channel: {\n readonly channelId: string;\n readonly hostOrigin: string;\n readonly hostWindow: Window;\n } | null = null;\n let outboundSequence = 0;\n let invalidEnvelopeReported = false;\n\n const reportInvalidEnvelope = (reason: string, value: unknown) => {\n options.onInvalidMessage?.(reason, value);\n\n if (!channel || invalidEnvelopeReported) {\n return;\n }\n\n invalidEnvelopeReported = true;\n channel.hostWindow.postMessage(\n {\n protocol: DREAMBOARD_PLUGIN_PROTOCOL,\n version: DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n channelId: channel.channelId,\n sequence: ++outboundSequence,\n payload: {\n type: \"runtime.error\",\n code: \"host-runtime-protocol-mismatch\",\n message:\n `Plugin runtime rejected a host message (${reason}). ` +\n `Bundled @dreamboard-games/sdk version: ${bundledSdkVersion}. ` +\n \"The host and plugin bundle may have incompatible SDK/runtime contract versions.\",\n },\n },\n channel.hostOrigin,\n );\n };\n\n return {\n start(onMessage) {\n const handleMessage = (event: MessageEvent) => {\n if (event.source !== parentWindow) {\n return;\n }\n const parseResult = HostToPluginEnvelopeSchema.safeParse(event.data);\n if (!parseResult.success) {\n reportInvalidEnvelope(\"invalid-envelope\", event.data);\n return;\n }\n const envelope = parseResult.data;\n if (!channel) {\n if (envelope.payload.type !== \"runtime.init\") {\n return;\n }\n channel = {\n channelId: envelope.channelId,\n hostOrigin: event.origin,\n hostWindow: event.source as Window,\n };\n }\n if (\n envelope.channelId !== channel.channelId ||\n event.origin !== channel.hostOrigin ||\n event.source !== channel.hostWindow\n ) {\n reportInvalidEnvelope(\"channel-mismatch\", event.data);\n return;\n }\n onMessage(envelope as HostToPluginEnvelope);\n };\n\n targetWindow.addEventListener(\"message\", handleMessage);\n return () => {\n targetWindow.removeEventListener(\"message\", handleMessage);\n channel = null;\n };\n },\n send(payload: PluginToHostPayload) {\n if (!channel) {\n throw new Error(\"Plugin transport is not initialized.\");\n }\n channel.hostWindow.postMessage(\n {\n protocol: DREAMBOARD_PLUGIN_PROTOCOL,\n version: DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n channelId: channel.channelId,\n sequence: ++outboundSequence,\n payload,\n },\n channel.hostOrigin,\n );\n },\n };\n}\n","import React from \"react\";\nimport { usePluginRuntime } from \"../hooks/usePluginRuntime.js\";\nimport { GameSkeleton } from \"../../ui.js\";\nimport type { RuntimeDiagnosticHandler } from \"../types/runtime-api.js\";\nimport { PluginRuntimeBoundary } from \"./PluginRuntimeBoundary.js\";\n\nexport interface PluginRuntimeProps {\n /** Child components to render after gameplay frame has started */\n children: React.ReactNode;\n /**\n * Timeout in milliseconds to wait for the first gameplay-frame snapshot.\n * @default 10000 (10 seconds)\n */\n timeout?: number;\n /** Custom loading component to show while waiting for gameplay frame */\n loadingComponent?: React.ReactNode;\n /** Custom error component to show when initialization fails */\n errorComponent?: (error: string) => React.ReactNode;\n onDiagnostic?: RuntimeDiagnosticHandler;\n}\n\n/**\n * PluginRuntime provides the RuntimeContext for plugin components.\n *\n * This component:\n * - Creates a transport-backed runtime client\n * - Waits for the first projected gameplay frame before rendering children\n * - Provides runtime commands plus session/frame state to all child components\n *\n * @example\n * ```tsx\n * // In your plugin's index.tsx\n * import { PluginRuntime } from \"./components/dreamboard\";\n * import App from './App';\n *\n * ReactDOM.createRoot(document.getElementById('root')!).render(\n * <PluginRuntime>\n * <App />\n * </PluginRuntime>\n * );\n * ```\n */\nexport function PluginRuntime({\n children,\n timeout = 10000,\n loadingComponent,\n errorComponent,\n onDiagnostic,\n}: PluginRuntimeProps) {\n const { runtime, isReady, waiting, error } = usePluginRuntime({\n timeout,\n onDiagnostic,\n });\n\n if (error) {\n if (errorComponent) {\n return <>{errorComponent(error)}</>;\n }\n return (\n <div className=\"flex h-full w-full items-center justify-center bg-gray-50\">\n <div className=\"text-center p-6\">\n <p className=\"text-red-600 font-medium mb-2\">Failed to load game</p>\n <p className=\"text-gray-600 text-sm\">{error}</p>\n </div>\n </div>\n );\n }\n\n if (!isReady) {\n if (loadingComponent) {\n return <>{loadingComponent}</>;\n }\n // Once the game has rendered, a view-less snapshot is a mid-game wait (you\n // acted and are waiting on the table), not a cold load — say so rather than\n // reading as a stalled \"Waiting for game state\".\n return (\n <GameSkeleton\n message={\n waiting\n ? \"Waiting for the other players…\"\n : \"Waiting for game state...\"\n }\n />\n );\n }\n\n return (\n <PluginRuntimeBoundary runtime={runtime}>{children}</PluginRuntimeBoundary>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type StaleContractArtifactKind = "base-states" | "session-state";
|
|
2
|
+
type StaleContractArtifactErrorOptions = {
|
|
3
|
+
artifact: StaleContractArtifactKind;
|
|
4
|
+
expected: string;
|
|
5
|
+
found: string;
|
|
6
|
+
remedy?: string;
|
|
7
|
+
};
|
|
8
|
+
declare class StaleContractArtifactError extends Error {
|
|
9
|
+
readonly code = "STALE_CONTRACT_ARTIFACT";
|
|
10
|
+
readonly artifact: StaleContractArtifactKind;
|
|
11
|
+
readonly expected: string;
|
|
12
|
+
readonly found: string;
|
|
13
|
+
readonly remedy: string;
|
|
14
|
+
constructor(options: StaleContractArtifactErrorOptions);
|
|
15
|
+
}
|
|
16
|
+
declare function isStaleContractArtifactError(error: unknown): error is StaleContractArtifactError;
|
|
17
|
+
|
|
18
|
+
export { StaleContractArtifactError as S, type StaleContractArtifactErrorOptions as a, type StaleContractArtifactKind as b, isStaleContractArtifactError as i };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { w as wire } from './index.d-DMASeF6M.js';
|
|
2
|
+
import { a as BaseDefinition, S as ScenarioDefinition, R as ReducerScenarioBundle } from './types-DcADVHe9.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
import './diagnostics-1BWjRo6-.js';
|
|
5
|
+
|
|
6
|
+
type BaseStateArtifact = {
|
|
7
|
+
readonly snapshot: wire.ReducerSessionState;
|
|
8
|
+
readonly fingerprint: {
|
|
9
|
+
readonly players: number;
|
|
10
|
+
readonly contractFingerprint?: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
type CandidateVerificationBase = BaseStateArtifact | (BaseDefinition & Partial<BaseStateArtifact>);
|
|
14
|
+
type CandidateVerificationScenario = ScenarioDefinition;
|
|
15
|
+
type CandidateVerificationInput = {
|
|
16
|
+
readonly manifest?: unknown;
|
|
17
|
+
readonly bases: Readonly<Record<string, CandidateVerificationBase>> | readonly CandidateVerificationBase[];
|
|
18
|
+
readonly scenarios: Readonly<Record<string, CandidateVerificationScenario>> | readonly CandidateVerificationScenario[];
|
|
19
|
+
readonly reducer: ReducerScenarioBundle;
|
|
20
|
+
readonly maxScenarios?: number;
|
|
21
|
+
readonly maxStepsPerScenario?: number;
|
|
22
|
+
};
|
|
23
|
+
type CandidateVerificationScenarioResult = {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly status: "passed" | "failed";
|
|
26
|
+
readonly diagnostic?: {
|
|
27
|
+
readonly kind: "assertion";
|
|
28
|
+
readonly message: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
type CandidateVerificationResult = {
|
|
32
|
+
readonly status: "passed" | "failed";
|
|
33
|
+
readonly scenarioSummary: {
|
|
34
|
+
readonly total: number;
|
|
35
|
+
readonly passed: number;
|
|
36
|
+
readonly failed: number;
|
|
37
|
+
readonly scenarios: readonly CandidateVerificationScenarioResult[];
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
declare function runCandidateVerification(input: CandidateVerificationInput): Promise<CandidateVerificationResult>;
|
|
41
|
+
|
|
42
|
+
export { type CandidateVerificationBase, type CandidateVerificationInput, type CandidateVerificationResult, type CandidateVerificationScenario, type CandidateVerificationScenarioResult, runCandidateVerification };
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createExpectApi,
|
|
3
|
+
createTestRuntime
|
|
4
|
+
} from "./chunk-IU6KGPY7.js";
|
|
5
|
+
import "./chunk-3OZMHZK3.js";
|
|
6
|
+
import "./chunk-5IHU5CUK.js";
|
|
7
|
+
import "./chunk-PZ5AY32C.js";
|
|
8
|
+
|
|
9
|
+
// src/testing-runtime.ts
|
|
10
|
+
async function runCandidateVerification(input) {
|
|
11
|
+
const bases = normalizeBases(input.bases);
|
|
12
|
+
const scenarios = normalizeScenarios(input.scenarios);
|
|
13
|
+
const maxScenarios = input.maxScenarios ?? scenarios.length;
|
|
14
|
+
if (!Number.isInteger(maxScenarios) || maxScenarios < 1) {
|
|
15
|
+
throw new Error("maxScenarios must be a positive integer.");
|
|
16
|
+
}
|
|
17
|
+
if (scenarios.length > maxScenarios) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Candidate verification contains ${scenarios.length} scenarios, exceeding limit ${maxScenarios}.`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
const maxStepsPerScenario = input.maxStepsPerScenario ?? 1e3;
|
|
23
|
+
if (!Number.isInteger(maxStepsPerScenario) || maxStepsPerScenario < 1) {
|
|
24
|
+
throw new Error("maxStepsPerScenario must be a positive integer.");
|
|
25
|
+
}
|
|
26
|
+
const results = [];
|
|
27
|
+
for (const scenario of scenarios) {
|
|
28
|
+
results.push(
|
|
29
|
+
await runScenario({
|
|
30
|
+
bases,
|
|
31
|
+
reducer: input.reducer,
|
|
32
|
+
scenario,
|
|
33
|
+
maxStepsPerScenario
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const failed = results.filter((result) => result.status === "failed").length;
|
|
38
|
+
return {
|
|
39
|
+
status: failed === 0 ? "passed" : "failed",
|
|
40
|
+
scenarioSummary: {
|
|
41
|
+
total: results.length,
|
|
42
|
+
passed: results.length - failed,
|
|
43
|
+
failed,
|
|
44
|
+
scenarios: results
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function runScenario(input) {
|
|
49
|
+
const runtime = createTestRuntime({
|
|
50
|
+
baseId: input.scenario.from,
|
|
51
|
+
baseStates: input.bases,
|
|
52
|
+
bundle: input.reducer,
|
|
53
|
+
phase: input.scenario.phase,
|
|
54
|
+
playerIds: input.bases[input.scenario.from]?.snapshot.domain?.flow?.activePlayers
|
|
55
|
+
});
|
|
56
|
+
const ctx = createScenarioContext(runtime, input.maxStepsPerScenario);
|
|
57
|
+
try {
|
|
58
|
+
await input.scenario.when(ctx);
|
|
59
|
+
await input.scenario.then(ctx);
|
|
60
|
+
return { id: input.scenario.id, status: "passed" };
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
id: input.scenario.id,
|
|
64
|
+
status: "failed",
|
|
65
|
+
diagnostic: {
|
|
66
|
+
kind: "assertion",
|
|
67
|
+
message: boundedMessage(error)
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function createScenarioContext(runtime, maxStepsPerScenario) {
|
|
73
|
+
let submittedSteps = 0;
|
|
74
|
+
const baseContext = {
|
|
75
|
+
game: {
|
|
76
|
+
start: async () => void 0,
|
|
77
|
+
submit: async (...args) => {
|
|
78
|
+
submittedSteps += 1;
|
|
79
|
+
if (submittedSteps > maxStepsPerScenario) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Scenario exceeded maxStepsPerScenario limit ${maxStepsPerScenario}.`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return runtime.submit(...args);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
players: runtime.players,
|
|
88
|
+
seat: runtime.seat
|
|
89
|
+
};
|
|
90
|
+
return {
|
|
91
|
+
...baseContext,
|
|
92
|
+
state: () => runtime.getFrame().flow.currentPhase ?? "",
|
|
93
|
+
view: (playerId) => {
|
|
94
|
+
const frame = runtime.getFrame();
|
|
95
|
+
if (frame.perspectivePlayerId === playerId) return frame.view;
|
|
96
|
+
return runtime.getFrame().view;
|
|
97
|
+
},
|
|
98
|
+
interactions: (playerId) => {
|
|
99
|
+
const frame = runtime.getFrame();
|
|
100
|
+
if (frame.perspectivePlayerId !== playerId) return [];
|
|
101
|
+
return frame.availableInteractions;
|
|
102
|
+
},
|
|
103
|
+
explain: runtime.explain,
|
|
104
|
+
diagnostics: runtime.diagnostics,
|
|
105
|
+
expect: createExpectApi({
|
|
106
|
+
lastDiagnosticRejection: () => {
|
|
107
|
+
for (let index = runtime.diagnostics.events.length - 1; index >= 0; index -= 1) {
|
|
108
|
+
const event = runtime.diagnostics.events[index];
|
|
109
|
+
if (event?.type === "submitRejected") return event;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function normalizeBases(input) {
|
|
117
|
+
const entries = Array.isArray(input) ? input.map((base) => [base.id, base]) : Object.entries(input);
|
|
118
|
+
return Object.fromEntries(
|
|
119
|
+
entries.map(([id, base]) => {
|
|
120
|
+
if (!id) throw new Error("Candidate verification base id is required.");
|
|
121
|
+
if (!("snapshot" in base) || !base.snapshot) {
|
|
122
|
+
throw new Error(`Candidate verification base '${id}' has no snapshot.`);
|
|
123
|
+
}
|
|
124
|
+
const players = base.fingerprint?.players ?? base.players ?? base.snapshot.domain?.flow?.activePlayers?.length ?? 1;
|
|
125
|
+
return [
|
|
126
|
+
id,
|
|
127
|
+
{
|
|
128
|
+
snapshot: base.snapshot,
|
|
129
|
+
fingerprint: {
|
|
130
|
+
players,
|
|
131
|
+
contractFingerprint: base.fingerprint?.contractFingerprint
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
];
|
|
135
|
+
})
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
function normalizeScenarios(input) {
|
|
139
|
+
const scenarios = Array.isArray(input) ? input : Object.values(input);
|
|
140
|
+
return scenarios.map((scenario) => {
|
|
141
|
+
if (!scenario.id)
|
|
142
|
+
throw new Error("Candidate verification scenario id is required.");
|
|
143
|
+
return scenario;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function boundedMessage(error) {
|
|
147
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
148
|
+
return message.slice(0, 2e3);
|
|
149
|
+
}
|
|
150
|
+
export {
|
|
151
|
+
runCandidateVerification
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=testing-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing-runtime.ts"],"sourcesContent":["import type { Wire } from \"@dreamboard-games/reducer-contract\";\nimport { createExpectApi } from \"./testing/create-expect-api.js\";\nimport { createTestRuntime } from \"./testing/create-test-runtime.js\";\nimport type {\n BaseContext,\n BaseDefinition,\n InteractionDescriptorLike,\n ScenarioDefinition,\n SharedScenarioContext,\n} from \"./testing/definitions.js\";\nimport type { ReducerScenarioBundle } from \"./testing/reducer-scenario/types.js\";\n\ntype BaseStateArtifact = {\n readonly snapshot: Wire.ReducerSessionState;\n readonly fingerprint: {\n readonly players: number;\n readonly contractFingerprint?: string;\n };\n};\n\nexport type CandidateVerificationBase =\n | BaseStateArtifact\n | (BaseDefinition & Partial<BaseStateArtifact>);\n\nexport type CandidateVerificationScenario = ScenarioDefinition;\n\nexport type CandidateVerificationInput = {\n readonly manifest?: unknown;\n readonly bases:\n | Readonly<Record<string, CandidateVerificationBase>>\n | readonly CandidateVerificationBase[];\n readonly scenarios:\n | Readonly<Record<string, CandidateVerificationScenario>>\n | readonly CandidateVerificationScenario[];\n readonly reducer: ReducerScenarioBundle;\n readonly maxScenarios?: number;\n readonly maxStepsPerScenario?: number;\n};\n\nexport type CandidateVerificationScenarioResult = {\n readonly id: string;\n readonly status: \"passed\" | \"failed\";\n readonly diagnostic?: {\n readonly kind: \"assertion\";\n readonly message: string;\n };\n};\n\nexport type CandidateVerificationResult = {\n readonly status: \"passed\" | \"failed\";\n readonly scenarioSummary: {\n readonly total: number;\n readonly passed: number;\n readonly failed: number;\n readonly scenarios: readonly CandidateVerificationScenarioResult[];\n };\n};\n\nexport async function runCandidateVerification(\n input: CandidateVerificationInput,\n): Promise<CandidateVerificationResult> {\n const bases = normalizeBases(input.bases);\n const scenarios = normalizeScenarios(input.scenarios);\n const maxScenarios = input.maxScenarios ?? scenarios.length;\n if (!Number.isInteger(maxScenarios) || maxScenarios < 1) {\n throw new Error(\"maxScenarios must be a positive integer.\");\n }\n if (scenarios.length > maxScenarios) {\n throw new Error(\n `Candidate verification contains ${scenarios.length} scenarios, exceeding limit ${maxScenarios}.`,\n );\n }\n const maxStepsPerScenario = input.maxStepsPerScenario ?? 1000;\n if (!Number.isInteger(maxStepsPerScenario) || maxStepsPerScenario < 1) {\n throw new Error(\"maxStepsPerScenario must be a positive integer.\");\n }\n\n const results: CandidateVerificationScenarioResult[] = [];\n for (const scenario of scenarios) {\n results.push(\n await runScenario({\n bases,\n reducer: input.reducer,\n scenario,\n maxStepsPerScenario,\n }),\n );\n }\n const failed = results.filter((result) => result.status === \"failed\").length;\n return {\n status: failed === 0 ? \"passed\" : \"failed\",\n scenarioSummary: {\n total: results.length,\n passed: results.length - failed,\n failed,\n scenarios: results,\n },\n };\n}\n\nasync function runScenario(input: {\n bases: Readonly<Record<string, BaseStateArtifact>>;\n reducer: ReducerScenarioBundle;\n scenario: CandidateVerificationScenario;\n maxStepsPerScenario: number;\n}): Promise<CandidateVerificationScenarioResult> {\n const runtime = createTestRuntime({\n baseId: input.scenario.from,\n baseStates: input.bases,\n bundle: input.reducer,\n phase: input.scenario.phase,\n playerIds:\n input.bases[input.scenario.from]?.snapshot.domain?.flow?.activePlayers,\n });\n const ctx = createScenarioContext(runtime, input.maxStepsPerScenario);\n try {\n await input.scenario.when(ctx);\n await input.scenario.then(ctx);\n return { id: input.scenario.id, status: \"passed\" };\n } catch (error) {\n return {\n id: input.scenario.id,\n status: \"failed\",\n diagnostic: {\n kind: \"assertion\",\n message: boundedMessage(error),\n },\n };\n }\n}\n\nfunction createScenarioContext(\n runtime: ReturnType<typeof createTestRuntime>,\n maxStepsPerScenario: number,\n): SharedScenarioContext {\n let submittedSteps = 0;\n const baseContext: BaseContext = {\n game: {\n start: async () => undefined,\n submit: async (...args) => {\n submittedSteps += 1;\n if (submittedSteps > maxStepsPerScenario) {\n throw new Error(\n `Scenario exceeded maxStepsPerScenario limit ${maxStepsPerScenario}.`,\n );\n }\n return runtime.submit(...args);\n },\n },\n players: runtime.players,\n seat: runtime.seat,\n };\n return {\n ...baseContext,\n state: () => runtime.getFrame().flow.currentPhase ?? \"\",\n view: (playerId) => {\n const frame = runtime.getFrame();\n if (frame.perspectivePlayerId === playerId) return frame.view;\n return runtime.getFrame().view;\n },\n interactions: (playerId) => {\n const frame = runtime.getFrame();\n if (frame.perspectivePlayerId !== playerId) return [];\n return frame.availableInteractions as unknown as readonly InteractionDescriptorLike[];\n },\n explain: runtime.explain,\n diagnostics: runtime.diagnostics,\n expect: createExpectApi({\n lastDiagnosticRejection: () => {\n for (\n let index = runtime.diagnostics.events.length - 1;\n index >= 0;\n index -= 1\n ) {\n const event = runtime.diagnostics.events[index];\n if (event?.type === \"submitRejected\") return event;\n }\n return null;\n },\n }),\n };\n}\n\nfunction normalizeBases(\n input:\n | Readonly<Record<string, CandidateVerificationBase>>\n | readonly CandidateVerificationBase[],\n): Record<string, BaseStateArtifact> {\n const entries = Array.isArray(input)\n ? input.map((base) => [base.id, base] as const)\n : Object.entries(input);\n return Object.fromEntries(\n entries.map(([id, base]) => {\n if (!id) throw new Error(\"Candidate verification base id is required.\");\n if (!(\"snapshot\" in base) || !base.snapshot) {\n throw new Error(`Candidate verification base '${id}' has no snapshot.`);\n }\n const players =\n base.fingerprint?.players ??\n base.players ??\n base.snapshot.domain?.flow?.activePlayers?.length ??\n 1;\n return [\n id,\n {\n snapshot: base.snapshot,\n fingerprint: {\n players,\n contractFingerprint: base.fingerprint?.contractFingerprint,\n },\n },\n ];\n }),\n );\n}\n\nfunction normalizeScenarios(\n input:\n | Readonly<Record<string, CandidateVerificationScenario>>\n | readonly CandidateVerificationScenario[],\n): CandidateVerificationScenario[] {\n const scenarios = Array.isArray(input) ? input : Object.values(input);\n return scenarios.map((scenario) => {\n if (!scenario.id)\n throw new Error(\"Candidate verification scenario id is required.\");\n return scenario;\n });\n}\n\nfunction boundedMessage(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return message.slice(0, 2000);\n}\n"],"mappings":"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","names":[]}
|