@dreamboard-games/sdk 0.5.0-alpha.0 → 0.5.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -0
- package/dist/browser-interaction.d.ts +22 -22
- package/dist/{chunk-VRRR6QZT.js → chunk-32PFKDV7.js} +170 -406
- package/dist/chunk-32PFKDV7.js.map +1 -0
- package/dist/{chunk-N33CGX2F.js → chunk-3BAD4VC2.js} +3 -3
- package/dist/{chunk-LMHCGCA6.js → chunk-3SKDNDPG.js} +2 -2
- package/dist/chunk-5YV2WHJ4.js +25 -0
- package/dist/chunk-5YV2WHJ4.js.map +1 -0
- package/dist/{chunk-VWTKGIYF.js → chunk-ANRB4XKA.js} +1 -1
- package/dist/chunk-ANRB4XKA.js.map +1 -0
- package/dist/{chunk-EOEA3I64.js → chunk-BI4G3PM2.js} +7 -7
- package/dist/chunk-BI4G3PM2.js.map +1 -0
- package/dist/{chunk-KRJPRYEA.js → chunk-EVCLTY4Q.js} +21 -8
- package/dist/chunk-EVCLTY4Q.js.map +1 -0
- package/dist/{chunk-DQS2EG5E.js → chunk-GDPKTBUR.js} +2 -2
- package/dist/{chunk-FL67RDID.js → chunk-H6VDGFL5.js} +128 -128
- package/dist/chunk-H6VDGFL5.js.map +1 -0
- package/dist/{chunk-6LMESVGT.js → chunk-LR3ZTWQF.js} +3 -3
- package/dist/chunk-LR3ZTWQF.js.map +1 -0
- package/dist/{chunk-TXELBVTG.js → chunk-PN5O6GG2.js} +2 -2
- package/dist/{chunk-533O7C4L.js → chunk-S2JEDVWH.js} +500 -430
- package/dist/chunk-S2JEDVWH.js.map +1 -0
- package/dist/{chunk-2GQIALJL.js → chunk-UGH54WZ2.js} +6 -2
- package/dist/chunk-UGH54WZ2.js.map +1 -0
- package/dist/chunk-VCDWP5VL.js +746 -0
- package/dist/chunk-VCDWP5VL.js.map +1 -0
- package/dist/{chunk-ZSTCUJKZ.js → chunk-Y75CFE77.js} +2 -6
- package/dist/chunk-Y75CFE77.js.map +1 -0
- package/dist/chunk-Z7QCREWI.js +3435 -0
- package/dist/chunk-Z7QCREWI.js.map +1 -0
- package/dist/chunk-ZZGN2ATS.js +1941 -0
- package/dist/chunk-ZZGN2ATS.js.map +1 -0
- package/dist/{components-CNAt5J1p.d.ts → components-gAbIz7hK.d.ts} +2 -18
- package/dist/{definitions-bZSBaPjj.d.ts → definitions-BgmV_GhC.d.ts} +3 -3
- package/dist/digest.d.ts +2 -2
- package/dist/game-CsZScpcn.d.ts +763 -0
- package/dist/{index-CR69MyWr.d.ts → index-CcT9Q7N7.d.ts} +1 -1
- package/dist/{index.d-Bw8AOcgp.d.ts → index.d-DjzoK7zn.d.ts} +67 -2
- package/dist/index.js +1 -2
- package/dist/package-set.js +1 -2
- package/dist/plugin-runtime-contract.d.ts +4 -4
- package/dist/plugin-runtime-contract.js +13 -15
- package/dist/{protocol-CVaSqPgX.d.ts → protocol-dYgafTYY.d.ts} +1 -7
- package/dist/reducer/advanced.d.ts +12 -11
- package/dist/reducer/advanced.js +10 -4
- package/dist/reducer-contract.d.ts +10 -2
- package/dist/reducer-contract.js +4 -4
- package/dist/reducer.d.ts +12 -689
- package/dist/reducer.js +19 -1293
- package/dist/reducer.js.map +1 -1
- package/dist/runtime/primitives.d.ts +4 -4
- package/dist/runtime/primitives.js +5 -5
- package/dist/runtime/runtime-api.d.ts +2 -2
- package/dist/runtime/workspace-contract.d.ts +50 -17
- package/dist/runtime/workspace-contract.js +15 -10
- package/dist/{runtime-C7Z2acNU.d.ts → runtime-RJ5orDJU.d.ts} +23 -30
- package/dist/{plugin-state-BRH3UiUp.d.ts → runtime-api-Bz5pwNU_.d.ts} +86 -4
- package/dist/runtime.d.ts +8 -8
- package/dist/runtime.js +19 -17
- package/dist/runtime.js.map +1 -1
- package/dist/schema.d.ts +2 -28
- package/dist/testing-compiler.d.ts +4 -4
- package/dist/testing-runtime.d.ts +7 -7
- package/dist/testing-runtime.js +6 -6
- package/dist/testing.d.ts +17 -17
- package/dist/testing.js +14 -14
- package/dist/{types-q1Guidm5.d.ts → types-DR7DoB1x.d.ts} +1 -1
- package/dist/{types-DN4O7kH_.d.ts → types-JWCYHmu7.d.ts} +2 -2
- package/dist/types.js +6 -18
- package/dist/types.js.map +1 -1
- package/dist/ui/components.d.ts +3 -4
- package/dist/ui/components.js +1 -5
- package/dist/{ui-contract-BC4JpysE.d.ts → ui-contract-GTUPkf8z.d.ts} +175 -176
- package/dist/ui.d.ts +4 -5
- package/dist/ui.js +2 -6
- package/dist/{views-D2Cfzr3h.d.ts → views-BpuWcOyN.d.ts} +101 -48
- package/package.json +3 -22
- package/dist/authoring/index.d.ts +0 -59
- package/dist/authoring/index.js +0 -24
- package/dist/authoring/index.js.map +0 -1
- package/dist/authoring-compiler.d.ts +0 -27
- package/dist/authoring-compiler.js +0 -11
- package/dist/authoring-compiler.js.map +0 -1
- package/dist/authoring-materialize-cli.d.ts +0 -1
- package/dist/authoring-materialize-cli.js +0 -45
- package/dist/authoring-materialize-cli.js.map +0 -1
- package/dist/chunk-2GQIALJL.js.map +0 -1
- package/dist/chunk-533O7C4L.js.map +0 -1
- package/dist/chunk-6LMESVGT.js.map +0 -1
- package/dist/chunk-EOEA3I64.js.map +0 -1
- package/dist/chunk-FL67RDID.js.map +0 -1
- package/dist/chunk-HIH6Y4FA.js +0 -7802
- package/dist/chunk-HIH6Y4FA.js.map +0 -1
- package/dist/chunk-HUK4234C.js +0 -166
- package/dist/chunk-HUK4234C.js.map +0 -1
- package/dist/chunk-KGV2EUNN.js +0 -532
- package/dist/chunk-KGV2EUNN.js.map +0 -1
- package/dist/chunk-KRJPRYEA.js.map +0 -1
- package/dist/chunk-KWHOFBDM.js +0 -9
- package/dist/chunk-KWHOFBDM.js.map +0 -1
- package/dist/chunk-VRRR6QZT.js.map +0 -1
- package/dist/chunk-VWTKGIYF.js.map +0 -1
- package/dist/chunk-XFMSLL3P.js +0 -637
- package/dist/chunk-XFMSLL3P.js.map +0 -1
- package/dist/chunk-ZSTCUJKZ.js.map +0 -1
- package/dist/codegen.d.ts +0 -941
- package/dist/codegen.js +0 -44
- package/dist/codegen.js.map +0 -1
- package/dist/runtime-api-CgPuEVeF.d.ts +0 -86
- /package/dist/{chunk-N33CGX2F.js.map → chunk-3BAD4VC2.js.map} +0 -0
- /package/dist/{chunk-LMHCGCA6.js.map → chunk-3SKDNDPG.js.map} +0 -0
- /package/dist/{chunk-DQS2EG5E.js.map → chunk-GDPKTBUR.js.map} +0 -0
- /package/dist/{chunk-TXELBVTG.js.map → chunk-PN5O6GG2.js.map} +0 -0
package/dist/reducer.js
CHANGED
|
@@ -3,15 +3,22 @@ import {
|
|
|
3
3
|
contractFingerprint,
|
|
4
4
|
createDerivedResolver,
|
|
5
5
|
createReducerBundle,
|
|
6
|
-
createReducerEdit,
|
|
7
6
|
createReducerOps,
|
|
8
|
-
createReducerTransaction,
|
|
9
7
|
createStateQueries,
|
|
10
8
|
createTableQueries,
|
|
11
9
|
defineDerived,
|
|
12
10
|
isStaleContractArtifactError,
|
|
13
11
|
noopDiagnosticsSink
|
|
14
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-S2JEDVWH.js";
|
|
13
|
+
import {
|
|
14
|
+
compileManifest,
|
|
15
|
+
createGame,
|
|
16
|
+
defineInputs,
|
|
17
|
+
many,
|
|
18
|
+
normalizeCommandParams,
|
|
19
|
+
sparseCounts,
|
|
20
|
+
sparseMap
|
|
21
|
+
} from "./chunk-ZZGN2ATS.js";
|
|
15
22
|
import {
|
|
16
23
|
FrameworkErrorCodes,
|
|
17
24
|
asPlayerId,
|
|
@@ -19,17 +26,10 @@ import {
|
|
|
19
26
|
boardRef,
|
|
20
27
|
boardRefKey,
|
|
21
28
|
boardRefSchema,
|
|
22
|
-
cardInput,
|
|
23
|
-
cardTarget,
|
|
24
|
-
createManifestStringLiteralSchema,
|
|
25
|
-
createTargetRule,
|
|
26
|
-
createTargetRuleBuilder,
|
|
27
|
-
isManifestScopedSchema,
|
|
28
29
|
isPerPlayer,
|
|
29
30
|
isPerPlayerBoardRef,
|
|
30
31
|
isPlayerId,
|
|
31
32
|
isSharedBoardRef,
|
|
32
|
-
markManifestScopedSchema,
|
|
33
33
|
parseBoardRefKey,
|
|
34
34
|
perPlayer,
|
|
35
35
|
perPlayerBoardRef,
|
|
@@ -45,1267 +45,15 @@ import {
|
|
|
45
45
|
perPlayerValues,
|
|
46
46
|
setActivePlayers,
|
|
47
47
|
sharedBoardRef
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-H6VDGFL5.js";
|
|
49
|
+
import "./chunk-5YV2WHJ4.js";
|
|
49
50
|
import "./chunk-PF7L4BMG.js";
|
|
50
|
-
import "./chunk-
|
|
51
|
+
import "./chunk-Z7QCREWI.js";
|
|
52
|
+
import "./chunk-UGH54WZ2.js";
|
|
51
53
|
import "./chunk-PZ5AY32C.js";
|
|
52
54
|
|
|
53
|
-
// src/reducer/schema-helpers.ts
|
|
54
|
-
import { z } from "zod";
|
|
55
|
-
var sparseSchemas = /* @__PURE__ */ new WeakMap();
|
|
56
|
-
function sparseMap(keySchema, valueSchema) {
|
|
57
|
-
const schema = z.partialRecord(keySchema, valueSchema);
|
|
58
|
-
sparseSchemas.set(schema, {
|
|
59
|
-
keySchema,
|
|
60
|
-
valueSchema
|
|
61
|
-
});
|
|
62
|
-
return schema;
|
|
63
|
-
}
|
|
64
|
-
function sparseCounts(keySchema) {
|
|
65
|
-
return sparseMap(keySchema, z.number().int().min(0));
|
|
66
|
-
}
|
|
67
|
-
function getZodDef(schema) {
|
|
68
|
-
const anySchema = schema;
|
|
69
|
-
const fromInternal = anySchema?._zod?.def;
|
|
70
|
-
if (fromInternal && typeof fromInternal === "object") {
|
|
71
|
-
return fromInternal;
|
|
72
|
-
}
|
|
73
|
-
const fromLegacy = anySchema?.def;
|
|
74
|
-
if (fromLegacy && typeof fromLegacy === "object") {
|
|
75
|
-
return fromLegacy;
|
|
76
|
-
}
|
|
77
|
-
return {};
|
|
78
|
-
}
|
|
79
|
-
function unwrapWrappers(schema) {
|
|
80
|
-
let current = schema;
|
|
81
|
-
while (true) {
|
|
82
|
-
const def = getZodDef(current);
|
|
83
|
-
const innerType = def.innerType;
|
|
84
|
-
if ((def.type === "nullable" || def.type === "optional" || def.type === "default" || def.type === "readonly" || def.type === "catch") && innerType) {
|
|
85
|
-
current = innerType;
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
return current;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function isPlainZodString(schema) {
|
|
92
|
-
return getZodDef(schema).type === "string";
|
|
93
|
-
}
|
|
94
|
-
function isZodArray(schema) {
|
|
95
|
-
return getZodDef(schema).type === "array";
|
|
96
|
-
}
|
|
97
|
-
function isEnumKeyedRecordSchema(schema) {
|
|
98
|
-
const def = getZodDef(schema);
|
|
99
|
-
const keyType = def.keyType;
|
|
100
|
-
return def.type === "record" && typeof keyType === "object" && keyType !== null && getZodDef(keyType).type === "enum";
|
|
101
|
-
}
|
|
102
|
-
function isSparseMapSchema(schema) {
|
|
103
|
-
const inner = unwrapWrappers(schema);
|
|
104
|
-
return typeof inner === "object" && inner !== null && sparseSchemas.has(inner);
|
|
105
|
-
}
|
|
106
|
-
function getSparseSchemaMetadata(schema) {
|
|
107
|
-
const inner = unwrapWrappers(schema);
|
|
108
|
-
if (typeof inner !== "object" || inner === null) {
|
|
109
|
-
return void 0;
|
|
110
|
-
}
|
|
111
|
-
return sparseSchemas.get(inner);
|
|
112
|
-
}
|
|
113
|
-
function isPlainObject(value) {
|
|
114
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
115
|
-
}
|
|
116
|
-
function getObjectShape(schema) {
|
|
117
|
-
const def = getZodDef(schema);
|
|
118
|
-
if (def.type !== "object") {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
const shape = def.shape;
|
|
122
|
-
if (typeof shape === "function") {
|
|
123
|
-
const resolved = shape();
|
|
124
|
-
return resolved && typeof resolved === "object" ? resolved : null;
|
|
125
|
-
}
|
|
126
|
-
return shape && typeof shape === "object" ? shape : null;
|
|
127
|
-
}
|
|
128
|
-
function normalizeSchemaInput(schema, input) {
|
|
129
|
-
const inner = unwrapWrappers(schema);
|
|
130
|
-
const sparse = getSparseSchemaMetadata(inner);
|
|
131
|
-
if (sparse && isPlainObject(input)) {
|
|
132
|
-
const filtered = Object.fromEntries(
|
|
133
|
-
Object.entries(input).filter(
|
|
134
|
-
([key, value]) => typeof value !== "undefined" && sparse.keySchema.safeParse(key).success
|
|
135
|
-
).map(([key, value]) => [
|
|
136
|
-
key,
|
|
137
|
-
normalizeSchemaInput(sparse.valueSchema, value)
|
|
138
|
-
])
|
|
139
|
-
);
|
|
140
|
-
return filtered;
|
|
141
|
-
}
|
|
142
|
-
const shape = getObjectShape(inner);
|
|
143
|
-
if (shape && isPlainObject(input)) {
|
|
144
|
-
return Object.fromEntries(
|
|
145
|
-
Object.entries(input).map(([key, value]) => {
|
|
146
|
-
const fieldSchema = shape[key];
|
|
147
|
-
return [
|
|
148
|
-
key,
|
|
149
|
-
typeof fieldSchema === "undefined" ? value : normalizeSchemaInput(fieldSchema, value)
|
|
150
|
-
];
|
|
151
|
-
})
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
const def = getZodDef(inner);
|
|
155
|
-
if (def.type === "array" && Array.isArray(input) && def.element) {
|
|
156
|
-
return input.map((value) => normalizeSchemaInput(def.element, value));
|
|
157
|
-
}
|
|
158
|
-
return input;
|
|
159
|
-
}
|
|
160
|
-
function normalizeCommandParams(schema, input) {
|
|
161
|
-
return schema.parse(normalizeSchemaInput(schema, input));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// src/reducer/authoring/validation.ts
|
|
165
|
-
var MANIFEST_SCOPED_ID_NAMES = [
|
|
166
|
-
"playerId",
|
|
167
|
-
"cardId",
|
|
168
|
-
"deckId",
|
|
169
|
-
"handId",
|
|
170
|
-
"zoneId",
|
|
171
|
-
"sharedZoneId",
|
|
172
|
-
"playerZoneId",
|
|
173
|
-
"boardId",
|
|
174
|
-
"boardContainerId",
|
|
175
|
-
"boardTypeId",
|
|
176
|
-
"boardBaseId",
|
|
177
|
-
"edgeId",
|
|
178
|
-
"edgeTypeId",
|
|
179
|
-
"vertexId",
|
|
180
|
-
"vertexTypeId",
|
|
181
|
-
"spaceId",
|
|
182
|
-
"spaceTypeId",
|
|
183
|
-
"relationTypeId",
|
|
184
|
-
"resourceId",
|
|
185
|
-
"pieceId",
|
|
186
|
-
"pieceTypeId",
|
|
187
|
-
"dieId",
|
|
188
|
-
"dieTypeId",
|
|
189
|
-
"setupOptionId",
|
|
190
|
-
"setupProfileId",
|
|
191
|
-
"cardSetId",
|
|
192
|
-
"cardType"
|
|
193
|
-
];
|
|
194
|
-
function matchManifestScopedIdName(key) {
|
|
195
|
-
for (const name of MANIFEST_SCOPED_ID_NAMES) {
|
|
196
|
-
const capitalized = `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
197
|
-
if (key === name || key.endsWith(capitalized)) {
|
|
198
|
-
return { name, kind: "singular" };
|
|
199
|
-
}
|
|
200
|
-
const plural = `${name}s`;
|
|
201
|
-
const capitalizedPlural = `${capitalized}s`;
|
|
202
|
-
if (key === plural || key.endsWith(capitalizedPlural)) {
|
|
203
|
-
return { name, kind: "plural" };
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
function validateInteractionParamsSchema(schema, context, path) {
|
|
209
|
-
const inner = unwrapWrappers(schema);
|
|
210
|
-
if (isEnumKeyedRecordSchema(inner) && !isSparseMapSchema(inner)) {
|
|
211
|
-
throw new Error(
|
|
212
|
-
`${context}: ${path} uses an enum-keyed z.record(...), which parses as a total map at runtime. Use sparseMap(...) or sparseCounts(...) from @dreamboard-games/sdk/reducer instead so interaction params stay sparse and match runtime validation.`
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
const shape = getObjectShape(inner);
|
|
216
|
-
if (shape) {
|
|
217
|
-
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
218
|
-
validateInteractionParamsSchema(fieldSchema, context, `${path}.${key}`);
|
|
219
|
-
}
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
const def = getZodDef(inner);
|
|
223
|
-
if (def.type === "array" && def.element) {
|
|
224
|
-
validateInteractionParamsSchema(def.element, context, `${path}[]`);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (def.type === "record" && def.valueType) {
|
|
228
|
-
validateInteractionParamsSchema(def.valueType, context, `${path}.*`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
function validateInteractionInputsSchema(inputs, context) {
|
|
232
|
-
if (!inputs) return;
|
|
233
|
-
for (const [key, collector] of Object.entries(inputs)) {
|
|
234
|
-
validateInteractionParamsSchema(collector.schema, context, `inputs.${key}`);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
function validateManyCommitPolicy(input) {
|
|
238
|
-
if (input.commit?.mode !== "autoWhenReady") return;
|
|
239
|
-
if (Object.values(input.inputs ?? {}).some(
|
|
240
|
-
(collector) => collector.selection?.mode === "many"
|
|
241
|
-
)) {
|
|
242
|
-
throw new Error(
|
|
243
|
-
`${input.context}: interactions with many(...) inputs must use commit: { mode: "manual" }.`
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
function validateInteractionLikeDefinition(input, context) {
|
|
248
|
-
validateInteractionInputsSchema(input.inputs, context);
|
|
249
|
-
validateManyCommitPolicy({
|
|
250
|
-
inputs: input.inputs,
|
|
251
|
-
commit: input.commit,
|
|
252
|
-
context
|
|
253
|
-
});
|
|
254
|
-
if (input.paramsSchema) {
|
|
255
|
-
validateInteractionParamsSchema(
|
|
256
|
-
input.paramsSchema,
|
|
257
|
-
context,
|
|
258
|
-
"paramsSchema"
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
function validateStateSchemaIdBranding(schema, scope) {
|
|
263
|
-
const def = getZodDef(schema);
|
|
264
|
-
if (def.type !== "object") {
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
const shape = def.shape;
|
|
268
|
-
if (!shape) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
272
|
-
const match = matchManifestScopedIdName(key);
|
|
273
|
-
if (!match) {
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
const inner = unwrapWrappers(fieldSchema);
|
|
277
|
-
if (match.kind === "singular") {
|
|
278
|
-
if (isPlainZodString(inner) && !isManifestScopedSchema(inner)) {
|
|
279
|
-
throw new Error(
|
|
280
|
-
`defineGameContract: state.${scope}.${key} uses a raw z.string() but its name identifies it as a manifest-scoped '${match.name}'. Use gameContract.schemas.${match.name} (or manifest.ids.${match.name}) so the branded literal union flows through state types.`
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
if (match.kind === "plural" && isZodArray(inner)) {
|
|
286
|
-
const element = unwrapWrappers(getZodDef(inner).element);
|
|
287
|
-
if (isPlainZodString(element) && !isManifestScopedSchema(element)) {
|
|
288
|
-
throw new Error(
|
|
289
|
-
`defineGameContract: state.${scope}.${key} uses z.array(z.string()) but its name identifies it as manifest-scoped '${match.name}' values. Use z.array(gameContract.schemas.${match.name}) (or manifest.ids.${match.name}) so the branded literal union flows through state types.`
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
function validateDefineGamePhaseNames(definition) {
|
|
296
|
-
const contractPhaseNames = definition.contract.phaseNames;
|
|
297
|
-
if (!Array.isArray(contractPhaseNames)) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
const declared = new Set(contractPhaseNames);
|
|
301
|
-
const actual = new Set(Object.keys(definition.phases));
|
|
302
|
-
const missing = [...declared].filter((name) => !actual.has(name));
|
|
303
|
-
const extra = [...actual].filter((name) => !declared.has(name));
|
|
304
|
-
if (missing.length > 0 || extra.length > 0) {
|
|
305
|
-
const parts = [];
|
|
306
|
-
if (missing.length > 0) {
|
|
307
|
-
parts.push(`missing: [${missing.join(", ")}]`);
|
|
308
|
-
}
|
|
309
|
-
if (extra.length > 0) {
|
|
310
|
-
parts.push(`extra: [${extra.join(", ")}]`);
|
|
311
|
-
}
|
|
312
|
-
throw new Error(
|
|
313
|
-
`defineGame: phases record does not match contract.phaseNames (${parts.join(
|
|
314
|
-
"; "
|
|
315
|
-
)}). Update contract.phaseNames or the phases record so they agree.`
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
if (definition.initialPhase !== void 0 && !declared.has(definition.initialPhase)) {
|
|
319
|
-
throw new Error(
|
|
320
|
-
`defineGame: initialPhase '${definition.initialPhase}' is not declared in contract.phaseNames.`
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
if (definition.setupProfiles) {
|
|
324
|
-
for (const [profileId, profile] of Object.entries(
|
|
325
|
-
definition.setupProfiles
|
|
326
|
-
)) {
|
|
327
|
-
const initial = profile?.initialPhase;
|
|
328
|
-
if (initial !== void 0 && !declared.has(initial)) {
|
|
329
|
-
throw new Error(
|
|
330
|
-
`defineGame: setupProfiles.${profileId}.initialPhase '${initial}' is not declared in contract.phaseNames.`
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
function validateDefineGameZoneWiring(definition) {
|
|
337
|
-
const manifestPlayerZoneIds = new Set(
|
|
338
|
-
definition.contract.manifest.literals.playerZoneIds ?? []
|
|
339
|
-
);
|
|
340
|
-
for (const [phaseName, phase] of Object.entries(definition.phases)) {
|
|
341
|
-
const phaseRecord = typeof phase === "object" && phase !== null ? phase : null;
|
|
342
|
-
if (!phaseRecord) continue;
|
|
343
|
-
if (phaseRecord.zones !== void 0 && !Array.isArray(phaseRecord.zones)) {
|
|
344
|
-
const zonesRecord = typeof phaseRecord.zones === "object" && phaseRecord.zones !== null ? phaseRecord.zones : null;
|
|
345
|
-
const hasRemovedZoneSpec = zonesRecord && Object.values(zonesRecord).some(
|
|
346
|
-
(zone) => typeof zone === "object" && zone !== null && ("cardsFrom" in zone || "playableVia" in zone || "from" in zone)
|
|
347
|
-
);
|
|
348
|
-
if (hasRemovedZoneSpec) {
|
|
349
|
-
throw new Error(
|
|
350
|
-
`defineGame: phases.${phaseName}.zones uses removed zone spec objects. Use zones: ["manifest-player-zone-id"] and cardActions[*].playFrom instead.`
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
throw new Error(
|
|
354
|
-
`defineGame: phases.${phaseName}.zones must be an array of manifest player zone ids.`
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
for (const [index, zoneId] of (phaseRecord.zones ?? []).entries()) {
|
|
358
|
-
if (typeof zoneId !== "string") {
|
|
359
|
-
throw new Error(
|
|
360
|
-
`defineGame: phases.${phaseName}.zones[${index}] must be a manifest player zone id string.`
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
if (!manifestPlayerZoneIds.has(zoneId)) {
|
|
364
|
-
throw new Error(
|
|
365
|
-
`defineGame: phases.${phaseName}.zones[${index}] '${zoneId}' is not declared in manifest.literals.playerZoneIds.`
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
for (const [actionId, action] of Object.entries(
|
|
370
|
-
phaseRecord.cardActions ?? {}
|
|
371
|
-
)) {
|
|
372
|
-
const actionRecord = typeof action === "object" && action !== null ? action : null;
|
|
373
|
-
const playFrom = actionRecord?.playFrom;
|
|
374
|
-
if (typeof playFrom === "string" && !manifestPlayerZoneIds.has(playFrom)) {
|
|
375
|
-
throw new Error(
|
|
376
|
-
`defineGame: phases.${phaseName}.cardActions.${actionId}.playFrom '${playFrom}' is not declared in manifest.literals.playerZoneIds.`
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
function validateDefineGameSimultaneousPhases(definition) {
|
|
383
|
-
for (const [phaseName, phase] of Object.entries(definition.phases)) {
|
|
384
|
-
const phaseRecord = typeof phase === "object" && phase !== null ? phase : null;
|
|
385
|
-
if (!phaseRecord || phaseRecord.kind !== "simultaneousPlayer") {
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
if (!phaseRecord.submit) {
|
|
389
|
-
throw new Error(
|
|
390
|
-
`defineGame: phases.${phaseName} is kind 'simultaneousPlayer' but does not declare submit.`
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
if (typeof phaseRecord.resolve !== "function") {
|
|
394
|
-
throw new Error(
|
|
395
|
-
`defineGame: phases.${phaseName} is kind 'simultaneousPlayer' but does not declare resolve.`
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
if (phaseRecord.interactions?.submit) {
|
|
399
|
-
throw new Error(
|
|
400
|
-
`defineGame: phases.${phaseName}.interactions.submit conflicts with the reserved simultaneous submit interaction id.`
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
validateInteractionInputsSchema(
|
|
404
|
-
phaseRecord.submit.inputs,
|
|
405
|
-
"defineInteraction"
|
|
406
|
-
);
|
|
407
|
-
validateManyCommitPolicy({
|
|
408
|
-
inputs: phaseRecord.submit.inputs,
|
|
409
|
-
commit: phaseRecord.submit.commit,
|
|
410
|
-
context: `defineGame: phases.${phaseName}.submit`
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// src/reducer/authoring/contract.ts
|
|
416
|
-
function validateErrorMap(errors) {
|
|
417
|
-
if (!errors) return;
|
|
418
|
-
const codePattern = /^[A-Z][A-Z0-9_]*$/;
|
|
419
|
-
for (const [code, message] of Object.entries(errors)) {
|
|
420
|
-
if (!codePattern.test(code)) {
|
|
421
|
-
throw new Error(
|
|
422
|
-
`defineGameContract: error code '${code}' must use UPPER_SNAKE_CASE.`
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
if (typeof message !== "string" || message.length === 0) {
|
|
426
|
-
throw new Error(
|
|
427
|
-
`defineGameContract: error code '${code}' must declare a non-empty default message.`
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
function defineGameContract(definition) {
|
|
433
|
-
validateStateSchemaIdBranding(definition.state.public, "public");
|
|
434
|
-
validateStateSchemaIdBranding(definition.state.private, "private");
|
|
435
|
-
validateStateSchemaIdBranding(definition.state.hidden, "hidden");
|
|
436
|
-
validateErrorMap(definition.errors);
|
|
437
|
-
const phaseNames = Object.keys(definition.phases);
|
|
438
|
-
if (phaseNames.length === 0) {
|
|
439
|
-
throw new Error(
|
|
440
|
-
"defineGameContract: phases must be a non-empty record of phase schemas."
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
for (const name of phaseNames) {
|
|
444
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
445
|
-
throw new Error(
|
|
446
|
-
"defineGameContract: phase names must be non-empty strings."
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
const phaseNameSchema = createManifestStringLiteralSchema(phaseNames);
|
|
451
|
-
const narrowedManifest = {
|
|
452
|
-
...definition.manifest,
|
|
453
|
-
literals: {
|
|
454
|
-
...definition.manifest.literals,
|
|
455
|
-
phaseNames
|
|
456
|
-
},
|
|
457
|
-
ids: {
|
|
458
|
-
...definition.manifest.ids,
|
|
459
|
-
phaseName: phaseNameSchema
|
|
460
|
-
}
|
|
461
|
-
};
|
|
462
|
-
const contract = {
|
|
463
|
-
manifest: narrowedManifest,
|
|
464
|
-
state: definition.state,
|
|
465
|
-
phases: definition.phases,
|
|
466
|
-
errors: definition.errors,
|
|
467
|
-
phaseNames,
|
|
468
|
-
schemas: narrowedManifest.ids
|
|
469
|
-
};
|
|
470
|
-
return contract;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// src/reducer/inputs/formInput.ts
|
|
474
|
-
import { z as z2 } from "zod";
|
|
475
|
-
function isResourceMapChoiceSource(choices) {
|
|
476
|
-
return choices === "resourceMap" || typeof choices === "object" && choices !== null && !Array.isArray(choices) && "source" in choices && choices.source === "resourceMap";
|
|
477
|
-
}
|
|
478
|
-
function resolveDomainNumber(value, context, fallback) {
|
|
479
|
-
if (typeof value === "function") return value(context);
|
|
480
|
-
return value ?? fallback;
|
|
481
|
-
}
|
|
482
|
-
function resolveDomainChoices(choices, context) {
|
|
483
|
-
if (isResourceMapChoiceSource(choices)) {
|
|
484
|
-
return resolveResourceMapChoices(choices, context);
|
|
485
|
-
}
|
|
486
|
-
const resolved = typeof choices === "function" ? choices(context) : choices;
|
|
487
|
-
return resolved.map((choice) => ({
|
|
488
|
-
value: choice.value,
|
|
489
|
-
label: choice.label,
|
|
490
|
-
icon: choice.icon,
|
|
491
|
-
badge: choice.badge,
|
|
492
|
-
description: choice.description,
|
|
493
|
-
disabled: choice.disabled,
|
|
494
|
-
disabledReason: choice.disabledReason
|
|
495
|
-
}));
|
|
496
|
-
}
|
|
497
|
-
function resolveDependentDomainChoices(choices, context) {
|
|
498
|
-
const resolved = typeof choices === "function" ? choices(context) : choices;
|
|
499
|
-
return resolved.map((choice) => ({
|
|
500
|
-
value: choice.value,
|
|
501
|
-
label: choice.label,
|
|
502
|
-
icon: choice.icon,
|
|
503
|
-
badge: choice.badge,
|
|
504
|
-
description: choice.description,
|
|
505
|
-
disabled: choice.disabled,
|
|
506
|
-
disabledReason: choice.disabledReason
|
|
507
|
-
}));
|
|
508
|
-
}
|
|
509
|
-
function choiceValuesInclude(choices, value) {
|
|
510
|
-
return choices.some((choice) => Object.is(choice.value, value));
|
|
511
|
-
}
|
|
512
|
-
function assertChoiceDefaultInChoices(inputName, choices, defaultValue) {
|
|
513
|
-
if (choiceValuesInclude(choices, defaultValue)) return;
|
|
514
|
-
const printable = defaultValue === null ? "null" : `'${defaultValue}'`;
|
|
515
|
-
throw new Error(
|
|
516
|
-
`${inputName} defaultValue ${printable} must be one of its choices. If null is a valid value, add an explicit { value: null, label: ... } choice.`
|
|
517
|
-
);
|
|
518
|
-
}
|
|
519
|
-
function choiceSchema(choices) {
|
|
520
|
-
const values = choices.map((choice) => choice.value);
|
|
521
|
-
const stringValues = values.filter(
|
|
522
|
-
(value) => value !== null
|
|
523
|
-
);
|
|
524
|
-
const hasNull = values.some((value) => value === null);
|
|
525
|
-
if (stringValues.length === 0) {
|
|
526
|
-
return z2.null();
|
|
527
|
-
}
|
|
528
|
-
const stringSchema = z2.enum(
|
|
529
|
-
stringValues
|
|
530
|
-
);
|
|
531
|
-
if (hasNull) {
|
|
532
|
-
return z2.union([stringSchema, z2.null()]);
|
|
533
|
-
}
|
|
534
|
-
return stringSchema;
|
|
535
|
-
}
|
|
536
|
-
function resolveResourceMapChoices(choices, context) {
|
|
537
|
-
const resources = context.state.table.resources;
|
|
538
|
-
const firstResourceMap = isPerPlayer(resources) && resources.entries.length > 0 ? resources.entries[0]?.[1] : resources;
|
|
539
|
-
if (typeof firstResourceMap !== "object" || firstResourceMap === null || Array.isArray(firstResourceMap)) {
|
|
540
|
-
return [];
|
|
541
|
-
}
|
|
542
|
-
const decorate = choices === "resourceMap" ? void 0 : choices.decorate;
|
|
543
|
-
return Object.keys(firstResourceMap).sort().map((resourceId) => {
|
|
544
|
-
const label = resourceId;
|
|
545
|
-
const presentation = decorate?.({ ...context, resourceId, label });
|
|
546
|
-
return {
|
|
547
|
-
value: resourceId,
|
|
548
|
-
label,
|
|
549
|
-
badge: presentation?.badge,
|
|
550
|
-
description: presentation?.description,
|
|
551
|
-
disabled: presentation?.disabled,
|
|
552
|
-
disabledReason: presentation?.disabledReason
|
|
553
|
-
};
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
function createFormInput(schema, options) {
|
|
557
|
-
return {
|
|
558
|
-
kind: "form",
|
|
559
|
-
schema,
|
|
560
|
-
...options && "defaultValue" in options ? { defaultValue: options.defaultValue } : {}
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
function baseFormInput(schema, options) {
|
|
564
|
-
return createFormInput(schema, options);
|
|
565
|
-
}
|
|
566
|
-
function resourceMapInput(options) {
|
|
567
|
-
return {
|
|
568
|
-
kind: "form",
|
|
569
|
-
schema: z2.record(z2.string(), z2.number().int().nonnegative()),
|
|
570
|
-
..."defaultValue" in options ? { defaultValue: options.defaultValue } : {},
|
|
571
|
-
domain: (state, playerId, q, derived) => {
|
|
572
|
-
const context = {
|
|
573
|
-
state,
|
|
574
|
-
playerId,
|
|
575
|
-
q,
|
|
576
|
-
derived,
|
|
577
|
-
values: {}
|
|
578
|
-
};
|
|
579
|
-
return {
|
|
580
|
-
type: "resourceMap",
|
|
581
|
-
resources: options.resources.map((resource) => ({
|
|
582
|
-
resourceId: resource.resourceId,
|
|
583
|
-
label: resource.label,
|
|
584
|
-
icon: resource.icon,
|
|
585
|
-
min: resolveDomainNumber(resource.min, context, 0),
|
|
586
|
-
max: resolveDomainNumber(resource.max, context, 0)
|
|
587
|
-
}))
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
function numberInput(options) {
|
|
593
|
-
return {
|
|
594
|
-
kind: "form",
|
|
595
|
-
schema: z2.number(),
|
|
596
|
-
..."defaultValue" in options ? { defaultValue: options.defaultValue } : {},
|
|
597
|
-
domain: (state, playerId, q, derived) => {
|
|
598
|
-
const context = {
|
|
599
|
-
state,
|
|
600
|
-
playerId,
|
|
601
|
-
q,
|
|
602
|
-
derived,
|
|
603
|
-
values: {}
|
|
604
|
-
};
|
|
605
|
-
return {
|
|
606
|
-
type: "boundedNumber",
|
|
607
|
-
min: resolveDomainNumber(options.min, context, 0),
|
|
608
|
-
max: resolveDomainNumber(options.max, context, 0),
|
|
609
|
-
step: options.step === void 0 ? void 0 : resolveDomainNumber(options.step, context, 1)
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
function choiceInput(options) {
|
|
615
|
-
const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
|
|
616
|
-
if (Array.isArray(options.choices) && options.choices.length === 0) {
|
|
617
|
-
throw new Error("formInput.choice requires at least one choice.");
|
|
618
|
-
}
|
|
619
|
-
const staticChoices = Array.isArray(options.choices) ? options.choices : null;
|
|
620
|
-
const hasStaticDefault = typeof options.defaultValue !== "function";
|
|
621
|
-
const staticDefault = options.defaultValue;
|
|
622
|
-
if (staticChoices && hasStaticDefault) {
|
|
623
|
-
assertChoiceDefaultInChoices(
|
|
624
|
-
"formInput.choice",
|
|
625
|
-
staticChoices,
|
|
626
|
-
staticDefault
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
|
-
const schema = staticChoices ? choiceSchema(staticChoices) : z2.string().nullable();
|
|
630
|
-
const dynamicDefault = typeof options.defaultValue === "function" ? options.defaultValue : void 0;
|
|
631
|
-
return {
|
|
632
|
-
kind: "form",
|
|
633
|
-
schema,
|
|
634
|
-
...hasStaticDefault ? { defaultValue: staticDefault } : {},
|
|
635
|
-
...dependsOn ? { dependsOn } : {},
|
|
636
|
-
domain: (state, playerId, q, derived, values) => {
|
|
637
|
-
const context = {
|
|
638
|
-
state,
|
|
639
|
-
playerId,
|
|
640
|
-
q,
|
|
641
|
-
derived
|
|
642
|
-
};
|
|
643
|
-
const choices = dependsOn ? resolveDependentDomainChoices(
|
|
644
|
-
options.choices,
|
|
645
|
-
{
|
|
646
|
-
...context,
|
|
647
|
-
values: values ?? {}
|
|
648
|
-
}
|
|
649
|
-
) : resolveDomainChoices(options.choices, {
|
|
650
|
-
...context,
|
|
651
|
-
values: {}
|
|
652
|
-
});
|
|
653
|
-
if (hasStaticDefault) {
|
|
654
|
-
assertChoiceDefaultInChoices(
|
|
655
|
-
"formInput.choice",
|
|
656
|
-
choices,
|
|
657
|
-
staticDefault
|
|
658
|
-
);
|
|
659
|
-
}
|
|
660
|
-
return {
|
|
661
|
-
type: "choice",
|
|
662
|
-
choices
|
|
663
|
-
};
|
|
664
|
-
},
|
|
665
|
-
...dynamicDefault ? {
|
|
666
|
-
resolveDefaultValue: (state, playerId, q, derived, domain) => {
|
|
667
|
-
const choices = domain.type === "choice" ? domain.choices.map((choice) => ({
|
|
668
|
-
value: choice.value,
|
|
669
|
-
label: choice.label,
|
|
670
|
-
icon: choice.icon,
|
|
671
|
-
badge: choice.badge,
|
|
672
|
-
description: choice.description,
|
|
673
|
-
disabled: choice.disabled,
|
|
674
|
-
disabledReason: choice.disabledReason
|
|
675
|
-
})) : [];
|
|
676
|
-
const resolved = dynamicDefault({
|
|
677
|
-
state,
|
|
678
|
-
playerId,
|
|
679
|
-
q,
|
|
680
|
-
derived,
|
|
681
|
-
values: {},
|
|
682
|
-
choices
|
|
683
|
-
});
|
|
684
|
-
if (resolved === void 0) return void 0;
|
|
685
|
-
assertChoiceDefaultInChoices("formInput.choice", choices, resolved);
|
|
686
|
-
return resolved;
|
|
687
|
-
}
|
|
688
|
-
} : {}
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
function choiceListInput(options) {
|
|
692
|
-
if (Array.isArray(options.choices) && options.choices.length === 0) {
|
|
693
|
-
throw new Error("formInput.choiceList requires at least one choice.");
|
|
694
|
-
}
|
|
695
|
-
const staticDefaultValue = Array.isArray(options.defaultValue) ? options.defaultValue : void 0;
|
|
696
|
-
const dynamicDefaultValue = options.defaultValue === "all" || typeof options.defaultValue === "function" ? options.defaultValue : void 0;
|
|
697
|
-
return {
|
|
698
|
-
kind: "form",
|
|
699
|
-
schema: z2.array(z2.string()),
|
|
700
|
-
...staticDefaultValue !== void 0 ? { defaultValue: staticDefaultValue } : {},
|
|
701
|
-
domain: (state, playerId, q, derived) => {
|
|
702
|
-
const context = {
|
|
703
|
-
state,
|
|
704
|
-
playerId,
|
|
705
|
-
q,
|
|
706
|
-
derived,
|
|
707
|
-
values: {}
|
|
708
|
-
};
|
|
709
|
-
const choices = resolveDomainChoices(options.choices, context).map(
|
|
710
|
-
(choice) => ({
|
|
711
|
-
...choice,
|
|
712
|
-
value: choice.value
|
|
713
|
-
})
|
|
714
|
-
);
|
|
715
|
-
return {
|
|
716
|
-
type: "choiceList",
|
|
717
|
-
choices,
|
|
718
|
-
min: resolveDomainNumber(options.min, context, 0),
|
|
719
|
-
max: resolveDomainNumber(options.max, context, choices.length)
|
|
720
|
-
};
|
|
721
|
-
},
|
|
722
|
-
...dynamicDefaultValue ? {
|
|
723
|
-
resolveDefaultValue: (state, playerId, q, derived, domain) => {
|
|
724
|
-
const choices = domain.type === "choiceList" ? domain.choices.map((choice) => ({
|
|
725
|
-
value: choice.value,
|
|
726
|
-
label: choice.label,
|
|
727
|
-
icon: choice.icon,
|
|
728
|
-
badge: choice.badge,
|
|
729
|
-
description: choice.description,
|
|
730
|
-
disabled: choice.disabled,
|
|
731
|
-
disabledReason: choice.disabledReason
|
|
732
|
-
})) : [];
|
|
733
|
-
if (dynamicDefaultValue === "all") {
|
|
734
|
-
return choices.map((choice) => choice.value);
|
|
735
|
-
}
|
|
736
|
-
return dynamicDefaultValue({
|
|
737
|
-
state,
|
|
738
|
-
playerId,
|
|
739
|
-
q,
|
|
740
|
-
derived,
|
|
741
|
-
values: {},
|
|
742
|
-
choices
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
} : {}
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
function formInputForState() {
|
|
749
|
-
return Object.assign(
|
|
750
|
-
((schema, options) => baseFormInput(schema, options)),
|
|
751
|
-
{
|
|
752
|
-
resourceMap: (options) => resourceMapInput(options),
|
|
753
|
-
resourceChoices: (options) => formInput.resourceChoices(options),
|
|
754
|
-
number: (options) => numberInput(options),
|
|
755
|
-
choice: (options) => choiceInput(options),
|
|
756
|
-
choiceList: (options) => choiceListInput(options)
|
|
757
|
-
}
|
|
758
|
-
);
|
|
759
|
-
}
|
|
760
|
-
var formInput = Object.assign(baseFormInput, {
|
|
761
|
-
resourceMap: resourceMapInput,
|
|
762
|
-
resourceChoices: (options) => ({
|
|
763
|
-
source: "resourceMap",
|
|
764
|
-
...options
|
|
765
|
-
}),
|
|
766
|
-
number: numberInput,
|
|
767
|
-
choice: choiceInput,
|
|
768
|
-
choiceList: choiceListInput,
|
|
769
|
-
forState: formInputForState
|
|
770
|
-
});
|
|
771
|
-
|
|
772
|
-
// src/reducer/inputs/defineInputs.ts
|
|
773
|
-
var InputBuilder = class {
|
|
774
|
-
add(key, collector) {
|
|
775
|
-
return { key, collector };
|
|
776
|
-
}
|
|
777
|
-
};
|
|
778
|
-
function defineInputs(define) {
|
|
779
|
-
const refs = define(new InputBuilder());
|
|
780
|
-
return Object.fromEntries(
|
|
781
|
-
Object.entries(refs).map(([key, ref]) => [key, ref.collector])
|
|
782
|
-
);
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
// src/reducer/inputs/boardInput.ts
|
|
786
|
-
import { z as z3 } from "zod";
|
|
787
|
-
function makeBoardCollector(kind) {
|
|
788
|
-
return function collector(options) {
|
|
789
|
-
const target = options.target;
|
|
790
|
-
const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
|
|
791
|
-
return {
|
|
792
|
-
kind,
|
|
793
|
-
schema: z3.string(),
|
|
794
|
-
eligibleTargets: ((state, playerId, q, values) => target.eligible({
|
|
795
|
-
state,
|
|
796
|
-
playerId,
|
|
797
|
-
q,
|
|
798
|
-
values
|
|
799
|
-
})),
|
|
800
|
-
validateTarget: ((state, playerId, q, targetId, values) => target.validate(
|
|
801
|
-
{
|
|
802
|
-
state,
|
|
803
|
-
playerId,
|
|
804
|
-
q,
|
|
805
|
-
values
|
|
806
|
-
},
|
|
807
|
-
targetId
|
|
808
|
-
)),
|
|
809
|
-
...dependsOn ? { dependsOn } : {},
|
|
810
|
-
domain: (state, playerId, q, _derived, values) => ({
|
|
811
|
-
type: "boardTarget",
|
|
812
|
-
projection: "resolved",
|
|
813
|
-
targetKind: target.targetKind,
|
|
814
|
-
boardId: target.boardId,
|
|
815
|
-
valueKind: target.valueKind,
|
|
816
|
-
eligibleTargets: target.eligible({
|
|
817
|
-
state,
|
|
818
|
-
playerId,
|
|
819
|
-
q,
|
|
820
|
-
values
|
|
821
|
-
}).map(String)
|
|
822
|
-
}),
|
|
823
|
-
meta: {
|
|
824
|
-
targetKind: target.targetKind,
|
|
825
|
-
boardId: target.boardId,
|
|
826
|
-
valueKind: target.valueKind
|
|
827
|
-
}
|
|
828
|
-
};
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
var vertexInput = makeBoardCollector("board-vertex");
|
|
832
|
-
var edgeInput = makeBoardCollector("board-edge");
|
|
833
|
-
var tileInput = makeBoardCollector("board-tile");
|
|
834
|
-
var spaceInput = makeBoardCollector("board-space");
|
|
835
|
-
function playerSpaceInput(options) {
|
|
836
|
-
const target = options.target;
|
|
837
|
-
const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
|
|
838
|
-
const playerIdSchema = markManifestScopedSchema(
|
|
839
|
-
z3.string(),
|
|
840
|
-
"playerId"
|
|
841
|
-
);
|
|
842
|
-
return {
|
|
843
|
-
kind: "board-space",
|
|
844
|
-
schema: z3.object({
|
|
845
|
-
boardId: z3.literal(target.boardId),
|
|
846
|
-
playerId: playerIdSchema,
|
|
847
|
-
spaceId: z3.string()
|
|
848
|
-
}),
|
|
849
|
-
eligibleTargets: ((state, playerId, q, values) => target.eligible({
|
|
850
|
-
state,
|
|
851
|
-
playerId,
|
|
852
|
-
q,
|
|
853
|
-
values
|
|
854
|
-
})),
|
|
855
|
-
validateTarget: ((state, playerId, q, targetValue, values) => target.validate(
|
|
856
|
-
{
|
|
857
|
-
state,
|
|
858
|
-
playerId,
|
|
859
|
-
q,
|
|
860
|
-
values
|
|
861
|
-
},
|
|
862
|
-
targetValue
|
|
863
|
-
)),
|
|
864
|
-
...dependsOn ? { dependsOn } : {},
|
|
865
|
-
domain: (state, playerId, q, _derived, values) => ({
|
|
866
|
-
type: "boardTarget",
|
|
867
|
-
projection: "resolved",
|
|
868
|
-
targetKind: target.targetKind,
|
|
869
|
-
boardId: target.boardId,
|
|
870
|
-
valueKind: target.valueKind,
|
|
871
|
-
eligibleTargets: target.eligible({
|
|
872
|
-
state,
|
|
873
|
-
playerId,
|
|
874
|
-
q,
|
|
875
|
-
values
|
|
876
|
-
}).map((candidate) => candidate.spaceId)
|
|
877
|
-
}),
|
|
878
|
-
meta: {
|
|
879
|
-
targetKind: target.targetKind,
|
|
880
|
-
boardId: target.boardId,
|
|
881
|
-
valueKind: target.valueKind
|
|
882
|
-
}
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
var boardInput = {
|
|
886
|
-
vertex: vertexInput,
|
|
887
|
-
edge: edgeInput,
|
|
888
|
-
tile: tileInput,
|
|
889
|
-
space: spaceInput,
|
|
890
|
-
playerSpace: playerSpaceInput
|
|
891
|
-
};
|
|
892
|
-
|
|
893
|
-
// src/reducer/inputs/boardTarget.ts
|
|
894
|
-
function candidateIdsForKind(q, boardId, targetKind) {
|
|
895
|
-
if (targetKind === "edge") {
|
|
896
|
-
return idsFromCollection(q.board.tiled(boardId).edges);
|
|
897
|
-
}
|
|
898
|
-
if (targetKind === "vertex") {
|
|
899
|
-
return idsFromCollection(q.board.tiled(boardId).vertices);
|
|
900
|
-
}
|
|
901
|
-
return idsFromCollection(q.board.get(boardId)?.spaces);
|
|
902
|
-
}
|
|
903
|
-
function idsFromCollection(collection) {
|
|
904
|
-
if (!collection) return [];
|
|
905
|
-
const values = Array.isArray(collection) ? collection : Object.values(collection);
|
|
906
|
-
return values.flatMap((value) => {
|
|
907
|
-
if (typeof value === "string") return [value];
|
|
908
|
-
if (typeof value === "object" && value !== null && "id" in value && typeof value.id === "string") {
|
|
909
|
-
return [value.id];
|
|
910
|
-
}
|
|
911
|
-
return [];
|
|
912
|
-
});
|
|
913
|
-
}
|
|
914
|
-
function createBoardTargetBuilder(targetKind, boardId) {
|
|
915
|
-
return createTargetRuleBuilder(
|
|
916
|
-
(predicates) => ({
|
|
917
|
-
...createTargetRule(
|
|
918
|
-
({ q }) => candidateIdsForKind(q, boardId, targetKind),
|
|
919
|
-
predicates,
|
|
920
|
-
{
|
|
921
|
-
missingCandidateIssue: {
|
|
922
|
-
errorCode: "BOARD_TARGET_NOT_ELIGIBLE",
|
|
923
|
-
message: "Board target is not eligible."
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
),
|
|
927
|
-
boardId,
|
|
928
|
-
targetKind,
|
|
929
|
-
valueKind: "board-id"
|
|
930
|
-
})
|
|
931
|
-
);
|
|
932
|
-
}
|
|
933
|
-
function createPlayerSpaceTargetBuilder(boardId) {
|
|
934
|
-
return createTargetRuleBuilder(
|
|
935
|
-
(predicates) => ({
|
|
936
|
-
...createTargetRule(
|
|
937
|
-
({ state, q }) => {
|
|
938
|
-
const spacesForPlayer = (playerId) => candidateIdsForKind(
|
|
939
|
-
q,
|
|
940
|
-
`${boardId}:${playerId}`,
|
|
941
|
-
"space"
|
|
942
|
-
);
|
|
943
|
-
return state.table.playerOrder.flatMap(
|
|
944
|
-
(playerId) => spacesForPlayer(playerId).map((spaceId) => ({
|
|
945
|
-
boardId,
|
|
946
|
-
playerId,
|
|
947
|
-
spaceId
|
|
948
|
-
}))
|
|
949
|
-
);
|
|
950
|
-
},
|
|
951
|
-
predicates,
|
|
952
|
-
{
|
|
953
|
-
missingCandidateIssue: {
|
|
954
|
-
errorCode: "BOARD_TARGET_NOT_ELIGIBLE",
|
|
955
|
-
message: "Board target is not eligible."
|
|
956
|
-
},
|
|
957
|
-
equals: (left, right) => isPlayerBoardSpaceTarget(left) && isPlayerBoardSpaceTarget(right) && left.boardId === right.boardId && left.playerId === right.playerId && left.spaceId === right.spaceId
|
|
958
|
-
}
|
|
959
|
-
),
|
|
960
|
-
boardId,
|
|
961
|
-
targetKind: "space",
|
|
962
|
-
valueKind: "player-board-space"
|
|
963
|
-
})
|
|
964
|
-
);
|
|
965
|
-
}
|
|
966
|
-
function isPlayerBoardSpaceTarget(value) {
|
|
967
|
-
return typeof value === "object" && value !== null && "boardId" in value && "playerId" in value && "spaceId" in value;
|
|
968
|
-
}
|
|
969
|
-
function makeBoardTargetFactory(targetKind) {
|
|
970
|
-
return function target(boardId) {
|
|
971
|
-
return createBoardTargetBuilder(targetKind, boardId);
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
var boardTarget = {
|
|
975
|
-
edge: makeBoardTargetFactory("edge"),
|
|
976
|
-
vertex: makeBoardTargetFactory("vertex"),
|
|
977
|
-
space: makeBoardTargetFactory("space"),
|
|
978
|
-
tile: makeBoardTargetFactory("tile"),
|
|
979
|
-
playerSpace(boardId) {
|
|
980
|
-
return createPlayerSpaceTargetBuilder(boardId);
|
|
981
|
-
}
|
|
982
|
-
};
|
|
983
|
-
|
|
984
|
-
// src/reducer/inputs/choiceTarget.ts
|
|
985
|
-
function normalizeOptions(options) {
|
|
986
|
-
if (typeof options === "function") return options;
|
|
987
|
-
return () => options;
|
|
988
|
-
}
|
|
989
|
-
function createChoiceTargetBuilder(options) {
|
|
990
|
-
const optionsFactory = normalizeOptions(options);
|
|
991
|
-
return createTargetRuleBuilder(
|
|
992
|
-
(predicates) => {
|
|
993
|
-
const baseRule = createTargetRule(
|
|
994
|
-
(ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q).map(
|
|
995
|
-
(option) => option.id
|
|
996
|
-
),
|
|
997
|
-
predicates,
|
|
998
|
-
{
|
|
999
|
-
missingCandidateIssue: {
|
|
1000
|
-
errorCode: "CHOICE_TARGET_NOT_ELIGIBLE",
|
|
1001
|
-
message: "Choice target is not eligible."
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
);
|
|
1005
|
-
return {
|
|
1006
|
-
...baseRule,
|
|
1007
|
-
targetKind: "choice",
|
|
1008
|
-
options: (ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q),
|
|
1009
|
-
eligibleOptions: (ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q).filter(
|
|
1010
|
-
(option) => baseRule.isEligible(ctx, option.id)
|
|
1011
|
-
)
|
|
1012
|
-
};
|
|
1013
|
-
}
|
|
1014
|
-
);
|
|
1015
|
-
}
|
|
1016
|
-
var choiceTarget = {
|
|
1017
|
-
options(options) {
|
|
1018
|
-
return createChoiceTargetBuilder(options);
|
|
1019
|
-
}
|
|
1020
|
-
};
|
|
1021
|
-
|
|
1022
|
-
// src/reducer/inputs/promptInput.ts
|
|
1023
|
-
function promptInput(options) {
|
|
1024
|
-
const target = options.target;
|
|
1025
|
-
return {
|
|
1026
|
-
kind: "prompt",
|
|
1027
|
-
schema: options.schema,
|
|
1028
|
-
eligibleTargets: target ? ((state, playerId, q) => target.eligible({
|
|
1029
|
-
state,
|
|
1030
|
-
playerId,
|
|
1031
|
-
q
|
|
1032
|
-
})) : void 0,
|
|
1033
|
-
validateTarget: target ? ((state, playerId, q, targetId) => target.validate(
|
|
1034
|
-
{
|
|
1035
|
-
state,
|
|
1036
|
-
playerId,
|
|
1037
|
-
q
|
|
1038
|
-
},
|
|
1039
|
-
targetId
|
|
1040
|
-
)) : void 0,
|
|
1041
|
-
meta: target ? {
|
|
1042
|
-
options: (state, playerId, q) => target.options({
|
|
1043
|
-
state,
|
|
1044
|
-
playerId,
|
|
1045
|
-
q
|
|
1046
|
-
}),
|
|
1047
|
-
eligibleOptions: (state, playerId, q) => target.eligibleOptions({
|
|
1048
|
-
state,
|
|
1049
|
-
playerId,
|
|
1050
|
-
q
|
|
1051
|
-
})
|
|
1052
|
-
} : void 0,
|
|
1053
|
-
domain: (state, playerId, q) => ({
|
|
1054
|
-
type: "choice",
|
|
1055
|
-
choices: target ? target.options({
|
|
1056
|
-
state,
|
|
1057
|
-
playerId,
|
|
1058
|
-
q
|
|
1059
|
-
}).map((option) => ({
|
|
1060
|
-
value: String(option.id),
|
|
1061
|
-
label: option.label ?? String(option.id)
|
|
1062
|
-
})) : []
|
|
1063
|
-
})
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
// src/reducer/inputs/rngInput.ts
|
|
1068
|
-
import { z as z4 } from "zod";
|
|
1069
|
-
function d6(count = 1) {
|
|
1070
|
-
return {
|
|
1071
|
-
kind: "rng",
|
|
1072
|
-
schema: z4.object({
|
|
1073
|
-
values: z4.array(z4.number().int().min(1).max(6)).length(count)
|
|
1074
|
-
}),
|
|
1075
|
-
meta: { rng: "d6", count }
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
function coin() {
|
|
1079
|
-
return {
|
|
1080
|
-
kind: "rng",
|
|
1081
|
-
schema: z4.object({
|
|
1082
|
-
value: z4.enum(["heads", "tails"])
|
|
1083
|
-
}),
|
|
1084
|
-
meta: { rng: "coin" }
|
|
1085
|
-
};
|
|
1086
|
-
}
|
|
1087
|
-
var rngInput = { d6, coin };
|
|
1088
|
-
|
|
1089
|
-
// src/reducer/inputs/many.ts
|
|
1090
|
-
import { z as z5 } from "zod";
|
|
1091
|
-
function normalizeManyOptions(options) {
|
|
1092
|
-
if ("count" in options) {
|
|
1093
|
-
assertNonNegativeInteger(options.count, "many(...).count");
|
|
1094
|
-
return {
|
|
1095
|
-
mode: "many",
|
|
1096
|
-
min: options.count,
|
|
1097
|
-
max: options.count,
|
|
1098
|
-
distinct: options.distinct
|
|
1099
|
-
};
|
|
1100
|
-
}
|
|
1101
|
-
const min = options.min ?? 0;
|
|
1102
|
-
assertNonNegativeInteger(min, "many(...).min");
|
|
1103
|
-
if (options.max !== void 0) {
|
|
1104
|
-
assertNonNegativeInteger(options.max, "many(...).max");
|
|
1105
|
-
if (options.max < min) {
|
|
1106
|
-
throw new Error("many(...).max must be greater than or equal to min.");
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
return {
|
|
1110
|
-
mode: "many",
|
|
1111
|
-
min,
|
|
1112
|
-
max: options.max,
|
|
1113
|
-
distinct: options.distinct
|
|
1114
|
-
};
|
|
1115
|
-
}
|
|
1116
|
-
function assertNonNegativeInteger(value, label) {
|
|
1117
|
-
if (!Number.isInteger(value) || value < 0) {
|
|
1118
|
-
throw new Error(`${label} must be a non-negative integer.`);
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
function many(collector, options) {
|
|
1122
|
-
if (collector.kind === "rng") {
|
|
1123
|
-
throw new Error("many(...) cannot wrap rngInput collectors.");
|
|
1124
|
-
}
|
|
1125
|
-
const selection = normalizeManyOptions(options);
|
|
1126
|
-
const rest = { ...collector };
|
|
1127
|
-
delete rest.schema;
|
|
1128
|
-
delete rest.selection;
|
|
1129
|
-
delete rest.defaultValue;
|
|
1130
|
-
return {
|
|
1131
|
-
...rest,
|
|
1132
|
-
schema: z5.array(
|
|
1133
|
-
collector.schema
|
|
1134
|
-
),
|
|
1135
|
-
selection
|
|
1136
|
-
};
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
// src/reducer/authoring/game.ts
|
|
1140
|
-
function defineGame(definition) {
|
|
1141
|
-
validateDefineGamePhaseNames(definition);
|
|
1142
|
-
validateDefineGameSimultaneousPhases(definition);
|
|
1143
|
-
validateDefineGameZoneWiring(definition);
|
|
1144
|
-
return definition;
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
// src/reducer/authoring/interaction.ts
|
|
1148
|
-
function defineInteraction() {
|
|
1149
|
-
return (definition) => {
|
|
1150
|
-
validateInteractionLikeDefinition(
|
|
1151
|
-
definition,
|
|
1152
|
-
"defineInteraction"
|
|
1153
|
-
);
|
|
1154
|
-
return definition;
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
function defineInteractionRule() {
|
|
1158
|
-
return (definition) => definition;
|
|
1159
|
-
}
|
|
1160
|
-
function defineCardAction() {
|
|
1161
|
-
return (definition) => {
|
|
1162
|
-
validateInteractionLikeDefinition(
|
|
1163
|
-
definition,
|
|
1164
|
-
"defineCardAction"
|
|
1165
|
-
);
|
|
1166
|
-
return definition;
|
|
1167
|
-
};
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
// src/reducer/authoring/phase.ts
|
|
1171
|
-
import { z as z6 } from "zod";
|
|
1172
|
-
function stepStateSchema(schema, steps) {
|
|
1173
|
-
const stepSchema = z6.enum(steps);
|
|
1174
|
-
const maybeObject = schema;
|
|
1175
|
-
if (typeof maybeObject.extend === "function") {
|
|
1176
|
-
return maybeObject.extend({ step: stepSchema });
|
|
1177
|
-
}
|
|
1178
|
-
return z6.intersection(schema, z6.object({ step: stepSchema }));
|
|
1179
|
-
}
|
|
1180
|
-
function unwrapStepInteractions(interactions) {
|
|
1181
|
-
if (!interactions) return void 0;
|
|
1182
|
-
return Object.fromEntries(
|
|
1183
|
-
Object.entries(interactions).map(([key, entry]) => [
|
|
1184
|
-
key,
|
|
1185
|
-
{
|
|
1186
|
-
...entry.interaction,
|
|
1187
|
-
__steps: entry.steps
|
|
1188
|
-
}
|
|
1189
|
-
])
|
|
1190
|
-
);
|
|
1191
|
-
}
|
|
1192
|
-
function unwrapStepCardActions(cardActions) {
|
|
1193
|
-
if (!cardActions) return void 0;
|
|
1194
|
-
return Object.fromEntries(
|
|
1195
|
-
Object.entries(cardActions).map(([key, entry]) => [
|
|
1196
|
-
key,
|
|
1197
|
-
{
|
|
1198
|
-
...entry.action,
|
|
1199
|
-
__steps: entry.steps
|
|
1200
|
-
}
|
|
1201
|
-
])
|
|
1202
|
-
);
|
|
1203
|
-
}
|
|
1204
|
-
function definePhase() {
|
|
1205
|
-
return (definition) => {
|
|
1206
|
-
return definition;
|
|
1207
|
-
};
|
|
1208
|
-
}
|
|
1209
|
-
function defineStepPhase() {
|
|
1210
|
-
return (definition) => {
|
|
1211
|
-
const [initialStep] = definition.steps;
|
|
1212
|
-
const state = stepStateSchema(definition.state, definition.steps);
|
|
1213
|
-
const initialState = definition.initialState ? (ctx) => ({
|
|
1214
|
-
...definition.initialState?.(ctx),
|
|
1215
|
-
step: initialStep
|
|
1216
|
-
}) : () => ({ step: initialStep });
|
|
1217
|
-
const { steps: _steps, ...rest } = definition;
|
|
1218
|
-
void _steps;
|
|
1219
|
-
const normalized = {
|
|
1220
|
-
...rest,
|
|
1221
|
-
state,
|
|
1222
|
-
initialState,
|
|
1223
|
-
interactions: unwrapStepInteractions(definition.interactions),
|
|
1224
|
-
cardActions: unwrapStepCardActions(definition.cardActions)
|
|
1225
|
-
};
|
|
1226
|
-
return normalized;
|
|
1227
|
-
};
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
// src/reducer/authoring/view-stage.ts
|
|
1231
|
-
function defineSharedView() {
|
|
1232
|
-
return (definition) => definition;
|
|
1233
|
-
}
|
|
1234
|
-
function definePlayerView() {
|
|
1235
|
-
return (definition) => definition;
|
|
1236
|
-
}
|
|
1237
|
-
function defineEmptyView() {
|
|
1238
|
-
return {
|
|
1239
|
-
project: () => ({})
|
|
1240
|
-
};
|
|
1241
|
-
}
|
|
1242
|
-
function defineStaticView() {
|
|
1243
|
-
return (definition) => definition;
|
|
1244
|
-
}
|
|
1245
|
-
function defineStage() {
|
|
1246
|
-
return (definition) => definition;
|
|
1247
|
-
}
|
|
1248
|
-
function definePhaseStage() {
|
|
1249
|
-
return (definition) => definition;
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
// src/reducer/authoring/contract-authoring.ts
|
|
1253
|
-
function createBoundInputBuilders() {
|
|
1254
|
-
return {
|
|
1255
|
-
board: boardInput,
|
|
1256
|
-
boardTarget,
|
|
1257
|
-
card: cardInput,
|
|
1258
|
-
cardTarget,
|
|
1259
|
-
choiceTarget,
|
|
1260
|
-
form: formInput.forState(),
|
|
1261
|
-
prompt: promptInput,
|
|
1262
|
-
rng: rngInput
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
function createPhaseAuthoring(_contract, schema) {
|
|
1266
|
-
return {
|
|
1267
|
-
interaction: (spec) => defineInteraction()(
|
|
1268
|
-
spec
|
|
1269
|
-
),
|
|
1270
|
-
cardAction: (spec) => defineCardAction()(
|
|
1271
|
-
spec
|
|
1272
|
-
),
|
|
1273
|
-
rule: (rule) => defineInteractionRule()(
|
|
1274
|
-
rule
|
|
1275
|
-
),
|
|
1276
|
-
define: (definition) => definePhase()({
|
|
1277
|
-
...definition,
|
|
1278
|
-
state: schema
|
|
1279
|
-
}),
|
|
1280
|
-
stepPhase: (definition) => defineStepPhase()({
|
|
1281
|
-
...definition,
|
|
1282
|
-
state: schema
|
|
1283
|
-
}),
|
|
1284
|
-
inputs: createBoundInputBuilders()
|
|
1285
|
-
};
|
|
1286
|
-
}
|
|
1287
|
-
function createContractAuthoring(contract) {
|
|
1288
|
-
const phaseCache = /* @__PURE__ */ new Map();
|
|
1289
|
-
return {
|
|
1290
|
-
contract,
|
|
1291
|
-
game: (definition) => defineGame({ contract, ...definition }),
|
|
1292
|
-
sharedView: (definition) => defineSharedView()(definition),
|
|
1293
|
-
playerView: (definition) => definePlayerView()(definition),
|
|
1294
|
-
emptyView: () => defineEmptyView(),
|
|
1295
|
-
staticView: (definition) => defineStaticView()(definition),
|
|
1296
|
-
phase: (name) => {
|
|
1297
|
-
const cached = phaseCache.get(name);
|
|
1298
|
-
if (cached) return cached;
|
|
1299
|
-
const schema = contract.phases[name];
|
|
1300
|
-
const bound = createPhaseAuthoring(contract, schema);
|
|
1301
|
-
phaseCache.set(name, bound);
|
|
1302
|
-
return bound;
|
|
1303
|
-
}
|
|
1304
|
-
};
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
55
|
// src/reducer/authoring/effect.ts
|
|
1308
|
-
import { z
|
|
56
|
+
import { z } from "zod";
|
|
1309
57
|
function createContinuationCallable(definition) {
|
|
1310
58
|
const continuation = ((data) => {
|
|
1311
59
|
return {
|
|
@@ -1334,11 +82,11 @@ function defineEffect() {
|
|
|
1334
82
|
contextSchema: definition.context
|
|
1335
83
|
};
|
|
1336
84
|
}
|
|
1337
|
-
const contextSchema = definition.context ??
|
|
85
|
+
const contextSchema = definition.context ?? z.object({});
|
|
1338
86
|
const continuation = createContinuationCallable({
|
|
1339
87
|
id: definition.id,
|
|
1340
88
|
data: contextSchema,
|
|
1341
|
-
response:
|
|
89
|
+
response: z.unknown(),
|
|
1342
90
|
effectKind,
|
|
1343
91
|
reduce: definition.reduce
|
|
1344
92
|
});
|
|
@@ -1379,40 +127,20 @@ export {
|
|
|
1379
127
|
StaleContractArtifactError,
|
|
1380
128
|
asPlayerId,
|
|
1381
129
|
assertCardAllowedInContainer,
|
|
1382
|
-
boardInput,
|
|
1383
130
|
boardRef,
|
|
1384
131
|
boardRefKey,
|
|
1385
132
|
boardRefSchema,
|
|
1386
|
-
|
|
1387
|
-
cardInput,
|
|
1388
|
-
cardTarget,
|
|
1389
|
-
choiceTarget,
|
|
133
|
+
compileManifest,
|
|
1390
134
|
contractFingerprint,
|
|
1391
|
-
createContractAuthoring,
|
|
1392
135
|
createDerivedResolver,
|
|
136
|
+
createGame,
|
|
1393
137
|
createReducerBundle,
|
|
1394
|
-
createReducerEdit,
|
|
1395
138
|
createReducerOps,
|
|
1396
|
-
createReducerTransaction,
|
|
1397
139
|
createStateQueries,
|
|
1398
140
|
createTableQueries,
|
|
1399
|
-
defineCardAction,
|
|
1400
141
|
defineDerived,
|
|
1401
142
|
defineEffect,
|
|
1402
|
-
defineEmptyView,
|
|
1403
|
-
defineGame,
|
|
1404
|
-
defineGameContract,
|
|
1405
143
|
defineInputs,
|
|
1406
|
-
defineInteraction,
|
|
1407
|
-
defineInteractionRule,
|
|
1408
|
-
definePhase,
|
|
1409
|
-
definePhaseStage,
|
|
1410
|
-
definePlayerView,
|
|
1411
|
-
defineSharedView,
|
|
1412
|
-
defineStage,
|
|
1413
|
-
defineStaticView,
|
|
1414
|
-
defineStepPhase,
|
|
1415
|
-
formInput,
|
|
1416
144
|
gameEvent,
|
|
1417
145
|
isPerPlayer,
|
|
1418
146
|
isPerPlayerBoardRef,
|
|
@@ -1436,8 +164,6 @@ export {
|
|
|
1436
164
|
perPlayerSize,
|
|
1437
165
|
perPlayerValues,
|
|
1438
166
|
pipe,
|
|
1439
|
-
promptInput,
|
|
1440
|
-
rngInput,
|
|
1441
167
|
setActivePlayers,
|
|
1442
168
|
sharedBoardRef,
|
|
1443
169
|
sparseCounts,
|