@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.
- package/REFERENCE.md +1292 -287
- package/dist/authoring/index.d.ts +4 -9
- package/dist/authoring/index.js +11 -547
- package/dist/authoring/index.js.map +1 -1
- package/dist/authoring-compiler.d.ts +27 -0
- package/dist/authoring-compiler.js +12 -0
- package/dist/authoring-compiler.js.map +1 -0
- package/dist/authoring-materialize-cli.d.ts +1 -0
- package/dist/authoring-materialize-cli.js +46 -0
- package/dist/authoring-materialize-cli.js.map +1 -0
- package/dist/browser-interaction.d.ts +1 -1
- package/dist/{chunk-TGMXBRKY.js → chunk-3PFDHTR7.js} +19 -7
- package/dist/chunk-3PFDHTR7.js.map +1 -0
- package/dist/chunk-45P5CEGH.js +176 -0
- package/dist/chunk-45P5CEGH.js.map +1 -0
- package/dist/chunk-5XTAQ4EQ.js +32 -0
- package/dist/chunk-5XTAQ4EQ.js.map +1 -0
- package/dist/chunk-7ADPYKFT.js +532 -0
- package/dist/chunk-7ADPYKFT.js.map +1 -0
- package/dist/{chunk-RKGJ64UN.js → chunk-BUOODBVO.js} +2 -2
- package/dist/{chunk-VLG4YST5.js → chunk-GMOBG7Y7.js} +4 -4
- package/dist/{chunk-Q322XCY2.js → chunk-JRGP6W4V.js} +3 -3
- package/dist/chunk-L3W2FPRQ.js +1793 -0
- package/dist/chunk-L3W2FPRQ.js.map +1 -0
- package/dist/{chunk-3QIZKXJ2.js → chunk-NGYFBNBP.js} +3 -3
- package/dist/chunk-P6IJ5YVY.js +154 -0
- package/dist/chunk-P6IJ5YVY.js.map +1 -0
- package/dist/{chunk-5IHU5CUK.js → chunk-QQNL4WTX.js} +25 -22
- package/dist/chunk-QQNL4WTX.js.map +1 -0
- package/dist/{chunk-52DH7VQF.js → chunk-SACZWUA6.js} +143 -47
- package/dist/chunk-SACZWUA6.js.map +1 -0
- package/dist/{chunk-KYEWGZ2Y.js → chunk-SFOAY5H4.js} +2 -2
- package/dist/{chunk-KYEWGZ2Y.js.map → chunk-SFOAY5H4.js.map} +1 -1
- package/dist/chunk-UNVCT5Z7.js +73 -0
- package/dist/chunk-UNVCT5Z7.js.map +1 -0
- package/dist/{chunk-NO537WSS.js → chunk-WDR7SKBM.js} +2 -2
- package/dist/chunk-XDGRC6OR.js +7039 -0
- package/dist/chunk-XDGRC6OR.js.map +1 -0
- package/dist/chunk-XLHLFTLI.js +399 -0
- package/dist/chunk-XLHLFTLI.js.map +1 -0
- package/dist/{chunk-B2YBS3SG.js → chunk-YNW3KBDE.js} +41 -13
- package/dist/chunk-YNW3KBDE.js.map +1 -0
- package/dist/codegen.js +1 -1
- package/dist/{components-BTwSIjXj.d.ts → components-BPzsSRs8.d.ts} +1 -1
- package/dist/definitions-0kjPV9wh.d.ts +294 -0
- package/dist/{diagnostics-1BWjRo6-.d.ts → diagnostics-DIi3ina7.d.ts} +2 -1
- package/dist/{index-CFTjJIXd.d.ts → index-CWzWpQzM.d.ts} +1 -1
- package/dist/{index.d-DMASeF6M.d.ts → index.d-C7Ztirg6.d.ts} +234 -5
- package/dist/index.js +2 -2
- package/dist/package-set.d.ts +2 -2
- package/dist/package-set.js +2 -2
- package/dist/{protocol-835hEGne.d.ts → protocol-B2LWcqB4.d.ts} +14 -0
- package/dist/reducer/advanced.d.ts +4 -4
- package/dist/reducer/advanced.js +7 -26
- package/dist/reducer/advanced.js.map +1 -1
- package/dist/reducer-contract.d.ts +1 -1
- package/dist/reducer-contract.js +2 -2
- package/dist/reducer.d.ts +37 -28
- package/dist/reducer.js +43 -6018
- package/dist/reducer.js.map +1 -1
- package/dist/reference-game-compiler.d.ts +45 -0
- package/dist/reference-game-compiler.js +25 -0
- package/dist/reference-game-compiler.js.map +1 -0
- package/dist/reference-game-source-manifest-cli.d.ts +1 -0
- package/dist/reference-game-source-manifest-cli.js +84 -0
- package/dist/reference-game-source-manifest-cli.js.map +1 -0
- package/dist/reference-games/index.d.ts +7 -217
- package/dist/reference-games/index.js +28 -208
- package/dist/reference-games/index.js.map +1 -1
- package/dist/runtime/primitives.d.ts +3 -3
- package/dist/runtime/primitives.js +3 -3
- package/dist/runtime/runtime-api.d.ts +1 -1
- package/dist/runtime/workspace-contract.d.ts +4 -4
- package/dist/runtime/workspace-contract.js +4 -4
- package/dist/{runtime-Dkfm1x2r.d.ts → runtime-B_w9AO2n.d.ts} +60 -5
- package/dist/{runtime-api-C6aWo9c0.d.ts → runtime-api-xCWLMQRT.d.ts} +2 -0
- package/dist/runtime.d.ts +7 -7
- package/dist/runtime.js +13 -13
- package/dist/schema-9jZzlEWZ.d.ts +220 -0
- package/dist/{stale-contract-artifact-error-C5AaZPJ8.d.ts → stale-contract-artifact-error-XLaweZtF.d.ts} +1 -1
- package/dist/testing-compiler.d.ts +36 -0
- package/dist/testing-compiler.js +236 -0
- package/dist/testing-compiler.js.map +1 -0
- package/dist/testing-runtime.d.ts +97 -21
- package/dist/testing-runtime.js +154 -95
- package/dist/testing-runtime.js.map +1 -1
- package/dist/testing.d.ts +178 -60
- package/dist/testing.js +641 -26
- package/dist/testing.js.map +1 -1
- package/dist/types-Bvptkukh.d.ts +122 -0
- package/dist/{types-aI4V9CWe.d.ts → types-_zfC_7CD.d.ts} +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/ui/components.d.ts +2 -2
- package/dist/ui/plugin-styles.css +1 -1
- package/dist/{ui-contract-Ue6SywvO.d.ts → ui-contract-CUC7Lyoc.d.ts} +1 -1
- package/dist/ui.d.ts +3 -3
- package/dist/{views-32rSsfeU.d.ts → views-DE2eZxPz.d.ts} +42 -13
- package/package.json +22 -3
- package/dist/chunk-3OZMHZK3.js +0 -40
- package/dist/chunk-3OZMHZK3.js.map +0 -1
- package/dist/chunk-52DH7VQF.js.map +0 -1
- package/dist/chunk-5IHU5CUK.js.map +0 -1
- package/dist/chunk-B2YBS3SG.js.map +0 -1
- package/dist/chunk-IU6KGPY7.js +0 -659
- package/dist/chunk-IU6KGPY7.js.map +0 -1
- package/dist/chunk-TGMXBRKY.js.map +0 -1
- package/dist/types-DcADVHe9.d.ts +0 -192
- /package/dist/{chunk-RKGJ64UN.js.map → chunk-BUOODBVO.js.map} +0 -0
- /package/dist/{chunk-VLG4YST5.js.map → chunk-GMOBG7Y7.js.map} +0 -0
- /package/dist/{chunk-Q322XCY2.js.map → chunk-JRGP6W4V.js.map} +0 -0
- /package/dist/{chunk-3QIZKXJ2.js.map → chunk-NGYFBNBP.js.map} +0 -0
- /package/dist/{chunk-NO537WSS.js.map → chunk-WDR7SKBM.js.map} +0 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import {
|
|
2
|
+
REFERENCE_GAME_SOURCE_MANIFEST_SCHEMA_VERSION,
|
|
3
|
+
parseReferenceGameSourceManifest
|
|
4
|
+
} from "./chunk-45P5CEGH.js";
|
|
5
|
+
import {
|
|
6
|
+
compareReferenceGameCanonicalStrings,
|
|
7
|
+
computeReferenceGameSourceFingerprint
|
|
8
|
+
} from "./chunk-UNVCT5Z7.js";
|
|
9
|
+
import {
|
|
10
|
+
WORKSPACE_CODEGEN_OWNERSHIP
|
|
11
|
+
} from "./chunk-SACZWUA6.js";
|
|
12
|
+
|
|
13
|
+
// src/reference-games/source-inventory-policy-core.mjs
|
|
14
|
+
var CANONICAL_REFERENCE_GAME_IDS = Object.freeze([
|
|
15
|
+
"automa-river-rival",
|
|
16
|
+
"deck-building-market",
|
|
17
|
+
"hearts",
|
|
18
|
+
"hex-network-trading",
|
|
19
|
+
"multiplayer-ranking-and-ties",
|
|
20
|
+
"roll-and-write-scorecard",
|
|
21
|
+
"simultaneous-card-drafting",
|
|
22
|
+
"solo-countdown-puzzle",
|
|
23
|
+
"worker-placement-tableau"
|
|
24
|
+
]);
|
|
25
|
+
function createReferenceGameSourceInventoryPolicy(ownership) {
|
|
26
|
+
return Object.freeze({
|
|
27
|
+
schemaVersion: 1,
|
|
28
|
+
workspaceOwnershipVersion: ownership.version,
|
|
29
|
+
excludedGameRelativePaths: Object.freeze(
|
|
30
|
+
[...ownership.dynamic.generatedFiles].sort()
|
|
31
|
+
),
|
|
32
|
+
excludedGameRelativePrefixes: Object.freeze(
|
|
33
|
+
[
|
|
34
|
+
".dreamboard/",
|
|
35
|
+
".turbo/",
|
|
36
|
+
"build/",
|
|
37
|
+
"coverage/",
|
|
38
|
+
"dist/",
|
|
39
|
+
"node_modules/",
|
|
40
|
+
"playwright-report/",
|
|
41
|
+
"test-results/",
|
|
42
|
+
"test/bases/",
|
|
43
|
+
"test/generated/",
|
|
44
|
+
"test/screenshots/"
|
|
45
|
+
].sort()
|
|
46
|
+
)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function referenceGamePathIdentity(repositoryPath) {
|
|
50
|
+
const prefix = "examples/reference-games/";
|
|
51
|
+
if (!repositoryPath.startsWith(prefix)) return null;
|
|
52
|
+
const remainder = repositoryPath.slice(prefix.length);
|
|
53
|
+
const separator = remainder.indexOf("/");
|
|
54
|
+
if (separator < 1) return null;
|
|
55
|
+
const gameId = remainder.slice(0, separator);
|
|
56
|
+
if (!/^[a-z0-9][a-z0-9-]*$/u.test(gameId)) return null;
|
|
57
|
+
return { gameId, relativePath: remainder.slice(separator + 1) };
|
|
58
|
+
}
|
|
59
|
+
function classifyReferenceGameSourcePath(repositoryPath, policy) {
|
|
60
|
+
const identity = referenceGamePathIdentity(repositoryPath);
|
|
61
|
+
if (!identity) return "included";
|
|
62
|
+
if (policy.excludedGameRelativePaths.includes(identity.relativePath)) {
|
|
63
|
+
return "workspace-generated";
|
|
64
|
+
}
|
|
65
|
+
const matchedPrefix = policy.excludedGameRelativePrefixes.find(
|
|
66
|
+
(prefix) => identity.relativePath.startsWith(prefix)
|
|
67
|
+
);
|
|
68
|
+
if (!matchedPrefix) return "included";
|
|
69
|
+
if (matchedPrefix === "test/generated/") return "test-generated";
|
|
70
|
+
if (matchedPrefix === "test/bases/") return "test-base";
|
|
71
|
+
if (matchedPrefix === "test/screenshots/") return "obsolete-screenshot";
|
|
72
|
+
return "derived-output";
|
|
73
|
+
}
|
|
74
|
+
function shouldDescendIntoReferenceGameDirectory(repositoryPath, policy) {
|
|
75
|
+
const normalized = repositoryPath.endsWith("/") ? repositoryPath : `${repositoryPath}/`;
|
|
76
|
+
const identity = referenceGamePathIdentity(normalized);
|
|
77
|
+
if (!identity) return true;
|
|
78
|
+
return !policy.excludedGameRelativePrefixes.some(
|
|
79
|
+
(prefix) => identity.relativePath.startsWith(prefix)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/reference-games/source-inventory-policy.ts
|
|
84
|
+
var REFERENCE_GAME_SOURCE_INVENTORY_POLICY = createReferenceGameSourceInventoryPolicy(WORKSPACE_CODEGEN_OWNERSHIP);
|
|
85
|
+
function classifyReferenceGameSourcePath2(repositoryPath) {
|
|
86
|
+
return classifyReferenceGameSourcePath(repositoryPath, REFERENCE_GAME_SOURCE_INVENTORY_POLICY);
|
|
87
|
+
}
|
|
88
|
+
function isReferenceGameSourceObject(repositoryPath) {
|
|
89
|
+
return classifyReferenceGameSourcePath2(repositoryPath) === "included";
|
|
90
|
+
}
|
|
91
|
+
function shouldDescendIntoReferenceGameDirectory2(repositoryPath) {
|
|
92
|
+
return shouldDescendIntoReferenceGameDirectory(repositoryPath, REFERENCE_GAME_SOURCE_INVENTORY_POLICY);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/reference-games/source-collector.ts
|
|
96
|
+
import { createHash } from "crypto";
|
|
97
|
+
import { readFile, readdir, stat } from "fs/promises";
|
|
98
|
+
import path from "path";
|
|
99
|
+
async function collectReferenceGameSourceManifest(options) {
|
|
100
|
+
const sourceRoot = path.resolve(options.sourceRoot);
|
|
101
|
+
const referenceGamesRoot = path.join(sourceRoot, "examples/reference-games");
|
|
102
|
+
const gameIds = await listGameIds(referenceGamesRoot);
|
|
103
|
+
if (gameIds.length === 0) {
|
|
104
|
+
throw new Error("No reference-game packages were found.");
|
|
105
|
+
}
|
|
106
|
+
const objects = await collectReferenceGameSourceObjects({
|
|
107
|
+
referenceGamesRoot,
|
|
108
|
+
sourceRoot
|
|
109
|
+
});
|
|
110
|
+
const games = await Promise.all(
|
|
111
|
+
gameIds.map(async (gameId) => {
|
|
112
|
+
const gameRoot = path.join(referenceGamesRoot, gameId);
|
|
113
|
+
const metadata = await readJson(
|
|
114
|
+
path.join(gameRoot, "reference-game.json")
|
|
115
|
+
);
|
|
116
|
+
return buildGameEntry({
|
|
117
|
+
gameId,
|
|
118
|
+
gameRoot,
|
|
119
|
+
sourceRoot,
|
|
120
|
+
metadata,
|
|
121
|
+
objects
|
|
122
|
+
});
|
|
123
|
+
})
|
|
124
|
+
);
|
|
125
|
+
const payload = {
|
|
126
|
+
inventoryPolicy: {
|
|
127
|
+
schemaVersion: REFERENCE_GAME_SOURCE_INVENTORY_POLICY.schemaVersion,
|
|
128
|
+
workspaceOwnershipVersion: REFERENCE_GAME_SOURCE_INVENTORY_POLICY.workspaceOwnershipVersion,
|
|
129
|
+
excludedGameRelativePaths: [
|
|
130
|
+
...REFERENCE_GAME_SOURCE_INVENTORY_POLICY.excludedGameRelativePaths
|
|
131
|
+
],
|
|
132
|
+
excludedGameRelativePrefixes: [
|
|
133
|
+
...REFERENCE_GAME_SOURCE_INVENTORY_POLICY.excludedGameRelativePrefixes
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
games: games.sort(
|
|
137
|
+
(left, right) => compareReferenceGameCanonicalStrings(left.id, right.id)
|
|
138
|
+
),
|
|
139
|
+
objects: objects.sort(
|
|
140
|
+
(left, right) => compareReferenceGameCanonicalStrings(left.path, right.path)
|
|
141
|
+
)
|
|
142
|
+
};
|
|
143
|
+
return parseReferenceGameSourceManifest({
|
|
144
|
+
schemaVersion: REFERENCE_GAME_SOURCE_MANIFEST_SCHEMA_VERSION,
|
|
145
|
+
manifestType: "dreamboard.reference-game-source",
|
|
146
|
+
sourceFingerprint: computeReferenceGameSourceFingerprint(payload),
|
|
147
|
+
payload,
|
|
148
|
+
provenance: options.provenance
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async function collectReferenceGameSourceObjects(options) {
|
|
152
|
+
const files = await walkFiles(options.referenceGamesRoot, {
|
|
153
|
+
shouldDescend: (directory) => shouldDescendIntoReferenceGameDirectory2(
|
|
154
|
+
toPosix(path.relative(options.sourceRoot, directory))
|
|
155
|
+
)
|
|
156
|
+
});
|
|
157
|
+
const objects = [];
|
|
158
|
+
for (const relative of files) {
|
|
159
|
+
const absolute = path.join(options.referenceGamesRoot, relative);
|
|
160
|
+
const repositoryPath = toPosix(path.relative(options.sourceRoot, absolute));
|
|
161
|
+
if (!isReferenceGameSourceObject(repositoryPath)) continue;
|
|
162
|
+
const content = await readFile(absolute);
|
|
163
|
+
objects.push({
|
|
164
|
+
path: repositoryPath,
|
|
165
|
+
sha256: `sha256:${sha256Buffer(content)}`,
|
|
166
|
+
byteLength: content.length
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return objects;
|
|
170
|
+
}
|
|
171
|
+
async function buildGameEntry(options) {
|
|
172
|
+
const root = `examples/reference-games/${options.gameId}`;
|
|
173
|
+
const workspace = objectValue(options.metadata.workspace);
|
|
174
|
+
const packageJsonPath = path.join(options.gameRoot, "package.json");
|
|
175
|
+
const lockfilePath = path.join(options.gameRoot, "pnpm-lock.yaml");
|
|
176
|
+
const packageJson = await readJson(packageJsonPath);
|
|
177
|
+
const sdkSpecifier = findSdkSpecifier(packageJson);
|
|
178
|
+
if (!sdkSpecifier) {
|
|
179
|
+
throw new Error(`${root}/package.json must declare @dreamboard-games/sdk.`);
|
|
180
|
+
}
|
|
181
|
+
const mechanics = stringArray(options.metadata.mechanics);
|
|
182
|
+
if (mechanics.length === 0) {
|
|
183
|
+
throw new Error(`${root}/reference-game.json must declare mechanics.`);
|
|
184
|
+
}
|
|
185
|
+
const teaching = objectValue(options.metadata.teaching);
|
|
186
|
+
const entry = {
|
|
187
|
+
id: options.gameId,
|
|
188
|
+
root,
|
|
189
|
+
sourceSha256: sourceSha256ForGameObjects(options.objects, root),
|
|
190
|
+
packageJsonSha256: `sha256:${await sha256File(packageJsonPath)}`,
|
|
191
|
+
lockfileSha256: `sha256:${await sha256File(lockfilePath)}`,
|
|
192
|
+
sdkSpecifier,
|
|
193
|
+
manifest: await firstExistingRelative(options.gameRoot, [
|
|
194
|
+
stringValue(workspace.manifest),
|
|
195
|
+
"manifest.ts",
|
|
196
|
+
"reference-game.json"
|
|
197
|
+
]),
|
|
198
|
+
reducer: await firstExistingRelative(options.gameRoot, [
|
|
199
|
+
stringValue(workspace.reducer),
|
|
200
|
+
"app/game.ts"
|
|
201
|
+
]),
|
|
202
|
+
ui: await firstExistingRelative(options.gameRoot, [
|
|
203
|
+
stringValue(workspace.ui),
|
|
204
|
+
"ui/index.tsx"
|
|
205
|
+
]),
|
|
206
|
+
behaviorScenarios: stringArray(workspace.behaviorScenarios).length > 0 ? stringArray(workspace.behaviorScenarios) : await collectScenarioEntries(options.gameRoot, ["test/scenarios"]),
|
|
207
|
+
uiScenarios: stringArray(workspace.uiScenarios).length > 0 ? stringArray(workspace.uiScenarios) : await collectScenarioEntries(options.gameRoot, ["test/ui-scenarios"]),
|
|
208
|
+
mechanics,
|
|
209
|
+
readFirst: stringArray(teaching.readFirst).length > 0 ? stringArray(teaching.readFirst) : await deriveReadFirst(options.gameRoot, options.sourceRoot)
|
|
210
|
+
};
|
|
211
|
+
assertGameEntryPathsAreSourceObjects(entry, options.objects);
|
|
212
|
+
return entry;
|
|
213
|
+
}
|
|
214
|
+
function assertGameEntryPathsAreSourceObjects(entry, objects) {
|
|
215
|
+
const objectPaths = new Set(
|
|
216
|
+
objects.map(({ path: objectPath }) => objectPath)
|
|
217
|
+
);
|
|
218
|
+
const paths = [
|
|
219
|
+
entry.manifest,
|
|
220
|
+
entry.reducer,
|
|
221
|
+
entry.ui,
|
|
222
|
+
...entry.behaviorScenarios,
|
|
223
|
+
...entry.uiScenarios,
|
|
224
|
+
...entry.readFirst
|
|
225
|
+
];
|
|
226
|
+
for (const relativePath of paths) {
|
|
227
|
+
if (path.isAbsolute(relativePath) || relativePath.split(/[\\/]+/u).includes("..")) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`${entry.root} source entry must stay within the game root: ${relativePath}.`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
const repositoryPath = path.posix.join(entry.root, toPosix(relativePath));
|
|
233
|
+
if (!objectPaths.has(repositoryPath)) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`${entry.root} source entry is missing from the authored object inventory: ${relativePath}.`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async function listGameIds(referenceGamesRoot) {
|
|
241
|
+
const entries = await readdir(referenceGamesRoot, { withFileTypes: true });
|
|
242
|
+
const discovered = [];
|
|
243
|
+
for (const entry of entries.filter(
|
|
244
|
+
(entry2) => entry2.isDirectory() && /^[a-z0-9][a-z0-9-]*$/u.test(entry2.name)
|
|
245
|
+
).sort(
|
|
246
|
+
(left, right) => compareReferenceGameCanonicalStrings(left.name, right.name)
|
|
247
|
+
)) {
|
|
248
|
+
if (await isFile(
|
|
249
|
+
path.join(referenceGamesRoot, entry.name, "reference-game.json")
|
|
250
|
+
)) {
|
|
251
|
+
discovered.push(entry.name);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const expected = [...CANONICAL_REFERENCE_GAME_IDS];
|
|
255
|
+
const missing = expected.filter((gameId) => !discovered.includes(gameId));
|
|
256
|
+
const extra = discovered.filter((gameId) => !expected.includes(gameId));
|
|
257
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
258
|
+
throw new Error(
|
|
259
|
+
`Reference-game identity mismatch (missing: ${missing.join(", ") || "none"}; extra: ${extra.join(", ") || "none"}).`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return expected;
|
|
263
|
+
}
|
|
264
|
+
async function deriveReadFirst(gameRoot, sourceRoot) {
|
|
265
|
+
const candidates = [
|
|
266
|
+
"README.md",
|
|
267
|
+
"rule.md",
|
|
268
|
+
"manifest.ts",
|
|
269
|
+
"app/game.ts",
|
|
270
|
+
"ui/index.tsx"
|
|
271
|
+
];
|
|
272
|
+
const existing = [];
|
|
273
|
+
for (const candidate of candidates) {
|
|
274
|
+
if (await isFile(path.join(gameRoot, candidate))) existing.push(candidate);
|
|
275
|
+
}
|
|
276
|
+
if (existing.length === 0) {
|
|
277
|
+
throw new Error(
|
|
278
|
+
`${path.relative(sourceRoot, gameRoot)} must provide at least one readFirst file.`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
return existing.slice(0, 5);
|
|
282
|
+
}
|
|
283
|
+
async function firstExistingRelative(root, candidates) {
|
|
284
|
+
const paths = candidates.filter(
|
|
285
|
+
(candidate) => typeof candidate === "string" && candidate.length > 0
|
|
286
|
+
);
|
|
287
|
+
for (const candidate of paths) {
|
|
288
|
+
if (path.isAbsolute(candidate) || candidate.includes("..")) {
|
|
289
|
+
throw new Error(`${candidate} must be a relative path within ${root}.`);
|
|
290
|
+
}
|
|
291
|
+
if (await isFile(path.join(root, candidate))) return candidate;
|
|
292
|
+
}
|
|
293
|
+
throw new Error(`${root} must provide one of: ${paths.join(", ")}`);
|
|
294
|
+
}
|
|
295
|
+
async function collectScenarioEntries(gameRoot, directories) {
|
|
296
|
+
for (const directory of directories) {
|
|
297
|
+
const absolute = path.join(gameRoot, directory);
|
|
298
|
+
if (!await isDirectory(absolute)) continue;
|
|
299
|
+
const files = (await walkFiles(absolute)).filter(
|
|
300
|
+
(relative) => relative.endsWith(".scenario.ts") || relative.endsWith(".scenario.mjs")
|
|
301
|
+
).map((relative) => path.posix.join(directory, toPosix(relative)));
|
|
302
|
+
if (files.length > 0) return files;
|
|
303
|
+
}
|
|
304
|
+
throw new Error(`${gameRoot} must provide at least one scenario entry.`);
|
|
305
|
+
}
|
|
306
|
+
async function walkFiles(root, options = {}) {
|
|
307
|
+
const files = [];
|
|
308
|
+
async function visit(current) {
|
|
309
|
+
const entries = await readdir(current, { withFileTypes: true });
|
|
310
|
+
for (const entry of entries.sort(
|
|
311
|
+
(left, right) => compareReferenceGameCanonicalStrings(left.name, right.name)
|
|
312
|
+
)) {
|
|
313
|
+
const entryPath = path.join(current, entry.name);
|
|
314
|
+
if (entry.isDirectory()) {
|
|
315
|
+
if (!options.shouldDescend || options.shouldDescend(entryPath)) {
|
|
316
|
+
await visit(entryPath);
|
|
317
|
+
}
|
|
318
|
+
} else if (entry.isFile()) {
|
|
319
|
+
files.push(path.relative(root, entryPath));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
await visit(root);
|
|
324
|
+
return files.sort();
|
|
325
|
+
}
|
|
326
|
+
async function readJson(filePath) {
|
|
327
|
+
const value = JSON.parse(await readFile(filePath, "utf8"));
|
|
328
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
329
|
+
throw new Error(`${filePath} must contain a JSON object.`);
|
|
330
|
+
}
|
|
331
|
+
return value;
|
|
332
|
+
}
|
|
333
|
+
function findSdkSpecifier(packageJson) {
|
|
334
|
+
for (const group of ["dependencies", "devDependencies", "peerDependencies"]) {
|
|
335
|
+
const value = objectValue(packageJson[group])["@dreamboard-games/sdk"];
|
|
336
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
function objectValue(value) {
|
|
341
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
342
|
+
}
|
|
343
|
+
function stringValue(value) {
|
|
344
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
345
|
+
}
|
|
346
|
+
function stringArray(value) {
|
|
347
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : [];
|
|
348
|
+
}
|
|
349
|
+
async function sha256File(filePath) {
|
|
350
|
+
return sha256Buffer(await readFile(filePath));
|
|
351
|
+
}
|
|
352
|
+
function sourceSha256ForGameObjects(objects, gameRoot) {
|
|
353
|
+
const hash = createHash("sha256");
|
|
354
|
+
hash.update("reference-game-authored-objects@1\0");
|
|
355
|
+
for (const object of objects.filter(({ path: objectPath }) => objectPath.startsWith(`${gameRoot}/`)).sort(
|
|
356
|
+
(left, right) => compareReferenceGameCanonicalStrings(left.path, right.path)
|
|
357
|
+
)) {
|
|
358
|
+
hash.update(object.path.slice(gameRoot.length + 1));
|
|
359
|
+
hash.update("\0");
|
|
360
|
+
hash.update(object.sha256);
|
|
361
|
+
hash.update("\0");
|
|
362
|
+
hash.update(String(object.byteLength));
|
|
363
|
+
hash.update("\0");
|
|
364
|
+
}
|
|
365
|
+
return `sha256:${hash.digest("hex")}`;
|
|
366
|
+
}
|
|
367
|
+
function sha256Buffer(buffer) {
|
|
368
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
369
|
+
}
|
|
370
|
+
async function isFile(filePath) {
|
|
371
|
+
return stat(filePath).then((value) => value.isFile()).catch((error) => {
|
|
372
|
+
if (isMissingPathError(error)) return false;
|
|
373
|
+
throw error;
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
async function isDirectory(filePath) {
|
|
377
|
+
return stat(filePath).then((value) => value.isDirectory()).catch((error) => {
|
|
378
|
+
if (isMissingPathError(error)) return false;
|
|
379
|
+
throw error;
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
function isMissingPathError(error) {
|
|
383
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
384
|
+
}
|
|
385
|
+
function toPosix(value) {
|
|
386
|
+
return value.split(path.sep).join("/");
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export {
|
|
390
|
+
CANONICAL_REFERENCE_GAME_IDS,
|
|
391
|
+
referenceGamePathIdentity,
|
|
392
|
+
REFERENCE_GAME_SOURCE_INVENTORY_POLICY,
|
|
393
|
+
classifyReferenceGameSourcePath2 as classifyReferenceGameSourcePath,
|
|
394
|
+
isReferenceGameSourceObject,
|
|
395
|
+
shouldDescendIntoReferenceGameDirectory2 as shouldDescendIntoReferenceGameDirectory,
|
|
396
|
+
collectReferenceGameSourceManifest,
|
|
397
|
+
collectReferenceGameSourceObjects
|
|
398
|
+
};
|
|
399
|
+
//# sourceMappingURL=chunk-XLHLFTLI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/reference-games/source-inventory-policy-core.mjs","../src/reference-games/source-inventory-policy.ts","../src/reference-games/source-collector.ts"],"sourcesContent":["export const CANONICAL_REFERENCE_GAME_IDS = Object.freeze([\n \"automa-river-rival\",\n \"deck-building-market\",\n \"hearts\",\n \"hex-network-trading\",\n \"multiplayer-ranking-and-ties\",\n \"roll-and-write-scorecard\",\n \"simultaneous-card-drafting\",\n \"solo-countdown-puzzle\",\n \"worker-placement-tableau\",\n]);\n\nexport function createReferenceGameSourceInventoryPolicy(ownership) {\n return Object.freeze({\n schemaVersion: 1,\n workspaceOwnershipVersion: ownership.version,\n excludedGameRelativePaths: Object.freeze(\n [...ownership.dynamic.generatedFiles].sort(),\n ),\n excludedGameRelativePrefixes: Object.freeze(\n [\n \".dreamboard/\",\n \".turbo/\",\n \"build/\",\n \"coverage/\",\n \"dist/\",\n \"node_modules/\",\n \"playwright-report/\",\n \"test-results/\",\n \"test/bases/\",\n \"test/generated/\",\n \"test/screenshots/\",\n ].sort(),\n ),\n });\n}\n\nexport function referenceGamePathIdentity(repositoryPath) {\n const prefix = \"examples/reference-games/\";\n if (!repositoryPath.startsWith(prefix)) return null;\n const remainder = repositoryPath.slice(prefix.length);\n const separator = remainder.indexOf(\"/\");\n if (separator < 1) return null;\n const gameId = remainder.slice(0, separator);\n if (!/^[a-z0-9][a-z0-9-]*$/u.test(gameId)) return null;\n return { gameId, relativePath: remainder.slice(separator + 1) };\n}\n\nexport function classifyReferenceGameSourcePath(repositoryPath, policy) {\n const identity = referenceGamePathIdentity(repositoryPath);\n if (!identity) return \"included\";\n if (policy.excludedGameRelativePaths.includes(identity.relativePath)) {\n return \"workspace-generated\";\n }\n const matchedPrefix = policy.excludedGameRelativePrefixes.find((prefix) =>\n identity.relativePath.startsWith(prefix),\n );\n if (!matchedPrefix) return \"included\";\n if (matchedPrefix === \"test/generated/\") return \"test-generated\";\n if (matchedPrefix === \"test/bases/\") return \"test-base\";\n if (matchedPrefix === \"test/screenshots/\") return \"obsolete-screenshot\";\n return \"derived-output\";\n}\n\nexport function shouldDescendIntoReferenceGameDirectory(\n repositoryPath,\n policy,\n) {\n const normalized = repositoryPath.endsWith(\"/\")\n ? repositoryPath\n : `${repositoryPath}/`;\n const identity = referenceGamePathIdentity(normalized);\n if (!identity) return true;\n return !policy.excludedGameRelativePrefixes.some((prefix) =>\n identity.relativePath.startsWith(prefix),\n );\n}\n","import { WORKSPACE_CODEGEN_OWNERSHIP } from \"@dreamboard-games/workspace-codegen\";\n\nimport {\n CANONICAL_REFERENCE_GAME_IDS,\n classifyReferenceGameSourcePath as classifyPath,\n createReferenceGameSourceInventoryPolicy,\n referenceGamePathIdentity,\n shouldDescendIntoReferenceGameDirectory as shouldDescend,\n type ReferenceGameSourcePathClass,\n} from \"./source-inventory-policy-core.mjs\";\n\nexport const REFERENCE_GAME_SOURCE_INVENTORY_POLICY =\n createReferenceGameSourceInventoryPolicy(WORKSPACE_CODEGEN_OWNERSHIP);\n\nexport {\n CANONICAL_REFERENCE_GAME_IDS,\n referenceGamePathIdentity,\n type ReferenceGameSourcePathClass,\n};\n\nexport function classifyReferenceGameSourcePath(\n repositoryPath: string,\n): ReferenceGameSourcePathClass {\n return classifyPath(repositoryPath, REFERENCE_GAME_SOURCE_INVENTORY_POLICY);\n}\n\nexport function isReferenceGameSourceObject(repositoryPath: string): boolean {\n return classifyReferenceGameSourcePath(repositoryPath) === \"included\";\n}\n\nexport function shouldDescendIntoReferenceGameDirectory(\n repositoryPath: string,\n): boolean {\n return shouldDescend(repositoryPath, REFERENCE_GAME_SOURCE_INVENTORY_POLICY);\n}\n","import { createHash } from \"node:crypto\";\nimport { readFile, readdir, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n REFERENCE_GAME_SOURCE_MANIFEST_SCHEMA_VERSION,\n parseReferenceGameSourceManifest,\n type ReferenceGameSourceManifest,\n type ReferenceGameSourceProvenance,\n} from \"./schema.js\";\nimport {\n compareReferenceGameCanonicalStrings,\n computeReferenceGameSourceFingerprint,\n} from \"./canonical.js\";\nimport {\n CANONICAL_REFERENCE_GAME_IDS,\n REFERENCE_GAME_SOURCE_INVENTORY_POLICY,\n isReferenceGameSourceObject,\n shouldDescendIntoReferenceGameDirectory,\n} from \"./source-inventory-policy.js\";\n\nexport {\n CANONICAL_REFERENCE_GAME_IDS,\n REFERENCE_GAME_SOURCE_INVENTORY_POLICY,\n classifyReferenceGameSourcePath,\n isReferenceGameSourceObject,\n referenceGamePathIdentity,\n shouldDescendIntoReferenceGameDirectory,\n type ReferenceGameSourcePathClass,\n} from \"./source-inventory-policy.js\";\n\nexport async function collectReferenceGameSourceManifest(options: {\n readonly sourceRoot: string;\n readonly provenance: ReferenceGameSourceProvenance;\n}): Promise<ReferenceGameSourceManifest> {\n const sourceRoot = path.resolve(options.sourceRoot);\n const referenceGamesRoot = path.join(sourceRoot, \"examples/reference-games\");\n const gameIds = await listGameIds(referenceGamesRoot);\n if (gameIds.length === 0) {\n throw new Error(\"No reference-game packages were found.\");\n }\n const objects = await collectReferenceGameSourceObjects({\n referenceGamesRoot,\n sourceRoot,\n });\n const games = await Promise.all(\n gameIds.map(async (gameId) => {\n const gameRoot = path.join(referenceGamesRoot, gameId);\n const metadata = await readJson(\n path.join(gameRoot, \"reference-game.json\"),\n );\n return buildGameEntry({\n gameId,\n gameRoot,\n sourceRoot,\n metadata,\n objects,\n });\n }),\n );\n const payload = {\n inventoryPolicy: {\n schemaVersion: REFERENCE_GAME_SOURCE_INVENTORY_POLICY.schemaVersion,\n workspaceOwnershipVersion:\n REFERENCE_GAME_SOURCE_INVENTORY_POLICY.workspaceOwnershipVersion,\n excludedGameRelativePaths: [\n ...REFERENCE_GAME_SOURCE_INVENTORY_POLICY.excludedGameRelativePaths,\n ],\n excludedGameRelativePrefixes: [\n ...REFERENCE_GAME_SOURCE_INVENTORY_POLICY.excludedGameRelativePrefixes,\n ],\n },\n games: games.sort((left, right) =>\n compareReferenceGameCanonicalStrings(left.id, right.id),\n ),\n objects: objects.sort((left, right) =>\n compareReferenceGameCanonicalStrings(left.path, right.path),\n ),\n };\n return parseReferenceGameSourceManifest({\n schemaVersion: REFERENCE_GAME_SOURCE_MANIFEST_SCHEMA_VERSION,\n manifestType: \"dreamboard.reference-game-source\",\n sourceFingerprint: computeReferenceGameSourceFingerprint(payload),\n payload,\n provenance: options.provenance,\n });\n}\n\nexport async function collectReferenceGameSourceObjects(options: {\n readonly referenceGamesRoot: string;\n readonly sourceRoot: string;\n}): Promise<\n Array<{\n readonly path: string;\n readonly sha256: string;\n readonly byteLength: number;\n }>\n> {\n const files = await walkFiles(options.referenceGamesRoot, {\n shouldDescend: (directory) =>\n shouldDescendIntoReferenceGameDirectory(\n toPosix(path.relative(options.sourceRoot, directory)),\n ),\n });\n const objects = [];\n for (const relative of files) {\n const absolute = path.join(options.referenceGamesRoot, relative);\n const repositoryPath = toPosix(path.relative(options.sourceRoot, absolute));\n if (!isReferenceGameSourceObject(repositoryPath)) continue;\n const content = await readFile(absolute);\n objects.push({\n path: repositoryPath,\n sha256: `sha256:${sha256Buffer(content)}`,\n byteLength: content.length,\n });\n }\n return objects;\n}\n\nasync function buildGameEntry(options: {\n readonly gameId: string;\n readonly gameRoot: string;\n readonly sourceRoot: string;\n readonly metadata: Record<string, unknown>;\n readonly objects: readonly {\n readonly path: string;\n readonly sha256: string;\n readonly byteLength: number;\n }[];\n}) {\n const root = `examples/reference-games/${options.gameId}`;\n const workspace = objectValue(options.metadata.workspace);\n const packageJsonPath = path.join(options.gameRoot, \"package.json\");\n const lockfilePath = path.join(options.gameRoot, \"pnpm-lock.yaml\");\n const packageJson = await readJson(packageJsonPath);\n const sdkSpecifier = findSdkSpecifier(packageJson);\n if (!sdkSpecifier) {\n throw new Error(`${root}/package.json must declare @dreamboard-games/sdk.`);\n }\n const mechanics = stringArray(options.metadata.mechanics);\n if (mechanics.length === 0) {\n throw new Error(`${root}/reference-game.json must declare mechanics.`);\n }\n const teaching = objectValue(options.metadata.teaching);\n const entry = {\n id: options.gameId,\n root,\n sourceSha256: sourceSha256ForGameObjects(options.objects, root),\n packageJsonSha256: `sha256:${await sha256File(packageJsonPath)}`,\n lockfileSha256: `sha256:${await sha256File(lockfilePath)}`,\n sdkSpecifier,\n manifest: await firstExistingRelative(options.gameRoot, [\n stringValue(workspace.manifest),\n \"manifest.ts\",\n \"reference-game.json\",\n ]),\n reducer: await firstExistingRelative(options.gameRoot, [\n stringValue(workspace.reducer),\n \"app/game.ts\",\n ]),\n ui: await firstExistingRelative(options.gameRoot, [\n stringValue(workspace.ui),\n \"ui/index.tsx\",\n ]),\n behaviorScenarios:\n stringArray(workspace.behaviorScenarios).length > 0\n ? stringArray(workspace.behaviorScenarios)\n : await collectScenarioEntries(options.gameRoot, [\"test/scenarios\"]),\n uiScenarios:\n stringArray(workspace.uiScenarios).length > 0\n ? stringArray(workspace.uiScenarios)\n : await collectScenarioEntries(options.gameRoot, [\"test/ui-scenarios\"]),\n mechanics,\n readFirst:\n stringArray(teaching.readFirst).length > 0\n ? stringArray(teaching.readFirst)\n : await deriveReadFirst(options.gameRoot, options.sourceRoot),\n };\n assertGameEntryPathsAreSourceObjects(entry, options.objects);\n return entry;\n}\n\nfunction assertGameEntryPathsAreSourceObjects(\n entry: {\n readonly root: string;\n readonly manifest: string;\n readonly reducer: string;\n readonly ui: string;\n readonly behaviorScenarios: readonly string[];\n readonly uiScenarios: readonly string[];\n readonly readFirst: readonly string[];\n },\n objects: readonly { readonly path: string }[],\n): void {\n const objectPaths = new Set(\n objects.map(({ path: objectPath }) => objectPath),\n );\n const paths = [\n entry.manifest,\n entry.reducer,\n entry.ui,\n ...entry.behaviorScenarios,\n ...entry.uiScenarios,\n ...entry.readFirst,\n ];\n for (const relativePath of paths) {\n if (\n path.isAbsolute(relativePath) ||\n relativePath.split(/[\\\\/]+/u).includes(\"..\")\n ) {\n throw new Error(\n `${entry.root} source entry must stay within the game root: ${relativePath}.`,\n );\n }\n const repositoryPath = path.posix.join(entry.root, toPosix(relativePath));\n if (!objectPaths.has(repositoryPath)) {\n throw new Error(\n `${entry.root} source entry is missing from the authored object inventory: ${relativePath}.`,\n );\n }\n }\n}\n\nasync function listGameIds(referenceGamesRoot: string): Promise<string[]> {\n const entries = await readdir(referenceGamesRoot, { withFileTypes: true });\n const discovered: string[] = [];\n for (const entry of entries\n .filter(\n (entry) =>\n entry.isDirectory() && /^[a-z0-9][a-z0-9-]*$/u.test(entry.name),\n )\n .sort((left, right) =>\n compareReferenceGameCanonicalStrings(left.name, right.name),\n )) {\n if (\n await isFile(\n path.join(referenceGamesRoot, entry.name, \"reference-game.json\"),\n )\n ) {\n discovered.push(entry.name);\n }\n }\n const expected = [...CANONICAL_REFERENCE_GAME_IDS];\n const missing = expected.filter((gameId) => !discovered.includes(gameId));\n const extra = discovered.filter((gameId) => !expected.includes(gameId));\n if (missing.length > 0 || extra.length > 0) {\n throw new Error(\n `Reference-game identity mismatch (missing: ${missing.join(\", \") || \"none\"}; extra: ${extra.join(\", \") || \"none\"}).`,\n );\n }\n return expected;\n}\n\nasync function deriveReadFirst(gameRoot: string, sourceRoot: string) {\n const candidates = [\n \"README.md\",\n \"rule.md\",\n \"manifest.ts\",\n \"app/game.ts\",\n \"ui/index.tsx\",\n ];\n const existing = [];\n for (const candidate of candidates) {\n if (await isFile(path.join(gameRoot, candidate))) existing.push(candidate);\n }\n if (existing.length === 0) {\n throw new Error(\n `${path.relative(sourceRoot, gameRoot)} must provide at least one readFirst file.`,\n );\n }\n return existing.slice(0, 5);\n}\n\nasync function firstExistingRelative(root: string, candidates: unknown[]) {\n const paths = candidates.filter(\n (candidate): candidate is string =>\n typeof candidate === \"string\" && candidate.length > 0,\n );\n for (const candidate of paths) {\n if (path.isAbsolute(candidate) || candidate.includes(\"..\")) {\n throw new Error(`${candidate} must be a relative path within ${root}.`);\n }\n if (await isFile(path.join(root, candidate))) return candidate;\n }\n throw new Error(`${root} must provide one of: ${paths.join(\", \")}`);\n}\n\nasync function collectScenarioEntries(gameRoot: string, directories: string[]) {\n for (const directory of directories) {\n const absolute = path.join(gameRoot, directory);\n if (!(await isDirectory(absolute))) continue;\n const files = (await walkFiles(absolute))\n .filter(\n (relative) =>\n relative.endsWith(\".scenario.ts\") ||\n relative.endsWith(\".scenario.mjs\"),\n )\n .map((relative) => path.posix.join(directory, toPosix(relative)));\n if (files.length > 0) return files;\n }\n throw new Error(`${gameRoot} must provide at least one scenario entry.`);\n}\n\nasync function walkFiles(\n root: string,\n options: { readonly shouldDescend?: (directory: string) => boolean } = {},\n): Promise<string[]> {\n const files: string[] = [];\n async function visit(current: string) {\n const entries = await readdir(current, { withFileTypes: true });\n for (const entry of entries.sort((left, right) =>\n compareReferenceGameCanonicalStrings(left.name, right.name),\n )) {\n const entryPath = path.join(current, entry.name);\n if (entry.isDirectory()) {\n if (!options.shouldDescend || options.shouldDescend(entryPath)) {\n await visit(entryPath);\n }\n } else if (entry.isFile()) {\n files.push(path.relative(root, entryPath));\n }\n }\n }\n await visit(root);\n return files.sort();\n}\n\nasync function readJson(filePath: string): Promise<Record<string, unknown>> {\n const value = JSON.parse(await readFile(filePath, \"utf8\")) as unknown;\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new Error(`${filePath} must contain a JSON object.`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction findSdkSpecifier(packageJson: Record<string, unknown>): string | null {\n for (const group of [\"dependencies\", \"devDependencies\", \"peerDependencies\"]) {\n const value = objectValue(packageJson[group])[\"@dreamboard-games/sdk\"];\n if (typeof value === \"string\" && value.length > 0) return value;\n }\n return null;\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction stringArray(value: unknown): string[] {\n return Array.isArray(value) && value.every((item) => typeof item === \"string\")\n ? value\n : [];\n}\n\nasync function sha256File(filePath: string): Promise<string> {\n return sha256Buffer(await readFile(filePath));\n}\n\nfunction sourceSha256ForGameObjects(\n objects: readonly {\n readonly path: string;\n readonly sha256: string;\n readonly byteLength: number;\n }[],\n gameRoot: string,\n) {\n const hash = createHash(\"sha256\");\n hash.update(\"reference-game-authored-objects@1\\0\");\n for (const object of objects\n .filter(({ path: objectPath }) => objectPath.startsWith(`${gameRoot}/`))\n .sort((left, right) =>\n compareReferenceGameCanonicalStrings(left.path, right.path),\n )) {\n hash.update(object.path.slice(gameRoot.length + 1));\n hash.update(\"\\0\");\n hash.update(object.sha256);\n hash.update(\"\\0\");\n hash.update(String(object.byteLength));\n hash.update(\"\\0\");\n }\n return `sha256:${hash.digest(\"hex\")}`;\n}\n\nfunction sha256Buffer(buffer: Uint8Array): string {\n return createHash(\"sha256\").update(buffer).digest(\"hex\");\n}\n\nasync function isFile(filePath: string): Promise<boolean> {\n return stat(filePath)\n .then((value) => value.isFile())\n .catch((error: unknown) => {\n if (isMissingPathError(error)) return false;\n throw error;\n });\n}\n\nasync function isDirectory(filePath: string): Promise<boolean> {\n return stat(filePath)\n .then((value) => value.isDirectory())\n .catch((error: unknown) => {\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":["classifyReferenceGameSourcePath","shouldDescendIntoReferenceGameDirectory","shouldDescendIntoReferenceGameDirectory","entry"]}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
zod_exports
|
|
3
|
+
} from "./chunk-3PFDHTR7.js";
|
|
4
|
+
|
|
1
5
|
// src/reducer/model/manifest.ts
|
|
2
6
|
import { z } from "zod";
|
|
3
7
|
function toNonEmptyStringTuple(values) {
|
|
@@ -7,17 +11,23 @@ function toNonEmptyStringTuple(values) {
|
|
|
7
11
|
}
|
|
8
12
|
return [first, ...rest];
|
|
9
13
|
}
|
|
10
|
-
var manifestScopedSchemas = /* @__PURE__ */ new
|
|
11
|
-
function markManifestScopedSchema(schema) {
|
|
12
|
-
manifestScopedSchemas.
|
|
14
|
+
var manifestScopedSchemas = /* @__PURE__ */ new WeakMap();
|
|
15
|
+
function markManifestScopedSchema(schema, family) {
|
|
16
|
+
manifestScopedSchemas.set(schema, family);
|
|
13
17
|
return schema;
|
|
14
18
|
}
|
|
15
19
|
function isManifestScopedSchema(schema) {
|
|
16
20
|
return typeof schema === "object" && schema !== null && manifestScopedSchemas.has(schema);
|
|
17
21
|
}
|
|
18
|
-
function
|
|
22
|
+
function manifestSchemaFamily(schema) {
|
|
23
|
+
if (typeof schema !== "object" || schema === null) {
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
return manifestScopedSchemas.get(schema);
|
|
27
|
+
}
|
|
28
|
+
function createManifestStringLiteralSchema(values, family) {
|
|
19
29
|
const schema = values.length === 0 ? z.string() : z.enum(toNonEmptyStringTuple(values));
|
|
20
|
-
return markManifestScopedSchema(schema);
|
|
30
|
+
return markManifestScopedSchema(schema, family);
|
|
21
31
|
}
|
|
22
32
|
function assumeManifestSchema(schema) {
|
|
23
33
|
return schema;
|
|
@@ -57,11 +67,13 @@ function createManifestRuntimeSchema({
|
|
|
57
67
|
rng: z.object({
|
|
58
68
|
seed: z.number().nullable().optional(),
|
|
59
69
|
cursor: z.number().int().default(0),
|
|
60
|
-
trace: z.array(z.string()).default([])
|
|
70
|
+
trace: z.array(z.string()).default([]),
|
|
71
|
+
draws: z.array(zod_exports.RngDrawSchema).default([])
|
|
61
72
|
}).default({
|
|
62
73
|
seed: null,
|
|
63
74
|
cursor: 0,
|
|
64
|
-
trace: []
|
|
75
|
+
trace: [],
|
|
76
|
+
draws: []
|
|
65
77
|
}),
|
|
66
78
|
setup: z.object({
|
|
67
79
|
profileId: setupProfileIdSchema,
|
|
@@ -122,6 +134,7 @@ var FrameworkErrorCodes = {
|
|
|
122
134
|
NOT_YOUR_TURN: "NOT_YOUR_TURN",
|
|
123
135
|
WRONG_PHASE: "WRONG_PHASE",
|
|
124
136
|
WRONG_STEP: "WRONG_STEP",
|
|
137
|
+
NO_LEGAL_INPUT: "NO_LEGAL_INPUT",
|
|
125
138
|
INVALID_PARAMS: "INVALID_PARAMS",
|
|
126
139
|
UNKNOWN_INTERACTION: "UNKNOWN_INTERACTION",
|
|
127
140
|
INTERNAL_ERROR: "INTERNAL_ERROR"
|
|
@@ -2275,13 +2288,25 @@ function dealCardsFromDeckToHandInPlace(table, fromZoneId, playerId, toZoneId, c
|
|
|
2275
2288
|
}
|
|
2276
2289
|
|
|
2277
2290
|
// src/reducer/rng.ts
|
|
2278
|
-
function nextRandomInt(bound, rng
|
|
2279
|
-
|
|
2280
|
-
|
|
2291
|
+
function nextRandomInt(bound, rng, operation = {
|
|
2292
|
+
kind: "integer",
|
|
2293
|
+
parameters: { minInclusive: 0, maxInclusive: bound - 1 }
|
|
2294
|
+
}) {
|
|
2295
|
+
if (!Number.isSafeInteger(bound) || bound <= 0) {
|
|
2296
|
+
throw new Error("Random bound must be a positive safe integer.");
|
|
2281
2297
|
}
|
|
2282
2298
|
const seed = rng.seed ?? 1;
|
|
2283
2299
|
const raw = hashSeedCursor(seed, rng.cursor);
|
|
2284
2300
|
const value = raw % bound;
|
|
2301
|
+
const draw = {
|
|
2302
|
+
index: rng.draws.length,
|
|
2303
|
+
cursorBefore: rng.cursor,
|
|
2304
|
+
cursorAfter: rng.cursor + 1,
|
|
2305
|
+
operation: {
|
|
2306
|
+
kind: operation.kind,
|
|
2307
|
+
parameters: { ...operation.parameters }
|
|
2308
|
+
}
|
|
2309
|
+
};
|
|
2285
2310
|
return [
|
|
2286
2311
|
value,
|
|
2287
2312
|
{
|
|
@@ -2290,8 +2315,10 @@ function nextRandomInt(bound, rng) {
|
|
|
2290
2315
|
trace: [
|
|
2291
2316
|
...rng.trace,
|
|
2292
2317
|
`cursor=${rng.cursor};bound=${bound};value=${value}`
|
|
2293
|
-
]
|
|
2294
|
-
|
|
2318
|
+
],
|
|
2319
|
+
draws: [...rng.draws, draw]
|
|
2320
|
+
},
|
|
2321
|
+
draw
|
|
2295
2322
|
];
|
|
2296
2323
|
}
|
|
2297
2324
|
function hashSeedCursor(seed, cursor) {
|
|
@@ -2738,6 +2765,7 @@ function collectReducerDefinitionIndex(definition) {
|
|
|
2738
2765
|
export {
|
|
2739
2766
|
markManifestScopedSchema,
|
|
2740
2767
|
isManifestScopedSchema,
|
|
2768
|
+
manifestSchemaFamily,
|
|
2741
2769
|
createManifestStringLiteralSchema,
|
|
2742
2770
|
assumeManifestSchema,
|
|
2743
2771
|
cloneManifestDefault,
|
|
@@ -2872,4 +2900,4 @@ export {
|
|
|
2872
2900
|
collectReducerDefinitionIndex,
|
|
2873
2901
|
applySetupBootstrap
|
|
2874
2902
|
};
|
|
2875
|
-
//# sourceMappingURL=chunk-
|
|
2903
|
+
//# sourceMappingURL=chunk-YNW3KBDE.js.map
|