@dreamboard-games/sdk 0.5.0-alpha.3 → 0.5.0-alpha.4
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 +52 -2
- 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-LRILEVKC.js → chunk-C77SYIVT.js} +82 -109
- package/dist/chunk-C77SYIVT.js.map +1 -0
- package/dist/{chunk-SP234IY4.js → chunk-OOFMBCFF.js} +178 -203
- package/dist/chunk-OOFMBCFF.js.map +1 -0
- package/dist/{chunk-ZPRKWPEP.js → chunk-UG2Q4NLG.js} +108 -29
- package/dist/chunk-UG2Q4NLG.js.map +1 -0
- package/dist/{chunk-FMM5LVJW.js → chunk-XU6WJW6K.js} +26 -12
- package/dist/chunk-XU6WJW6K.js.map +1 -0
- package/dist/{diagnostics-B0lgnuZ6.d.ts → diagnostics-B8d5aLad.d.ts} +2 -2
- package/dist/{definition-BaHNPZol.d.ts → extract-gVKcB8Og.d.ts} +484 -387
- package/dist/index.d.ts +404 -175
- package/dist/index.js +266 -215
- package/dist/index.js.map +1 -1
- package/dist/model-vdpLHrxh.d.ts +432 -0
- package/dist/react.d.ts +35 -7
- package/dist/react.js +136 -8
- package/dist/react.js.map +1 -1
- package/dist/reducer.d.ts +169 -118
- package/dist/reducer.js +206 -328
- package/dist/reducer.js.map +1 -1
- package/dist/testing.d.ts +5 -3
- package/dist/testing.js +9 -6
- package/dist/testing.js.map +1 -1
- package/dist/{types-DimqnJBq.d.ts → types-Bj5ZLTUV.d.ts} +38 -10
- package/package.json +19 -16
- 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,12 @@ 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";
|
|
7
11
|
|
|
8
12
|
// src/headless/instance.ts
|
|
9
13
|
import { createStore } from "@tanstack/store";
|
|
@@ -30,68 +34,13 @@ function validateInteractionInputDomains(descriptor, params) {
|
|
|
30
34
|
for (const rawInput of descriptor.inputs) {
|
|
31
35
|
const input = rawInput;
|
|
32
36
|
const value = params[input.key];
|
|
33
|
-
if (value === void 0
|
|
34
|
-
const
|
|
35
|
-
|
|
37
|
+
if (value === void 0) continue;
|
|
38
|
+
for (const error of inputDomainErrors(
|
|
39
|
+
input.domain,
|
|
40
|
+
value,
|
|
41
|
+
input.domain.selection
|
|
42
|
+
))
|
|
36
43
|
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
44
|
}
|
|
96
45
|
return fieldErrors;
|
|
97
46
|
}
|
|
@@ -110,10 +59,10 @@ function isManyInput(input) {
|
|
|
110
59
|
}
|
|
111
60
|
function toggleManyValue(current, value, selection) {
|
|
112
61
|
if (selection.mode !== "many") return [value];
|
|
113
|
-
const previous = Array.isArray(current) ? current
|
|
114
|
-
const existing = previous.
|
|
62
|
+
const previous = Array.isArray(current) ? current : [];
|
|
63
|
+
const existing = previous.findIndex((item) => sameValue(item, value));
|
|
115
64
|
if (existing >= 0) {
|
|
116
|
-
return previous.filter((item) => item
|
|
65
|
+
return previous.filter((item) => !sameValue(item, value));
|
|
117
66
|
}
|
|
118
67
|
if (selection.max !== void 0 && previous.length >= selection.max) {
|
|
119
68
|
return previous;
|
|
@@ -123,9 +72,8 @@ function toggleManyValue(current, value, selection) {
|
|
|
123
72
|
function isManyTargetSelectable(input, current, targetId) {
|
|
124
73
|
const selection = inputSelection(input);
|
|
125
74
|
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;
|
|
75
|
+
const currentValues = Array.isArray(current) ? current : [];
|
|
76
|
+
if (currentValues.some((item) => sameValue(item, targetId))) return true;
|
|
129
77
|
return selection.max === void 0 || currentValues.length < selection.max;
|
|
130
78
|
}
|
|
131
79
|
function hasInteractionFieldErrors(fieldErrors) {
|
|
@@ -136,52 +84,21 @@ function hasInteractionFieldErrors(fieldErrors) {
|
|
|
136
84
|
function inputByKey(descriptor, key) {
|
|
137
85
|
return descriptor.inputs.find((input) => input.key === key);
|
|
138
86
|
}
|
|
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
87
|
function inputSelection(input) {
|
|
178
|
-
|
|
88
|
+
if (input.domain.selection) return input.domain.selection;
|
|
89
|
+
if (input.domain.type === "choiceList")
|
|
90
|
+
return {
|
|
91
|
+
mode: "many",
|
|
92
|
+
min: input.domain.min ?? 0,
|
|
93
|
+
max: input.domain.max ?? input.domain.choices.length
|
|
94
|
+
};
|
|
95
|
+
return void 0;
|
|
179
96
|
}
|
|
180
97
|
function pushFieldError(fieldErrors, key, message) {
|
|
181
98
|
fieldErrors[key] = [...fieldErrors[key] ?? [], message];
|
|
182
99
|
}
|
|
183
|
-
function
|
|
184
|
-
return
|
|
100
|
+
function sameValue(left, right) {
|
|
101
|
+
return inputValueKey(left) === inputValueKey(right);
|
|
185
102
|
}
|
|
186
103
|
|
|
187
104
|
// src/headless/interaction-router.ts
|
|
@@ -236,8 +153,12 @@ function getInteractionDraftReadiness(descriptor, draft) {
|
|
|
236
153
|
function routeInteractionTarget(store, descriptor, target) {
|
|
237
154
|
const input = inputByKey(descriptor, target.inputKey);
|
|
238
155
|
const currentDraft = store.getDraft(descriptor.interactionKey);
|
|
239
|
-
const selection =
|
|
240
|
-
const targetValue = selection?.mode === "many" ? toggleManyValue(
|
|
156
|
+
const selection = input ? inputSelection(input) : void 0;
|
|
157
|
+
const targetValue = selection?.mode === "many" ? toggleManyValue(
|
|
158
|
+
currentDraft[target.inputKey] ?? input?.defaultValue,
|
|
159
|
+
target.value,
|
|
160
|
+
selection
|
|
161
|
+
) : target.value;
|
|
241
162
|
const params = applyInteractionDraftMutation(store, descriptor, [
|
|
242
163
|
...Object.entries(target.extraInputs ?? {}).map(([key, value]) => ({
|
|
243
164
|
key,
|
|
@@ -258,18 +179,22 @@ function routeCardInputIntent(store, descriptor, intent) {
|
|
|
258
179
|
});
|
|
259
180
|
}
|
|
260
181
|
function shouldAutoSubmitInteraction(descriptor) {
|
|
261
|
-
return descriptor.commit.mode === "autoWhenReady" && !descriptor.inputs.some((input) =>
|
|
182
|
+
return descriptor.commit.mode === "autoWhenReady" && !descriptor.inputs.some((input) => input.domain.selection?.mode === "many");
|
|
262
183
|
}
|
|
263
184
|
|
|
264
185
|
// src/headless/instance.ts
|
|
265
186
|
var EMPTY = Object.freeze({});
|
|
266
187
|
var EMPTY_DRAFTS = Object.freeze({});
|
|
267
|
-
var equalValue = (a, b) => Object.is(a, b) || typeof a === "object" && typeof b === "object" &&
|
|
188
|
+
var equalValue = (a, b) => Object.is(a, b) || typeof a === "object" && typeof b === "object" && inputValueKey(a) === inputValueKey(b);
|
|
268
189
|
function inDomain(input, value, partial = false) {
|
|
269
190
|
return inputValueInDomain(input.domain, value, input.domain.selection, {
|
|
270
191
|
ignoreMinimum: partial
|
|
271
192
|
});
|
|
272
193
|
}
|
|
194
|
+
function matchesBoardTarget(input, target) {
|
|
195
|
+
const domain = input.domain;
|
|
196
|
+
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);
|
|
197
|
+
}
|
|
273
198
|
function immutableValues(value) {
|
|
274
199
|
return immutableCopy(value);
|
|
275
200
|
}
|
|
@@ -286,7 +211,7 @@ function data(action, interaction, input, value) {
|
|
|
286
211
|
var AmbiguousTargetError = class extends Error {
|
|
287
212
|
constructor(id) {
|
|
288
213
|
super(
|
|
289
|
-
`Target '${id}' belongs to more than one
|
|
214
|
+
`Target '${id}' belongs to more than one eligible input. Choose an interaction and input explicitly.`
|
|
290
215
|
);
|
|
291
216
|
this.name = "AmbiguousTargetError";
|
|
292
217
|
}
|
|
@@ -351,19 +276,20 @@ var InteractionObject = class {
|
|
|
351
276
|
return this.descriptor.step?.index ?? null;
|
|
352
277
|
}
|
|
353
278
|
getInput(key) {
|
|
279
|
+
return requireLookup(
|
|
280
|
+
this.findInput(key),
|
|
281
|
+
`Input in interaction ${this.key}`,
|
|
282
|
+
key
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
findInput(key) {
|
|
354
286
|
return this.inputObjects.find((input) => input.key === key);
|
|
355
287
|
}
|
|
356
288
|
getInputs() {
|
|
357
289
|
return this.inputObjects;
|
|
358
290
|
}
|
|
359
291
|
readiness() {
|
|
360
|
-
|
|
361
|
-
return {
|
|
362
|
-
...readiness,
|
|
363
|
-
ready: readiness.ready && this.descriptor.inputs.every(
|
|
364
|
-
(input) => inDomain(input, readiness.values[input.key])
|
|
365
|
-
)
|
|
366
|
-
};
|
|
292
|
+
return getInteractionDraftReadiness(this.descriptor, this.draft);
|
|
367
293
|
}
|
|
368
294
|
getIsReady() {
|
|
369
295
|
return this.readiness().ready;
|
|
@@ -392,7 +318,7 @@ var InteractionObject = class {
|
|
|
392
318
|
getSubmitHandler() {
|
|
393
319
|
return (event) => {
|
|
394
320
|
event?.preventDefault();
|
|
395
|
-
this.owner.handle(this.submit());
|
|
321
|
+
this.owner.handle(() => this.submit());
|
|
396
322
|
};
|
|
397
323
|
}
|
|
398
324
|
getSubmitProps() {
|
|
@@ -443,7 +369,7 @@ var InputObject = class {
|
|
|
443
369
|
};
|
|
444
370
|
return getInteractionDraftReadiness(descriptor, {
|
|
445
371
|
[this.key]: this.getValue()
|
|
446
|
-
}).ready
|
|
372
|
+
}).ready;
|
|
447
373
|
}
|
|
448
374
|
getEligibleTargets() {
|
|
449
375
|
const domain = this.descriptor.domain;
|
|
@@ -455,11 +381,7 @@ var InputObject = class {
|
|
|
455
381
|
}
|
|
456
382
|
getIsEligible(value) {
|
|
457
383
|
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)));
|
|
384
|
+
return inputTargetInDomain(input.domain, value) && isManyTargetSelectable(input, this.getValue(), value);
|
|
463
385
|
}
|
|
464
386
|
getIsSelected(value) {
|
|
465
387
|
const current = this.getValue();
|
|
@@ -544,16 +466,16 @@ var CardObject = class {
|
|
|
544
466
|
)
|
|
545
467
|
);
|
|
546
468
|
}
|
|
547
|
-
getCanSelect() {
|
|
469
|
+
getCanSelect(options) {
|
|
548
470
|
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)
|
|
471
|
+
(route) => route.getIsAvailable() && (!options?.interaction || route.key === options.interaction) && route.status === "open" && route.connected && route.getInputs().some(
|
|
472
|
+
(input) => input.descriptor.domain.type === "cardTarget" && (!options?.input || input.key === options.input) && input.getIsEligible(this.id)
|
|
551
473
|
)
|
|
552
474
|
);
|
|
553
475
|
}
|
|
554
476
|
select(options) {
|
|
555
477
|
if (this.epoch !== this.owner.epoch || this.owner.disposed) return;
|
|
556
|
-
this.owner.selectCard(this.id, options
|
|
478
|
+
this.owner.selectCard(this.id, options);
|
|
557
479
|
}
|
|
558
480
|
getSelectHandler(options) {
|
|
559
481
|
return () => this.select(options);
|
|
@@ -561,13 +483,14 @@ var CardObject = class {
|
|
|
561
483
|
getProps(options) {
|
|
562
484
|
return {
|
|
563
485
|
type: "button",
|
|
564
|
-
disabled: !this.getCanSelect(),
|
|
486
|
+
disabled: !this.getCanSelect(options),
|
|
565
487
|
"data-action": "select",
|
|
566
488
|
"data-value": this.id,
|
|
567
489
|
"data-interaction": options?.interaction,
|
|
490
|
+
"data-input": options?.input,
|
|
568
491
|
"data-eligible": this.getIsEligible(),
|
|
569
492
|
"data-selected": this.getIsSelected(),
|
|
570
|
-
"data-disabled": !this.getCanSelect(),
|
|
493
|
+
"data-disabled": !this.getCanSelect(options),
|
|
571
494
|
"data-hidden": this.hidden,
|
|
572
495
|
"data-seat": this.seat,
|
|
573
496
|
onClick: this.getSelectHandler(options)
|
|
@@ -593,6 +516,9 @@ var ZoneObject = class {
|
|
|
593
516
|
return this.count === 0;
|
|
594
517
|
}
|
|
595
518
|
getCard(id) {
|
|
519
|
+
return requireLookup(this.findCard(id), `Card in zone ${this.id}`, id);
|
|
520
|
+
}
|
|
521
|
+
findCard(id) {
|
|
596
522
|
return this.cards.find((card) => card.id === id);
|
|
597
523
|
}
|
|
598
524
|
getCards(options) {
|
|
@@ -649,6 +575,7 @@ var Controller = class {
|
|
|
649
575
|
};
|
|
650
576
|
subscription;
|
|
651
577
|
sourceState;
|
|
578
|
+
reportedFailures = /* @__PURE__ */ new WeakMap();
|
|
652
579
|
pending = null;
|
|
653
580
|
building;
|
|
654
581
|
rootProperties = /* @__PURE__ */ new Map();
|
|
@@ -693,6 +620,7 @@ var Controller = class {
|
|
|
693
620
|
"view",
|
|
694
621
|
"version",
|
|
695
622
|
"connection",
|
|
623
|
+
"failure",
|
|
696
624
|
"request",
|
|
697
625
|
"state",
|
|
698
626
|
"phase",
|
|
@@ -729,7 +657,7 @@ var Controller = class {
|
|
|
729
657
|
data: immutableCopy(data2),
|
|
730
658
|
game: this.instance
|
|
731
659
|
}),
|
|
732
|
-
routeTarget: (
|
|
660
|
+
routeTarget: (target, options2) => this.routeTarget(target, options2),
|
|
733
661
|
routeCardDrop: (cardId, target) => this.routeCardDrop(cardId, target),
|
|
734
662
|
invalidate: () => {
|
|
735
663
|
if (!this.disposed) this.refresh();
|
|
@@ -762,6 +690,7 @@ var Controller = class {
|
|
|
762
690
|
}
|
|
763
691
|
this.refresh();
|
|
764
692
|
this.subscribeSource();
|
|
693
|
+
this.reportSourceFailure();
|
|
765
694
|
}
|
|
766
695
|
install(target, extension) {
|
|
767
696
|
if (!extension) return;
|
|
@@ -843,7 +772,7 @@ var Controller = class {
|
|
|
843
772
|
return base;
|
|
844
773
|
}
|
|
845
774
|
current(key) {
|
|
846
|
-
return this.store.get().interactions.
|
|
775
|
+
return this.store.get().interactions.find(key);
|
|
847
776
|
}
|
|
848
777
|
editable(key) {
|
|
849
778
|
const interaction = this.current(key);
|
|
@@ -851,11 +780,11 @@ var Controller = class {
|
|
|
851
780
|
}
|
|
852
781
|
setInput(key, inputKey, value) {
|
|
853
782
|
const interaction = this.editable(key);
|
|
854
|
-
if (!interaction?.
|
|
783
|
+
if (!interaction?.findInput(inputKey)) return;
|
|
855
784
|
this.writeDraft(key, { ...this.drafts()[key], [inputKey]: value });
|
|
856
785
|
}
|
|
857
786
|
clearInput(key, inputKey) {
|
|
858
|
-
if (!this.editable(key)?.
|
|
787
|
+
if (!this.editable(key)?.findInput(inputKey)) return;
|
|
859
788
|
const value = { ...this.drafts()[key] };
|
|
860
789
|
delete value[inputKey];
|
|
861
790
|
this.writeDraft(key, value);
|
|
@@ -869,9 +798,9 @@ var Controller = class {
|
|
|
869
798
|
const interaction = route ?? this.editable(key);
|
|
870
799
|
if (route && (!route.currentLifetime() || !route.getIsAvailable() || this.sourceState.connection !== "ready" || this.sourceState.request || this.pending))
|
|
871
800
|
return;
|
|
872
|
-
const input = interaction?.
|
|
801
|
+
const input = interaction?.findInput(inputKey);
|
|
873
802
|
if (!interaction || !input?.getIsEligible(value)) return;
|
|
874
|
-
if (typeof value === "string" && (input.descriptor.domain.type === "cardTarget" || input.descriptor.domain.type === "boardTarget")) {
|
|
803
|
+
if (isManyInput(input.descriptor) || typeof value === "string" && (input.descriptor.domain.type === "cardTarget" || input.descriptor.domain.type === "boardTarget")) {
|
|
875
804
|
let next = { ...this.drafts()[key] };
|
|
876
805
|
routeInteractionTarget(
|
|
877
806
|
{
|
|
@@ -891,33 +820,45 @@ var Controller = class {
|
|
|
891
820
|
this.activate(key);
|
|
892
821
|
const current = this.current(key);
|
|
893
822
|
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
|
-
|
|
823
|
+
this.handle(() => this.submit(key, false));
|
|
824
|
+
}
|
|
825
|
+
selectCard(id, options) {
|
|
826
|
+
const card = this.store.get().cards.find(id);
|
|
827
|
+
if (!card || this.sourceState.request || this.sourceState.connection !== "ready")
|
|
828
|
+
return;
|
|
829
|
+
const candidates = card.routes.flatMap((interaction) => {
|
|
830
|
+
if (!interaction.getIsAvailable() || !interaction.currentLifetime() || options?.interaction && interaction.key !== options.interaction)
|
|
831
|
+
return [];
|
|
832
|
+
return interaction.getInputs().filter(
|
|
833
|
+
(input) => input.descriptor.domain.type === "cardTarget" && (!options?.input || input.key === options.input) && input.getIsEligible(id)
|
|
834
|
+
).map((input) => ({ interaction, input }));
|
|
835
|
+
});
|
|
836
|
+
if (candidates.length > 1) throw new AmbiguousTargetError(id);
|
|
837
|
+
const candidate = candidates[0];
|
|
838
|
+
if (candidate)
|
|
839
|
+
this.select(
|
|
840
|
+
candidate.interaction.key,
|
|
841
|
+
candidate.input.key,
|
|
842
|
+
id,
|
|
843
|
+
candidate.interaction
|
|
844
|
+
);
|
|
911
845
|
}
|
|
912
|
-
handle(
|
|
913
|
-
|
|
846
|
+
handle(submit) {
|
|
847
|
+
const source = this.options.source;
|
|
848
|
+
const active = () => !this.disposed && this.options.source === source;
|
|
849
|
+
void submit().then(
|
|
914
850
|
(result) => {
|
|
915
|
-
if (!result.accepted)
|
|
851
|
+
if (active() && !result.accepted)
|
|
916
852
|
this.options.onError?.(
|
|
917
853
|
new Error(result.message ?? result.errorCode, { cause: result })
|
|
918
854
|
);
|
|
919
855
|
},
|
|
920
|
-
(error) =>
|
|
856
|
+
(error) => {
|
|
857
|
+
if (!active()) return;
|
|
858
|
+
const state = source.store.get();
|
|
859
|
+
if (state.failure === error || state.connection === "closed") return;
|
|
860
|
+
this.options.onError?.(error);
|
|
861
|
+
}
|
|
921
862
|
);
|
|
922
863
|
}
|
|
923
864
|
async submit(key, cancel) {
|
|
@@ -968,7 +909,7 @@ var Controller = class {
|
|
|
968
909
|
const operation = this.pending;
|
|
969
910
|
if (!operation?.accepted || this.sourceState.request || operation.source !== this.options.source || operation.epoch !== this.epoch)
|
|
970
911
|
return;
|
|
971
|
-
if (this.sourceState.connection === "closed") {
|
|
912
|
+
if (this.sourceState.connection === "closed" || this.sourceState.connection === "failed") {
|
|
972
913
|
this.pending = null;
|
|
973
914
|
this.refresh();
|
|
974
915
|
return;
|
|
@@ -980,6 +921,13 @@ var Controller = class {
|
|
|
980
921
|
this.reset(operation.key);
|
|
981
922
|
else this.refresh();
|
|
982
923
|
}
|
|
924
|
+
reportSourceFailure() {
|
|
925
|
+
const failure = this.sourceState.failure;
|
|
926
|
+
if (!failure || !this.options.onError || this.reportedFailures.get(this.options.source) === failure)
|
|
927
|
+
return;
|
|
928
|
+
this.reportedFailures.set(this.options.source, failure);
|
|
929
|
+
this.options.onError?.(failure);
|
|
930
|
+
}
|
|
983
931
|
subscribeSource() {
|
|
984
932
|
const source = this.options.source;
|
|
985
933
|
this.subscription = source.store.subscribe(() => {
|
|
@@ -999,6 +947,7 @@ var Controller = class {
|
|
|
999
947
|
this.reconcile();
|
|
1000
948
|
this.refresh();
|
|
1001
949
|
this.finishBarrier();
|
|
950
|
+
this.reportSourceFailure();
|
|
1002
951
|
});
|
|
1003
952
|
}
|
|
1004
953
|
setOptions(next) {
|
|
@@ -1022,6 +971,7 @@ var Controller = class {
|
|
|
1022
971
|
}
|
|
1023
972
|
this.reconcile();
|
|
1024
973
|
this.refresh();
|
|
974
|
+
this.reportSourceFailure();
|
|
1025
975
|
}
|
|
1026
976
|
reconcile() {
|
|
1027
977
|
const snapshot = this.sourceState.snapshot;
|
|
@@ -1047,11 +997,12 @@ var Controller = class {
|
|
|
1047
997
|
for (const [name, value] of Object.entries(values)) {
|
|
1048
998
|
const input = descriptor.inputs.find((input2) => input2.key === name);
|
|
1049
999
|
if (!input && this.pending?.key === key) continue;
|
|
1050
|
-
|
|
1000
|
+
const selection = input && inputSelection(input);
|
|
1001
|
+
if (input && selection?.mode === "many" && Array.isArray(value)) {
|
|
1051
1002
|
const eligible = value.filter(
|
|
1052
|
-
(item) =>
|
|
1003
|
+
(item) => inputTargetInDomain(input.domain, item)
|
|
1053
1004
|
);
|
|
1054
|
-
const max =
|
|
1005
|
+
const max = selection.max;
|
|
1055
1006
|
const retained = max === void 0 ? eligible : eligible.slice(0, max);
|
|
1056
1007
|
if (retained.length !== value.length) {
|
|
1057
1008
|
kept[name] = retained;
|
|
@@ -1082,11 +1033,7 @@ var Controller = class {
|
|
|
1082
1033
|
this.subscription?.unsubscribe();
|
|
1083
1034
|
this.pending = null;
|
|
1084
1035
|
this.options.source.dispose();
|
|
1085
|
-
this.sourceState =
|
|
1086
|
-
...this.sourceState,
|
|
1087
|
-
connection: "closed",
|
|
1088
|
-
request: null
|
|
1089
|
-
};
|
|
1036
|
+
this.sourceState = this.options.source.store.get();
|
|
1090
1037
|
this.refresh();
|
|
1091
1038
|
}
|
|
1092
1039
|
assertCoverage() {
|
|
@@ -1096,40 +1043,35 @@ var Controller = class {
|
|
|
1096
1043
|
if (missing.length)
|
|
1097
1044
|
throw new Error(`Interactions not read: ${missing.join(", ")}`);
|
|
1098
1045
|
}
|
|
1099
|
-
routeTarget(
|
|
1100
|
-
if (kind === "card") {
|
|
1101
|
-
this.selectCard(
|
|
1046
|
+
routeTarget(target, options) {
|
|
1047
|
+
if (target.kind === "card") {
|
|
1048
|
+
this.selectCard(target.value, options);
|
|
1102
1049
|
return;
|
|
1103
1050
|
}
|
|
1104
1051
|
const candidates = this.lastInteractions.flatMap(
|
|
1105
1052
|
(interaction) => interaction.getInputs().filter(
|
|
1106
|
-
(input) => input.descriptor
|
|
1053
|
+
(input) => matchesBoardTarget(input.descriptor, target) && input.getIsEligible(target.value) && interaction.getIsAvailable() && (!options?.interaction || interaction.key === options.interaction) && (!options?.input || input.key === options.input)
|
|
1107
1054
|
).map((input) => ({ interaction, input }))
|
|
1108
1055
|
);
|
|
1109
|
-
if (candidates.length > 1)
|
|
1056
|
+
if (candidates.length > 1)
|
|
1057
|
+
throw new AmbiguousTargetError(JSON.stringify(target.value));
|
|
1110
1058
|
const match = candidates[0];
|
|
1111
|
-
if (match)
|
|
1059
|
+
if (match)
|
|
1060
|
+
this.select(match.interaction.key, match.input.key, target.value);
|
|
1112
1061
|
}
|
|
1113
1062
|
routeCardDrop(cardId, target) {
|
|
1114
1063
|
if (this.disposed || this.sourceState.request || this.pending || this.sourceState.connection !== "ready")
|
|
1115
1064
|
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;
|
|
1065
|
+
const card = this.store.get().cards.find(cardId);
|
|
1066
|
+
const interaction = card?.routes.find(
|
|
1067
|
+
(route) => route.key === target.interactionKey
|
|
1068
|
+
);
|
|
1069
|
+
if (!interaction?.currentLifetime() || !interaction.getIsAvailable())
|
|
1070
|
+
return;
|
|
1071
|
+
const cardInput = interaction.findInput(target.cardInputKey);
|
|
1072
|
+
const input = interaction.findInput(target.inputKey);
|
|
1073
|
+
if (!cardInput || cardInput.descriptor.domain.type !== "cardTarget" || !cardInput.getIsEligible(cardId) || !input || !matchesBoardTarget(input.descriptor, target) || !input.getIsEligible(target.value))
|
|
1074
|
+
return;
|
|
1133
1075
|
let next = { ...this.drafts()[interaction.key] };
|
|
1134
1076
|
routeCardInputIntent(
|
|
1135
1077
|
{
|
|
@@ -1145,14 +1087,14 @@ var Controller = class {
|
|
|
1145
1087
|
{
|
|
1146
1088
|
cardId,
|
|
1147
1089
|
cardInputKey: cardInput.key,
|
|
1148
|
-
dropTarget: { inputKey: input.key, value: target.
|
|
1090
|
+
dropTarget: { inputKey: input.key, value: target.value }
|
|
1149
1091
|
}
|
|
1150
1092
|
);
|
|
1151
1093
|
this.writeDraft(interaction.key, next);
|
|
1152
1094
|
this.activate(interaction.key);
|
|
1153
1095
|
const current = this.current(interaction.key);
|
|
1154
1096
|
if (current && shouldAutoSubmitInteraction(current.descriptor) && current.getIsReady())
|
|
1155
|
-
this.handle(current.submit());
|
|
1097
|
+
this.handle(() => current.submit());
|
|
1156
1098
|
}
|
|
1157
1099
|
warnUnread() {
|
|
1158
1100
|
const environment = import.meta.env?.DEV ?? globalThis.process?.env?.NODE_ENV === "development";
|
|
@@ -1170,7 +1112,7 @@ var Controller = class {
|
|
|
1170
1112
|
}
|
|
1171
1113
|
build(previous) {
|
|
1172
1114
|
this.trackDrafts();
|
|
1173
|
-
const { snapshot, connection, request } = this.sourceState;
|
|
1115
|
+
const { snapshot, connection, request, failure } = this.sourceState;
|
|
1174
1116
|
const old = previous?.snapshot;
|
|
1175
1117
|
const drafts = this.drafts();
|
|
1176
1118
|
const active = this.active();
|
|
@@ -1193,11 +1135,20 @@ var Controller = class {
|
|
|
1193
1135
|
);
|
|
1194
1136
|
const players = sameActors && previous ? previous.players : {
|
|
1195
1137
|
order: Object.freeze(playerObjects.map((p) => p.id)),
|
|
1196
|
-
get: (id) =>
|
|
1138
|
+
get: (id) => requireLookup(
|
|
1139
|
+
playerObjects.find((p) => p.id === id),
|
|
1140
|
+
"Player",
|
|
1141
|
+
id
|
|
1142
|
+
),
|
|
1143
|
+
find: (id) => playerObjects.find((p) => p.id === id),
|
|
1197
1144
|
getAll: () => playerObjects,
|
|
1198
1145
|
next: (id) => {
|
|
1199
1146
|
const index = playerObjects.findIndex((p) => p.id === id);
|
|
1200
|
-
return
|
|
1147
|
+
return requireLookup(
|
|
1148
|
+
index < 0 ? void 0 : playerObjects[(index + 1) % playerObjects.length],
|
|
1149
|
+
"Next player after",
|
|
1150
|
+
id
|
|
1151
|
+
);
|
|
1201
1152
|
}
|
|
1202
1153
|
};
|
|
1203
1154
|
const me = sameActors && previous ? previous.me : snapshot ? {
|
|
@@ -1233,6 +1184,14 @@ var Controller = class {
|
|
|
1233
1184
|
this.lastInteractions = Object.freeze(interactionObjects);
|
|
1234
1185
|
const interactions = interactionsSame ? previous.interactions : {
|
|
1235
1186
|
get: (key) => {
|
|
1187
|
+
this.observed.add(key);
|
|
1188
|
+
return requireLookup(
|
|
1189
|
+
interactionObjects.find((value) => value.key === key),
|
|
1190
|
+
"Interaction",
|
|
1191
|
+
key
|
|
1192
|
+
);
|
|
1193
|
+
},
|
|
1194
|
+
find: (key) => {
|
|
1236
1195
|
this.observed.add(key);
|
|
1237
1196
|
return interactionObjects.find((value) => value.key === key);
|
|
1238
1197
|
},
|
|
@@ -1249,7 +1208,12 @@ var Controller = class {
|
|
|
1249
1208
|
}
|
|
1250
1209
|
};
|
|
1251
1210
|
const inputs = interactionsSame && previous ? previous.inputs : {
|
|
1252
|
-
get: (key, name) =>
|
|
1211
|
+
get: (key, name) => requireLookup(
|
|
1212
|
+
interactions.find(key)?.findInput(name),
|
|
1213
|
+
`Input in interaction ${key}`,
|
|
1214
|
+
name
|
|
1215
|
+
),
|
|
1216
|
+
find: (key, name) => interactions.find(key)?.findInput(name)
|
|
1253
1217
|
};
|
|
1254
1218
|
const zonesSame = sameSnapshot && interactionsSame && previous;
|
|
1255
1219
|
const zones = zonesSame ? previous.zones : (() => {
|
|
@@ -1291,12 +1255,22 @@ var Controller = class {
|
|
|
1291
1255
|
)
|
|
1292
1256
|
);
|
|
1293
1257
|
return {
|
|
1294
|
-
get: (id) =>
|
|
1258
|
+
get: (id) => requireLookup(
|
|
1259
|
+
objects.find((zone) => zone.id === id),
|
|
1260
|
+
"Zone",
|
|
1261
|
+
id
|
|
1262
|
+
),
|
|
1263
|
+
find: (id) => objects.find((zone) => zone.id === id),
|
|
1295
1264
|
getAll: () => Object.freeze(objects)
|
|
1296
1265
|
};
|
|
1297
1266
|
})();
|
|
1298
1267
|
const cards = zonesSame ? previous.cards : {
|
|
1299
|
-
get: (id) =>
|
|
1268
|
+
get: (id) => requireLookup(
|
|
1269
|
+
zones.getAll().map((zone) => zone.findCard(id)).find((card) => card !== void 0),
|
|
1270
|
+
"Card",
|
|
1271
|
+
id
|
|
1272
|
+
),
|
|
1273
|
+
find: (id) => zones.getAll().map((zone) => zone.findCard(id)).find((card) => card !== void 0)
|
|
1300
1274
|
};
|
|
1301
1275
|
const capturedState = this.lastSnapshotDrafts === drafts && previous?.state.activeInteraction === active ? previous.state : immutableCopy({ drafts, activeInteraction: active });
|
|
1302
1276
|
this.lastSnapshotDrafts = drafts;
|
|
@@ -1308,6 +1282,7 @@ var Controller = class {
|
|
|
1308
1282
|
version: snapshot?.version ?? null,
|
|
1309
1283
|
connection,
|
|
1310
1284
|
request,
|
|
1285
|
+
failure,
|
|
1311
1286
|
state: capturedState,
|
|
1312
1287
|
phase: sameSnapshot && previous ? previous.phase : Object.freeze(
|
|
1313
1288
|
new PhaseObject(snapshot?.frame.flow.currentPhase ?? null)
|
|
@@ -1360,4 +1335,4 @@ export {
|
|
|
1360
1335
|
AmbiguousTargetError,
|
|
1361
1336
|
createGameInstance
|
|
1362
1337
|
};
|
|
1363
|
-
//# sourceMappingURL=chunk-
|
|
1338
|
+
//# sourceMappingURL=chunk-OOFMBCFF.js.map
|