@dreamboard-games/sdk 0.5.0-alpha.2 → 0.5.0-alpha.3

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 (150) hide show
  1. package/README.md +136 -45
  2. package/dist/chunk-DMFVAZI2.js +16 -0
  3. package/dist/chunk-DMFVAZI2.js.map +1 -0
  4. package/dist/chunk-FMM5LVJW.js +833 -0
  5. package/dist/chunk-FMM5LVJW.js.map +1 -0
  6. package/dist/{chunk-S2JEDVWH.js → chunk-LRILEVKC.js} +6113 -6489
  7. package/dist/chunk-LRILEVKC.js.map +1 -0
  8. package/dist/chunk-SP234IY4.js +1363 -0
  9. package/dist/chunk-SP234IY4.js.map +1 -0
  10. package/dist/chunk-VUWNJXLJ.js +52 -0
  11. package/dist/chunk-VUWNJXLJ.js.map +1 -0
  12. package/dist/chunk-ZPRKWPEP.js +511 -0
  13. package/dist/chunk-ZPRKWPEP.js.map +1 -0
  14. package/dist/definition-BaHNPZol.d.ts +4639 -0
  15. package/dist/diagnostics-B0lgnuZ6.d.ts +65 -0
  16. package/dist/index.d.ts +3553 -1
  17. package/dist/index.js +1045 -6
  18. package/dist/index.js.map +1 -1
  19. package/dist/model-BHro6yXu.d.ts +288 -0
  20. package/dist/react.d.ts +32 -0
  21. package/dist/react.js +80 -0
  22. package/dist/react.js.map +1 -0
  23. package/dist/reducer.d.ts +1194 -79
  24. package/dist/reducer.js +4326 -121
  25. package/dist/reducer.js.map +1 -1
  26. package/dist/testing.d.ts +518 -564
  27. package/dist/testing.js +2448 -915
  28. package/dist/testing.js.map +1 -1
  29. package/dist/types-DimqnJBq.d.ts +86 -0
  30. package/package.json +26 -131
  31. package/dist/HandView-Bi2lxzQP.d.ts +0 -79
  32. package/dist/ResourceCounter-BFxJknqp.d.ts +0 -98
  33. package/dist/ThemeProvider-CElaL2ik.d.ts +0 -99
  34. package/dist/attributes-DbvyMbXw.d.ts +0 -68
  35. package/dist/browser-interaction.d.ts +0 -910
  36. package/dist/browser-interaction.js +0 -119
  37. package/dist/browser-interaction.js.map +0 -1
  38. package/dist/chunk-32PFKDV7.js +0 -11705
  39. package/dist/chunk-32PFKDV7.js.map +0 -1
  40. package/dist/chunk-3BAD4VC2.js +0 -263
  41. package/dist/chunk-3BAD4VC2.js.map +0 -1
  42. package/dist/chunk-3SKDNDPG.js +0 -104
  43. package/dist/chunk-3SKDNDPG.js.map +0 -1
  44. package/dist/chunk-5YV2WHJ4.js +0 -25
  45. package/dist/chunk-5YV2WHJ4.js.map +0 -1
  46. package/dist/chunk-ANRB4XKA.js +0 -90
  47. package/dist/chunk-ANRB4XKA.js.map +0 -1
  48. package/dist/chunk-BI4G3PM2.js +0 -1864
  49. package/dist/chunk-BI4G3PM2.js.map +0 -1
  50. package/dist/chunk-EVCLTY4Q.js +0 -935
  51. package/dist/chunk-EVCLTY4Q.js.map +0 -1
  52. package/dist/chunk-GDPKTBUR.js +0 -564
  53. package/dist/chunk-GDPKTBUR.js.map +0 -1
  54. package/dist/chunk-H6VDGFL5.js +0 -2903
  55. package/dist/chunk-H6VDGFL5.js.map +0 -1
  56. package/dist/chunk-LR3ZTWQF.js +0 -5960
  57. package/dist/chunk-LR3ZTWQF.js.map +0 -1
  58. package/dist/chunk-PF7L4BMG.js +0 -117
  59. package/dist/chunk-PF7L4BMG.js.map +0 -1
  60. package/dist/chunk-PN5O6GG2.js +0 -32
  61. package/dist/chunk-PN5O6GG2.js.map +0 -1
  62. package/dist/chunk-PZ5AY32C.js +0 -10
  63. package/dist/chunk-PZ5AY32C.js.map +0 -1
  64. package/dist/chunk-S2JEDVWH.js.map +0 -1
  65. package/dist/chunk-T3ZKNUZ7.js +0 -1
  66. package/dist/chunk-T3ZKNUZ7.js.map +0 -1
  67. package/dist/chunk-UGH54WZ2.js +0 -223
  68. package/dist/chunk-UGH54WZ2.js.map +0 -1
  69. package/dist/chunk-VCDWP5VL.js +0 -746
  70. package/dist/chunk-VCDWP5VL.js.map +0 -1
  71. package/dist/chunk-VDXOF4FW.js +0 -69
  72. package/dist/chunk-VDXOF4FW.js.map +0 -1
  73. package/dist/chunk-WHR5UW3F.js +0 -1988
  74. package/dist/chunk-WHR5UW3F.js.map +0 -1
  75. package/dist/chunk-Y75CFE77.js +0 -17
  76. package/dist/chunk-Y75CFE77.js.map +0 -1
  77. package/dist/chunk-Z7QCREWI.js +0 -3435
  78. package/dist/chunk-Z7QCREWI.js.map +0 -1
  79. package/dist/chunk-ZZGN2ATS.js +0 -1941
  80. package/dist/chunk-ZZGN2ATS.js.map +0 -1
  81. package/dist/components-gAbIz7hK.d.ts +0 -1284
  82. package/dist/definitions-BgmV_GhC.d.ts +0 -300
  83. package/dist/diagnostics-DIi3ina7.d.ts +0 -50
  84. package/dist/digest.d.ts +0 -8
  85. package/dist/game-CsZScpcn.d.ts +0 -763
  86. package/dist/hex-board-view-aKkblDp6.d.ts +0 -1228
  87. package/dist/index-CcT9Q7N7.d.ts +0 -193
  88. package/dist/index.d-DjzoK7zn.d.ts +0 -2101
  89. package/dist/package-set.d.ts +0 -13
  90. package/dist/package-set.js +0 -12
  91. package/dist/package-set.js.map +0 -1
  92. package/dist/player-state-Cqpyeql0.d.ts +0 -371
  93. package/dist/plugin-runtime-contract.d.ts +0 -17
  94. package/dist/plugin-runtime-contract.js +0 -92
  95. package/dist/plugin-runtime-contract.js.map +0 -1
  96. package/dist/primitive-props-BNHDkgd7.d.ts +0 -16
  97. package/dist/protocol-dYgafTYY.d.ts +0 -314
  98. package/dist/reducer/advanced.d.ts +0 -82
  99. package/dist/reducer/advanced.js +0 -51
  100. package/dist/reducer/advanced.js.map +0 -1
  101. package/dist/reducer-contract.d.ts +0 -11
  102. package/dist/reducer-contract.js +0 -16
  103. package/dist/reducer-contract.js.map +0 -1
  104. package/dist/reference-games/index.d.ts +0 -31
  105. package/dist/reference-games/index.js +0 -48
  106. package/dist/reference-games/index.js.map +0 -1
  107. package/dist/runtime/primitives.d.ts +0 -250
  108. package/dist/runtime/primitives.js +0 -189
  109. package/dist/runtime/primitives.js.map +0 -1
  110. package/dist/runtime/runtime-api.d.ts +0 -2
  111. package/dist/runtime/runtime-api.js +0 -1
  112. package/dist/runtime/runtime-api.js.map +0 -1
  113. package/dist/runtime/workspace-contract.d.ts +0 -392
  114. package/dist/runtime/workspace-contract.js +0 -28
  115. package/dist/runtime/workspace-contract.js.map +0 -1
  116. package/dist/runtime-RJ5orDJU.d.ts +0 -1699
  117. package/dist/runtime-api-Bz5pwNU_.d.ts +0 -296
  118. package/dist/runtime-json-CQ9QbLZ5.d.ts +0 -5
  119. package/dist/runtime.d.ts +0 -83
  120. package/dist/runtime.js +0 -242
  121. package/dist/runtime.js.map +0 -1
  122. package/dist/schema.d.ts +0 -379
  123. package/dist/stale-contract-artifact-error-XLaweZtF.d.ts +0 -18
  124. package/dist/testing-compiler.d.ts +0 -37
  125. package/dist/testing-compiler.js +0 -272
  126. package/dist/testing-compiler.js.map +0 -1
  127. package/dist/testing-runtime.d.ts +0 -119
  128. package/dist/testing-runtime.js +0 -212
  129. package/dist/testing-runtime.js.map +0 -1
  130. package/dist/types-DJj5MJkl.d.ts +0 -256
  131. package/dist/types-DR7DoB1x.d.ts +0 -28
  132. package/dist/types-JWCYHmu7.d.ts +0 -122
  133. package/dist/types.d.ts +0 -1958
  134. package/dist/types.js +0 -14
  135. package/dist/types.js.map +0 -1
  136. package/dist/ui/components.d.ts +0 -17
  137. package/dist/ui/components.js +0 -216
  138. package/dist/ui/components.js.map +0 -1
  139. package/dist/ui/defaults.d.ts +0 -19
  140. package/dist/ui/defaults.js +0 -104
  141. package/dist/ui/defaults.js.map +0 -1
  142. package/dist/ui/player-state.d.ts +0 -2
  143. package/dist/ui/player-state.js +0 -1
  144. package/dist/ui/player-state.js.map +0 -1
  145. package/dist/ui/plugin-styles.css +0 -2
  146. package/dist/ui-contract-GTUPkf8z.d.ts +0 -1168
  147. package/dist/ui.d.ts +0 -317
  148. package/dist/ui.js +0 -277
  149. package/dist/ui.js.map +0 -1
  150. package/dist/views-BpuWcOyN.d.ts +0 -1641
@@ -1,1941 +0,0 @@
1
- import {
2
- asPlayerId,
3
- assumeManifestSchema,
4
- cardInput,
5
- cardTarget,
6
- createManifestGameStateSchema,
7
- createManifestRuntimeSchema,
8
- createManifestStringLiteralSchema,
9
- createTargetRule,
10
- createTargetRuleBuilder,
11
- isManifestScopedSchema,
12
- isPerPlayer,
13
- markManifestScopedSchema,
14
- perPlayer,
15
- perPlayerSchema
16
- } from "./chunk-H6VDGFL5.js";
17
- import {
18
- buildTypedRecord
19
- } from "./chunk-5YV2WHJ4.js";
20
- import {
21
- analyzeManifest,
22
- materializeManifestTable
23
- } from "./chunk-Z7QCREWI.js";
24
-
25
- // src/reducer/schema-helpers.ts
26
- import { z } from "zod";
27
- var sparseSchemas = /* @__PURE__ */ new WeakMap();
28
- function sparseMap(keySchema, valueSchema) {
29
- const schema = z.partialRecord(keySchema, valueSchema);
30
- sparseSchemas.set(schema, {
31
- keySchema,
32
- valueSchema
33
- });
34
- return schema;
35
- }
36
- function sparseCounts(keySchema) {
37
- return sparseMap(keySchema, z.number().int().min(0));
38
- }
39
- function getZodDef(schema) {
40
- const anySchema = schema;
41
- const fromInternal = anySchema?._zod?.def;
42
- if (fromInternal && typeof fromInternal === "object") {
43
- return fromInternal;
44
- }
45
- const fromLegacy = anySchema?.def;
46
- if (fromLegacy && typeof fromLegacy === "object") {
47
- return fromLegacy;
48
- }
49
- return {};
50
- }
51
- function unwrapWrappers(schema) {
52
- let current = schema;
53
- while (true) {
54
- const def = getZodDef(current);
55
- const innerType = def.innerType;
56
- if ((def.type === "nullable" || def.type === "optional" || def.type === "default" || def.type === "readonly" || def.type === "catch") && innerType) {
57
- current = innerType;
58
- continue;
59
- }
60
- return current;
61
- }
62
- }
63
- function isPlainZodString(schema) {
64
- return getZodDef(schema).type === "string";
65
- }
66
- function isZodArray(schema) {
67
- return getZodDef(schema).type === "array";
68
- }
69
- function isEnumKeyedRecordSchema(schema) {
70
- const def = getZodDef(schema);
71
- const keyType = def.keyType;
72
- return def.type === "record" && typeof keyType === "object" && keyType !== null && getZodDef(keyType).type === "enum";
73
- }
74
- function isSparseMapSchema(schema) {
75
- const inner = unwrapWrappers(schema);
76
- return typeof inner === "object" && inner !== null && sparseSchemas.has(inner);
77
- }
78
- function getSparseSchemaMetadata(schema) {
79
- const inner = unwrapWrappers(schema);
80
- if (typeof inner !== "object" || inner === null) {
81
- return void 0;
82
- }
83
- return sparseSchemas.get(inner);
84
- }
85
- function isPlainObject(value) {
86
- return typeof value === "object" && value !== null && !Array.isArray(value);
87
- }
88
- function getObjectShape(schema) {
89
- const def = getZodDef(schema);
90
- if (def.type !== "object") {
91
- return null;
92
- }
93
- const shape = def.shape;
94
- if (typeof shape === "function") {
95
- const resolved = shape();
96
- return resolved && typeof resolved === "object" ? resolved : null;
97
- }
98
- return shape && typeof shape === "object" ? shape : null;
99
- }
100
- function normalizeSchemaInput(schema, input) {
101
- const inner = unwrapWrappers(schema);
102
- const sparse = getSparseSchemaMetadata(inner);
103
- if (sparse && isPlainObject(input)) {
104
- const filtered = Object.fromEntries(
105
- Object.entries(input).filter(
106
- ([key, value]) => typeof value !== "undefined" && sparse.keySchema.safeParse(key).success
107
- ).map(([key, value]) => [
108
- key,
109
- normalizeSchemaInput(sparse.valueSchema, value)
110
- ])
111
- );
112
- return filtered;
113
- }
114
- const shape = getObjectShape(inner);
115
- if (shape && isPlainObject(input)) {
116
- return Object.fromEntries(
117
- Object.entries(input).map(([key, value]) => {
118
- const fieldSchema = shape[key];
119
- return [
120
- key,
121
- typeof fieldSchema === "undefined" ? value : normalizeSchemaInput(fieldSchema, value)
122
- ];
123
- })
124
- );
125
- }
126
- const def = getZodDef(inner);
127
- if (def.type === "array" && Array.isArray(input) && def.element) {
128
- return input.map((value) => normalizeSchemaInput(def.element, value));
129
- }
130
- return input;
131
- }
132
- function normalizeCommandParams(schema, input) {
133
- return schema.parse(normalizeSchemaInput(schema, input));
134
- }
135
-
136
- // src/reducer/inputs/defineInputs.ts
137
- var InputBuilder = class {
138
- add(key, collector) {
139
- return { key, collector };
140
- }
141
- };
142
- function defineInputs(define) {
143
- const refs = define(new InputBuilder());
144
- return Object.fromEntries(
145
- Object.entries(refs).map(([key, ref]) => [key, ref.collector])
146
- );
147
- }
148
-
149
- // src/reducer/inputs/many.ts
150
- import { z as z2 } from "zod";
151
- function normalizeManyOptions(options) {
152
- if ("count" in options) {
153
- assertNonNegativeInteger(options.count, "many(...).count");
154
- return {
155
- mode: "many",
156
- min: options.count,
157
- max: options.count,
158
- distinct: options.distinct
159
- };
160
- }
161
- const min = options.min ?? 0;
162
- assertNonNegativeInteger(min, "many(...).min");
163
- if (options.max !== void 0) {
164
- assertNonNegativeInteger(options.max, "many(...).max");
165
- if (options.max < min) {
166
- throw new Error("many(...).max must be greater than or equal to min.");
167
- }
168
- }
169
- return {
170
- mode: "many",
171
- min,
172
- max: options.max,
173
- distinct: options.distinct
174
- };
175
- }
176
- function assertNonNegativeInteger(value, label) {
177
- if (!Number.isInteger(value) || value < 0) {
178
- throw new Error(`${label} must be a non-negative integer.`);
179
- }
180
- }
181
- function many(collector, options) {
182
- if (collector.kind === "rng") {
183
- throw new Error("many(...) cannot wrap rngInput collectors.");
184
- }
185
- const selection = normalizeManyOptions(options);
186
- const rest = { ...collector };
187
- delete rest.schema;
188
- delete rest.selection;
189
- delete rest.defaultValue;
190
- return {
191
- ...rest,
192
- schema: z2.array(
193
- collector.schema
194
- ),
195
- selection
196
- };
197
- }
198
-
199
- // src/reducer/inputs/formInput.ts
200
- import { z as z3 } from "zod";
201
- function isResourceMapChoiceSource(choices) {
202
- return choices === "resourceMap" || typeof choices === "object" && choices !== null && !Array.isArray(choices) && "source" in choices && choices.source === "resourceMap";
203
- }
204
- function resolveDomainNumber(value, context, fallback) {
205
- if (typeof value === "function") return value(context);
206
- return value ?? fallback;
207
- }
208
- function resolveDomainChoices(choices, context) {
209
- if (isResourceMapChoiceSource(choices)) {
210
- return resolveResourceMapChoices(choices, context);
211
- }
212
- const resolved = typeof choices === "function" ? choices(context) : choices;
213
- return resolved.map((choice) => ({
214
- value: choice.value,
215
- label: choice.label,
216
- icon: choice.icon,
217
- badge: choice.badge,
218
- description: choice.description,
219
- disabled: choice.disabled,
220
- disabledReason: choice.disabledReason
221
- }));
222
- }
223
- function resolveDependentDomainChoices(choices, context) {
224
- const resolved = typeof choices === "function" ? choices(context) : choices;
225
- return resolved.map((choice) => ({
226
- value: choice.value,
227
- label: choice.label,
228
- icon: choice.icon,
229
- badge: choice.badge,
230
- description: choice.description,
231
- disabled: choice.disabled,
232
- disabledReason: choice.disabledReason
233
- }));
234
- }
235
- function choiceValuesInclude(choices, value) {
236
- return choices.some((choice) => Object.is(choice.value, value));
237
- }
238
- function assertChoiceDefaultInChoices(inputName, choices, defaultValue) {
239
- if (choiceValuesInclude(choices, defaultValue)) return;
240
- const printable = defaultValue === null ? "null" : `'${defaultValue}'`;
241
- throw new Error(
242
- `${inputName} defaultValue ${printable} must be one of its choices. If null is a valid value, add an explicit { value: null, label: ... } choice.`
243
- );
244
- }
245
- function choiceSchema(choices) {
246
- const values = choices.map((choice) => choice.value);
247
- const stringValues = values.filter(
248
- (value) => value !== null
249
- );
250
- const hasNull = values.some((value) => value === null);
251
- if (stringValues.length === 0) {
252
- return z3.null();
253
- }
254
- const stringSchema = z3.enum(
255
- stringValues
256
- );
257
- if (hasNull) {
258
- return z3.union([stringSchema, z3.null()]);
259
- }
260
- return stringSchema;
261
- }
262
- function resolveResourceMapChoices(choices, context) {
263
- const resources = context.state.table.resources;
264
- const firstResourceMap = isPerPlayer(resources) && resources.entries.length > 0 ? resources.entries[0]?.[1] : resources;
265
- if (typeof firstResourceMap !== "object" || firstResourceMap === null || Array.isArray(firstResourceMap)) {
266
- return [];
267
- }
268
- const decorate = choices === "resourceMap" ? void 0 : choices.decorate;
269
- return Object.keys(firstResourceMap).sort().map((resourceId) => {
270
- const label = resourceId;
271
- const presentation = decorate?.({ ...context, resourceId, label });
272
- return {
273
- value: resourceId,
274
- label,
275
- badge: presentation?.badge,
276
- description: presentation?.description,
277
- disabled: presentation?.disabled,
278
- disabledReason: presentation?.disabledReason
279
- };
280
- });
281
- }
282
- function createFormInput(schema, options) {
283
- return {
284
- kind: "form",
285
- schema,
286
- ...options && "defaultValue" in options ? { defaultValue: options.defaultValue } : {}
287
- };
288
- }
289
- function baseFormInput(schema, options) {
290
- return createFormInput(schema, options);
291
- }
292
- function resourceMapInput(options) {
293
- return {
294
- kind: "form",
295
- schema: z3.record(z3.string(), z3.number().int().nonnegative()),
296
- ..."defaultValue" in options ? { defaultValue: options.defaultValue } : {},
297
- domain: (state, playerId, q, derived) => {
298
- const context = {
299
- state,
300
- playerId,
301
- q,
302
- derived,
303
- values: {}
304
- };
305
- return {
306
- type: "resourceMap",
307
- resources: options.resources.map((resource) => ({
308
- resourceId: resource.resourceId,
309
- label: resource.label,
310
- icon: resource.icon,
311
- min: resolveDomainNumber(resource.min, context, 0),
312
- max: resolveDomainNumber(resource.max, context, 0)
313
- }))
314
- };
315
- }
316
- };
317
- }
318
- function numberInput(options) {
319
- return {
320
- kind: "form",
321
- schema: z3.number(),
322
- ..."defaultValue" in options ? { defaultValue: options.defaultValue } : {},
323
- domain: (state, playerId, q, derived) => {
324
- const context = {
325
- state,
326
- playerId,
327
- q,
328
- derived,
329
- values: {}
330
- };
331
- return {
332
- type: "boundedNumber",
333
- min: resolveDomainNumber(options.min, context, 0),
334
- max: resolveDomainNumber(options.max, context, 0),
335
- step: options.step === void 0 ? void 0 : resolveDomainNumber(options.step, context, 1)
336
- };
337
- }
338
- };
339
- }
340
- function choiceInput(options) {
341
- const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
342
- if (Array.isArray(options.choices) && options.choices.length === 0) {
343
- throw new Error("formInput.choice requires at least one choice.");
344
- }
345
- const staticChoices = Array.isArray(options.choices) ? options.choices : null;
346
- const hasStaticDefault = typeof options.defaultValue !== "function";
347
- const staticDefault = options.defaultValue;
348
- if (staticChoices && hasStaticDefault) {
349
- assertChoiceDefaultInChoices(
350
- "formInput.choice",
351
- staticChoices,
352
- staticDefault
353
- );
354
- }
355
- const schema = staticChoices ? choiceSchema(staticChoices) : z3.string().nullable();
356
- const dynamicDefault = typeof options.defaultValue === "function" ? options.defaultValue : void 0;
357
- return {
358
- kind: "form",
359
- schema,
360
- ...hasStaticDefault ? { defaultValue: staticDefault } : {},
361
- ...dependsOn ? { dependsOn } : {},
362
- domain: (state, playerId, q, derived, values) => {
363
- const context = {
364
- state,
365
- playerId,
366
- q,
367
- derived
368
- };
369
- const choices = dependsOn ? resolveDependentDomainChoices(
370
- options.choices,
371
- {
372
- ...context,
373
- values: values ?? {}
374
- }
375
- ) : resolveDomainChoices(options.choices, {
376
- ...context,
377
- values: {}
378
- });
379
- if (hasStaticDefault) {
380
- assertChoiceDefaultInChoices(
381
- "formInput.choice",
382
- choices,
383
- staticDefault
384
- );
385
- }
386
- return {
387
- type: "choice",
388
- choices
389
- };
390
- },
391
- ...dynamicDefault ? {
392
- resolveDefaultValue: (state, playerId, q, derived, domain) => {
393
- const choices = domain.type === "choice" ? domain.choices.map((choice) => ({
394
- value: choice.value,
395
- label: choice.label,
396
- icon: choice.icon,
397
- badge: choice.badge,
398
- description: choice.description,
399
- disabled: choice.disabled,
400
- disabledReason: choice.disabledReason
401
- })) : [];
402
- const resolved = dynamicDefault({
403
- state,
404
- playerId,
405
- q,
406
- derived,
407
- values: {},
408
- choices
409
- });
410
- if (resolved === void 0) return void 0;
411
- assertChoiceDefaultInChoices("formInput.choice", choices, resolved);
412
- return resolved;
413
- }
414
- } : {}
415
- };
416
- }
417
- function choiceListInput(options) {
418
- if (Array.isArray(options.choices) && options.choices.length === 0) {
419
- throw new Error("formInput.choiceList requires at least one choice.");
420
- }
421
- const staticDefaultValue = Array.isArray(options.defaultValue) ? options.defaultValue : void 0;
422
- const dynamicDefaultValue = options.defaultValue === "all" || typeof options.defaultValue === "function" ? options.defaultValue : void 0;
423
- return {
424
- kind: "form",
425
- schema: z3.array(z3.string()),
426
- ...staticDefaultValue !== void 0 ? { defaultValue: staticDefaultValue } : {},
427
- domain: (state, playerId, q, derived) => {
428
- const context = {
429
- state,
430
- playerId,
431
- q,
432
- derived,
433
- values: {}
434
- };
435
- const choices = resolveDomainChoices(options.choices, context).map(
436
- (choice) => ({
437
- ...choice,
438
- value: choice.value
439
- })
440
- );
441
- return {
442
- type: "choiceList",
443
- choices,
444
- min: resolveDomainNumber(options.min, context, 0),
445
- max: resolveDomainNumber(options.max, context, choices.length)
446
- };
447
- },
448
- ...dynamicDefaultValue ? {
449
- resolveDefaultValue: (state, playerId, q, derived, domain) => {
450
- const choices = domain.type === "choiceList" ? domain.choices.map((choice) => ({
451
- value: choice.value,
452
- label: choice.label,
453
- icon: choice.icon,
454
- badge: choice.badge,
455
- description: choice.description,
456
- disabled: choice.disabled,
457
- disabledReason: choice.disabledReason
458
- })) : [];
459
- if (dynamicDefaultValue === "all") {
460
- return choices.map((choice) => choice.value);
461
- }
462
- return dynamicDefaultValue({
463
- state,
464
- playerId,
465
- q,
466
- derived,
467
- values: {},
468
- choices
469
- });
470
- }
471
- } : {}
472
- };
473
- }
474
- function formInputForState() {
475
- return Object.assign(
476
- ((schema, options) => baseFormInput(schema, options)),
477
- {
478
- resourceMap: (options) => resourceMapInput(options),
479
- resourceChoices: (options) => formInput.resourceChoices(options),
480
- number: (options) => numberInput(options),
481
- choice: (options) => choiceInput(options),
482
- choiceList: (options) => choiceListInput(options)
483
- }
484
- );
485
- }
486
- var formInput = Object.assign(baseFormInput, {
487
- resourceMap: resourceMapInput,
488
- resourceChoices: (options) => ({
489
- source: "resourceMap",
490
- ...options
491
- }),
492
- number: numberInput,
493
- choice: choiceInput,
494
- choiceList: choiceListInput,
495
- forState: formInputForState
496
- });
497
-
498
- // src/reducer/inputs/boardInput.ts
499
- import { z as z4 } from "zod";
500
- function makeBoardCollector(kind) {
501
- return function collector(options) {
502
- const target = options.target;
503
- const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
504
- return {
505
- kind,
506
- schema: z4.string(),
507
- eligibleTargets: ((state, playerId, q, values) => target.eligible({
508
- state,
509
- playerId,
510
- q,
511
- values
512
- })),
513
- validateTarget: ((state, playerId, q, targetId, values) => target.validate(
514
- {
515
- state,
516
- playerId,
517
- q,
518
- values
519
- },
520
- targetId
521
- )),
522
- ...dependsOn ? { dependsOn } : {},
523
- domain: (state, playerId, q, _derived, values) => ({
524
- type: "boardTarget",
525
- projection: "resolved",
526
- targetKind: target.targetKind,
527
- boardId: target.boardId,
528
- valueKind: target.valueKind,
529
- eligibleTargets: target.eligible({
530
- state,
531
- playerId,
532
- q,
533
- values
534
- }).map(String)
535
- }),
536
- meta: {
537
- targetKind: target.targetKind,
538
- boardId: target.boardId,
539
- valueKind: target.valueKind
540
- }
541
- };
542
- };
543
- }
544
- var vertexInput = makeBoardCollector("board-vertex");
545
- var edgeInput = makeBoardCollector("board-edge");
546
- var tileInput = makeBoardCollector("board-tile");
547
- var spaceInput = makeBoardCollector("board-space");
548
- function playerSpaceInput(options) {
549
- const target = options.target;
550
- const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
551
- const playerIdSchema = markManifestScopedSchema(
552
- z4.string(),
553
- "playerId"
554
- );
555
- return {
556
- kind: "board-space",
557
- schema: z4.object({
558
- boardId: z4.literal(target.boardId),
559
- playerId: playerIdSchema,
560
- spaceId: z4.string()
561
- }),
562
- eligibleTargets: ((state, playerId, q, values) => target.eligible({
563
- state,
564
- playerId,
565
- q,
566
- values
567
- })),
568
- validateTarget: ((state, playerId, q, targetValue, values) => target.validate(
569
- {
570
- state,
571
- playerId,
572
- q,
573
- values
574
- },
575
- targetValue
576
- )),
577
- ...dependsOn ? { dependsOn } : {},
578
- domain: (state, playerId, q, _derived, values) => ({
579
- type: "boardTarget",
580
- projection: "resolved",
581
- targetKind: target.targetKind,
582
- boardId: target.boardId,
583
- valueKind: target.valueKind,
584
- eligibleTargets: target.eligible({
585
- state,
586
- playerId,
587
- q,
588
- values
589
- }).map((candidate) => candidate.spaceId)
590
- }),
591
- meta: {
592
- targetKind: target.targetKind,
593
- boardId: target.boardId,
594
- valueKind: target.valueKind
595
- }
596
- };
597
- }
598
- var boardInput = {
599
- vertex: vertexInput,
600
- edge: edgeInput,
601
- tile: tileInput,
602
- space: spaceInput,
603
- playerSpace: playerSpaceInput
604
- };
605
-
606
- // src/reducer/inputs/boardTarget.ts
607
- function candidateIdsForKind(q, boardId, targetKind) {
608
- if (targetKind === "edge") {
609
- return idsFromCollection(q.board.tiled(boardId).edges);
610
- }
611
- if (targetKind === "vertex") {
612
- return idsFromCollection(q.board.tiled(boardId).vertices);
613
- }
614
- return idsFromCollection(q.board.get(boardId)?.spaces);
615
- }
616
- function idsFromCollection(collection) {
617
- if (!collection) return [];
618
- const values = Array.isArray(collection) ? collection : Object.values(collection);
619
- return values.flatMap((value) => {
620
- if (typeof value === "string") return [value];
621
- if (typeof value === "object" && value !== null && "id" in value && typeof value.id === "string") {
622
- return [value.id];
623
- }
624
- return [];
625
- });
626
- }
627
- function createBoardTargetBuilder(targetKind, boardId) {
628
- return createTargetRuleBuilder(
629
- (predicates) => ({
630
- ...createTargetRule(
631
- ({ q }) => candidateIdsForKind(q, boardId, targetKind),
632
- predicates,
633
- {
634
- missingCandidateIssue: {
635
- errorCode: "BOARD_TARGET_NOT_ELIGIBLE",
636
- message: "Board target is not eligible."
637
- }
638
- }
639
- ),
640
- boardId,
641
- targetKind,
642
- valueKind: "board-id"
643
- })
644
- );
645
- }
646
- function createPlayerSpaceTargetBuilder(boardId) {
647
- return createTargetRuleBuilder(
648
- (predicates) => ({
649
- ...createTargetRule(
650
- ({ state, q }) => {
651
- const spacesForPlayer = (playerId) => candidateIdsForKind(
652
- q,
653
- `${boardId}:${playerId}`,
654
- "space"
655
- );
656
- return state.table.playerOrder.flatMap(
657
- (playerId) => spacesForPlayer(playerId).map((spaceId) => ({
658
- boardId,
659
- playerId,
660
- spaceId
661
- }))
662
- );
663
- },
664
- predicates,
665
- {
666
- missingCandidateIssue: {
667
- errorCode: "BOARD_TARGET_NOT_ELIGIBLE",
668
- message: "Board target is not eligible."
669
- },
670
- equals: (left, right) => isPlayerBoardSpaceTarget(left) && isPlayerBoardSpaceTarget(right) && left.boardId === right.boardId && left.playerId === right.playerId && left.spaceId === right.spaceId
671
- }
672
- ),
673
- boardId,
674
- targetKind: "space",
675
- valueKind: "player-board-space"
676
- })
677
- );
678
- }
679
- function isPlayerBoardSpaceTarget(value) {
680
- return typeof value === "object" && value !== null && "boardId" in value && "playerId" in value && "spaceId" in value;
681
- }
682
- function makeBoardTargetFactory(targetKind) {
683
- return function target(boardId) {
684
- return createBoardTargetBuilder(targetKind, boardId);
685
- };
686
- }
687
- var boardTarget = {
688
- edge: makeBoardTargetFactory("edge"),
689
- vertex: makeBoardTargetFactory("vertex"),
690
- space: makeBoardTargetFactory("space"),
691
- tile: makeBoardTargetFactory("tile"),
692
- playerSpace(boardId) {
693
- return createPlayerSpaceTargetBuilder(boardId);
694
- }
695
- };
696
-
697
- // src/reducer/inputs/choiceTarget.ts
698
- function normalizeOptions(options) {
699
- if (typeof options === "function") return options;
700
- return () => options;
701
- }
702
- function createChoiceTargetBuilder(options) {
703
- const optionsFactory = normalizeOptions(options);
704
- return createTargetRuleBuilder(
705
- (predicates) => {
706
- const baseRule = createTargetRule(
707
- (ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q).map(
708
- (option) => option.id
709
- ),
710
- predicates,
711
- {
712
- missingCandidateIssue: {
713
- errorCode: "CHOICE_TARGET_NOT_ELIGIBLE",
714
- message: "Choice target is not eligible."
715
- }
716
- }
717
- );
718
- return {
719
- ...baseRule,
720
- targetKind: "choice",
721
- options: (ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q),
722
- eligibleOptions: (ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q).filter(
723
- (option) => baseRule.isEligible(ctx, option.id)
724
- )
725
- };
726
- }
727
- );
728
- }
729
- var choiceTarget = {
730
- options(options) {
731
- return createChoiceTargetBuilder(options);
732
- }
733
- };
734
-
735
- // src/reducer/inputs/promptInput.ts
736
- function promptInput(options) {
737
- const target = options.target;
738
- return {
739
- kind: "prompt",
740
- schema: options.schema,
741
- eligibleTargets: target ? ((state, playerId, q) => target.eligible({
742
- state,
743
- playerId,
744
- q
745
- })) : void 0,
746
- validateTarget: target ? ((state, playerId, q, targetId) => target.validate(
747
- {
748
- state,
749
- playerId,
750
- q
751
- },
752
- targetId
753
- )) : void 0,
754
- meta: target ? {
755
- options: (state, playerId, q) => target.options({
756
- state,
757
- playerId,
758
- q
759
- }),
760
- eligibleOptions: (state, playerId, q) => target.eligibleOptions({
761
- state,
762
- playerId,
763
- q
764
- })
765
- } : void 0,
766
- domain: (state, playerId, q) => ({
767
- type: "choice",
768
- choices: target ? target.options({
769
- state,
770
- playerId,
771
- q
772
- }).map((option) => ({
773
- value: String(option.id),
774
- label: option.label ?? String(option.id)
775
- })) : []
776
- })
777
- };
778
- }
779
-
780
- // src/reducer/inputs/rngInput.ts
781
- import { z as z5 } from "zod";
782
- function d6(count = 1) {
783
- return {
784
- kind: "rng",
785
- schema: z5.object({
786
- values: z5.array(z5.number().int().min(1).max(6)).length(count)
787
- }),
788
- meta: { rng: "d6", count }
789
- };
790
- }
791
- function coin() {
792
- return {
793
- kind: "rng",
794
- schema: z5.object({
795
- value: z5.enum(["heads", "tails"])
796
- }),
797
- meta: { rng: "coin" }
798
- };
799
- }
800
- var rngInput = { d6, coin };
801
-
802
- // src/reducer/manifest/compiler.ts
803
- import { z as z7 } from "zod";
804
-
805
- // src/reducer/manifest/schema.ts
806
- import { z as z6 } from "zod";
807
- function createTableSchema(analysis, ids) {
808
- const unknownRecordSchema = z6.record(z6.string(), z6.unknown());
809
- const objectSchema = (schema) => schema && Object.keys(schema.properties).length ? z6.object(
810
- Object.fromEntries(
811
- Object.entries(schema.properties).map(([key, value]) => [
812
- key,
813
- propertySchema(value)
814
- ])
815
- )
816
- ) : unknownRecordSchema;
817
- function propertySchema(schema) {
818
- if (!schema) return z6.unknown();
819
- let result;
820
- switch (schema.type) {
821
- case "string":
822
- result = z6.string();
823
- break;
824
- case "integer":
825
- result = z6.number().int();
826
- break;
827
- case "number":
828
- result = z6.number();
829
- break;
830
- case "boolean":
831
- result = z6.boolean();
832
- break;
833
- case "enum":
834
- result = schema.enums?.length ? z6.enum(schema.enums) : z6.string();
835
- break;
836
- case "array":
837
- result = z6.array(propertySchema(schema.items));
838
- break;
839
- case "record":
840
- result = z6.record(z6.string(), propertySchema(schema.values));
841
- break;
842
- case "object":
843
- result = objectSchema({ properties: schema.properties ?? {} });
844
- break;
845
- default:
846
- result = ids[schema.type];
847
- }
848
- if (schema.nullable) result = result.nullable();
849
- if (schema.optional) result = result.optional();
850
- if (Object.prototype.hasOwnProperty.call(schema, "default"))
851
- result = result.default(schema.default);
852
- return result;
853
- }
854
- const shape = (items, getKey, getSchema) => z6.object(
855
- Object.fromEntries(items.map((item) => [getKey(item), getSchema(item)]))
856
- );
857
- const cardStateByIdSchema = shape(
858
- analysis.cardIds,
859
- (id) => id,
860
- (id) => {
861
- const setId = analysis.cardSetIdByCardId.get(id);
862
- const type = analysis.cardTypeByCardId.get(id);
863
- const schema = analysis.cardSets.find(
864
- (set) => set.id === setId
865
- ).cardSchema;
866
- const properties = schema && "variants" in schema ? objectSchema({
867
- properties: {
868
- ...schema.shared,
869
- ...schema.variants[type]?.properties
870
- }
871
- }) : objectSchema(schema);
872
- return z6.object({
873
- componentType: z6.string().optional(),
874
- id: z6.literal(id),
875
- cardSetId: z6.literal(setId),
876
- cardType: z6.literal(type),
877
- name: z6.string().optional(),
878
- text: z6.string().optional(),
879
- properties
880
- });
881
- }
882
- );
883
- const pieceStateByIdSchema = shape(
884
- analysis.pieceIds,
885
- (id) => id,
886
- (id) => {
887
- const type = analysis.pieceTypeIdByPieceId.get(id);
888
- return z6.object({
889
- componentType: z6.string().optional(),
890
- id: z6.literal(id),
891
- pieceTypeId: z6.literal(type),
892
- pieceName: z6.string().nullish(),
893
- ownerId: ids.playerId.nullish(),
894
- properties: objectSchema(analysis.pieceTypeSchemasById.get(type))
895
- });
896
- }
897
- );
898
- const dieStateByIdSchema = shape(
899
- analysis.dieIds,
900
- (id) => id,
901
- (id) => {
902
- const type = analysis.dieTypeIdByDieId.get(id);
903
- return z6.object({
904
- componentType: z6.string().optional(),
905
- id: z6.literal(id),
906
- dieTypeId: z6.literal(type),
907
- dieName: z6.string().nullish(),
908
- ownerId: ids.playerId.nullish(),
909
- sides: z6.literal(
910
- analysis.manifest.dieTypes?.find((die) => die.id === type)?.sides ?? 6
911
- ),
912
- value: z6.number().int().nullish(),
913
- properties: objectSchema(analysis.dieTypeSchemasById.get(type))
914
- });
915
- }
916
- );
917
- const sharedZoneSchema = shape(
918
- analysis.sharedZones,
919
- (zone) => zone.id,
920
- () => z6.array(ids.cardId)
921
- );
922
- const playerZoneSchema = shape(
923
- analysis.playerZones,
924
- (zone) => zone.id,
925
- () => perPlayerSchema(z6.array(ids.cardId))
926
- );
927
- const zoneIdSchema = ids.zoneId;
928
- const playerZoneIdSchema = ids.playerZoneId;
929
- const slotVariants = analysis.strictSlotHosts.flatMap(
930
- (host) => host.slotIds.map(
931
- (slotId) => z6.object({
932
- type: z6.literal("InSlot"),
933
- host: z6.object({ kind: z6.literal(host.kind), id: z6.literal(host.id) }),
934
- slotId: z6.literal(slotId),
935
- position: z6.number().int().nullish()
936
- })
937
- )
938
- );
939
- const slotLocationSchema = slotVariants.length ? z6.union(
940
- slotVariants
941
- ) : z6.never();
942
- const boardSpaceTypeIdSchema = ids.spaceTypeId.nullable().optional();
943
- const boardSpaceStateSchema = z6.object({
944
- id: ids.spaceId,
945
- name: z6.string().nullable().optional(),
946
- typeId: boardSpaceTypeIdSchema,
947
- fields: unknownRecordSchema,
948
- zoneId: z6.string().nullable().optional()
949
- });
950
- const hexSpaceStateSchema = boardSpaceStateSchema.extend({
951
- q: z6.number().int(),
952
- r: z6.number().int()
953
- });
954
- const squareSpaceStateSchema = boardSpaceStateSchema.extend({
955
- row: z6.number().int(),
956
- col: z6.number().int()
957
- });
958
- const boardRelationStateSchema = z6.object({
959
- id: z6.string().nullable().optional(),
960
- typeId: ids.relationTypeId,
961
- fromSpaceId: ids.spaceId,
962
- toSpaceId: ids.spaceId,
963
- directed: z6.boolean(),
964
- fields: unknownRecordSchema
965
- });
966
- const boardContainerStateSchema = z6.object({
967
- id: ids.boardContainerId,
968
- name: z6.string(),
969
- host: z6.discriminatedUnion("type", [
970
- z6.object({ type: z6.literal("board") }),
971
- z6.object({ type: z6.literal("space"), spaceId: ids.spaceId })
972
- ]),
973
- allowedCardSetIds: z6.array(ids.cardSetId).optional(),
974
- zoneId: z6.string(),
975
- fields: unknownRecordSchema
976
- });
977
- const runtimeGenericBoardStateSchema = z6.object({
978
- id: ids.boardId,
979
- baseId: ids.boardBaseId,
980
- layout: z6.literal("generic"),
981
- typeId: ids.boardTypeId.nullable().optional(),
982
- scope: z6.enum(["shared", "perPlayer"]),
983
- playerId: ids.playerId.nullable().optional(),
984
- templateId: z6.string().nullable().optional(),
985
- fields: unknownRecordSchema,
986
- // T220: per-board state.spaces is loose-keyed by string. See the
987
- // codegen-template comment in renderGenericBoardStateSchema for
988
- // the rationale; the wire shape is unchanged (additionalProperties
989
- // JSON), and the inner id field narrows at parse time.
990
- spaces: z6.record(z6.string(), boardSpaceStateSchema),
991
- relations: z6.array(boardRelationStateSchema),
992
- containers: z6.record(z6.string(), boardContainerStateSchema)
993
- });
994
- const hexEdgeStateSchema = z6.object({
995
- id: ids.edgeId,
996
- spaceIds: z6.array(ids.spaceId).min(1).max(2),
997
- typeId: ids.edgeTypeId.nullable().optional(),
998
- label: z6.string().nullable().optional(),
999
- ownerId: ids.playerId.nullable().optional(),
1000
- fields: unknownRecordSchema
1001
- });
1002
- const hexVertexStateSchema = z6.object({
1003
- id: ids.vertexId,
1004
- spaceIds: z6.array(ids.spaceId).min(1).max(3),
1005
- typeId: ids.vertexTypeId.nullable().optional(),
1006
- label: z6.string().nullable().optional(),
1007
- ownerId: ids.playerId.nullable().optional(),
1008
- fields: unknownRecordSchema
1009
- });
1010
- const squareVertexStateSchema = z6.object({
1011
- id: ids.vertexId,
1012
- spaceIds: z6.array(ids.spaceId).min(1).max(4),
1013
- typeId: ids.vertexTypeId.nullable().optional(),
1014
- label: z6.string().nullable().optional(),
1015
- ownerId: ids.playerId.nullable().optional(),
1016
- fields: unknownRecordSchema
1017
- });
1018
- const runtimeHexBoardStateSchema = runtimeGenericBoardStateSchema.extend({
1019
- layout: z6.literal("hex"),
1020
- // T220: loose-keyed by string — see comment above.
1021
- spaces: z6.record(z6.string(), hexSpaceStateSchema),
1022
- relations: z6.array(boardRelationStateSchema),
1023
- containers: z6.object({}),
1024
- orientation: z6.enum(["pointy-top", "flat-top"]),
1025
- edges: z6.array(hexEdgeStateSchema),
1026
- vertices: z6.array(hexVertexStateSchema)
1027
- });
1028
- const runtimeSquareBoardStateSchema = runtimeGenericBoardStateSchema.extend({
1029
- layout: z6.literal("square"),
1030
- // T220: loose-keyed by string — see comment above.
1031
- spaces: z6.record(z6.string(), squareSpaceStateSchema),
1032
- relations: z6.array(boardRelationStateSchema),
1033
- containers: z6.record(z6.string(), boardContainerStateSchema),
1034
- edges: z6.array(hexEdgeStateSchema),
1035
- vertices: z6.array(squareVertexStateSchema)
1036
- });
1037
- const boards = analysis.analyzedBoards.flatMap(
1038
- (board) => board.runtimeBoardIds.map((id) => {
1039
- const base = {
1040
- id: board.board.scope === "perPlayer" ? z6.templateLiteral([board.board.id, ":", z6.string().min(1)]) : z6.literal(id),
1041
- baseId: z6.literal(board.board.id),
1042
- scope: z6.literal(board.board.scope),
1043
- fields: objectSchema(board.boardFieldsSchema)
1044
- };
1045
- const spaces = boardSpaceStateSchema.extend({
1046
- fields: objectSchema(board.spaceFieldsSchema)
1047
- });
1048
- const relations = z6.array(
1049
- boardRelationStateSchema.extend({
1050
- fields: objectSchema(
1051
- "relationFieldsSchema" in board ? board.relationFieldsSchema : void 0
1052
- )
1053
- })
1054
- );
1055
- const containers = "containers" in board ? shape(
1056
- board.containers,
1057
- (item) => item.id,
1058
- (item) => boardContainerStateSchema.extend({
1059
- id: z6.literal(item.id),
1060
- fields: objectSchema(board.containerFieldsSchema)
1061
- })
1062
- ) : z6.object({});
1063
- if (board.layout === "generic")
1064
- return {
1065
- id,
1066
- scope: board.board.scope,
1067
- layout: board.layout,
1068
- schema: runtimeGenericBoardStateSchema.extend({
1069
- ...base,
1070
- spaces: z6.record(z6.string(), spaces),
1071
- relations,
1072
- containers
1073
- })
1074
- };
1075
- const edges = z6.array(
1076
- hexEdgeStateSchema.extend({
1077
- fields: objectSchema(board.edgeFieldsSchema)
1078
- })
1079
- );
1080
- const vertices = z6.array(
1081
- (board.layout === "hex" ? hexVertexStateSchema : squareVertexStateSchema).extend({ fields: objectSchema(board.vertexFieldsSchema) })
1082
- );
1083
- return {
1084
- id,
1085
- scope: board.board.scope,
1086
- layout: board.layout,
1087
- schema: board.layout === "hex" ? runtimeHexBoardStateSchema.extend({
1088
- ...base,
1089
- spaces: z6.record(
1090
- z6.string(),
1091
- spaces.extend({ q: z6.number().int(), r: z6.number().int() })
1092
- ),
1093
- edges,
1094
- vertices
1095
- }) : runtimeSquareBoardStateSchema.extend({
1096
- ...base,
1097
- spaces: z6.record(
1098
- z6.string(),
1099
- spaces.extend({
1100
- row: z6.number().int(),
1101
- col: z6.number().int()
1102
- })
1103
- ),
1104
- relations,
1105
- containers,
1106
- edges,
1107
- vertices
1108
- })
1109
- };
1110
- })
1111
- );
1112
- const boardCollection = (entries) => {
1113
- const shared = entries.filter((board) => board.scope === "shared");
1114
- const scoped = entries.filter((board) => board.scope === "perPlayer").map((board) => board.schema);
1115
- return shape(
1116
- shared,
1117
- (board) => board.id,
1118
- (board) => board.schema
1119
- ).catchall(scoped.length ? z6.union(scoped) : z6.never());
1120
- };
1121
- const boardStateByIdSchema = boardCollection(boards);
1122
- const hexBoardStateByIdSchema = boardCollection(
1123
- boards.filter((board) => board.layout === "hex")
1124
- );
1125
- const squareBoardStateByIdSchema = boardCollection(
1126
- boards.filter((board) => board.layout === "square")
1127
- );
1128
- return z6.object({
1129
- playerOrder: z6.array(ids.playerId),
1130
- zones: z6.object({
1131
- shared: sharedZoneSchema,
1132
- perPlayer: playerZoneSchema,
1133
- visibility: z6.record(
1134
- zoneIdSchema,
1135
- z6.enum(["all", "ownerOnly", "public", "hidden"])
1136
- ),
1137
- cardSetIdsByZoneId: z6.record(zoneIdSchema, z6.array(ids.cardSetId)).optional()
1138
- }),
1139
- decks: sharedZoneSchema,
1140
- hands: playerZoneSchema,
1141
- handVisibility: z6.record(
1142
- playerZoneIdSchema,
1143
- z6.enum(["all", "ownerOnly", "public", "hidden"])
1144
- ),
1145
- cards: cardStateByIdSchema,
1146
- pieces: pieceStateByIdSchema,
1147
- componentLocations: z6.record(
1148
- z6.string(),
1149
- z6.union([
1150
- z6.object({ type: z6.literal("Detached") }),
1151
- z6.object({
1152
- type: z6.literal("InDeck"),
1153
- deckId: ids.deckId,
1154
- playedBy: ids.playerId.nullable(),
1155
- position: z6.number().int().nullable().optional()
1156
- }),
1157
- z6.object({
1158
- type: z6.literal("InHand"),
1159
- handId: ids.handId,
1160
- playerId: ids.playerId,
1161
- position: z6.number().int().nullable().optional()
1162
- }),
1163
- z6.object({
1164
- type: z6.literal("InZone"),
1165
- zoneId: z6.string(),
1166
- playedBy: ids.playerId.nullable().optional(),
1167
- position: z6.number().int().nullable().optional()
1168
- }),
1169
- z6.object({
1170
- type: z6.literal("OnSpace"),
1171
- boardId: ids.boardId,
1172
- spaceId: ids.spaceId,
1173
- position: z6.number().int().nullable().optional()
1174
- }),
1175
- z6.object({
1176
- type: z6.literal("InContainer"),
1177
- boardId: ids.boardId,
1178
- containerId: ids.boardContainerId,
1179
- position: z6.number().int().nullable().optional()
1180
- }),
1181
- z6.object({
1182
- type: z6.literal("OnEdge"),
1183
- boardId: ids.boardId,
1184
- edgeId: ids.edgeId,
1185
- position: z6.number().int().nullable().optional()
1186
- }),
1187
- z6.object({
1188
- type: z6.literal("OnVertex"),
1189
- boardId: ids.boardId,
1190
- vertexId: ids.vertexId,
1191
- position: z6.number().int().nullable().optional()
1192
- }),
1193
- slotLocationSchema
1194
- ])
1195
- ),
1196
- ownerOfCard: z6.record(ids.cardId, ids.playerId.nullable()),
1197
- visibility: z6.record(
1198
- ids.cardId,
1199
- z6.object({
1200
- faceUp: z6.boolean(),
1201
- visibleTo: z6.array(ids.playerId).nullable().optional()
1202
- })
1203
- ),
1204
- resources: perPlayerSchema(z6.record(ids.resourceId, z6.number().int())),
1205
- boards: z6.object({
1206
- byId: boardStateByIdSchema,
1207
- hex: hexBoardStateByIdSchema,
1208
- square: squareBoardStateByIdSchema,
1209
- network: z6.record(z6.string(), unknownRecordSchema).default({}),
1210
- track: z6.record(z6.string(), unknownRecordSchema).default({})
1211
- }),
1212
- dice: dieStateByIdSchema
1213
- });
1214
- }
1215
-
1216
- // src/reducer/manifest/compiler.ts
1217
- function compileManifest(manifest) {
1218
- const source = manifest;
1219
- const analysis = analyzeManifest(source);
1220
- const initial = materializeManifestTable({
1221
- manifest: source,
1222
- playerIds: analysis.playerIds,
1223
- shuffleItems: (values) => [...values]
1224
- });
1225
- const sharedZoneIds = analysis.sharedZones.map((zone) => zone.id).sort();
1226
- const playerZoneIds = analysis.playerZones.map((zone) => zone.id).sort();
1227
- const literals = {
1228
- ...Object.fromEntries(
1229
- Object.entries(analysis).filter(([key]) => key.endsWith("Ids") || key === "cardTypes").map(([key, value]) => [key, value])
1230
- ),
1231
- playerIds: analysis.playerIds.map(asPlayerId),
1232
- phaseNames: [],
1233
- boardLayouts: ["generic", "hex", "square"],
1234
- deckIds: sharedZoneIds,
1235
- handIds: playerZoneIds,
1236
- sharedZoneIds,
1237
- playerZoneIds,
1238
- resourcePresentationById: analysis.resourcePresentationById,
1239
- handVisibilityById: Object.fromEntries(
1240
- playerZoneIds.map((id) => [
1241
- id,
1242
- analysis.zoneVisibilityById.get(id) ?? "ownerOnly"
1243
- ])
1244
- ),
1245
- zoneVisibilityById: Object.fromEntries(analysis.zoneVisibilityById),
1246
- cardSetIdByCardId: Object.fromEntries(analysis.cardSetIdByCardId),
1247
- cardTypeByCardId: Object.fromEntries(analysis.cardTypeByCardId),
1248
- setupChoiceIdsByOptionId: Object.fromEntries(
1249
- analysis.setupChoiceIdsByOptionId
1250
- ),
1251
- cardSetIdsBySharedZoneId: Object.fromEntries(analysis.sharedZoneCardSetIds),
1252
- cardSetIdsByPlayerZoneId: Object.fromEntries(analysis.playerZoneCardSetIds)
1253
- };
1254
- const families = [
1255
- "phaseName",
1256
- "boardLayout",
1257
- "setupOptionId",
1258
- "setupProfileId",
1259
- "cardSetId",
1260
- "cardType",
1261
- "cardId",
1262
- "deckId",
1263
- "handId",
1264
- "sharedZoneId",
1265
- "playerZoneId",
1266
- "zoneId",
1267
- "resourceId",
1268
- "pieceTypeId",
1269
- "pieceId",
1270
- "dieTypeId",
1271
- "dieId",
1272
- "boardTypeId",
1273
- "boardBaseId",
1274
- "boardId",
1275
- "boardContainerId",
1276
- "relationTypeId",
1277
- "edgeId",
1278
- "edgeTypeId",
1279
- "vertexId",
1280
- "vertexTypeId",
1281
- "spaceId",
1282
- "spaceTypeId"
1283
- ];
1284
- const ids = {
1285
- ...Object.fromEntries(
1286
- families.map((family) => {
1287
- const values = literals[`${family}s`];
1288
- return [
1289
- family,
1290
- family === "phaseName" ? markManifestScopedSchema(z7.string(), family) : values.length ? createManifestStringLiteralSchema(values, family) : markManifestScopedSchema(z7.never(), family)
1291
- ];
1292
- })
1293
- ),
1294
- playerId: markManifestScopedSchema(
1295
- z7.string().min(1).transform(asPlayerId),
1296
- "playerId"
1297
- )
1298
- };
1299
- const boardIdSchemas = analysis.analyzedBoards.map(
1300
- (board) => board.board.scope === "perPlayer" ? z7.templateLiteral([board.board.id, ":", z7.string().min(1)]) : z7.literal(board.board.id)
1301
- );
1302
- ids.boardId = markManifestScopedSchema(
1303
- boardIdSchemas.length ? z7.union(boardIdSchemas) : z7.never(),
1304
- "boardId"
1305
- );
1306
- const tableSchema = assumeManifestSchema(
1307
- createTableSchema(analysis, ids)
1308
- );
1309
- const resolvePlayers = (players = analysis.playerIds) => players.map(asPlayerId);
1310
- const emptyDecks = () => Object.fromEntries(sharedZoneIds.map((id) => [id, []]));
1311
- const hands = (players) => Object.fromEntries(
1312
- playerZoneIds.map((id) => [
1313
- id,
1314
- perPlayer(resolvePlayers(players), () => [])
1315
- ])
1316
- );
1317
- const defaults = {
1318
- zones: (players) => ({
1319
- shared: emptyDecks(),
1320
- perPlayer: hands(players),
1321
- visibility: structuredClone(literals.zoneVisibilityById),
1322
- cardSetIdsByZoneId: Object.fromEntries(analysis.zoneCardSetIdsById)
1323
- }),
1324
- decks: emptyDecks,
1325
- hands,
1326
- handVisibility: () => structuredClone(literals.handVisibilityById),
1327
- ownerOfCard: () => Object.fromEntries(analysis.cardIds.map((id) => [id, null])),
1328
- visibility: () => Object.fromEntries(analysis.cardIds.map((id) => [id, { faceUp: true }])),
1329
- resources: (players) => perPlayer(
1330
- resolvePlayers(players),
1331
- () => Object.fromEntries(analysis.resourceIds.map((id) => [id, 0]))
1332
- )
1333
- };
1334
- const runtimeSchema = createManifestRuntimeSchema({
1335
- phaseNameSchema: z7.string(),
1336
- playerIdSchema: ids.playerId,
1337
- setupProfileIdSchema: ids.setupProfileId
1338
- });
1339
- const createInitialTable = (options = {}) => tableSchema.parse(
1340
- materializeManifestTable({
1341
- manifest: source,
1342
- playerIds: options.playerIds ?? analysis.playerIds,
1343
- shuffleItems: options.shuffleItems ?? ((values) => [...values])
1344
- })
1345
- );
1346
- return {
1347
- literals,
1348
- ids,
1349
- defaults,
1350
- records: Object.fromEntries(
1351
- [...families, "playerId"].map((family) => [
1352
- `${family}s`,
1353
- (initial2) => buildTypedRecord(
1354
- literals[`${family}s`],
1355
- initial2
1356
- )
1357
- ])
1358
- ),
1359
- tableSchema,
1360
- runtimeSchema,
1361
- schemas: { table: tableSchema, runtime: runtimeSchema },
1362
- staticBoards: initial.boards,
1363
- setupOptionsById: analysis.setupOptionsById,
1364
- setupChoiceIdsByOptionId: literals.setupChoiceIdsByOptionId,
1365
- setupProfilesById: analysis.setupProfilesById,
1366
- createInitialTable,
1367
- normalSetup: {
1368
- minPlayers: source.players.minPlayers,
1369
- maxPlayers: source.players.maxPlayers,
1370
- createInitialTable
1371
- },
1372
- createGameStateSchema: (config) => createManifestGameStateSchema({
1373
- ...config,
1374
- tableSchema,
1375
- playerIdSchema: ids.playerId,
1376
- setupProfileIdSchema: ids.setupProfileId
1377
- })
1378
- };
1379
- }
1380
-
1381
- // src/reducer/authoring/validation.ts
1382
- var MANIFEST_SCOPED_ID_NAMES = [
1383
- "playerId",
1384
- "cardId",
1385
- "deckId",
1386
- "handId",
1387
- "zoneId",
1388
- "sharedZoneId",
1389
- "playerZoneId",
1390
- "boardId",
1391
- "boardContainerId",
1392
- "boardTypeId",
1393
- "boardBaseId",
1394
- "edgeId",
1395
- "edgeTypeId",
1396
- "vertexId",
1397
- "vertexTypeId",
1398
- "spaceId",
1399
- "spaceTypeId",
1400
- "relationTypeId",
1401
- "resourceId",
1402
- "pieceId",
1403
- "pieceTypeId",
1404
- "dieId",
1405
- "dieTypeId",
1406
- "setupOptionId",
1407
- "setupProfileId",
1408
- "cardSetId",
1409
- "cardType"
1410
- ];
1411
- function matchManifestScopedIdName(key) {
1412
- for (const name of MANIFEST_SCOPED_ID_NAMES) {
1413
- const capitalized = `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
1414
- if (key === name || key.endsWith(capitalized)) {
1415
- return { name, kind: "singular" };
1416
- }
1417
- const plural = `${name}s`;
1418
- const capitalizedPlural = `${capitalized}s`;
1419
- if (key === plural || key.endsWith(capitalizedPlural)) {
1420
- return { name, kind: "plural" };
1421
- }
1422
- }
1423
- return null;
1424
- }
1425
- function validateInteractionParamsSchema(schema, context, path) {
1426
- const inner = unwrapWrappers(schema);
1427
- if (isEnumKeyedRecordSchema(inner) && !isSparseMapSchema(inner)) {
1428
- throw new Error(
1429
- `${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.`
1430
- );
1431
- }
1432
- const shape = getObjectShape(inner);
1433
- if (shape) {
1434
- for (const [key, fieldSchema] of Object.entries(shape)) {
1435
- validateInteractionParamsSchema(fieldSchema, context, `${path}.${key}`);
1436
- }
1437
- return;
1438
- }
1439
- const def = getZodDef(inner);
1440
- if (def.type === "array" && def.element) {
1441
- validateInteractionParamsSchema(def.element, context, `${path}[]`);
1442
- return;
1443
- }
1444
- if (def.type === "record" && def.valueType) {
1445
- validateInteractionParamsSchema(def.valueType, context, `${path}.*`);
1446
- }
1447
- }
1448
- function validateInteractionInputsSchema(inputs, context) {
1449
- if (!inputs) return;
1450
- for (const [key, collector] of Object.entries(inputs)) {
1451
- validateInteractionParamsSchema(collector.schema, context, `inputs.${key}`);
1452
- }
1453
- }
1454
- function validateManyCommitPolicy(input) {
1455
- if (input.commit?.mode !== "autoWhenReady") return;
1456
- if (Object.values(input.inputs ?? {}).some(
1457
- (collector) => collector.selection?.mode === "many"
1458
- )) {
1459
- throw new Error(
1460
- `${input.context}: interactions with many(...) inputs must use commit: { mode: "manual" }.`
1461
- );
1462
- }
1463
- }
1464
- function validateInteractionLikeDefinition(input, context) {
1465
- validateInteractionInputsSchema(input.inputs, context);
1466
- validateManyCommitPolicy({
1467
- inputs: input.inputs,
1468
- commit: input.commit,
1469
- context
1470
- });
1471
- if (input.paramsSchema) {
1472
- validateInteractionParamsSchema(
1473
- input.paramsSchema,
1474
- context,
1475
- "paramsSchema"
1476
- );
1477
- }
1478
- }
1479
- function validateStateSchemaIdBranding(schema, scope) {
1480
- const def = getZodDef(schema);
1481
- if (def.type !== "object") {
1482
- return;
1483
- }
1484
- const shape = def.shape;
1485
- if (!shape) {
1486
- return;
1487
- }
1488
- for (const [key, fieldSchema] of Object.entries(shape)) {
1489
- const match = matchManifestScopedIdName(key);
1490
- if (!match) {
1491
- continue;
1492
- }
1493
- const inner = unwrapWrappers(fieldSchema);
1494
- if (match.kind === "singular") {
1495
- if (isPlainZodString(inner) && !isManifestScopedSchema(inner)) {
1496
- throw new Error(
1497
- `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.`
1498
- );
1499
- }
1500
- continue;
1501
- }
1502
- if (match.kind === "plural" && isZodArray(inner)) {
1503
- const element = unwrapWrappers(getZodDef(inner).element);
1504
- if (isPlainZodString(element) && !isManifestScopedSchema(element)) {
1505
- throw new Error(
1506
- `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.`
1507
- );
1508
- }
1509
- }
1510
- }
1511
- }
1512
- function validateDefineGamePhaseNames(definition) {
1513
- const contractPhaseNames = definition.contract.phaseNames;
1514
- if (!Array.isArray(contractPhaseNames)) {
1515
- return;
1516
- }
1517
- const declared = new Set(contractPhaseNames);
1518
- const actual = new Set(Object.keys(definition.phases));
1519
- const missing = [...declared].filter((name) => !actual.has(name));
1520
- const extra = [...actual].filter((name) => !declared.has(name));
1521
- if (missing.length > 0 || extra.length > 0) {
1522
- const parts = [];
1523
- if (missing.length > 0) {
1524
- parts.push(`missing: [${missing.join(", ")}]`);
1525
- }
1526
- if (extra.length > 0) {
1527
- parts.push(`extra: [${extra.join(", ")}]`);
1528
- }
1529
- throw new Error(
1530
- `defineGame: phases record does not match contract.phaseNames (${parts.join(
1531
- "; "
1532
- )}). Update contract.phaseNames or the phases record so they agree.`
1533
- );
1534
- }
1535
- if (definition.initialPhase !== void 0 && !declared.has(definition.initialPhase)) {
1536
- throw new Error(
1537
- `defineGame: initialPhase '${definition.initialPhase}' is not declared in contract.phaseNames.`
1538
- );
1539
- }
1540
- if (definition.setupProfiles) {
1541
- for (const [profileId, profile] of Object.entries(
1542
- definition.setupProfiles
1543
- )) {
1544
- const initial = profile?.initialPhase;
1545
- if (initial !== void 0 && !declared.has(initial)) {
1546
- throw new Error(
1547
- `defineGame: setupProfiles.${profileId}.initialPhase '${initial}' is not declared in contract.phaseNames.`
1548
- );
1549
- }
1550
- }
1551
- }
1552
- }
1553
- function validateDefineGameZoneWiring(definition) {
1554
- const manifestPlayerZoneIds = new Set(
1555
- definition.contract.manifest.literals.playerZoneIds ?? []
1556
- );
1557
- for (const [phaseName, phase] of Object.entries(definition.phases)) {
1558
- const phaseRecord = typeof phase === "object" && phase !== null ? phase : null;
1559
- if (!phaseRecord) continue;
1560
- if (phaseRecord.zones !== void 0 && !Array.isArray(phaseRecord.zones)) {
1561
- const zonesRecord = typeof phaseRecord.zones === "object" && phaseRecord.zones !== null ? phaseRecord.zones : null;
1562
- const hasRemovedZoneSpec = zonesRecord && Object.values(zonesRecord).some(
1563
- (zone) => typeof zone === "object" && zone !== null && ("cardsFrom" in zone || "playableVia" in zone || "from" in zone)
1564
- );
1565
- if (hasRemovedZoneSpec) {
1566
- throw new Error(
1567
- `defineGame: phases.${phaseName}.zones uses removed zone spec objects. Use zones: ["manifest-player-zone-id"] and cardActions[*].playFrom instead.`
1568
- );
1569
- }
1570
- throw new Error(
1571
- `defineGame: phases.${phaseName}.zones must be an array of manifest player zone ids.`
1572
- );
1573
- }
1574
- for (const [index, zoneId] of (phaseRecord.zones ?? []).entries()) {
1575
- if (typeof zoneId !== "string") {
1576
- throw new Error(
1577
- `defineGame: phases.${phaseName}.zones[${index}] must be a manifest player zone id string.`
1578
- );
1579
- }
1580
- if (!manifestPlayerZoneIds.has(zoneId)) {
1581
- throw new Error(
1582
- `defineGame: phases.${phaseName}.zones[${index}] '${zoneId}' is not declared in manifest.literals.playerZoneIds.`
1583
- );
1584
- }
1585
- }
1586
- for (const [actionId, action] of Object.entries(
1587
- phaseRecord.cardActions ?? {}
1588
- )) {
1589
- const actionRecord = typeof action === "object" && action !== null ? action : null;
1590
- const playFrom = actionRecord?.playFrom;
1591
- if (typeof playFrom === "string" && !manifestPlayerZoneIds.has(playFrom)) {
1592
- throw new Error(
1593
- `defineGame: phases.${phaseName}.cardActions.${actionId}.playFrom '${playFrom}' is not declared in manifest.literals.playerZoneIds.`
1594
- );
1595
- }
1596
- }
1597
- }
1598
- }
1599
- function validateDefineGameSimultaneousPhases(definition) {
1600
- for (const [phaseName, phase] of Object.entries(definition.phases)) {
1601
- const phaseRecord = typeof phase === "object" && phase !== null ? phase : null;
1602
- if (!phaseRecord || phaseRecord.kind !== "simultaneousPlayer") {
1603
- continue;
1604
- }
1605
- if (!phaseRecord.submit) {
1606
- throw new Error(
1607
- `defineGame: phases.${phaseName} is kind 'simultaneousPlayer' but does not declare submit.`
1608
- );
1609
- }
1610
- if (typeof phaseRecord.resolve !== "function") {
1611
- throw new Error(
1612
- `defineGame: phases.${phaseName} is kind 'simultaneousPlayer' but does not declare resolve.`
1613
- );
1614
- }
1615
- if (phaseRecord.interactions?.submit) {
1616
- throw new Error(
1617
- `defineGame: phases.${phaseName}.interactions.submit conflicts with the reserved simultaneous submit interaction id.`
1618
- );
1619
- }
1620
- validateInteractionInputsSchema(
1621
- phaseRecord.submit.inputs,
1622
- "defineInteraction"
1623
- );
1624
- validateManyCommitPolicy({
1625
- inputs: phaseRecord.submit.inputs,
1626
- commit: phaseRecord.submit.commit,
1627
- context: `defineGame: phases.${phaseName}.submit`
1628
- });
1629
- }
1630
- }
1631
-
1632
- // src/reducer/authoring/interaction.ts
1633
- function defineInteraction() {
1634
- return (definition) => {
1635
- validateInteractionLikeDefinition(
1636
- definition,
1637
- "defineInteraction"
1638
- );
1639
- return definition;
1640
- };
1641
- }
1642
- function defineInteractionRule() {
1643
- return (definition) => definition;
1644
- }
1645
- function defineCardAction() {
1646
- return (definition) => {
1647
- validateInteractionLikeDefinition(
1648
- definition,
1649
- "defineCardAction"
1650
- );
1651
- return definition;
1652
- };
1653
- }
1654
-
1655
- // src/reducer/authoring/phase.ts
1656
- import { z as z8 } from "zod";
1657
- function stepStateSchema(schema, steps) {
1658
- const stepSchema = z8.enum(steps);
1659
- const maybeObject = schema;
1660
- if (typeof maybeObject.extend === "function") {
1661
- return maybeObject.extend({ step: stepSchema });
1662
- }
1663
- return z8.intersection(schema, z8.object({ step: stepSchema }));
1664
- }
1665
- function unwrapStepInteractions(interactions) {
1666
- if (!interactions) return void 0;
1667
- return Object.fromEntries(
1668
- Object.entries(interactions).map(([key, entry]) => [
1669
- key,
1670
- {
1671
- ...entry.interaction,
1672
- __steps: entry.steps
1673
- }
1674
- ])
1675
- );
1676
- }
1677
- function unwrapStepCardActions(cardActions) {
1678
- if (!cardActions) return void 0;
1679
- return Object.fromEntries(
1680
- Object.entries(cardActions).map(([key, entry]) => [
1681
- key,
1682
- {
1683
- ...entry.action,
1684
- __steps: entry.steps
1685
- }
1686
- ])
1687
- );
1688
- }
1689
- function definePhase() {
1690
- return (definition) => {
1691
- return definition;
1692
- };
1693
- }
1694
- function defineStepPhase() {
1695
- return (definition) => {
1696
- const [initialStep] = definition.steps;
1697
- const state = stepStateSchema(definition.state, definition.steps);
1698
- const initialState = definition.initialState ? (ctx) => ({
1699
- ...definition.initialState?.(ctx),
1700
- step: initialStep
1701
- }) : () => ({ step: initialStep });
1702
- const { steps: _steps, ...rest } = definition;
1703
- void _steps;
1704
- const normalized = {
1705
- ...rest,
1706
- state,
1707
- initialState,
1708
- interactions: unwrapStepInteractions(definition.interactions),
1709
- cardActions: unwrapStepCardActions(definition.cardActions)
1710
- };
1711
- return normalized;
1712
- };
1713
- }
1714
-
1715
- // src/reducer/authoring/view-stage.ts
1716
- function defineSharedView() {
1717
- return (definition) => definition;
1718
- }
1719
- function definePlayerView() {
1720
- return (definition) => definition;
1721
- }
1722
- function defineEmptyView() {
1723
- return {
1724
- project: () => ({})
1725
- };
1726
- }
1727
- function defineStaticView() {
1728
- return (definition) => definition;
1729
- }
1730
-
1731
- // src/reducer/authoring/contract-authoring.ts
1732
- var PHANTOM_TYPES_MESSAGE = "`.types` is a compile-time carrier: use it only in `typeof` positions.";
1733
- function phantomTypes() {
1734
- return new Proxy(Object.freeze({}), {
1735
- get() {
1736
- throw new TypeError(PHANTOM_TYPES_MESSAGE);
1737
- }
1738
- });
1739
- }
1740
- function toPredicateList(where) {
1741
- if (!where) return [];
1742
- return Array.isArray(where) ? where : [where];
1743
- }
1744
- function applyWhere(builder, where) {
1745
- return toPredicateList(where).reduce(
1746
- (current, predicate) => current.where(predicate),
1747
- builder
1748
- );
1749
- }
1750
- function createFusedCardInput() {
1751
- return ((options) => {
1752
- const target = applyWhere(
1753
- cardTarget.zones(options.from),
1754
- options.where
1755
- ).build();
1756
- return cardInput({
1757
- target,
1758
- ...options.dependsOn ? { dependsOn: options.dependsOn } : {}
1759
- });
1760
- });
1761
- }
1762
- function createFusedBoardInputs() {
1763
- const fuse = (kind) => (options) => {
1764
- const target = applyWhere(
1765
- boardTarget[kind](options.boardId),
1766
- options.where
1767
- ).build();
1768
- return boardInput[kind]({
1769
- target,
1770
- ...options.dependsOn ? { dependsOn: options.dependsOn } : {}
1771
- });
1772
- };
1773
- const playerSpace = (options) => boardInput.playerSpace({
1774
- target: applyWhere(
1775
- boardTarget.playerSpace(options.boardId),
1776
- options.where
1777
- ).build(),
1778
- ...options.dependsOn ? { dependsOn: options.dependsOn } : {}
1779
- });
1780
- return {
1781
- vertex: fuse("vertex"),
1782
- edge: fuse("edge"),
1783
- space: fuse("space"),
1784
- tile: fuse("tile"),
1785
- playerSpace
1786
- };
1787
- }
1788
- function createFusedPromptInput() {
1789
- return ((options) => promptInput({
1790
- schema: options.schema,
1791
- ...options.choices ? {
1792
- target: applyWhere(
1793
- choiceTarget.options(
1794
- options.choices
1795
- ),
1796
- options.where
1797
- ).build()
1798
- } : {}
1799
- }));
1800
- }
1801
- function createBoundInputBuilders() {
1802
- return {
1803
- board: createFusedBoardInputs(),
1804
- card: createFusedCardInput(),
1805
- form: formInput.forState(),
1806
- prompt: createFusedPromptInput(),
1807
- rng: rngInput
1808
- };
1809
- }
1810
- function createPhaseAuthoring(_contract, schema) {
1811
- return {
1812
- interaction: (spec) => defineInteraction()(
1813
- spec
1814
- ),
1815
- cardAction: (spec) => defineCardAction()(
1816
- spec
1817
- ),
1818
- rule: (rule) => defineInteractionRule()(
1819
- rule
1820
- ),
1821
- define: (definition) => definePhase()({
1822
- ...definition,
1823
- state: schema
1824
- }),
1825
- stepPhase: (definition) => defineStepPhase()({
1826
- ...definition,
1827
- state: schema
1828
- }),
1829
- inputs: createBoundInputBuilders(),
1830
- types: phantomTypes()
1831
- };
1832
- }
1833
- function createContractAuthoring(contract) {
1834
- const phaseCache = /* @__PURE__ */ new Map();
1835
- const views = {
1836
- shared: (definition) => defineSharedView()(definition),
1837
- player: (definition) => definePlayerView()(definition),
1838
- empty: () => defineEmptyView(),
1839
- static: (definition) => defineStaticView()(definition)
1840
- };
1841
- const assemble = (definition) => defineGameDefinition({
1842
- contract,
1843
- ...definition
1844
- });
1845
- return {
1846
- contract,
1847
- views,
1848
- types: phantomTypes(),
1849
- assemble,
1850
- phase: (name) => {
1851
- const cached = phaseCache.get(name);
1852
- if (cached) return cached;
1853
- const schema = contract.phases[name];
1854
- const bound = createPhaseAuthoring(contract, schema);
1855
- phaseCache.set(name, bound);
1856
- return bound;
1857
- }
1858
- };
1859
- }
1860
-
1861
- // src/reducer/authoring/contract.ts
1862
- function validateErrorMap(errors) {
1863
- if (!errors) return;
1864
- const codePattern = /^[A-Z][A-Z0-9_]*$/;
1865
- for (const [code, message] of Object.entries(errors)) {
1866
- if (!codePattern.test(code)) {
1867
- throw new Error(
1868
- `defineGameContract: error code '${code}' must use UPPER_SNAKE_CASE.`
1869
- );
1870
- }
1871
- if (typeof message !== "string" || message.length === 0) {
1872
- throw new Error(
1873
- `defineGameContract: error code '${code}' must declare a non-empty default message.`
1874
- );
1875
- }
1876
- }
1877
- }
1878
- function defineGameContract(definition) {
1879
- validateStateSchemaIdBranding(definition.state.public, "public");
1880
- validateStateSchemaIdBranding(definition.state.private, "private");
1881
- validateStateSchemaIdBranding(definition.state.hidden, "hidden");
1882
- validateErrorMap(definition.errors);
1883
- const phaseNames = Object.keys(definition.phases);
1884
- if (phaseNames.length === 0) {
1885
- throw new Error(
1886
- "defineGameContract: phases must be a non-empty record of phase schemas."
1887
- );
1888
- }
1889
- for (const name of phaseNames) {
1890
- if (typeof name !== "string" || name.length === 0) {
1891
- throw new Error(
1892
- "defineGameContract: phase names must be non-empty strings."
1893
- );
1894
- }
1895
- }
1896
- const phaseNameSchema = createManifestStringLiteralSchema(phaseNames);
1897
- const narrowedManifest = {
1898
- ...definition.manifest,
1899
- literals: {
1900
- ...definition.manifest.literals,
1901
- phaseNames
1902
- },
1903
- ids: {
1904
- ...definition.manifest.ids,
1905
- phaseName: phaseNameSchema
1906
- }
1907
- };
1908
- const contract = {
1909
- manifest: narrowedManifest,
1910
- state: definition.state,
1911
- phases: definition.phases,
1912
- errors: definition.errors,
1913
- phaseNames,
1914
- schemas: narrowedManifest.ids
1915
- };
1916
- return contract;
1917
- }
1918
-
1919
- // src/reducer/authoring/game.ts
1920
- function defineGameDefinition(definition) {
1921
- validateDefineGamePhaseNames(definition);
1922
- validateDefineGameSimultaneousPhases(definition);
1923
- validateDefineGameZoneWiring(definition);
1924
- return definition;
1925
- }
1926
- function createGame(model) {
1927
- const manifest = "literals" in model.manifest ? model.manifest : compileManifest(model.manifest);
1928
- return createContractAuthoring(defineGameContract({ ...model, manifest }));
1929
- }
1930
-
1931
- export {
1932
- sparseMap,
1933
- sparseCounts,
1934
- normalizeCommandParams,
1935
- defineInputs,
1936
- many,
1937
- compileManifest,
1938
- defineGameDefinition,
1939
- createGame
1940
- };
1941
- //# sourceMappingURL=chunk-ZZGN2ATS.js.map