@dreamboard-games/sdk 0.5.0-alpha.3 → 0.5.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -4
- package/dist/board-target-B0QG6OYx.d.ts +8 -0
- package/dist/chunk-3JXUL4VN.js +139 -0
- package/dist/chunk-3JXUL4VN.js.map +1 -0
- package/dist/{chunk-SP234IY4.js → chunk-7RGMPJQG.js} +340 -248
- package/dist/chunk-7RGMPJQG.js.map +1 -0
- package/dist/{chunk-FMM5LVJW.js → chunk-K75F5UIJ.js} +27 -12
- package/dist/chunk-K75F5UIJ.js.map +1 -0
- package/dist/{chunk-ZPRKWPEP.js → chunk-N37D7NPB.js} +116 -29
- package/dist/chunk-N37D7NPB.js.map +1 -0
- package/dist/{chunk-LRILEVKC.js → chunk-UESVBUPU.js} +473 -496
- package/dist/chunk-UESVBUPU.js.map +1 -0
- package/dist/{diagnostics-B0lgnuZ6.d.ts → diagnostics-9gJgI85c.d.ts} +2 -2
- package/dist/{definition-BaHNPZol.d.ts → extract-Bjuw_gdF.d.ts} +2513 -2390
- package/dist/index.d.ts +524 -185
- package/dist/index.js +280 -226
- package/dist/index.js.map +1 -1
- package/dist/model-BCl8WsB6.d.ts +551 -0
- package/dist/react.d.ts +35 -7
- package/dist/react.js +137 -11
- package/dist/react.js.map +1 -1
- package/dist/reducer.d.ts +227 -151
- package/dist/reducer.js +343 -569
- package/dist/reducer.js.map +1 -1
- package/dist/testing.d.ts +54 -42
- package/dist/testing.js +120 -69
- package/dist/testing.js.map +1 -1
- package/dist/{types-DimqnJBq.d.ts → types-B3kIhBWb.d.ts} +41 -10
- package/package.json +20 -17
- package/dist/chunk-FMM5LVJW.js.map +0 -1
- package/dist/chunk-LRILEVKC.js.map +0 -1
- package/dist/chunk-SP234IY4.js.map +0 -1
- package/dist/chunk-VUWNJXLJ.js +0 -52
- package/dist/chunk-VUWNJXLJ.js.map +0 -1
- package/dist/chunk-ZPRKWPEP.js.map +0 -1
- package/dist/model-BHro6yXu.d.ts +0 -288
|
@@ -2,8 +2,72 @@ import {
|
|
|
2
2
|
immutableCopy
|
|
3
3
|
} from "./chunk-DMFVAZI2.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
inputDomainErrors,
|
|
6
|
+
inputTargetInDomain,
|
|
7
|
+
inputValueInDomain,
|
|
8
|
+
inputValueKey,
|
|
9
|
+
requireLookup
|
|
10
|
+
} from "./chunk-3JXUL4VN.js";
|
|
11
|
+
|
|
12
|
+
// src/headless/runtime-features.ts
|
|
13
|
+
var runtimeFeatures = /* @__PURE__ */ Symbol("runtimeFeatures");
|
|
14
|
+
|
|
15
|
+
// src/headless/input-control.ts
|
|
16
|
+
function resourceValue(domain, value) {
|
|
17
|
+
const record = value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
18
|
+
return Object.fromEntries(
|
|
19
|
+
domain.resources.map((resource) => {
|
|
20
|
+
const amount = record[resource.resourceId];
|
|
21
|
+
return [resource.resourceId, typeof amount === "number" ? amount : 0];
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
function createInputControl(input, props) {
|
|
26
|
+
const domain = input.getDomain();
|
|
27
|
+
const current = input.getValue();
|
|
28
|
+
const common = { key: input.key, disabled: props.disabled, props };
|
|
29
|
+
if (domain.type === "boundedNumber") {
|
|
30
|
+
if (domain.selection?.mode === "many")
|
|
31
|
+
return {
|
|
32
|
+
...common,
|
|
33
|
+
type: "boundedNumber",
|
|
34
|
+
domain,
|
|
35
|
+
mode: "many",
|
|
36
|
+
value: Array.isArray(current) ? current.filter(
|
|
37
|
+
(value) => typeof value === "number"
|
|
38
|
+
) : [],
|
|
39
|
+
setValue: (value) => input.setValue(value)
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
...common,
|
|
43
|
+
type: "boundedNumber",
|
|
44
|
+
domain,
|
|
45
|
+
mode: "single",
|
|
46
|
+
value: typeof current === "number" ? current : void 0,
|
|
47
|
+
setValue: (value) => value === void 0 ? input.clear() : input.setValue(value)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (domain.type === "resourceMap") {
|
|
51
|
+
if (domain.selection?.mode === "many")
|
|
52
|
+
return {
|
|
53
|
+
...common,
|
|
54
|
+
type: "resourceMap",
|
|
55
|
+
domain,
|
|
56
|
+
mode: "many",
|
|
57
|
+
value: Array.isArray(current) ? current.map((value) => resourceValue(domain, value)) : [],
|
|
58
|
+
setValue: (value) => input.setValue(value)
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
...common,
|
|
62
|
+
type: "resourceMap",
|
|
63
|
+
domain,
|
|
64
|
+
mode: "single",
|
|
65
|
+
value: current === void 0 ? void 0 : resourceValue(domain, current),
|
|
66
|
+
setValue: (value) => value === void 0 ? input.clear() : input.setValue(value)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return { ...common, type: "targets", options: input.getTargetOptions() };
|
|
70
|
+
}
|
|
7
71
|
|
|
8
72
|
// src/headless/instance.ts
|
|
9
73
|
import { createStore } from "@tanstack/store";
|
|
@@ -30,68 +94,13 @@ function validateInteractionInputDomains(descriptor, params) {
|
|
|
30
94
|
for (const rawInput of descriptor.inputs) {
|
|
31
95
|
const input = rawInput;
|
|
32
96
|
const value = params[input.key];
|
|
33
|
-
if (value === void 0
|
|
34
|
-
const
|
|
35
|
-
|
|
97
|
+
if (value === void 0) continue;
|
|
98
|
+
for (const error of inputDomainErrors(
|
|
99
|
+
input.domain,
|
|
100
|
+
value,
|
|
101
|
+
input.domain.selection
|
|
102
|
+
))
|
|
36
103
|
pushFieldError(fieldErrors, input.key, error);
|
|
37
|
-
}
|
|
38
|
-
if (input.domain.type === "choiceList") {
|
|
39
|
-
if (!Array.isArray(value)) {
|
|
40
|
-
pushFieldError(fieldErrors, input.key, "Expected a list of choices.");
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
const min = input.domain.min ?? 0;
|
|
44
|
-
const max = input.domain.max ?? input.domain.choices?.length ?? Number.POSITIVE_INFINITY;
|
|
45
|
-
if (value.length < min) {
|
|
46
|
-
pushFieldError(
|
|
47
|
-
fieldErrors,
|
|
48
|
-
input.key,
|
|
49
|
-
`Choose at least ${min} ${pluralize("option", min)}.`
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
if (value.length > max) {
|
|
53
|
-
pushFieldError(
|
|
54
|
-
fieldErrors,
|
|
55
|
-
input.key,
|
|
56
|
-
`Choose at most ${max} ${pluralize("option", max)}.`
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
const allowed = new Set(
|
|
60
|
-
input.domain.choices?.map((choice) => choice.value)
|
|
61
|
-
);
|
|
62
|
-
if (allowed.size > 0 && value.some((item) => !allowed.has(String(item)))) {
|
|
63
|
-
pushFieldError(
|
|
64
|
-
fieldErrors,
|
|
65
|
-
input.key,
|
|
66
|
-
"Selected choice is not eligible."
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (input.domain.type === "choice") {
|
|
71
|
-
const allowed = new Set(
|
|
72
|
-
input.domain.choices?.map((choice) => choice.value)
|
|
73
|
-
);
|
|
74
|
-
if (allowed.size > 0 && !allowed.has(value)) {
|
|
75
|
-
pushFieldError(
|
|
76
|
-
fieldErrors,
|
|
77
|
-
input.key,
|
|
78
|
-
"Selected choice is not eligible."
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (isResolvedTargetDomain(input.domain)) {
|
|
83
|
-
const values = valuesForSelection(input.domain.selection, value);
|
|
84
|
-
for (const item of values) {
|
|
85
|
-
if (!input.domain.eligibleTargets.includes(String(item))) {
|
|
86
|
-
pushFieldError(
|
|
87
|
-
fieldErrors,
|
|
88
|
-
input.key,
|
|
89
|
-
"Selected target is not eligible."
|
|
90
|
-
);
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
104
|
}
|
|
96
105
|
return fieldErrors;
|
|
97
106
|
}
|
|
@@ -110,10 +119,10 @@ function isManyInput(input) {
|
|
|
110
119
|
}
|
|
111
120
|
function toggleManyValue(current, value, selection) {
|
|
112
121
|
if (selection.mode !== "many") return [value];
|
|
113
|
-
const previous = Array.isArray(current) ? current
|
|
114
|
-
const existing = previous.
|
|
122
|
+
const previous = Array.isArray(current) ? current : [];
|
|
123
|
+
const existing = previous.findIndex((item) => sameValue(item, value));
|
|
115
124
|
if (existing >= 0) {
|
|
116
|
-
return previous.filter((item) => item
|
|
125
|
+
return previous.filter((item) => !sameValue(item, value));
|
|
117
126
|
}
|
|
118
127
|
if (selection.max !== void 0 && previous.length >= selection.max) {
|
|
119
128
|
return previous;
|
|
@@ -123,9 +132,8 @@ function toggleManyValue(current, value, selection) {
|
|
|
123
132
|
function isManyTargetSelectable(input, current, targetId) {
|
|
124
133
|
const selection = inputSelection(input);
|
|
125
134
|
if (selection?.mode !== "many") return true;
|
|
126
|
-
const currentValues = Array.isArray(current) ? current
|
|
127
|
-
if (currentValues.
|
|
128
|
-
if (selection.distinct && currentValues.includes(targetId)) return false;
|
|
135
|
+
const currentValues = Array.isArray(current) ? current : [];
|
|
136
|
+
if (currentValues.some((item) => sameValue(item, targetId))) return true;
|
|
129
137
|
return selection.max === void 0 || currentValues.length < selection.max;
|
|
130
138
|
}
|
|
131
139
|
function hasInteractionFieldErrors(fieldErrors) {
|
|
@@ -136,52 +144,21 @@ function hasInteractionFieldErrors(fieldErrors) {
|
|
|
136
144
|
function inputByKey(descriptor, key) {
|
|
137
145
|
return descriptor.inputs.find((input) => input.key === key);
|
|
138
146
|
}
|
|
139
|
-
function isTargetDomain(domain) {
|
|
140
|
-
if (!domain) return false;
|
|
141
|
-
return domain.type === "cardTarget" || domain.type === "boardTarget";
|
|
142
|
-
}
|
|
143
|
-
function isResolvedTargetDomain(domain) {
|
|
144
|
-
return (domain.type === "cardTarget" || domain.type === "boardTarget") && domain.projection === "resolved";
|
|
145
|
-
}
|
|
146
|
-
function validateInputSelection(input, value) {
|
|
147
|
-
const selection = inputSelection(input);
|
|
148
|
-
if (selection?.mode !== "many") return [];
|
|
149
|
-
if (!Array.isArray(value)) return ["Expected a list of values."];
|
|
150
|
-
const errors = [];
|
|
151
|
-
const min = selection.min;
|
|
152
|
-
if (value.length < min) {
|
|
153
|
-
errors.push(`Choose at least ${min} ${pluralize("value", min)}.`);
|
|
154
|
-
}
|
|
155
|
-
if (selection.max !== void 0 && value.length > selection.max) {
|
|
156
|
-
errors.push(
|
|
157
|
-
`Choose at most ${selection.max} ${pluralize("value", selection.max)}.`
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
if (selection.distinct) {
|
|
161
|
-
const seen = /* @__PURE__ */ new Set();
|
|
162
|
-
for (const item of value) {
|
|
163
|
-
const key = String(item);
|
|
164
|
-
if (seen.has(key)) {
|
|
165
|
-
errors.push("Choose each value only once.");
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
168
|
-
seen.add(key);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return errors;
|
|
172
|
-
}
|
|
173
|
-
function valuesForSelection(selection, value) {
|
|
174
|
-
if (selection?.mode === "many") return Array.isArray(value) ? value : [];
|
|
175
|
-
return [value];
|
|
176
|
-
}
|
|
177
147
|
function inputSelection(input) {
|
|
178
|
-
|
|
148
|
+
if (input.domain.selection) return input.domain.selection;
|
|
149
|
+
if (input.domain.type === "choiceList")
|
|
150
|
+
return {
|
|
151
|
+
mode: "many",
|
|
152
|
+
min: input.domain.min ?? 0,
|
|
153
|
+
max: input.domain.max ?? input.domain.choices.length
|
|
154
|
+
};
|
|
155
|
+
return void 0;
|
|
179
156
|
}
|
|
180
157
|
function pushFieldError(fieldErrors, key, message) {
|
|
181
158
|
fieldErrors[key] = [...fieldErrors[key] ?? [], message];
|
|
182
159
|
}
|
|
183
|
-
function
|
|
184
|
-
return
|
|
160
|
+
function sameValue(left, right) {
|
|
161
|
+
return inputValueKey(left) === inputValueKey(right);
|
|
185
162
|
}
|
|
186
163
|
|
|
187
164
|
// src/headless/interaction-router.ts
|
|
@@ -236,8 +213,12 @@ function getInteractionDraftReadiness(descriptor, draft) {
|
|
|
236
213
|
function routeInteractionTarget(store, descriptor, target) {
|
|
237
214
|
const input = inputByKey(descriptor, target.inputKey);
|
|
238
215
|
const currentDraft = store.getDraft(descriptor.interactionKey);
|
|
239
|
-
const selection =
|
|
240
|
-
const targetValue = selection?.mode === "many" ? toggleManyValue(
|
|
216
|
+
const selection = input ? inputSelection(input) : void 0;
|
|
217
|
+
const targetValue = selection?.mode === "many" ? toggleManyValue(
|
|
218
|
+
currentDraft[target.inputKey] ?? input?.defaultValue,
|
|
219
|
+
target.value,
|
|
220
|
+
selection
|
|
221
|
+
) : target.value;
|
|
241
222
|
const params = applyInteractionDraftMutation(store, descriptor, [
|
|
242
223
|
...Object.entries(target.extraInputs ?? {}).map(([key, value]) => ({
|
|
243
224
|
key,
|
|
@@ -258,18 +239,22 @@ function routeCardInputIntent(store, descriptor, intent) {
|
|
|
258
239
|
});
|
|
259
240
|
}
|
|
260
241
|
function shouldAutoSubmitInteraction(descriptor) {
|
|
261
|
-
return descriptor.commit.mode === "autoWhenReady" && !descriptor.inputs.some((input) =>
|
|
242
|
+
return descriptor.commit.mode === "autoWhenReady" && !descriptor.inputs.some((input) => input.domain.selection?.mode === "many");
|
|
262
243
|
}
|
|
263
244
|
|
|
264
245
|
// src/headless/instance.ts
|
|
265
246
|
var EMPTY = Object.freeze({});
|
|
266
247
|
var EMPTY_DRAFTS = Object.freeze({});
|
|
267
|
-
var equalValue = (a, b) => Object.is(a, b) || typeof a === "object" && typeof b === "object" &&
|
|
248
|
+
var equalValue = (a, b) => Object.is(a, b) || typeof a === "object" && typeof b === "object" && inputValueKey(a) === inputValueKey(b);
|
|
268
249
|
function inDomain(input, value, partial = false) {
|
|
269
250
|
return inputValueInDomain(input.domain, value, input.domain.selection, {
|
|
270
251
|
ignoreMinimum: partial
|
|
271
252
|
});
|
|
272
253
|
}
|
|
254
|
+
function matchesBoardTarget(input, target) {
|
|
255
|
+
const domain = input.domain;
|
|
256
|
+
return domain.type === "boardTarget" && domain.valueKind === target.valueKind && (domain.targetKind === target.kind || target.kind === "space" && domain.targetKind === "tile") && domain.boardId === (target.valueKind === "board-id" ? target.boardId : target.value.boardId);
|
|
257
|
+
}
|
|
273
258
|
function immutableValues(value) {
|
|
274
259
|
return immutableCopy(value);
|
|
275
260
|
}
|
|
@@ -286,7 +271,7 @@ function data(action, interaction, input, value) {
|
|
|
286
271
|
var AmbiguousTargetError = class extends Error {
|
|
287
272
|
constructor(id) {
|
|
288
273
|
super(
|
|
289
|
-
`Target '${id}' belongs to more than one
|
|
274
|
+
`Target '${id}' belongs to more than one eligible input. Choose an interaction and input explicitly.`
|
|
290
275
|
);
|
|
291
276
|
this.name = "AmbiguousTargetError";
|
|
292
277
|
}
|
|
@@ -351,19 +336,20 @@ var InteractionObject = class {
|
|
|
351
336
|
return this.descriptor.step?.index ?? null;
|
|
352
337
|
}
|
|
353
338
|
getInput(key) {
|
|
339
|
+
return requireLookup(
|
|
340
|
+
this.findInput(key),
|
|
341
|
+
`Input in interaction ${this.key}`,
|
|
342
|
+
key
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
findInput(key) {
|
|
354
346
|
return this.inputObjects.find((input) => input.key === key);
|
|
355
347
|
}
|
|
356
348
|
getInputs() {
|
|
357
349
|
return this.inputObjects;
|
|
358
350
|
}
|
|
359
351
|
readiness() {
|
|
360
|
-
|
|
361
|
-
return {
|
|
362
|
-
...readiness,
|
|
363
|
-
ready: readiness.ready && this.descriptor.inputs.every(
|
|
364
|
-
(input) => inDomain(input, readiness.values[input.key])
|
|
365
|
-
)
|
|
366
|
-
};
|
|
352
|
+
return getInteractionDraftReadiness(this.descriptor, this.draft);
|
|
367
353
|
}
|
|
368
354
|
getIsReady() {
|
|
369
355
|
return this.readiness().ready;
|
|
@@ -392,7 +378,7 @@ var InteractionObject = class {
|
|
|
392
378
|
getSubmitHandler() {
|
|
393
379
|
return (event) => {
|
|
394
380
|
event?.preventDefault();
|
|
395
|
-
this.owner.handle(this.submit());
|
|
381
|
+
this.owner.handle(() => this.submit());
|
|
396
382
|
};
|
|
397
383
|
}
|
|
398
384
|
getSubmitProps() {
|
|
@@ -422,6 +408,21 @@ var InputObject = class {
|
|
|
422
408
|
get game() {
|
|
423
409
|
return this.interaction.game;
|
|
424
410
|
}
|
|
411
|
+
get domainType() {
|
|
412
|
+
return this.descriptor.domain.type;
|
|
413
|
+
}
|
|
414
|
+
get selectionMode() {
|
|
415
|
+
return isManyInput(this.descriptor) ? "many" : "single";
|
|
416
|
+
}
|
|
417
|
+
getTargetOptions() {
|
|
418
|
+
const domain = this.getDomain();
|
|
419
|
+
return this.getEligibleTargets().map((value) => ({
|
|
420
|
+
value,
|
|
421
|
+
label: (domain.type === "choice" || domain.type === "choiceList" ? domain.choices.find((choice) => Object.is(choice.value, value))?.label : void 0) ?? (value === null ? "None" : typeof value === "object" ? JSON.stringify(value) : String(value)),
|
|
422
|
+
selected: this.getIsSelected(value),
|
|
423
|
+
props: this.getTargetProps(value)
|
|
424
|
+
}));
|
|
425
|
+
}
|
|
425
426
|
getDomain() {
|
|
426
427
|
return this.descriptor.domain;
|
|
427
428
|
}
|
|
@@ -443,7 +444,7 @@ var InputObject = class {
|
|
|
443
444
|
};
|
|
444
445
|
return getInteractionDraftReadiness(descriptor, {
|
|
445
446
|
[this.key]: this.getValue()
|
|
446
|
-
}).ready
|
|
447
|
+
}).ready;
|
|
447
448
|
}
|
|
448
449
|
getEligibleTargets() {
|
|
449
450
|
const domain = this.descriptor.domain;
|
|
@@ -455,11 +456,7 @@ var InputObject = class {
|
|
|
455
456
|
}
|
|
456
457
|
getIsEligible(value) {
|
|
457
458
|
const input = this.descriptor;
|
|
458
|
-
|
|
459
|
-
return inDomain(
|
|
460
|
-
{ ...input, domain: { ...input.domain, selection: void 0 } },
|
|
461
|
-
value
|
|
462
|
-
) && (!selection || selection.mode !== "many" || isManyTargetSelectable(input, this.getValue(), String(value)));
|
|
459
|
+
return inputTargetInDomain(input.domain, value) && isManyTargetSelectable(input, this.getValue(), value);
|
|
463
460
|
}
|
|
464
461
|
getIsSelected(value) {
|
|
465
462
|
const current = this.getValue();
|
|
@@ -485,28 +482,18 @@ var InputObject = class {
|
|
|
485
482
|
onClick: () => this.getSelectHandler(value)()
|
|
486
483
|
};
|
|
487
484
|
}
|
|
488
|
-
|
|
485
|
+
getControl() {
|
|
489
486
|
const disabled = !this.interaction.getIsAvailable() || this.interaction.status !== "open" || !this.interaction.connected;
|
|
490
|
-
return {
|
|
487
|
+
return createInputControl(this, {
|
|
491
488
|
...data("option", this.interaction.key, this.key),
|
|
492
489
|
"data-seat": this.interaction.seat,
|
|
493
|
-
value: this.getValue() ?? "",
|
|
494
490
|
disabled,
|
|
495
|
-
"data-disabled": disabled
|
|
496
|
-
|
|
497
|
-
if (event.currentTarget.value === "") {
|
|
498
|
-
this.clear();
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
|
-
this.setValue(
|
|
502
|
-
this.descriptor.domain.type === "boundedNumber" ? Number(event.currentTarget.value) : event.currentTarget.value
|
|
503
|
-
);
|
|
504
|
-
}
|
|
505
|
-
};
|
|
491
|
+
"data-disabled": disabled
|
|
492
|
+
});
|
|
506
493
|
}
|
|
507
494
|
};
|
|
508
495
|
var CardObject = class {
|
|
509
|
-
constructor(owner, id, zone, index, encoded, routes) {
|
|
496
|
+
constructor(owner, id, zone, index, encoded, backImage, routes) {
|
|
510
497
|
this.owner = owner;
|
|
511
498
|
this.id = id;
|
|
512
499
|
this.zone = zone;
|
|
@@ -518,6 +505,7 @@ var CardObject = class {
|
|
|
518
505
|
) ?? -1;
|
|
519
506
|
this.view = encoded ? immutableCopy(JSON.parse(encoded)) : null;
|
|
520
507
|
this.hidden = this.view === null;
|
|
508
|
+
this.backImage = backImage ?? null;
|
|
521
509
|
}
|
|
522
510
|
owner;
|
|
523
511
|
id;
|
|
@@ -528,6 +516,7 @@ var CardObject = class {
|
|
|
528
516
|
seat;
|
|
529
517
|
view;
|
|
530
518
|
hidden;
|
|
519
|
+
backImage;
|
|
531
520
|
get game() {
|
|
532
521
|
return this.owner.instance;
|
|
533
522
|
}
|
|
@@ -544,16 +533,16 @@ var CardObject = class {
|
|
|
544
533
|
)
|
|
545
534
|
);
|
|
546
535
|
}
|
|
547
|
-
getCanSelect() {
|
|
536
|
+
getCanSelect(options) {
|
|
548
537
|
return this.routes.some(
|
|
549
|
-
(route) => route.getIsAvailable() && route.status === "open" && route.connected && route.getInputs().some(
|
|
550
|
-
(input) => input.descriptor.domain.type === "cardTarget" && input.getIsEligible(this.id)
|
|
538
|
+
(route) => route.getIsAvailable() && (!options?.interaction || route.key === options.interaction) && route.status === "open" && route.connected && route.getInputs().some(
|
|
539
|
+
(input) => input.descriptor.domain.type === "cardTarget" && (!options?.input || input.key === options.input) && input.getIsEligible(this.id)
|
|
551
540
|
)
|
|
552
541
|
);
|
|
553
542
|
}
|
|
554
543
|
select(options) {
|
|
555
544
|
if (this.epoch !== this.owner.epoch || this.owner.disposed) return;
|
|
556
|
-
this.owner.selectCard(this.id, options
|
|
545
|
+
this.owner.selectCard(this.id, options);
|
|
557
546
|
}
|
|
558
547
|
getSelectHandler(options) {
|
|
559
548
|
return () => this.select(options);
|
|
@@ -561,13 +550,14 @@ var CardObject = class {
|
|
|
561
550
|
getProps(options) {
|
|
562
551
|
return {
|
|
563
552
|
type: "button",
|
|
564
|
-
disabled: !this.getCanSelect(),
|
|
553
|
+
disabled: !this.getCanSelect(options),
|
|
565
554
|
"data-action": "select",
|
|
566
555
|
"data-value": this.id,
|
|
567
556
|
"data-interaction": options?.interaction,
|
|
557
|
+
"data-input": options?.input,
|
|
568
558
|
"data-eligible": this.getIsEligible(),
|
|
569
559
|
"data-selected": this.getIsSelected(),
|
|
570
|
-
"data-disabled": !this.getCanSelect(),
|
|
560
|
+
"data-disabled": !this.getCanSelect(options),
|
|
571
561
|
"data-hidden": this.hidden,
|
|
572
562
|
"data-seat": this.seat,
|
|
573
563
|
onClick: this.getSelectHandler(options)
|
|
@@ -593,6 +583,9 @@ var ZoneObject = class {
|
|
|
593
583
|
return this.count === 0;
|
|
594
584
|
}
|
|
595
585
|
getCard(id) {
|
|
586
|
+
return requireLookup(this.findCard(id), `Card in zone ${this.id}`, id);
|
|
587
|
+
}
|
|
588
|
+
findCard(id) {
|
|
596
589
|
return this.cards.find((card) => card.id === id);
|
|
597
590
|
}
|
|
598
591
|
getCards(options) {
|
|
@@ -649,6 +642,7 @@ var Controller = class {
|
|
|
649
642
|
};
|
|
650
643
|
subscription;
|
|
651
644
|
sourceState;
|
|
645
|
+
reportedFailures = /* @__PURE__ */ new WeakMap();
|
|
652
646
|
pending = null;
|
|
653
647
|
building;
|
|
654
648
|
rootProperties = /* @__PURE__ */ new Map();
|
|
@@ -675,7 +669,60 @@ var Controller = class {
|
|
|
675
669
|
this.localDrafts = options.initialState?.drafts ?? EMPTY_DRAFTS;
|
|
676
670
|
this.localActive = options.initialState?.activeInteraction ?? null;
|
|
677
671
|
this.sourceState = options.source.store.get();
|
|
672
|
+
const current = () => this.building ?? this.store.get();
|
|
678
673
|
const root = {
|
|
674
|
+
get snapshot() {
|
|
675
|
+
return current().snapshot;
|
|
676
|
+
},
|
|
677
|
+
get view() {
|
|
678
|
+
return current().view;
|
|
679
|
+
},
|
|
680
|
+
get version() {
|
|
681
|
+
return current().version;
|
|
682
|
+
},
|
|
683
|
+
get connection() {
|
|
684
|
+
return current().connection;
|
|
685
|
+
},
|
|
686
|
+
get failure() {
|
|
687
|
+
return current().failure;
|
|
688
|
+
},
|
|
689
|
+
get request() {
|
|
690
|
+
return current().request;
|
|
691
|
+
},
|
|
692
|
+
get state() {
|
|
693
|
+
return current().state;
|
|
694
|
+
},
|
|
695
|
+
get phase() {
|
|
696
|
+
return current().phase;
|
|
697
|
+
},
|
|
698
|
+
get turn() {
|
|
699
|
+
return current().turn;
|
|
700
|
+
},
|
|
701
|
+
get me() {
|
|
702
|
+
return current().me;
|
|
703
|
+
},
|
|
704
|
+
get players() {
|
|
705
|
+
return current().players;
|
|
706
|
+
},
|
|
707
|
+
get interactions() {
|
|
708
|
+
return current().interactions;
|
|
709
|
+
},
|
|
710
|
+
get inputs() {
|
|
711
|
+
return current().inputs;
|
|
712
|
+
},
|
|
713
|
+
get zones() {
|
|
714
|
+
return current().zones;
|
|
715
|
+
},
|
|
716
|
+
get cards() {
|
|
717
|
+
return current().cards;
|
|
718
|
+
},
|
|
719
|
+
get events() {
|
|
720
|
+
return current().events;
|
|
721
|
+
},
|
|
722
|
+
store: {
|
|
723
|
+
get: () => this.store.get(),
|
|
724
|
+
subscribe: (listener) => this.store.subscribe(listener)
|
|
725
|
+
},
|
|
679
726
|
getSnapshot: () => this.building ?? this.store.get(),
|
|
680
727
|
getOptions: () => this.options,
|
|
681
728
|
setOptions: (next) => this.setOptions(next),
|
|
@@ -687,34 +734,23 @@ var Controller = class {
|
|
|
687
734
|
assertCoverage: () => this.assertCoverage(),
|
|
688
735
|
inspect: () => this.store.get()
|
|
689
736
|
};
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
"phase",
|
|
699
|
-
"turn",
|
|
700
|
-
"me",
|
|
701
|
-
"players",
|
|
702
|
-
"interactions",
|
|
703
|
-
"inputs",
|
|
704
|
-
"zones",
|
|
705
|
-
"cards",
|
|
706
|
-
"events"
|
|
707
|
-
])
|
|
708
|
-
Object.defineProperty(root, key, {
|
|
709
|
-
get: () => (this.building ?? this.store.get())[key]
|
|
710
|
-
});
|
|
711
|
-
this.store = createStore(Object.freeze(this.build()));
|
|
712
|
-
Object.defineProperty(root, "store", {
|
|
713
|
-
value: {
|
|
714
|
-
get: () => this.store.get(),
|
|
715
|
-
subscribe: (listener) => this.store.subscribe(listener)
|
|
737
|
+
for (const [key, descriptor] of Object.entries(
|
|
738
|
+
Object.getOwnPropertyDescriptors(root)
|
|
739
|
+
)) {
|
|
740
|
+
if (descriptor.get) {
|
|
741
|
+
Object.defineProperty(root, key, {
|
|
742
|
+
enumerable: false,
|
|
743
|
+
configurable: false
|
|
744
|
+
});
|
|
716
745
|
}
|
|
746
|
+
}
|
|
747
|
+
Object.defineProperty(root, "store", {
|
|
748
|
+
enumerable: false,
|
|
749
|
+
configurable: false,
|
|
750
|
+
writable: false
|
|
717
751
|
});
|
|
752
|
+
this.instance = root;
|
|
753
|
+
this.store = createStore(Object.freeze(this.build()));
|
|
718
754
|
if ("apply" in options.source)
|
|
719
755
|
Object.defineProperty(root, "apply", {
|
|
720
756
|
value: (action) => this.options.source.apply(action)
|
|
@@ -723,18 +759,24 @@ var Controller = class {
|
|
|
723
759
|
Object.defineProperty(root, "explore", {
|
|
724
760
|
value: (...args) => this.options.source.explore(...args)
|
|
725
761
|
});
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
762
|
+
const runtime = {
|
|
763
|
+
game: this.instance,
|
|
764
|
+
getBoards: () => {
|
|
765
|
+
const view = this.instance.view;
|
|
766
|
+
return view?.boards?.byId ?? {};
|
|
767
|
+
},
|
|
768
|
+
createBoard: (data2) => this.object("board", {
|
|
769
|
+
id: data2.id,
|
|
729
770
|
data: immutableCopy(data2),
|
|
730
771
|
game: this.instance
|
|
731
772
|
}),
|
|
732
|
-
routeTarget: (
|
|
773
|
+
routeTarget: (target, options2) => this.routeTarget(target, options2),
|
|
733
774
|
routeCardDrop: (cardId, target) => this.routeCardDrop(cardId, target),
|
|
734
775
|
invalidate: () => {
|
|
735
776
|
if (!this.disposed) this.refresh();
|
|
736
777
|
}
|
|
737
778
|
};
|
|
779
|
+
const context = { ...runtime, [runtimeFeatures]: runtime };
|
|
738
780
|
for (const feature of Object.values(
|
|
739
781
|
features?.(this.instance, context) ?? {}
|
|
740
782
|
)) {
|
|
@@ -762,6 +804,7 @@ var Controller = class {
|
|
|
762
804
|
}
|
|
763
805
|
this.refresh();
|
|
764
806
|
this.subscribeSource();
|
|
807
|
+
this.reportSourceFailure();
|
|
765
808
|
}
|
|
766
809
|
install(target, extension) {
|
|
767
810
|
if (!extension) return;
|
|
@@ -796,7 +839,8 @@ var Controller = class {
|
|
|
796
839
|
);
|
|
797
840
|
}
|
|
798
841
|
object(hook, value) {
|
|
799
|
-
|
|
842
|
+
Object.setPrototypeOf(value, this.prototypes[hook]);
|
|
843
|
+
return Object.freeze(value);
|
|
800
844
|
}
|
|
801
845
|
drafts() {
|
|
802
846
|
if (this.options.state && this.options.state === this.invalidControlledState)
|
|
@@ -843,7 +887,7 @@ var Controller = class {
|
|
|
843
887
|
return base;
|
|
844
888
|
}
|
|
845
889
|
current(key) {
|
|
846
|
-
return this.store.get().interactions.
|
|
890
|
+
return this.store.get().interactions.find(key);
|
|
847
891
|
}
|
|
848
892
|
editable(key) {
|
|
849
893
|
const interaction = this.current(key);
|
|
@@ -851,11 +895,11 @@ var Controller = class {
|
|
|
851
895
|
}
|
|
852
896
|
setInput(key, inputKey, value) {
|
|
853
897
|
const interaction = this.editable(key);
|
|
854
|
-
if (!interaction?.
|
|
898
|
+
if (!interaction?.findInput(inputKey)) return;
|
|
855
899
|
this.writeDraft(key, { ...this.drafts()[key], [inputKey]: value });
|
|
856
900
|
}
|
|
857
901
|
clearInput(key, inputKey) {
|
|
858
|
-
if (!this.editable(key)?.
|
|
902
|
+
if (!this.editable(key)?.findInput(inputKey)) return;
|
|
859
903
|
const value = { ...this.drafts()[key] };
|
|
860
904
|
delete value[inputKey];
|
|
861
905
|
this.writeDraft(key, value);
|
|
@@ -869,9 +913,9 @@ var Controller = class {
|
|
|
869
913
|
const interaction = route ?? this.editable(key);
|
|
870
914
|
if (route && (!route.currentLifetime() || !route.getIsAvailable() || this.sourceState.connection !== "ready" || this.sourceState.request || this.pending))
|
|
871
915
|
return;
|
|
872
|
-
const input = interaction?.
|
|
916
|
+
const input = interaction?.findInput(inputKey);
|
|
873
917
|
if (!interaction || !input?.getIsEligible(value)) return;
|
|
874
|
-
if (typeof value === "string" && (input.descriptor.domain.type === "cardTarget" || input.descriptor.domain.type === "boardTarget")) {
|
|
918
|
+
if (isManyInput(input.descriptor) || typeof value === "string" && (input.descriptor.domain.type === "cardTarget" || input.descriptor.domain.type === "boardTarget")) {
|
|
875
919
|
let next = { ...this.drafts()[key] };
|
|
876
920
|
routeInteractionTarget(
|
|
877
921
|
{
|
|
@@ -891,33 +935,45 @@ var Controller = class {
|
|
|
891
935
|
this.activate(key);
|
|
892
936
|
const current = this.current(key);
|
|
893
937
|
if (current && Object.hasOwn(this.drafts()[key] ?? EMPTY, inputKey) && shouldAutoSubmitInteraction(current.descriptor) && current.getIsReady())
|
|
894
|
-
this.handle(this.submit(key, false));
|
|
895
|
-
}
|
|
896
|
-
selectCard(id,
|
|
897
|
-
const card = this.store.get().cards.
|
|
898
|
-
if (!card)
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
)
|
|
910
|
-
|
|
938
|
+
this.handle(() => this.submit(key, false));
|
|
939
|
+
}
|
|
940
|
+
selectCard(id, options) {
|
|
941
|
+
const card = this.store.get().cards.find(id);
|
|
942
|
+
if (!card || this.sourceState.request || this.sourceState.connection !== "ready")
|
|
943
|
+
return;
|
|
944
|
+
const candidates = card.routes.flatMap((interaction) => {
|
|
945
|
+
if (!interaction.getIsAvailable() || !interaction.currentLifetime() || options?.interaction && interaction.key !== options.interaction)
|
|
946
|
+
return [];
|
|
947
|
+
return interaction.getInputs().filter(
|
|
948
|
+
(input) => input.descriptor.domain.type === "cardTarget" && (!options?.input || input.key === options.input) && input.getIsEligible(id)
|
|
949
|
+
).map((input) => ({ interaction, input }));
|
|
950
|
+
});
|
|
951
|
+
if (candidates.length > 1) throw new AmbiguousTargetError(id);
|
|
952
|
+
const candidate = candidates[0];
|
|
953
|
+
if (candidate)
|
|
954
|
+
this.select(
|
|
955
|
+
candidate.interaction.key,
|
|
956
|
+
candidate.input.key,
|
|
957
|
+
id,
|
|
958
|
+
candidate.interaction
|
|
959
|
+
);
|
|
911
960
|
}
|
|
912
|
-
handle(
|
|
913
|
-
|
|
961
|
+
handle(submit) {
|
|
962
|
+
const source = this.options.source;
|
|
963
|
+
const active = () => !this.disposed && this.options.source === source;
|
|
964
|
+
void submit().then(
|
|
914
965
|
(result) => {
|
|
915
|
-
if (!result.accepted)
|
|
966
|
+
if (active() && !result.accepted)
|
|
916
967
|
this.options.onError?.(
|
|
917
968
|
new Error(result.message ?? result.errorCode, { cause: result })
|
|
918
969
|
);
|
|
919
970
|
},
|
|
920
|
-
(error) =>
|
|
971
|
+
(error) => {
|
|
972
|
+
if (!active()) return;
|
|
973
|
+
const state = source.store.get();
|
|
974
|
+
if (state.failure === error || state.connection === "closed") return;
|
|
975
|
+
this.options.onError?.(error);
|
|
976
|
+
}
|
|
921
977
|
);
|
|
922
978
|
}
|
|
923
979
|
async submit(key, cancel) {
|
|
@@ -968,7 +1024,7 @@ var Controller = class {
|
|
|
968
1024
|
const operation = this.pending;
|
|
969
1025
|
if (!operation?.accepted || this.sourceState.request || operation.source !== this.options.source || operation.epoch !== this.epoch)
|
|
970
1026
|
return;
|
|
971
|
-
if (this.sourceState.connection === "closed") {
|
|
1027
|
+
if (this.sourceState.connection === "closed" || this.sourceState.connection === "failed") {
|
|
972
1028
|
this.pending = null;
|
|
973
1029
|
this.refresh();
|
|
974
1030
|
return;
|
|
@@ -980,6 +1036,13 @@ var Controller = class {
|
|
|
980
1036
|
this.reset(operation.key);
|
|
981
1037
|
else this.refresh();
|
|
982
1038
|
}
|
|
1039
|
+
reportSourceFailure() {
|
|
1040
|
+
const failure = this.sourceState.failure;
|
|
1041
|
+
if (!failure || !this.options.onError || this.reportedFailures.get(this.options.source) === failure)
|
|
1042
|
+
return;
|
|
1043
|
+
this.reportedFailures.set(this.options.source, failure);
|
|
1044
|
+
this.options.onError?.(failure);
|
|
1045
|
+
}
|
|
983
1046
|
subscribeSource() {
|
|
984
1047
|
const source = this.options.source;
|
|
985
1048
|
this.subscription = source.store.subscribe(() => {
|
|
@@ -999,6 +1062,7 @@ var Controller = class {
|
|
|
999
1062
|
this.reconcile();
|
|
1000
1063
|
this.refresh();
|
|
1001
1064
|
this.finishBarrier();
|
|
1065
|
+
this.reportSourceFailure();
|
|
1002
1066
|
});
|
|
1003
1067
|
}
|
|
1004
1068
|
setOptions(next) {
|
|
@@ -1022,6 +1086,7 @@ var Controller = class {
|
|
|
1022
1086
|
}
|
|
1023
1087
|
this.reconcile();
|
|
1024
1088
|
this.refresh();
|
|
1089
|
+
this.reportSourceFailure();
|
|
1025
1090
|
}
|
|
1026
1091
|
reconcile() {
|
|
1027
1092
|
const snapshot = this.sourceState.snapshot;
|
|
@@ -1047,11 +1112,12 @@ var Controller = class {
|
|
|
1047
1112
|
for (const [name, value] of Object.entries(values)) {
|
|
1048
1113
|
const input = descriptor.inputs.find((input2) => input2.key === name);
|
|
1049
1114
|
if (!input && this.pending?.key === key) continue;
|
|
1050
|
-
|
|
1115
|
+
const selection = input && inputSelection(input);
|
|
1116
|
+
if (input && selection?.mode === "many" && Array.isArray(value)) {
|
|
1051
1117
|
const eligible = value.filter(
|
|
1052
|
-
(item) =>
|
|
1118
|
+
(item) => inputTargetInDomain(input.domain, item)
|
|
1053
1119
|
);
|
|
1054
|
-
const max =
|
|
1120
|
+
const max = selection.max;
|
|
1055
1121
|
const retained = max === void 0 ? eligible : eligible.slice(0, max);
|
|
1056
1122
|
if (retained.length !== value.length) {
|
|
1057
1123
|
kept[name] = retained;
|
|
@@ -1082,11 +1148,7 @@ var Controller = class {
|
|
|
1082
1148
|
this.subscription?.unsubscribe();
|
|
1083
1149
|
this.pending = null;
|
|
1084
1150
|
this.options.source.dispose();
|
|
1085
|
-
this.sourceState =
|
|
1086
|
-
...this.sourceState,
|
|
1087
|
-
connection: "closed",
|
|
1088
|
-
request: null
|
|
1089
|
-
};
|
|
1151
|
+
this.sourceState = this.options.source.store.get();
|
|
1090
1152
|
this.refresh();
|
|
1091
1153
|
}
|
|
1092
1154
|
assertCoverage() {
|
|
@@ -1096,40 +1158,35 @@ var Controller = class {
|
|
|
1096
1158
|
if (missing.length)
|
|
1097
1159
|
throw new Error(`Interactions not read: ${missing.join(", ")}`);
|
|
1098
1160
|
}
|
|
1099
|
-
routeTarget(
|
|
1100
|
-
if (kind === "card") {
|
|
1101
|
-
this.selectCard(
|
|
1161
|
+
routeTarget(target, options) {
|
|
1162
|
+
if (target.kind === "card") {
|
|
1163
|
+
this.selectCard(target.value, options);
|
|
1102
1164
|
return;
|
|
1103
1165
|
}
|
|
1104
1166
|
const candidates = this.lastInteractions.flatMap(
|
|
1105
1167
|
(interaction) => interaction.getInputs().filter(
|
|
1106
|
-
(input) => input.descriptor
|
|
1168
|
+
(input) => matchesBoardTarget(input.descriptor, target) && input.getIsEligible(target.value) && interaction.getIsAvailable() && (!options?.interaction || interaction.key === options.interaction) && (!options?.input || input.key === options.input)
|
|
1107
1169
|
).map((input) => ({ interaction, input }))
|
|
1108
1170
|
);
|
|
1109
|
-
if (candidates.length > 1)
|
|
1171
|
+
if (candidates.length > 1)
|
|
1172
|
+
throw new AmbiguousTargetError(JSON.stringify(target.value));
|
|
1110
1173
|
const match = candidates[0];
|
|
1111
|
-
if (match)
|
|
1174
|
+
if (match)
|
|
1175
|
+
this.select(match.interaction.key, match.input.key, target.value);
|
|
1112
1176
|
}
|
|
1113
1177
|
routeCardDrop(cardId, target) {
|
|
1114
1178
|
if (this.disposed || this.sourceState.request || this.pending || this.sourceState.connection !== "ready")
|
|
1115
1179
|
return;
|
|
1116
|
-
const card = this.store.get().cards.
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
return
|
|
1126
|
-
(input2) => input2.descriptor.domain.type === "boardTarget" && (input2.descriptor.domain.targetKind === target.kind || target.kind === "space" && input2.descriptor.domain.targetKind === "tile") && (!target.boardId || input2.descriptor.domain.boardId === target.boardId) && input2.getIsEligible(target.id)
|
|
1127
|
-
).map((input2) => ({ interaction: interaction2, cardInput: cardInput2, input: input2 }));
|
|
1128
|
-
});
|
|
1129
|
-
if (candidates.length > 1) throw new AmbiguousTargetError(target.id);
|
|
1130
|
-
const candidate = candidates[0];
|
|
1131
|
-
if (!candidate) return;
|
|
1132
|
-
const { interaction, cardInput, input } = candidate;
|
|
1180
|
+
const card = this.store.get().cards.find(cardId);
|
|
1181
|
+
const interaction = card?.routes.find(
|
|
1182
|
+
(route) => route.key === target.interactionKey
|
|
1183
|
+
);
|
|
1184
|
+
if (!interaction?.currentLifetime() || !interaction.getIsAvailable())
|
|
1185
|
+
return;
|
|
1186
|
+
const cardInput = interaction.findInput(target.cardInputKey);
|
|
1187
|
+
const input = interaction.findInput(target.inputKey);
|
|
1188
|
+
if (!cardInput || cardInput.descriptor.domain.type !== "cardTarget" || !cardInput.getIsEligible(cardId) || !input || !matchesBoardTarget(input.descriptor, target) || !input.getIsEligible(target.value))
|
|
1189
|
+
return;
|
|
1133
1190
|
let next = { ...this.drafts()[interaction.key] };
|
|
1134
1191
|
routeCardInputIntent(
|
|
1135
1192
|
{
|
|
@@ -1145,14 +1202,14 @@ var Controller = class {
|
|
|
1145
1202
|
{
|
|
1146
1203
|
cardId,
|
|
1147
1204
|
cardInputKey: cardInput.key,
|
|
1148
|
-
dropTarget: { inputKey: input.key, value: target.
|
|
1205
|
+
dropTarget: { inputKey: input.key, value: target.value }
|
|
1149
1206
|
}
|
|
1150
1207
|
);
|
|
1151
1208
|
this.writeDraft(interaction.key, next);
|
|
1152
1209
|
this.activate(interaction.key);
|
|
1153
1210
|
const current = this.current(interaction.key);
|
|
1154
1211
|
if (current && shouldAutoSubmitInteraction(current.descriptor) && current.getIsReady())
|
|
1155
|
-
this.handle(current.submit());
|
|
1212
|
+
this.handle(() => current.submit());
|
|
1156
1213
|
}
|
|
1157
1214
|
warnUnread() {
|
|
1158
1215
|
const environment = import.meta.env?.DEV ?? globalThis.process?.env?.NODE_ENV === "development";
|
|
@@ -1170,7 +1227,7 @@ var Controller = class {
|
|
|
1170
1227
|
}
|
|
1171
1228
|
build(previous) {
|
|
1172
1229
|
this.trackDrafts();
|
|
1173
|
-
const { snapshot, connection, request } = this.sourceState;
|
|
1230
|
+
const { snapshot, connection, request, failure } = this.sourceState;
|
|
1174
1231
|
const old = previous?.snapshot;
|
|
1175
1232
|
const drafts = this.drafts();
|
|
1176
1233
|
const active = this.active();
|
|
@@ -1193,11 +1250,20 @@ var Controller = class {
|
|
|
1193
1250
|
);
|
|
1194
1251
|
const players = sameActors && previous ? previous.players : {
|
|
1195
1252
|
order: Object.freeze(playerObjects.map((p) => p.id)),
|
|
1196
|
-
get: (id) =>
|
|
1253
|
+
get: (id) => requireLookup(
|
|
1254
|
+
playerObjects.find((p) => p.id === id),
|
|
1255
|
+
"Player",
|
|
1256
|
+
id
|
|
1257
|
+
),
|
|
1258
|
+
find: (id) => playerObjects.find((p) => p.id === id),
|
|
1197
1259
|
getAll: () => playerObjects,
|
|
1198
1260
|
next: (id) => {
|
|
1199
1261
|
const index = playerObjects.findIndex((p) => p.id === id);
|
|
1200
|
-
return
|
|
1262
|
+
return requireLookup(
|
|
1263
|
+
index < 0 ? void 0 : playerObjects[(index + 1) % playerObjects.length],
|
|
1264
|
+
"Next player after",
|
|
1265
|
+
id
|
|
1266
|
+
);
|
|
1201
1267
|
}
|
|
1202
1268
|
};
|
|
1203
1269
|
const me = sameActors && previous ? previous.me : snapshot ? {
|
|
@@ -1233,6 +1299,14 @@ var Controller = class {
|
|
|
1233
1299
|
this.lastInteractions = Object.freeze(interactionObjects);
|
|
1234
1300
|
const interactions = interactionsSame ? previous.interactions : {
|
|
1235
1301
|
get: (key) => {
|
|
1302
|
+
this.observed.add(key);
|
|
1303
|
+
return requireLookup(
|
|
1304
|
+
interactionObjects.find((value) => value.key === key),
|
|
1305
|
+
"Interaction",
|
|
1306
|
+
key
|
|
1307
|
+
);
|
|
1308
|
+
},
|
|
1309
|
+
find: (key) => {
|
|
1236
1310
|
this.observed.add(key);
|
|
1237
1311
|
return interactionObjects.find((value) => value.key === key);
|
|
1238
1312
|
},
|
|
@@ -1249,7 +1323,12 @@ var Controller = class {
|
|
|
1249
1323
|
}
|
|
1250
1324
|
};
|
|
1251
1325
|
const inputs = interactionsSame && previous ? previous.inputs : {
|
|
1252
|
-
get: (key, name) =>
|
|
1326
|
+
get: (key, name) => requireLookup(
|
|
1327
|
+
interactions.find(key)?.findInput(name),
|
|
1328
|
+
`Input in interaction ${key}`,
|
|
1329
|
+
name
|
|
1330
|
+
),
|
|
1331
|
+
find: (key, name) => interactions.find(key)?.findInput(name)
|
|
1253
1332
|
};
|
|
1254
1333
|
const zonesSame = sameSnapshot && interactionsSame && previous;
|
|
1255
1334
|
const zones = zonesSame ? previous.zones : (() => {
|
|
@@ -1269,6 +1348,7 @@ var Controller = class {
|
|
|
1269
1348
|
id,
|
|
1270
1349
|
index,
|
|
1271
1350
|
zone.cardViewsById[cardId],
|
|
1351
|
+
zone.cardBacksById[cardId],
|
|
1272
1352
|
Object.freeze(
|
|
1273
1353
|
(zone.playableByCardId[cardId] ?? []).map(
|
|
1274
1354
|
(descriptor) => this.object(
|
|
@@ -1291,12 +1371,22 @@ var Controller = class {
|
|
|
1291
1371
|
)
|
|
1292
1372
|
);
|
|
1293
1373
|
return {
|
|
1294
|
-
get: (id) =>
|
|
1374
|
+
get: (id) => requireLookup(
|
|
1375
|
+
objects.find((zone) => zone.id === id),
|
|
1376
|
+
"Zone",
|
|
1377
|
+
id
|
|
1378
|
+
),
|
|
1379
|
+
find: (id) => objects.find((zone) => zone.id === id),
|
|
1295
1380
|
getAll: () => Object.freeze(objects)
|
|
1296
1381
|
};
|
|
1297
1382
|
})();
|
|
1298
1383
|
const cards = zonesSame ? previous.cards : {
|
|
1299
|
-
get: (id) =>
|
|
1384
|
+
get: (id) => requireLookup(
|
|
1385
|
+
zones.getAll().map((zone) => zone.findCard(id)).find((card) => card !== void 0),
|
|
1386
|
+
"Card",
|
|
1387
|
+
id
|
|
1388
|
+
),
|
|
1389
|
+
find: (id) => zones.getAll().map((zone) => zone.findCard(id)).find((card) => card !== void 0)
|
|
1300
1390
|
};
|
|
1301
1391
|
const capturedState = this.lastSnapshotDrafts === drafts && previous?.state.activeInteraction === active ? previous.state : immutableCopy({ drafts, activeInteraction: active });
|
|
1302
1392
|
this.lastSnapshotDrafts = drafts;
|
|
@@ -1308,6 +1398,7 @@ var Controller = class {
|
|
|
1308
1398
|
version: snapshot?.version ?? null,
|
|
1309
1399
|
connection,
|
|
1310
1400
|
request,
|
|
1401
|
+
failure,
|
|
1311
1402
|
state: capturedState,
|
|
1312
1403
|
phase: sameSnapshot && previous ? previous.phase : Object.freeze(
|
|
1313
1404
|
new PhaseObject(snapshot?.frame.flow.currentPhase ?? null)
|
|
@@ -1357,7 +1448,8 @@ function createGameInstance() {
|
|
|
1357
1448
|
}
|
|
1358
1449
|
|
|
1359
1450
|
export {
|
|
1451
|
+
runtimeFeatures,
|
|
1360
1452
|
AmbiguousTargetError,
|
|
1361
1453
|
createGameInstance
|
|
1362
1454
|
};
|
|
1363
|
-
//# sourceMappingURL=chunk-
|
|
1455
|
+
//# sourceMappingURL=chunk-7RGMPJQG.js.map
|