@dreamboard-games/sdk 0.4.0-alpha.7 → 0.4.0-alpha.9

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 (112) hide show
  1. package/REFERENCE.md +1292 -287
  2. package/dist/authoring/index.d.ts +4 -9
  3. package/dist/authoring/index.js +11 -547
  4. package/dist/authoring/index.js.map +1 -1
  5. package/dist/authoring-compiler.d.ts +27 -0
  6. package/dist/authoring-compiler.js +12 -0
  7. package/dist/authoring-compiler.js.map +1 -0
  8. package/dist/authoring-materialize-cli.d.ts +1 -0
  9. package/dist/authoring-materialize-cli.js +46 -0
  10. package/dist/authoring-materialize-cli.js.map +1 -0
  11. package/dist/browser-interaction.d.ts +1 -1
  12. package/dist/{chunk-TGMXBRKY.js → chunk-3PFDHTR7.js} +19 -7
  13. package/dist/chunk-3PFDHTR7.js.map +1 -0
  14. package/dist/chunk-45P5CEGH.js +176 -0
  15. package/dist/chunk-45P5CEGH.js.map +1 -0
  16. package/dist/chunk-5XTAQ4EQ.js +32 -0
  17. package/dist/chunk-5XTAQ4EQ.js.map +1 -0
  18. package/dist/chunk-7ADPYKFT.js +532 -0
  19. package/dist/chunk-7ADPYKFT.js.map +1 -0
  20. package/dist/{chunk-RKGJ64UN.js → chunk-BUOODBVO.js} +2 -2
  21. package/dist/{chunk-VLG4YST5.js → chunk-GMOBG7Y7.js} +4 -4
  22. package/dist/{chunk-Q322XCY2.js → chunk-JRGP6W4V.js} +3 -3
  23. package/dist/chunk-L3W2FPRQ.js +1793 -0
  24. package/dist/chunk-L3W2FPRQ.js.map +1 -0
  25. package/dist/{chunk-3QIZKXJ2.js → chunk-NGYFBNBP.js} +3 -3
  26. package/dist/chunk-P6IJ5YVY.js +154 -0
  27. package/dist/chunk-P6IJ5YVY.js.map +1 -0
  28. package/dist/{chunk-5IHU5CUK.js → chunk-QQNL4WTX.js} +25 -22
  29. package/dist/chunk-QQNL4WTX.js.map +1 -0
  30. package/dist/{chunk-52DH7VQF.js → chunk-SACZWUA6.js} +143 -47
  31. package/dist/chunk-SACZWUA6.js.map +1 -0
  32. package/dist/{chunk-KYEWGZ2Y.js → chunk-SFOAY5H4.js} +2 -2
  33. package/dist/{chunk-KYEWGZ2Y.js.map → chunk-SFOAY5H4.js.map} +1 -1
  34. package/dist/chunk-UNVCT5Z7.js +73 -0
  35. package/dist/chunk-UNVCT5Z7.js.map +1 -0
  36. package/dist/{chunk-NO537WSS.js → chunk-WDR7SKBM.js} +2 -2
  37. package/dist/chunk-XDGRC6OR.js +7039 -0
  38. package/dist/chunk-XDGRC6OR.js.map +1 -0
  39. package/dist/chunk-XLHLFTLI.js +399 -0
  40. package/dist/chunk-XLHLFTLI.js.map +1 -0
  41. package/dist/{chunk-B2YBS3SG.js → chunk-YNW3KBDE.js} +41 -13
  42. package/dist/chunk-YNW3KBDE.js.map +1 -0
  43. package/dist/codegen.js +1 -1
  44. package/dist/{components-BTwSIjXj.d.ts → components-BPzsSRs8.d.ts} +1 -1
  45. package/dist/definitions-0kjPV9wh.d.ts +294 -0
  46. package/dist/{diagnostics-1BWjRo6-.d.ts → diagnostics-DIi3ina7.d.ts} +2 -1
  47. package/dist/{index-CFTjJIXd.d.ts → index-CWzWpQzM.d.ts} +1 -1
  48. package/dist/{index.d-DMASeF6M.d.ts → index.d-C7Ztirg6.d.ts} +234 -5
  49. package/dist/index.js +2 -2
  50. package/dist/package-set.d.ts +2 -2
  51. package/dist/package-set.js +2 -2
  52. package/dist/{protocol-835hEGne.d.ts → protocol-B2LWcqB4.d.ts} +14 -0
  53. package/dist/reducer/advanced.d.ts +4 -4
  54. package/dist/reducer/advanced.js +7 -26
  55. package/dist/reducer/advanced.js.map +1 -1
  56. package/dist/reducer-contract.d.ts +1 -1
  57. package/dist/reducer-contract.js +2 -2
  58. package/dist/reducer.d.ts +37 -28
  59. package/dist/reducer.js +43 -6018
  60. package/dist/reducer.js.map +1 -1
  61. package/dist/reference-game-compiler.d.ts +45 -0
  62. package/dist/reference-game-compiler.js +25 -0
  63. package/dist/reference-game-compiler.js.map +1 -0
  64. package/dist/reference-game-source-manifest-cli.d.ts +1 -0
  65. package/dist/reference-game-source-manifest-cli.js +84 -0
  66. package/dist/reference-game-source-manifest-cli.js.map +1 -0
  67. package/dist/reference-games/index.d.ts +7 -217
  68. package/dist/reference-games/index.js +28 -208
  69. package/dist/reference-games/index.js.map +1 -1
  70. package/dist/runtime/primitives.d.ts +3 -3
  71. package/dist/runtime/primitives.js +3 -3
  72. package/dist/runtime/runtime-api.d.ts +1 -1
  73. package/dist/runtime/workspace-contract.d.ts +4 -4
  74. package/dist/runtime/workspace-contract.js +4 -4
  75. package/dist/{runtime-Dkfm1x2r.d.ts → runtime-B_w9AO2n.d.ts} +60 -5
  76. package/dist/{runtime-api-C6aWo9c0.d.ts → runtime-api-xCWLMQRT.d.ts} +2 -0
  77. package/dist/runtime.d.ts +7 -7
  78. package/dist/runtime.js +13 -13
  79. package/dist/schema-9jZzlEWZ.d.ts +220 -0
  80. package/dist/{stale-contract-artifact-error-C5AaZPJ8.d.ts → stale-contract-artifact-error-XLaweZtF.d.ts} +1 -1
  81. package/dist/testing-compiler.d.ts +36 -0
  82. package/dist/testing-compiler.js +236 -0
  83. package/dist/testing-compiler.js.map +1 -0
  84. package/dist/testing-runtime.d.ts +97 -21
  85. package/dist/testing-runtime.js +154 -95
  86. package/dist/testing-runtime.js.map +1 -1
  87. package/dist/testing.d.ts +178 -60
  88. package/dist/testing.js +641 -26
  89. package/dist/testing.js.map +1 -1
  90. package/dist/types-Bvptkukh.d.ts +122 -0
  91. package/dist/{types-aI4V9CWe.d.ts → types-_zfC_7CD.d.ts} +1 -1
  92. package/dist/types.d.ts +4 -0
  93. package/dist/ui/components.d.ts +2 -2
  94. package/dist/ui/plugin-styles.css +1 -1
  95. package/dist/{ui-contract-Ue6SywvO.d.ts → ui-contract-CUC7Lyoc.d.ts} +1 -1
  96. package/dist/ui.d.ts +3 -3
  97. package/dist/{views-32rSsfeU.d.ts → views-DE2eZxPz.d.ts} +42 -13
  98. package/package.json +22 -3
  99. package/dist/chunk-3OZMHZK3.js +0 -40
  100. package/dist/chunk-3OZMHZK3.js.map +0 -1
  101. package/dist/chunk-52DH7VQF.js.map +0 -1
  102. package/dist/chunk-5IHU5CUK.js.map +0 -1
  103. package/dist/chunk-B2YBS3SG.js.map +0 -1
  104. package/dist/chunk-IU6KGPY7.js +0 -659
  105. package/dist/chunk-IU6KGPY7.js.map +0 -1
  106. package/dist/chunk-TGMXBRKY.js.map +0 -1
  107. package/dist/types-DcADVHe9.d.ts +0 -192
  108. /package/dist/{chunk-RKGJ64UN.js.map → chunk-BUOODBVO.js.map} +0 -0
  109. /package/dist/{chunk-VLG4YST5.js.map → chunk-GMOBG7Y7.js.map} +0 -0
  110. /package/dist/{chunk-Q322XCY2.js.map → chunk-JRGP6W4V.js.map} +0 -0
  111. /package/dist/{chunk-3QIZKXJ2.js.map → chunk-NGYFBNBP.js.map} +0 -0
  112. /package/dist/{chunk-NO537WSS.js.map → chunk-WDR7SKBM.js.map} +0 -0
@@ -0,0 +1,36 @@
1
+ import { h as ScenarioCheckpoint, m as ScenarioDefinitionGameLike, v as ScenarioReplayDefinition } from './definitions-0kjPV9wh.js';
2
+ import 'zod';
3
+ import './views-DE2eZxPz.js';
4
+ import './runtime-B_w9AO2n.js';
5
+ import './types.js';
6
+ import './diagnostics-DIi3ina7.js';
7
+
8
+ type CompiledScenarioReplay<Game extends ScenarioDefinitionGameLike = ScenarioDefinitionGameLike> = {
9
+ readonly schemaVersion: 1;
10
+ readonly scenario: {
11
+ readonly path: string;
12
+ /** Covers the local game/scenario module graph, including assertions. */
13
+ readonly sourceDigest: `sha256:${string}`;
14
+ };
15
+ /** Canonical serializable scenario projection; never contains `then`. */
16
+ readonly definition: ScenarioReplayDefinition<Game>;
17
+ readonly checkpoint: ScenarioCheckpoint;
18
+ readonly expected: {
19
+ readonly checkpointDigest: `sha256:${string}`;
20
+ readonly publicProjectionDigest: `sha256:${string}`;
21
+ };
22
+ };
23
+ type CompileScenarioReplayOptions = {
24
+ readonly scenarioPath: string;
25
+ readonly at?: ScenarioCheckpoint;
26
+ };
27
+ /**
28
+ * Compile one authored scenario into the trusted, serializable replay DTO used
29
+ * by dev-host, Workbench, demo, and performance adapters.
30
+ *
31
+ * The DTO may contain sealed/private command parameters. It must never cross a
32
+ * player, spectator, browser, ordinary-log, or public-receipt boundary.
33
+ */
34
+ declare function compileScenarioReplay(options: CompileScenarioReplayOptions): Promise<CompiledScenarioReplay>;
35
+
36
+ export { type CompileScenarioReplayOptions, type CompiledScenarioReplay, compileScenarioReplay };
@@ -0,0 +1,236 @@
1
+ import {
2
+ compareReferenceGameCanonicalStrings
3
+ } from "./chunk-UNVCT5Z7.js";
4
+ import "./chunk-PZ5AY32C.js";
5
+
6
+ // src/testing/compile-scenario-replay.ts
7
+ import { createHash } from "crypto";
8
+ import {
9
+ lstat,
10
+ mkdtemp,
11
+ readFile,
12
+ realpath,
13
+ rm,
14
+ stat,
15
+ writeFile
16
+ } from "fs/promises";
17
+ import { tmpdir } from "os";
18
+ import path from "path";
19
+ import { pathToFileURL } from "url";
20
+ import { build } from "esbuild";
21
+ var scenarioSourceDigestVersion = "dreamboard-scenario-source-closure@1";
22
+ var syntheticSourceFile = "__dreamboard_compile_scenario_replay__.ts";
23
+ async function compileScenarioReplay(options) {
24
+ const source = await resolveScenarioSource(options.scenarioPath);
25
+ const syntheticSource = buildSyntheticSource(source);
26
+ const bundled = await build({
27
+ absWorkingDir: source.projectRoot,
28
+ stdin: {
29
+ contents: syntheticSource,
30
+ loader: "ts",
31
+ resolveDir: source.projectRoot,
32
+ sourcefile: syntheticSourceFile
33
+ },
34
+ bundle: true,
35
+ format: "esm",
36
+ platform: "node",
37
+ target: "node24",
38
+ sourcemap: "inline",
39
+ metafile: true,
40
+ write: false,
41
+ logLevel: "silent"
42
+ });
43
+ const output = bundled.outputFiles?.[0];
44
+ if (!output || !bundled.metafile) {
45
+ throw new Error("Scenario replay compilation did not produce a bundle.");
46
+ }
47
+ const sourceDigest = await digestSourceClosure({
48
+ projectRoot: source.projectRoot,
49
+ inputPaths: Object.keys(bundled.metafile.inputs)
50
+ });
51
+ const tempRoot = await mkdtemp(
52
+ path.join(tmpdir(), "dreamboard-compiled-scenario-")
53
+ );
54
+ const outputPath = path.join(tempRoot, "compiled-scenario.mjs");
55
+ try {
56
+ await writeFile(outputPath, output.text);
57
+ const loaded = await import(`${pathToFileURL(outputPath).href}?source=${sourceDigest.slice(7, 19)}`);
58
+ if (typeof loaded.compile !== "function") {
59
+ throw new Error("Scenario replay bundle is missing compile().");
60
+ }
61
+ const materialized = await loaded.compile({
62
+ ...options.at === void 0 ? {} : { at: options.at },
63
+ scenarioPath: source.relativeScenarioPath,
64
+ sourceDigest
65
+ });
66
+ const compiled = {
67
+ schemaVersion: 1,
68
+ scenario: {
69
+ path: source.relativeScenarioPath,
70
+ sourceDigest
71
+ },
72
+ definition: materialized.definition,
73
+ checkpoint: materialized.checkpoint,
74
+ expected: materialized.expected
75
+ };
76
+ return assertSerializableCompiledReplay(compiled);
77
+ } finally {
78
+ await rm(tempRoot, { recursive: true, force: true });
79
+ }
80
+ }
81
+ async function resolveScenarioSource(requestedPath) {
82
+ if (typeof requestedPath !== "string" || requestedPath.length === 0) {
83
+ throw new Error("scenarioPath must be a non-empty string.");
84
+ }
85
+ const requestedAbsolute = path.resolve(process.cwd(), requestedPath);
86
+ const requestedStats = await lstat(requestedAbsolute).catch((error) => {
87
+ if (isMissingPathError(error)) return null;
88
+ throw error;
89
+ });
90
+ if (!requestedStats?.isFile()) {
91
+ throw new Error(`Scenario path does not name a file: ${requestedPath}.`);
92
+ }
93
+ const scenarioPath = await realpath(requestedAbsolute);
94
+ const projectRoot = await findProjectRoot(path.dirname(scenarioPath));
95
+ const canonicalProjectRoot = await realpath(projectRoot);
96
+ const scenarioRoot = path.join(canonicalProjectRoot, "test", "scenarios");
97
+ const canonicalScenarioRoot = await realpath(scenarioRoot).catch((error) => {
98
+ if (isMissingPathError(error)) return null;
99
+ throw error;
100
+ });
101
+ if (canonicalScenarioRoot === null || !isWithinDirectory(canonicalScenarioRoot, scenarioPath) || !scenarioPath.endsWith(".scenario.ts")) {
102
+ throw new Error(
103
+ "scenarioPath must resolve to test/scenarios/**/*.scenario.ts inside one game package."
104
+ );
105
+ }
106
+ const gamePath = path.join(canonicalProjectRoot, "app", "game.ts");
107
+ if (!await isFile(gamePath)) {
108
+ throw new Error(`Game package is missing ${gamePath}.`);
109
+ }
110
+ return {
111
+ projectRoot: canonicalProjectRoot,
112
+ scenarioPath,
113
+ relativeScenarioPath: toPosix(
114
+ path.relative(canonicalProjectRoot, scenarioPath)
115
+ ),
116
+ gamePath
117
+ };
118
+ }
119
+ async function findProjectRoot(start) {
120
+ let current = path.resolve(start);
121
+ for (; ; ) {
122
+ if (await isFile(path.join(current, "package.json")) && await isFile(path.join(current, "app", "game.ts"))) {
123
+ return current;
124
+ }
125
+ const parent = path.dirname(current);
126
+ if (parent === current) {
127
+ throw new Error(
128
+ "Could not find a game package containing package.json and app/game.ts."
129
+ );
130
+ }
131
+ current = parent;
132
+ }
133
+ }
134
+ function buildSyntheticSource(source) {
135
+ const gameSpecifier = localImportSpecifier(
136
+ source.projectRoot,
137
+ source.gamePath
138
+ );
139
+ const scenarioSpecifier = localImportSpecifier(
140
+ source.projectRoot,
141
+ source.scenarioPath
142
+ );
143
+ return [
144
+ `import * as gameModule from ${JSON.stringify(gameSpecifier)};`,
145
+ `import * as scenarioModule from ${JSON.stringify(scenarioSpecifier)};`,
146
+ 'import { inspectScenario, toScenarioReplayDefinition } from "@dreamboard-games/sdk/testing";',
147
+ 'import { digestScenarioProjection, scenarioProjectionParityFromInspectNode } from "@dreamboard-games/sdk/testing-runtime";',
148
+ "const game = gameModule.game ?? gameModule.default;",
149
+ "const scenario = scenarioModule.scenario ?? scenarioModule.default;",
150
+ "export async function compile(options) {",
151
+ " if (!game || !scenario) {",
152
+ ' throw new Error("Compiled scenario entry is missing game or scenario authority.");',
153
+ " }",
154
+ " const definition = toScenarioReplayDefinition(scenario);",
155
+ " const inspected = await inspectScenario({",
156
+ " game,",
157
+ " scenario: definition,",
158
+ " identity: {",
159
+ " id: definition.id,",
160
+ " path: options.scenarioPath,",
161
+ " sourceDigest: options.sourceDigest,",
162
+ " },",
163
+ ' perspective: { kind: "spectator" },',
164
+ " ...(options.at === undefined ? {} : { at: options.at }),",
165
+ " });",
166
+ " return {",
167
+ " definition,",
168
+ " checkpoint: inspected.node.checkpoint,",
169
+ " expected: {",
170
+ " checkpointDigest: inspected.node.checkpointDigest,",
171
+ " publicProjectionDigest: digestScenarioProjection(",
172
+ " scenarioProjectionParityFromInspectNode(inspected.node),",
173
+ " ),",
174
+ " },",
175
+ " };",
176
+ "}"
177
+ ].join("\n");
178
+ }
179
+ async function digestSourceClosure(options) {
180
+ const syntheticPath = path.resolve(options.projectRoot, syntheticSourceFile);
181
+ const localPaths = options.inputPaths.map(
182
+ (inputPath) => path.isAbsolute(inputPath) ? inputPath : path.resolve(options.projectRoot, inputPath)
183
+ ).filter(
184
+ (inputPath) => inputPath !== syntheticPath && isWithinDirectory(options.projectRoot, inputPath) && !toPosix(path.relative(options.projectRoot, inputPath)).split("/").includes("node_modules")
185
+ );
186
+ const inputs = await Promise.all(
187
+ [...new Set(localPaths)].map(async (inputPath) => {
188
+ const content = await readFile(inputPath);
189
+ return {
190
+ path: toPosix(path.relative(options.projectRoot, inputPath)),
191
+ sha256: createHash("sha256").update(content).digest("hex")
192
+ };
193
+ })
194
+ );
195
+ inputs.sort(
196
+ (left, right) => compareReferenceGameCanonicalStrings(left.path, right.path)
197
+ );
198
+ return `sha256:${createHash("sha256").update(
199
+ JSON.stringify({
200
+ digestVersion: scenarioSourceDigestVersion,
201
+ inputs
202
+ })
203
+ ).digest("hex")}`;
204
+ }
205
+ function assertSerializableCompiledReplay(value) {
206
+ const serialized = JSON.stringify(value);
207
+ const parsed = JSON.parse(serialized);
208
+ if (parsed.schemaVersion !== 1 || !/^sha256:[a-f0-9]{64}$/.test(parsed.scenario.sourceDigest) || !/^sha256:[a-f0-9]{64}$/.test(parsed.expected.checkpointDigest) || !/^sha256:[a-f0-9]{64}$/.test(parsed.expected.publicProjectionDigest)) {
209
+ throw new Error("Compiled scenario replay failed digest validation.");
210
+ }
211
+ return parsed;
212
+ }
213
+ function localImportSpecifier(projectRoot, filePath) {
214
+ const relative = toPosix(path.relative(projectRoot, filePath));
215
+ return relative.startsWith(".") ? relative : `./${relative}`;
216
+ }
217
+ function isWithinDirectory(directory, filePath) {
218
+ const relative = path.relative(directory, filePath);
219
+ return relative !== "" && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
220
+ }
221
+ async function isFile(filePath) {
222
+ return stat(filePath).then((value) => value.isFile()).catch((error) => {
223
+ if (isMissingPathError(error)) return false;
224
+ throw error;
225
+ });
226
+ }
227
+ function isMissingPathError(error) {
228
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
229
+ }
230
+ function toPosix(value) {
231
+ return value.split(path.sep).join("/");
232
+ }
233
+ export {
234
+ compileScenarioReplay
235
+ };
236
+ //# sourceMappingURL=testing-compiler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing/compile-scenario-replay.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n lstat,\n mkdtemp,\n readFile,\n realpath,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { compareReferenceGameCanonicalStrings } from \"../reference-games/canonical.js\";\nimport { pathToFileURL } from \"node:url\";\nimport { build } from \"esbuild\";\nimport type {\n ScenarioCheckpoint,\n ScenarioReplayDefinition,\n} from \"./definitions.js\";\nimport type { ScenarioDefinitionGameLike } from \"./scenario-definition-validation.js\";\n\nexport type CompiledScenarioReplay<\n Game extends ScenarioDefinitionGameLike = ScenarioDefinitionGameLike,\n> = {\n readonly schemaVersion: 1;\n readonly scenario: {\n readonly path: string;\n /** Covers the local game/scenario module graph, including assertions. */\n readonly sourceDigest: `sha256:${string}`;\n };\n /** Canonical serializable scenario projection; never contains `then`. */\n readonly definition: ScenarioReplayDefinition<Game>;\n readonly checkpoint: ScenarioCheckpoint;\n readonly expected: {\n readonly checkpointDigest: `sha256:${string}`;\n readonly publicProjectionDigest: `sha256:${string}`;\n };\n};\n\nexport type CompileScenarioReplayOptions = {\n readonly scenarioPath: string;\n readonly at?: ScenarioCheckpoint;\n};\n\ntype SyntheticCompileResult = Omit<\n CompiledScenarioReplay,\n \"schemaVersion\" | \"scenario\"\n>;\n\ntype SyntheticCompileModule = {\n readonly compile: (options: {\n readonly at?: ScenarioCheckpoint;\n readonly scenarioPath: string;\n readonly sourceDigest: `sha256:${string}`;\n }) => Promise<SyntheticCompileResult>;\n};\n\ntype ScenarioSource = {\n readonly projectRoot: string;\n readonly scenarioPath: string;\n readonly relativeScenarioPath: string;\n readonly gamePath: string;\n};\n\nconst scenarioSourceDigestVersion = \"dreamboard-scenario-source-closure@1\";\nconst syntheticSourceFile = \"__dreamboard_compile_scenario_replay__.ts\";\n\n/**\n * Compile one authored scenario into the trusted, serializable replay DTO used\n * by dev-host, Workbench, demo, and performance adapters.\n *\n * The DTO may contain sealed/private command parameters. It must never cross a\n * player, spectator, browser, ordinary-log, or public-receipt boundary.\n */\nexport async function compileScenarioReplay(\n options: CompileScenarioReplayOptions,\n): Promise<CompiledScenarioReplay> {\n const source = await resolveScenarioSource(options.scenarioPath);\n const syntheticSource = buildSyntheticSource(source);\n const bundled = await build({\n absWorkingDir: source.projectRoot,\n stdin: {\n contents: syntheticSource,\n loader: \"ts\",\n resolveDir: source.projectRoot,\n sourcefile: syntheticSourceFile,\n },\n bundle: true,\n format: \"esm\",\n platform: \"node\",\n target: \"node24\",\n sourcemap: \"inline\",\n metafile: true,\n write: false,\n logLevel: \"silent\",\n });\n const output = bundled.outputFiles?.[0];\n if (!output || !bundled.metafile) {\n throw new Error(\"Scenario replay compilation did not produce a bundle.\");\n }\n const sourceDigest = await digestSourceClosure({\n projectRoot: source.projectRoot,\n inputPaths: Object.keys(bundled.metafile.inputs),\n });\n\n const tempRoot = await mkdtemp(\n path.join(tmpdir(), \"dreamboard-compiled-scenario-\"),\n );\n const outputPath = path.join(tempRoot, \"compiled-scenario.mjs\");\n try {\n await writeFile(outputPath, output.text);\n const loaded = (await import(\n `${pathToFileURL(outputPath).href}?source=${sourceDigest.slice(7, 19)}`\n )) as SyntheticCompileModule;\n if (typeof loaded.compile !== \"function\") {\n throw new Error(\"Scenario replay bundle is missing compile().\");\n }\n const materialized = await loaded.compile({\n ...(options.at === undefined ? {} : { at: options.at }),\n scenarioPath: source.relativeScenarioPath,\n sourceDigest,\n });\n const compiled = {\n schemaVersion: 1,\n scenario: {\n path: source.relativeScenarioPath,\n sourceDigest,\n },\n definition: materialized.definition,\n checkpoint: materialized.checkpoint,\n expected: materialized.expected,\n } satisfies CompiledScenarioReplay;\n return assertSerializableCompiledReplay(compiled);\n } finally {\n await rm(tempRoot, { recursive: true, force: true });\n }\n}\n\nasync function resolveScenarioSource(\n requestedPath: string,\n): Promise<ScenarioSource> {\n if (typeof requestedPath !== \"string\" || requestedPath.length === 0) {\n throw new Error(\"scenarioPath must be a non-empty string.\");\n }\n const requestedAbsolute = path.resolve(process.cwd(), requestedPath);\n const requestedStats = await lstat(requestedAbsolute).catch((error) => {\n if (isMissingPathError(error)) return null;\n throw error;\n });\n if (!requestedStats?.isFile()) {\n throw new Error(`Scenario path does not name a file: ${requestedPath}.`);\n }\n const scenarioPath = await realpath(requestedAbsolute);\n const projectRoot = await findProjectRoot(path.dirname(scenarioPath));\n const canonicalProjectRoot = await realpath(projectRoot);\n const scenarioRoot = path.join(canonicalProjectRoot, \"test\", \"scenarios\");\n const canonicalScenarioRoot = await realpath(scenarioRoot).catch((error) => {\n if (isMissingPathError(error)) return null;\n throw error;\n });\n if (\n canonicalScenarioRoot === null ||\n !isWithinDirectory(canonicalScenarioRoot, scenarioPath) ||\n !scenarioPath.endsWith(\".scenario.ts\")\n ) {\n throw new Error(\n \"scenarioPath must resolve to test/scenarios/**/*.scenario.ts inside one game package.\",\n );\n }\n const gamePath = path.join(canonicalProjectRoot, \"app\", \"game.ts\");\n if (!(await isFile(gamePath))) {\n throw new Error(`Game package is missing ${gamePath}.`);\n }\n return {\n projectRoot: canonicalProjectRoot,\n scenarioPath,\n relativeScenarioPath: toPosix(\n path.relative(canonicalProjectRoot, scenarioPath),\n ),\n gamePath,\n };\n}\n\nasync function findProjectRoot(start: string): Promise<string> {\n let current = path.resolve(start);\n for (;;) {\n if (\n (await isFile(path.join(current, \"package.json\"))) &&\n (await isFile(path.join(current, \"app\", \"game.ts\")))\n ) {\n return current;\n }\n const parent = path.dirname(current);\n if (parent === current) {\n throw new Error(\n \"Could not find a game package containing package.json and app/game.ts.\",\n );\n }\n current = parent;\n }\n}\n\nfunction buildSyntheticSource(source: ScenarioSource): string {\n const gameSpecifier = localImportSpecifier(\n source.projectRoot,\n source.gamePath,\n );\n const scenarioSpecifier = localImportSpecifier(\n source.projectRoot,\n source.scenarioPath,\n );\n return [\n `import * as gameModule from ${JSON.stringify(gameSpecifier)};`,\n `import * as scenarioModule from ${JSON.stringify(scenarioSpecifier)};`,\n 'import { inspectScenario, toScenarioReplayDefinition } from \"@dreamboard-games/sdk/testing\";',\n 'import { digestScenarioProjection, scenarioProjectionParityFromInspectNode } from \"@dreamboard-games/sdk/testing-runtime\";',\n \"const game = gameModule.game ?? gameModule.default;\",\n \"const scenario = scenarioModule.scenario ?? scenarioModule.default;\",\n \"export async function compile(options) {\",\n \" if (!game || !scenario) {\",\n ' throw new Error(\"Compiled scenario entry is missing game or scenario authority.\");',\n \" }\",\n \" const definition = toScenarioReplayDefinition(scenario);\",\n \" const inspected = await inspectScenario({\",\n \" game,\",\n \" scenario: definition,\",\n \" identity: {\",\n \" id: definition.id,\",\n \" path: options.scenarioPath,\",\n \" sourceDigest: options.sourceDigest,\",\n \" },\",\n ' perspective: { kind: \"spectator\" },',\n \" ...(options.at === undefined ? {} : { at: options.at }),\",\n \" });\",\n \" return {\",\n \" definition,\",\n \" checkpoint: inspected.node.checkpoint,\",\n \" expected: {\",\n \" checkpointDigest: inspected.node.checkpointDigest,\",\n \" publicProjectionDigest: digestScenarioProjection(\",\n \" scenarioProjectionParityFromInspectNode(inspected.node),\",\n \" ),\",\n \" },\",\n \" };\",\n \"}\",\n ].join(\"\\n\");\n}\n\nasync function digestSourceClosure(options: {\n readonly projectRoot: string;\n readonly inputPaths: readonly string[];\n}): Promise<`sha256:${string}`> {\n const syntheticPath = path.resolve(options.projectRoot, syntheticSourceFile);\n const localPaths = options.inputPaths\n .map((inputPath) =>\n path.isAbsolute(inputPath)\n ? inputPath\n : path.resolve(options.projectRoot, inputPath),\n )\n .filter(\n (inputPath) =>\n inputPath !== syntheticPath &&\n isWithinDirectory(options.projectRoot, inputPath) &&\n !toPosix(path.relative(options.projectRoot, inputPath))\n .split(\"/\")\n .includes(\"node_modules\"),\n );\n const inputs = await Promise.all(\n [...new Set(localPaths)].map(async (inputPath) => {\n const content = await readFile(inputPath);\n return {\n path: toPosix(path.relative(options.projectRoot, inputPath)),\n sha256: createHash(\"sha256\").update(content).digest(\"hex\"),\n };\n }),\n );\n inputs.sort((left, right) =>\n compareReferenceGameCanonicalStrings(left.path, right.path),\n );\n return `sha256:${createHash(\"sha256\")\n .update(\n JSON.stringify({\n digestVersion: scenarioSourceDigestVersion,\n inputs,\n }),\n )\n .digest(\"hex\")}`;\n}\n\nfunction assertSerializableCompiledReplay(\n value: CompiledScenarioReplay,\n): CompiledScenarioReplay {\n const serialized = JSON.stringify(value);\n const parsed = JSON.parse(serialized) as CompiledScenarioReplay;\n if (\n parsed.schemaVersion !== 1 ||\n !/^sha256:[a-f0-9]{64}$/.test(parsed.scenario.sourceDigest) ||\n !/^sha256:[a-f0-9]{64}$/.test(parsed.expected.checkpointDigest) ||\n !/^sha256:[a-f0-9]{64}$/.test(parsed.expected.publicProjectionDigest)\n ) {\n throw new Error(\"Compiled scenario replay failed digest validation.\");\n }\n return parsed;\n}\n\nfunction localImportSpecifier(projectRoot: string, filePath: string): string {\n const relative = toPosix(path.relative(projectRoot, filePath));\n return relative.startsWith(\".\") ? relative : `./${relative}`;\n}\n\nfunction isWithinDirectory(directory: string, filePath: string): boolean {\n const relative = path.relative(directory, filePath);\n return (\n relative !== \"\" &&\n relative !== \"..\" &&\n !relative.startsWith(`..${path.sep}`) &&\n !path.isAbsolute(relative)\n );\n}\n\nasync function isFile(filePath: string): Promise<boolean> {\n return stat(filePath)\n .then((value) => value.isFile())\n .catch((error) => {\n if (isMissingPathError(error)) return false;\n throw error;\n });\n}\n\nfunction isMissingPathError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { readonly code?: unknown }).code === \"ENOENT\"\n );\n}\n\nfunction toPosix(value: string): string {\n return value.split(path.sep).join(\"/\");\n}\n"],"mappings":"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","names":[]}
@@ -1,32 +1,108 @@
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';
1
+ import { D as DispatchTraceSummaryEntry } from './diagnostics-DIi3ina7.js';
2
+ import { m as ScenarioDefinitionGameLike, l as ScenarioDefinition } from './definitions-0kjPV9wh.js';
3
+ import { i as Sha256Digest, d as InspectNode } from './types-Bvptkukh.js';
4
+ export { h as ScenarioRuntimeCheckpointMaterialization, m as materializeScenarioRuntimeCheckpoint } from './types-Bvptkukh.js';
3
5
  import 'zod';
4
- import './diagnostics-1BWjRo6-.js';
6
+ import './views-DE2eZxPz.js';
7
+ import './runtime-B_w9AO2n.js';
8
+ import './types.js';
9
+ import './index.d-C7Ztirg6.js';
5
10
 
6
- type BaseStateArtifact = {
7
- readonly snapshot: wire.ReducerSessionState;
8
- readonly fingerprint: {
9
- readonly players: number;
10
- readonly contractFingerprint?: string;
11
+ type GameLike = {
12
+ readonly phases: Readonly<Record<string, unknown>>;
13
+ };
14
+ declare function resolveScenarioCommandParams(options: {
15
+ readonly game: GameLike;
16
+ readonly phase: string;
17
+ readonly interactionId: string;
18
+ readonly params: unknown;
19
+ readonly playerIds: readonly string[];
20
+ readonly path: string;
21
+ }): Record<string, unknown>;
22
+
23
+ type ScenarioProjectionInteractionInput = {
24
+ readonly key: string;
25
+ readonly kind: string;
26
+ readonly domain: unknown;
27
+ };
28
+ /** Shared SDK normalization for inspect DTOs and backend parity projections. */
29
+ declare function scenarioProjectionInputMetadata(input: ScenarioProjectionInteractionInput): {
30
+ readonly key: string;
31
+ readonly kind: string;
32
+ readonly eligibleCount: number | "lazy";
33
+ };
34
+ type ScenarioProjectionParity = {
35
+ readonly perspective: "spectator" | {
36
+ readonly seat: number;
37
+ };
38
+ readonly flow: {
39
+ readonly phase: string;
40
+ readonly step: string | null;
41
+ readonly activeSeats: readonly number[];
42
+ readonly pendingSeats: readonly number[];
43
+ readonly continuationWaiterSeats: readonly number[];
44
+ readonly blockedBy: readonly {
45
+ readonly actorSeat: number;
46
+ readonly blockerSeats: readonly number[];
47
+ }[];
11
48
  };
49
+ readonly view: unknown;
50
+ readonly interactions: readonly {
51
+ readonly actorSeat: number;
52
+ readonly interactionId: string;
53
+ readonly availability: {
54
+ readonly status: string;
55
+ readonly code?: string;
56
+ readonly reason?: string;
57
+ };
58
+ readonly inputs: readonly {
59
+ readonly key: string;
60
+ readonly kind: string;
61
+ readonly eligibleCount: number | "lazy";
62
+ }[];
63
+ }[];
12
64
  };
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;
65
+ /**
66
+ * Canonical local/backend parity authority. It deliberately excludes raw
67
+ * reducer public/private state, interaction explanations, entropy, and trace:
68
+ * backend gameplay frames expose the selected projection, not reducer state.
69
+ */
70
+ declare function scenarioProjectionParityFromInspectNode(node: InspectNode): ScenarioProjectionParity;
71
+ declare function digestScenarioProjection(projection: ScenarioProjectionParity): Sha256Digest;
72
+
73
+ type CandidateVerificationScenario<Game extends ScenarioDefinitionGameLike> = ScenarioDefinition<Game>;
74
+ type CandidateVerificationInput<Game extends ScenarioDefinitionGameLike> = {
75
+ /** The authored reducer game definition used by production dispatch. */
76
+ readonly reducer: Game;
77
+ readonly scenarios: Readonly<Record<string, CandidateVerificationScenario<Game>>> | readonly CandidateVerificationScenario<Game>[];
20
78
  readonly maxScenarios?: number;
21
79
  readonly maxStepsPerScenario?: number;
22
80
  };
81
+ type CandidateVerificationReplayDiagnostic = {
82
+ readonly kind: "replay";
83
+ readonly message: string;
84
+ readonly scenarioId?: string;
85
+ readonly segment?: "given" | "when";
86
+ readonly index?: number;
87
+ readonly interactionId?: string;
88
+ readonly errorCode?: string;
89
+ readonly reducerMessage?: string;
90
+ readonly trace?: readonly DispatchTraceSummaryEntry[];
91
+ };
92
+ type CandidateVerificationAssertionDiagnostic = {
93
+ readonly kind: "assertion";
94
+ readonly message: string;
95
+ };
96
+ type CandidateVerificationLimitDiagnostic = {
97
+ readonly kind: "limit";
98
+ readonly message: string;
99
+ readonly actualSteps: number;
100
+ readonly maxStepsPerScenario: number;
101
+ };
23
102
  type CandidateVerificationScenarioResult = {
24
103
  readonly id: string;
25
104
  readonly status: "passed" | "failed";
26
- readonly diagnostic?: {
27
- readonly kind: "assertion";
28
- readonly message: string;
29
- };
105
+ readonly diagnostic?: CandidateVerificationReplayDiagnostic | CandidateVerificationAssertionDiagnostic | CandidateVerificationLimitDiagnostic;
30
106
  };
31
107
  type CandidateVerificationResult = {
32
108
  readonly status: "passed" | "failed";
@@ -37,6 +113,6 @@ type CandidateVerificationResult = {
37
113
  readonly scenarios: readonly CandidateVerificationScenarioResult[];
38
114
  };
39
115
  };
40
- declare function runCandidateVerification(input: CandidateVerificationInput): Promise<CandidateVerificationResult>;
116
+ declare function runCandidateVerification<const Game extends ScenarioDefinitionGameLike>(input: CandidateVerificationInput<Game>): Promise<CandidateVerificationResult>;
41
117
 
42
- export { type CandidateVerificationBase, type CandidateVerificationInput, type CandidateVerificationResult, type CandidateVerificationScenario, type CandidateVerificationScenarioResult, runCandidateVerification };
118
+ export { type CandidateVerificationAssertionDiagnostic, type CandidateVerificationInput, type CandidateVerificationLimitDiagnostic, type CandidateVerificationReplayDiagnostic, type CandidateVerificationResult, type CandidateVerificationScenario, type CandidateVerificationScenarioResult, type ScenarioProjectionInteractionInput, type ScenarioProjectionParity, digestScenarioProjection, resolveScenarioCommandParams, runCandidateVerification, scenarioProjectionInputMetadata, scenarioProjectionParityFromInspectNode };