@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.
Files changed (113) hide show
  1. package/README.md +127 -0
  2. package/dist/browser-interaction.d.ts +22 -22
  3. package/dist/{chunk-VRRR6QZT.js → chunk-32PFKDV7.js} +170 -406
  4. package/dist/chunk-32PFKDV7.js.map +1 -0
  5. package/dist/{chunk-N33CGX2F.js → chunk-3BAD4VC2.js} +3 -3
  6. package/dist/{chunk-LMHCGCA6.js → chunk-3SKDNDPG.js} +2 -2
  7. package/dist/chunk-5YV2WHJ4.js +25 -0
  8. package/dist/chunk-5YV2WHJ4.js.map +1 -0
  9. package/dist/{chunk-VWTKGIYF.js → chunk-ANRB4XKA.js} +1 -1
  10. package/dist/chunk-ANRB4XKA.js.map +1 -0
  11. package/dist/{chunk-EOEA3I64.js → chunk-BI4G3PM2.js} +7 -7
  12. package/dist/chunk-BI4G3PM2.js.map +1 -0
  13. package/dist/{chunk-KRJPRYEA.js → chunk-EVCLTY4Q.js} +21 -8
  14. package/dist/chunk-EVCLTY4Q.js.map +1 -0
  15. package/dist/{chunk-DQS2EG5E.js → chunk-GDPKTBUR.js} +2 -2
  16. package/dist/{chunk-FL67RDID.js → chunk-H6VDGFL5.js} +128 -128
  17. package/dist/chunk-H6VDGFL5.js.map +1 -0
  18. package/dist/{chunk-6LMESVGT.js → chunk-LR3ZTWQF.js} +3 -3
  19. package/dist/chunk-LR3ZTWQF.js.map +1 -0
  20. package/dist/{chunk-TXELBVTG.js → chunk-PN5O6GG2.js} +2 -2
  21. package/dist/{chunk-533O7C4L.js → chunk-S2JEDVWH.js} +500 -430
  22. package/dist/chunk-S2JEDVWH.js.map +1 -0
  23. package/dist/{chunk-2GQIALJL.js → chunk-UGH54WZ2.js} +6 -2
  24. package/dist/chunk-UGH54WZ2.js.map +1 -0
  25. package/dist/chunk-VCDWP5VL.js +746 -0
  26. package/dist/chunk-VCDWP5VL.js.map +1 -0
  27. package/dist/{chunk-ZSTCUJKZ.js → chunk-Y75CFE77.js} +2 -6
  28. package/dist/chunk-Y75CFE77.js.map +1 -0
  29. package/dist/chunk-Z7QCREWI.js +3435 -0
  30. package/dist/chunk-Z7QCREWI.js.map +1 -0
  31. package/dist/chunk-ZZGN2ATS.js +1941 -0
  32. package/dist/chunk-ZZGN2ATS.js.map +1 -0
  33. package/dist/{components-CNAt5J1p.d.ts → components-gAbIz7hK.d.ts} +2 -18
  34. package/dist/{definitions-bZSBaPjj.d.ts → definitions-BgmV_GhC.d.ts} +3 -3
  35. package/dist/digest.d.ts +2 -2
  36. package/dist/game-CsZScpcn.d.ts +763 -0
  37. package/dist/{index-CR69MyWr.d.ts → index-CcT9Q7N7.d.ts} +1 -1
  38. package/dist/{index.d-Bw8AOcgp.d.ts → index.d-DjzoK7zn.d.ts} +67 -2
  39. package/dist/index.js +1 -2
  40. package/dist/package-set.js +1 -2
  41. package/dist/plugin-runtime-contract.d.ts +4 -4
  42. package/dist/plugin-runtime-contract.js +13 -15
  43. package/dist/{protocol-CVaSqPgX.d.ts → protocol-dYgafTYY.d.ts} +1 -7
  44. package/dist/reducer/advanced.d.ts +12 -11
  45. package/dist/reducer/advanced.js +10 -4
  46. package/dist/reducer-contract.d.ts +10 -2
  47. package/dist/reducer-contract.js +4 -4
  48. package/dist/reducer.d.ts +12 -689
  49. package/dist/reducer.js +19 -1293
  50. package/dist/reducer.js.map +1 -1
  51. package/dist/runtime/primitives.d.ts +4 -4
  52. package/dist/runtime/primitives.js +5 -5
  53. package/dist/runtime/runtime-api.d.ts +2 -2
  54. package/dist/runtime/workspace-contract.d.ts +50 -17
  55. package/dist/runtime/workspace-contract.js +15 -10
  56. package/dist/{runtime-C7Z2acNU.d.ts → runtime-RJ5orDJU.d.ts} +23 -30
  57. package/dist/{plugin-state-BRH3UiUp.d.ts → runtime-api-Bz5pwNU_.d.ts} +86 -4
  58. package/dist/runtime.d.ts +8 -8
  59. package/dist/runtime.js +19 -17
  60. package/dist/runtime.js.map +1 -1
  61. package/dist/schema.d.ts +2 -28
  62. package/dist/testing-compiler.d.ts +4 -4
  63. package/dist/testing-runtime.d.ts +7 -7
  64. package/dist/testing-runtime.js +6 -6
  65. package/dist/testing.d.ts +17 -17
  66. package/dist/testing.js +14 -14
  67. package/dist/{types-q1Guidm5.d.ts → types-DR7DoB1x.d.ts} +1 -1
  68. package/dist/{types-DN4O7kH_.d.ts → types-JWCYHmu7.d.ts} +2 -2
  69. package/dist/types.js +6 -18
  70. package/dist/types.js.map +1 -1
  71. package/dist/ui/components.d.ts +3 -4
  72. package/dist/ui/components.js +1 -5
  73. package/dist/{ui-contract-BC4JpysE.d.ts → ui-contract-GTUPkf8z.d.ts} +175 -176
  74. package/dist/ui.d.ts +4 -5
  75. package/dist/ui.js +2 -6
  76. package/dist/{views-D2Cfzr3h.d.ts → views-BpuWcOyN.d.ts} +101 -48
  77. package/package.json +3 -22
  78. package/dist/authoring/index.d.ts +0 -59
  79. package/dist/authoring/index.js +0 -24
  80. package/dist/authoring/index.js.map +0 -1
  81. package/dist/authoring-compiler.d.ts +0 -27
  82. package/dist/authoring-compiler.js +0 -11
  83. package/dist/authoring-compiler.js.map +0 -1
  84. package/dist/authoring-materialize-cli.d.ts +0 -1
  85. package/dist/authoring-materialize-cli.js +0 -45
  86. package/dist/authoring-materialize-cli.js.map +0 -1
  87. package/dist/chunk-2GQIALJL.js.map +0 -1
  88. package/dist/chunk-533O7C4L.js.map +0 -1
  89. package/dist/chunk-6LMESVGT.js.map +0 -1
  90. package/dist/chunk-EOEA3I64.js.map +0 -1
  91. package/dist/chunk-FL67RDID.js.map +0 -1
  92. package/dist/chunk-HIH6Y4FA.js +0 -7802
  93. package/dist/chunk-HIH6Y4FA.js.map +0 -1
  94. package/dist/chunk-HUK4234C.js +0 -166
  95. package/dist/chunk-HUK4234C.js.map +0 -1
  96. package/dist/chunk-KGV2EUNN.js +0 -532
  97. package/dist/chunk-KGV2EUNN.js.map +0 -1
  98. package/dist/chunk-KRJPRYEA.js.map +0 -1
  99. package/dist/chunk-KWHOFBDM.js +0 -9
  100. package/dist/chunk-KWHOFBDM.js.map +0 -1
  101. package/dist/chunk-VRRR6QZT.js.map +0 -1
  102. package/dist/chunk-VWTKGIYF.js.map +0 -1
  103. package/dist/chunk-XFMSLL3P.js +0 -637
  104. package/dist/chunk-XFMSLL3P.js.map +0 -1
  105. package/dist/chunk-ZSTCUJKZ.js.map +0 -1
  106. package/dist/codegen.d.ts +0 -941
  107. package/dist/codegen.js +0 -44
  108. package/dist/codegen.js.map +0 -1
  109. package/dist/runtime-api-CgPuEVeF.d.ts +0 -86
  110. /package/dist/{chunk-N33CGX2F.js.map → chunk-3BAD4VC2.js.map} +0 -0
  111. /package/dist/{chunk-LMHCGCA6.js.map → chunk-3SKDNDPG.js.map} +0 -0
  112. /package/dist/{chunk-DQS2EG5E.js.map → chunk-GDPKTBUR.js.map} +0 -0
  113. /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-533O7C4L.js";
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-FL67RDID.js";
48
+ } from "./chunk-H6VDGFL5.js";
49
+ import "./chunk-5YV2WHJ4.js";
49
50
  import "./chunk-PF7L4BMG.js";
50
- import "./chunk-2GQIALJL.js";
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 as z7 } from "zod";
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 ?? z7.object({});
85
+ const contextSchema = definition.context ?? z.object({});
1338
86
  const continuation = createContinuationCallable({
1339
87
  id: definition.id,
1340
88
  data: contextSchema,
1341
- response: z7.unknown(),
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
- boardTarget,
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,