@domino-sdk/relay 1.11.1 → 1.14.0
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 +1 -0
- package/build.mjs +15 -0
- package/dist/accounts-5ciAkCMP.d.ts +147 -0
- package/dist/{activity-CNiPDPK6.d.ts → activity-D_R3J-gU.d.ts} +115 -115
- package/dist/attempt-captures-DZldPZJc.d.ts +285 -0
- package/dist/authoring.d.ts +49 -47
- package/dist/authoring.js +6 -4
- package/dist/{automatic-outcomes-kPIDv6X_.d.ts → automatic-outcomes-6lJGnSDe.d.ts} +1 -1
- package/dist/browser.d.ts +8 -7
- package/dist/browser.js +7 -6
- package/dist/capability-error-oTd3eYFH.d.ts +151 -0
- package/dist/chunk-2UAVZCMH.js +314 -0
- package/dist/chunk-5TS3OAWS.js +470 -0
- package/dist/{chunk-PUDL4JBY.js → chunk-6DD7DVNQ.js} +2 -2
- package/dist/{chunk-AGFUDCNM.js → chunk-C3CB4WIQ.js} +1 -1
- package/dist/{chunk-T657WO56.js → chunk-LLMJ2SUT.js} +6 -2
- package/dist/chunk-NIYCAW2I.js +79 -0
- package/dist/chunk-UJACD6K2.js +987 -0
- package/dist/{chunk-XK5E4HAS.js → chunk-VBHFJH3P.js} +80 -28
- package/dist/chunk-W335CWYJ.js +53 -0
- package/dist/{chunk-X7ECZ3AK.js → chunk-XMBM2XD5.js} +1 -1
- package/dist/{chunk-2K2QBPAD.js → chunk-ZLYBUM7K.js} +6 -4
- package/dist/{client-fUSERMAC.d.ts → client-BTd_CyX3.d.ts} +26 -6
- package/dist/{groups-BK8ts2yK.d.ts → groups-4Jb3uYFO.d.ts} +1 -1
- package/dist/{images-aw6W7vFZ.d.ts → images-D5kpqHxv.d.ts} +1 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.js +8 -6
- package/dist/{capability-error-ty3SqD_b.d.ts → integrations-Cr9EhGI_.d.ts} +1 -149
- package/dist/internal.d.ts +32 -5
- package/dist/internal.js +8 -3
- package/dist/{offers-C2FANzrG.d.ts → offers-BFI5t-e-.d.ts} +2 -2
- package/dist/{pages-Chb6OZSB.d.ts → pages-nIoMT9J3.d.ts} +1 -1
- package/dist/{participant-activity-DkL3nY5a.d.ts → participant-activity-DYdUUhw2.d.ts} +1 -0
- package/dist/portal-proxy.js +1 -1
- package/dist/react/index.d.ts +246 -177
- package/dist/react/index.js +954 -383
- package/dist/{referral-reward-kinds-M3f0PdiR.d.ts → referral-reward-kinds-DnvQXL8L.d.ts} +100 -3
- package/dist/{schema-DEM8y8Fm.d.ts → schema-K-Pg5lPz.d.ts} +1 -1
- package/dist/schema.d.ts +316 -314
- package/dist/schema.js +16 -14
- package/dist/server/index.d.ts +2546 -377
- package/dist/server/index.js +594 -841
- package/dist/{sign-in-options-iWOp9puZ.d.ts → sign-in-options-DBjMzgnu.d.ts} +2 -2
- package/dist/submission-input-CPIsJt-_.d.ts +146 -0
- package/dist/testing.d.ts +641 -0
- package/dist/testing.js +1282 -0
- package/package.json +6 -2
- package/dist/chunk-OCXGG75K.js +0 -171
- package/dist/chunk-ZFABFKIY.js +0 -1295
- package/dist/submission-input-BbBJTVlT.d.ts +0 -290
package/dist/react/index.js
CHANGED
|
@@ -8,23 +8,25 @@ import {
|
|
|
8
8
|
discoverSolanaWallets,
|
|
9
9
|
readSignInMethods,
|
|
10
10
|
signInOptionsFrom
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-6DD7DVNQ.js";
|
|
12
|
+
import "../chunk-VBHFJH3P.js";
|
|
13
13
|
import {
|
|
14
14
|
createRelayAction
|
|
15
|
-
} from "../chunk-
|
|
16
|
-
import "../chunk-
|
|
15
|
+
} from "../chunk-XMBM2XD5.js";
|
|
16
|
+
import "../chunk-LLMJ2SUT.js";
|
|
17
|
+
import "../chunk-UJACD6K2.js";
|
|
17
18
|
import {
|
|
18
19
|
RelayError,
|
|
19
20
|
RelayErrorCode,
|
|
20
21
|
asRelayError,
|
|
22
|
+
clientError,
|
|
21
23
|
isRelayError
|
|
22
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-2UAVZCMH.js";
|
|
23
25
|
import "../chunk-6QJ3LADK.js";
|
|
24
26
|
import {
|
|
25
27
|
isRequestError
|
|
26
28
|
} from "../chunk-NPGENI7K.js";
|
|
27
|
-
import "../chunk-
|
|
29
|
+
import "../chunk-C3CB4WIQ.js";
|
|
28
30
|
import {
|
|
29
31
|
sessionMember
|
|
30
32
|
} from "../chunk-PT5STHFH.js";
|
|
@@ -70,35 +72,41 @@ var QueryCache = class {
|
|
|
70
72
|
get disposed() {
|
|
71
73
|
return this.#disposed;
|
|
72
74
|
}
|
|
73
|
-
snapshot(key) {
|
|
74
|
-
return this.#entries.get(hashKey(key))?.state ??
|
|
75
|
+
snapshot(key, fallback = LOADING) {
|
|
76
|
+
return this.#entries.get(hashKey(key))?.state ?? fallback;
|
|
75
77
|
}
|
|
76
|
-
/**
|
|
77
|
-
|
|
78
|
-
if (this.#disposed) {
|
|
79
|
-
return () => {
|
|
80
|
-
};
|
|
81
|
-
}
|
|
78
|
+
/** The entry for `key`, created with `seed` as its value when there is none yet. */
|
|
79
|
+
#entry(key, read, seed) {
|
|
82
80
|
const hash = hashKey(key);
|
|
83
81
|
let entry = this.#entries.get(hash);
|
|
84
82
|
if (!entry) {
|
|
85
83
|
entry = {
|
|
86
84
|
key,
|
|
87
85
|
read,
|
|
88
|
-
state: LOADING,
|
|
86
|
+
state: seed ? { status: "ready", data: seed.data, error: null } : LOADING,
|
|
89
87
|
listeners: /* @__PURE__ */ new Set(),
|
|
90
88
|
intervals: /* @__PURE__ */ new Map(),
|
|
91
89
|
focus: /* @__PURE__ */ new Set(),
|
|
90
|
+
stale: /* @__PURE__ */ new Map(),
|
|
92
91
|
controller: null,
|
|
93
92
|
pending: null,
|
|
94
|
-
settledAt: 0,
|
|
93
|
+
settledAt: seed?.at ?? 0,
|
|
95
94
|
version: 0,
|
|
96
95
|
timer: void 0,
|
|
97
96
|
unused: void 0
|
|
98
97
|
};
|
|
99
98
|
this.#entries.set(hash, entry);
|
|
100
99
|
}
|
|
101
|
-
|
|
100
|
+
return entry;
|
|
101
|
+
}
|
|
102
|
+
/** Starts observing `key`, reading it now unless a read is cached or in flight. */
|
|
103
|
+
subscribe(key, read, options, listener, seed) {
|
|
104
|
+
if (this.#disposed) {
|
|
105
|
+
return () => {
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const hash = hashKey(key);
|
|
109
|
+
const current = this.#entry(key, read, seed);
|
|
102
110
|
const token = {};
|
|
103
111
|
const unseen = current.listeners.size === 0;
|
|
104
112
|
current.read = read;
|
|
@@ -110,7 +118,11 @@ var QueryCache = class {
|
|
|
110
118
|
if (options.refetchOnFocus) {
|
|
111
119
|
current.focus.add(token);
|
|
112
120
|
}
|
|
113
|
-
if (
|
|
121
|
+
if (options.staleMs !== void 0 && options.staleMs >= 0) {
|
|
122
|
+
current.stale.set(token, options.staleMs);
|
|
123
|
+
}
|
|
124
|
+
const staleMs = current.stale.size > 0 ? Math.min(...current.stale.values()) : STALE_MS;
|
|
125
|
+
if (!current.pending && (current.settledAt === 0 || unseen && Date.now() - current.settledAt >= staleMs)) {
|
|
114
126
|
void this.#fetch(current, false);
|
|
115
127
|
} else {
|
|
116
128
|
this.#schedule(current);
|
|
@@ -119,6 +131,7 @@ var QueryCache = class {
|
|
|
119
131
|
current.listeners.delete(listener);
|
|
120
132
|
current.intervals.delete(token);
|
|
121
133
|
current.focus.delete(token);
|
|
134
|
+
current.stale.delete(token);
|
|
122
135
|
if (current.listeners.size === 0 && !this.#disposed) {
|
|
123
136
|
clearTimeout(current.timer);
|
|
124
137
|
current.unused = setTimeout(() => {
|
|
@@ -129,6 +142,29 @@ var QueryCache = class {
|
|
|
129
142
|
}
|
|
130
143
|
};
|
|
131
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Reads `key` unless it has a value or a read in flight, for a component that suspends until it
|
|
147
|
+
* has one: settles when the read does. A value nobody comes to show is forgotten like any other.
|
|
148
|
+
*/
|
|
149
|
+
ensure(key, read, seed) {
|
|
150
|
+
if (this.#disposed) {
|
|
151
|
+
return Promise.resolve();
|
|
152
|
+
}
|
|
153
|
+
const hash = hashKey(key);
|
|
154
|
+
const entry = this.#entry(key, read, seed);
|
|
155
|
+
if (entry.listeners.size === 0) {
|
|
156
|
+
clearTimeout(entry.unused);
|
|
157
|
+
entry.unused = setTimeout(() => {
|
|
158
|
+
if (entry.listeners.size === 0) {
|
|
159
|
+
this.#drop(hash, entry);
|
|
160
|
+
}
|
|
161
|
+
}, UNUSED_MS);
|
|
162
|
+
}
|
|
163
|
+
if (entry.pending) {
|
|
164
|
+
return entry.pending;
|
|
165
|
+
}
|
|
166
|
+
return entry.settledAt === 0 ? this.#fetch(entry, false) : Promise.resolve();
|
|
167
|
+
}
|
|
132
168
|
/** Reads `key` again now, replacing any read in flight. */
|
|
133
169
|
refresh(key) {
|
|
134
170
|
const entry = this.#entries.get(hashKey(key));
|
|
@@ -173,12 +209,13 @@ var QueryCache = class {
|
|
|
173
209
|
}
|
|
174
210
|
/**
|
|
175
211
|
* Replaces the cached value of `key` with one a change returned, cancelling a read in flight that
|
|
176
|
-
* may have started before the change. Does nothing for a key nobody has read.
|
|
212
|
+
* may have started before the change. Does nothing for a key nobody has read. Returns whether it
|
|
213
|
+
* applied.
|
|
177
214
|
*/
|
|
178
215
|
set(key, data) {
|
|
179
216
|
const entry = this.#entries.get(hashKey(key));
|
|
180
217
|
if (this.#disposed || !entry) {
|
|
181
|
-
return;
|
|
218
|
+
return false;
|
|
182
219
|
}
|
|
183
220
|
entry.controller?.abort();
|
|
184
221
|
entry.controller = null;
|
|
@@ -187,6 +224,7 @@ var QueryCache = class {
|
|
|
187
224
|
entry.settledAt = Date.now();
|
|
188
225
|
this.#write(entry, { status: "ready", data, error: null });
|
|
189
226
|
this.#schedule(entry);
|
|
227
|
+
return true;
|
|
190
228
|
}
|
|
191
229
|
version(key) {
|
|
192
230
|
return this.#entries.get(hashKey(key))?.version ?? -1;
|
|
@@ -394,13 +432,26 @@ function useActivity(options = {}) {
|
|
|
394
432
|
|
|
395
433
|
// src/react/action.ts
|
|
396
434
|
import { useCallback as useCallback2, useRef as useRef2, useState as useState2 } from "react";
|
|
435
|
+
var IDLE = Object.freeze({
|
|
436
|
+
status: "idle",
|
|
437
|
+
data: void 0,
|
|
438
|
+
error: null
|
|
439
|
+
});
|
|
440
|
+
function actionError(cause) {
|
|
441
|
+
return isRequestError(cause) && !isRelayError(cause) ? new RelayError(cause.message, {
|
|
442
|
+
kind: cause.kind,
|
|
443
|
+
status: cause.status,
|
|
444
|
+
code: cause.code,
|
|
445
|
+
uncertain: cause.uncertain,
|
|
446
|
+
operationId: cause.operationId,
|
|
447
|
+
replaySafe: cause.recovery === "replay",
|
|
448
|
+
retryAfter: cause.retryAfter,
|
|
449
|
+
cause
|
|
450
|
+
}) : asRelayError(cause);
|
|
451
|
+
}
|
|
397
452
|
function useRelayAction(scope) {
|
|
398
453
|
const owner = useRef2({ scope, action: createRelayAction() });
|
|
399
|
-
const [state, setState] = useState2({
|
|
400
|
-
owner: owner.current,
|
|
401
|
-
busy: false,
|
|
402
|
-
error: null
|
|
403
|
-
});
|
|
454
|
+
const [state, setState] = useState2({ owner: owner.current, ...IDLE });
|
|
404
455
|
if (owner.current.scope !== scope) {
|
|
405
456
|
owner.current = { scope, action: createRelayAction() };
|
|
406
457
|
}
|
|
@@ -411,33 +462,29 @@ function useRelayAction(scope) {
|
|
|
411
462
|
return { ok: false };
|
|
412
463
|
}
|
|
413
464
|
const result = task ? current2.action.run(task) : current2.action.retry();
|
|
414
|
-
setState({
|
|
465
|
+
setState({
|
|
466
|
+
owner: current2,
|
|
467
|
+
status: "pending",
|
|
468
|
+
data: void 0,
|
|
469
|
+
error: null
|
|
470
|
+
});
|
|
415
471
|
try {
|
|
416
472
|
const value = await result;
|
|
417
473
|
if (owner.current === current2) {
|
|
418
|
-
setState({
|
|
474
|
+
setState({
|
|
475
|
+
owner: current2,
|
|
476
|
+
status: "success",
|
|
477
|
+
data: value,
|
|
478
|
+
error: null
|
|
479
|
+
});
|
|
419
480
|
}
|
|
420
481
|
return { ok: true, value };
|
|
421
482
|
} catch (caught) {
|
|
483
|
+
const error = actionError(current2.action.error ?? caught);
|
|
422
484
|
if (owner.current === current2) {
|
|
423
|
-
|
|
424
|
-
const error = isRequestError(cause) && !isRelayError(cause) ? new RelayError(cause.message, {
|
|
425
|
-
kind: cause.kind,
|
|
426
|
-
status: cause.status,
|
|
427
|
-
code: cause.code,
|
|
428
|
-
uncertain: cause.uncertain,
|
|
429
|
-
operationId: cause.operationId,
|
|
430
|
-
replaySafe: cause.recovery === "replay",
|
|
431
|
-
retryAfter: cause.retryAfter,
|
|
432
|
-
cause
|
|
433
|
-
}) : asRelayError(cause);
|
|
434
|
-
setState({
|
|
435
|
-
owner: current2,
|
|
436
|
-
busy: false,
|
|
437
|
-
error
|
|
438
|
-
});
|
|
485
|
+
setState({ owner: current2, status: "error", data: void 0, error });
|
|
439
486
|
}
|
|
440
|
-
return { ok: false };
|
|
487
|
+
return { ok: false, error };
|
|
441
488
|
}
|
|
442
489
|
},
|
|
443
490
|
[]
|
|
@@ -448,31 +495,232 @@ function useRelayAction(scope) {
|
|
|
448
495
|
if (!current2.action.settle()) {
|
|
449
496
|
return false;
|
|
450
497
|
}
|
|
451
|
-
setState({ owner: current2,
|
|
498
|
+
setState({ owner: current2, ...IDLE });
|
|
452
499
|
return true;
|
|
453
500
|
}, []);
|
|
454
|
-
const
|
|
501
|
+
const reset = useCallback2(() => {
|
|
502
|
+
const current2 = owner.current;
|
|
503
|
+
if (!current2.action.busy && current2.action.actionId === void 0) {
|
|
504
|
+
setState({ owner: current2, ...IDLE });
|
|
505
|
+
}
|
|
506
|
+
}, []);
|
|
507
|
+
const current = state.owner === owner.current ? state : IDLE;
|
|
508
|
+
const isPending = current.status === "pending";
|
|
455
509
|
return {
|
|
456
510
|
run: execute,
|
|
457
511
|
retry,
|
|
458
512
|
settle,
|
|
459
|
-
|
|
460
|
-
|
|
513
|
+
reset,
|
|
514
|
+
status: current.status,
|
|
515
|
+
isPending,
|
|
516
|
+
data: current.data,
|
|
517
|
+
error: current.error,
|
|
518
|
+
/** @deprecated Use `isPending`. Removed in 2.0.0. */
|
|
519
|
+
busy: isPending
|
|
461
520
|
};
|
|
462
521
|
}
|
|
463
522
|
|
|
464
|
-
// src/react/
|
|
465
|
-
import {
|
|
523
|
+
// src/react/mutation.ts
|
|
524
|
+
import { useCallback as useCallback4, useLayoutEffect as useLayoutEffect3, useMemo as useMemo2, useRef as useRef4 } from "react";
|
|
466
525
|
|
|
467
|
-
// src/react/
|
|
526
|
+
// src/react/query.ts
|
|
468
527
|
import {
|
|
469
|
-
createContext as createContext2,
|
|
470
528
|
useCallback as useCallback3,
|
|
471
|
-
|
|
529
|
+
useEffect as useEffect2,
|
|
530
|
+
useLayoutEffect as useLayoutEffect2,
|
|
472
531
|
useMemo,
|
|
532
|
+
useRef as useRef3,
|
|
533
|
+
useState as useState3,
|
|
473
534
|
useSyncExternalStore as useSyncExternalStore2
|
|
474
535
|
} from "react";
|
|
475
536
|
|
|
537
|
+
// src/react/feed.ts
|
|
538
|
+
function feedOwner(session) {
|
|
539
|
+
return JSON.stringify([
|
|
540
|
+
session.organization,
|
|
541
|
+
session.project,
|
|
542
|
+
session.environment,
|
|
543
|
+
sessionMember(session)
|
|
544
|
+
]);
|
|
545
|
+
}
|
|
546
|
+
var ActivityFeed = class {
|
|
547
|
+
/** The provider scope the feed was started for. */
|
|
548
|
+
scope;
|
|
549
|
+
owner;
|
|
550
|
+
#client;
|
|
551
|
+
#intervalMs;
|
|
552
|
+
#on;
|
|
553
|
+
#observer = null;
|
|
554
|
+
#generation = {};
|
|
555
|
+
#session;
|
|
556
|
+
#cursor;
|
|
557
|
+
/** The feed knows where it starts: events from now on are new. */
|
|
558
|
+
#ready = false;
|
|
559
|
+
/** A read answered since the feed (re)started. */
|
|
560
|
+
#answered = false;
|
|
561
|
+
#disposed = false;
|
|
562
|
+
/** When a read last answered, for a focus that should not read again so soon. */
|
|
563
|
+
settledAt = 0;
|
|
564
|
+
constructor(client, session, options, on) {
|
|
565
|
+
this.scope = options.scope;
|
|
566
|
+
this.owner = feedOwner(session);
|
|
567
|
+
this.#client = client;
|
|
568
|
+
this.#session = session.id;
|
|
569
|
+
this.#intervalMs = options.intervalMs;
|
|
570
|
+
this.#on = on;
|
|
571
|
+
this.#start(options.cursor, session);
|
|
572
|
+
}
|
|
573
|
+
/** The cursor after the last events read, for the same member's next session. */
|
|
574
|
+
get cursor() {
|
|
575
|
+
return this.#cursor;
|
|
576
|
+
}
|
|
577
|
+
/** True once the feed knows where it starts. */
|
|
578
|
+
get ready() {
|
|
579
|
+
return this.#ready;
|
|
580
|
+
}
|
|
581
|
+
refresh() {
|
|
582
|
+
return this.#observer?.refresh() ?? Promise.resolve();
|
|
583
|
+
}
|
|
584
|
+
dispose() {
|
|
585
|
+
this.#disposed = true;
|
|
586
|
+
this.#observer?.dispose();
|
|
587
|
+
this.#observer = null;
|
|
588
|
+
}
|
|
589
|
+
#start(cursor, session) {
|
|
590
|
+
this.#observer?.dispose();
|
|
591
|
+
const generation = {};
|
|
592
|
+
this.#generation = generation;
|
|
593
|
+
this.#cursor = cursor;
|
|
594
|
+
this.#ready = cursor !== void 0;
|
|
595
|
+
this.#answered = false;
|
|
596
|
+
this.#observer = this.#client.me.activity.observe(() => {
|
|
597
|
+
}, {
|
|
598
|
+
cursor,
|
|
599
|
+
// Without a cursor, and whenever the client drops it for another session, start from the
|
|
600
|
+
// newest event rather than replay the member's history.
|
|
601
|
+
start: "latest",
|
|
602
|
+
// The provider knows the session: the first poll reads the feed at once.
|
|
603
|
+
session,
|
|
604
|
+
intervalMs: this.#intervalMs,
|
|
605
|
+
maxBackoffMs: Math.max(6e4, this.#intervalMs),
|
|
606
|
+
onState: (state) => {
|
|
607
|
+
if (!this.#disposed && this.#generation === generation) {
|
|
608
|
+
this.#observe(state, cursor !== void 0);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
#observe(state, carried) {
|
|
614
|
+
switch (state.kind) {
|
|
615
|
+
case "loading":
|
|
616
|
+
return;
|
|
617
|
+
case "session": {
|
|
618
|
+
const session = state.session;
|
|
619
|
+
if ((session?.id ?? null) === this.#session) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if (session && feedOwner(session) === this.owner) {
|
|
623
|
+
this.#session = session.id;
|
|
624
|
+
this.#start(this.#cursor, session);
|
|
625
|
+
} else {
|
|
626
|
+
this.dispose();
|
|
627
|
+
}
|
|
628
|
+
this.#on.session(session);
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
case "ready":
|
|
632
|
+
this.settledAt = Date.now();
|
|
633
|
+
this.#answered = true;
|
|
634
|
+
this.#cursor = state.progress.nextCursor;
|
|
635
|
+
if (this.#ready) {
|
|
636
|
+
this.#on.events(state.progress.items);
|
|
637
|
+
} else {
|
|
638
|
+
this.#ready = true;
|
|
639
|
+
}
|
|
640
|
+
return;
|
|
641
|
+
case "error": {
|
|
642
|
+
this.settledAt = Date.now();
|
|
643
|
+
const error = relayError(state.error);
|
|
644
|
+
const status = error.kind === "http" ? error.status : void 0;
|
|
645
|
+
if (status === 400 && !this.#answered && carried) {
|
|
646
|
+
this.#start(void 0);
|
|
647
|
+
} else if (status === 404 || status === 400 && !this.#answered) {
|
|
648
|
+
this.#on.missing();
|
|
649
|
+
}
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
default: {
|
|
653
|
+
const _exhaustive = state;
|
|
654
|
+
return _exhaustive;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
// src/react/keys.ts
|
|
661
|
+
var relayKeys = {
|
|
662
|
+
/** `useExperience`: invalidating it reads the quest experience again. */
|
|
663
|
+
experience: ["experience"],
|
|
664
|
+
/** `useMe`. */
|
|
665
|
+
me: ["me"],
|
|
666
|
+
/** `useAccounts`. */
|
|
667
|
+
accounts: ["accounts"],
|
|
668
|
+
/** `useWallets`. */
|
|
669
|
+
wallets: ["wallets"],
|
|
670
|
+
/** `useMyProfile`, `useProfile`, `useProfileCompletions`, `useProfileReferral`. */
|
|
671
|
+
profiles: ["profiles"],
|
|
672
|
+
/** `useLeaderboard`, `useLeaderboardPlacement`. */
|
|
673
|
+
leaderboards: ["leaderboards"],
|
|
674
|
+
/** `useReferralSummary`. */
|
|
675
|
+
referrals: ["referrals"],
|
|
676
|
+
/** `usePointLedgers`. */
|
|
677
|
+
pointLedgers: ["point-ledgers"],
|
|
678
|
+
/** `useTieredRewards`. */
|
|
679
|
+
tieredRewards: ["tiered-rewards"],
|
|
680
|
+
/** `useSignInMethods`. */
|
|
681
|
+
signInMethods: ["sign-in-methods"],
|
|
682
|
+
/** `useEntitlements`, `useDeliveries`. */
|
|
683
|
+
rewards: ["rewards"],
|
|
684
|
+
/** `useBalances`, `usePointHistory`. */
|
|
685
|
+
balances: ["balances"],
|
|
686
|
+
/** `useQuestOutcomes`. */
|
|
687
|
+
outcomes: ["outcomes"],
|
|
688
|
+
/** `useOffers`, `useRedeemOffer`. */
|
|
689
|
+
offers: ["offers"]
|
|
690
|
+
};
|
|
691
|
+
var rewardKeys = {
|
|
692
|
+
entitlements: [...relayKeys.rewards, "entitlements"],
|
|
693
|
+
deliveries: [...relayKeys.rewards, "deliveries"]
|
|
694
|
+
};
|
|
695
|
+
var completionChanges = [
|
|
696
|
+
relayKeys.rewards,
|
|
697
|
+
relayKeys.balances,
|
|
698
|
+
relayKeys.leaderboards,
|
|
699
|
+
relayKeys.profiles,
|
|
700
|
+
relayKeys.referrals,
|
|
701
|
+
relayKeys.offers
|
|
702
|
+
];
|
|
703
|
+
var activityChanges = {
|
|
704
|
+
"attempt.accepted": [
|
|
705
|
+
relayKeys.experience,
|
|
706
|
+
relayKeys.outcomes,
|
|
707
|
+
...completionChanges
|
|
708
|
+
],
|
|
709
|
+
"attempt.rejected": [relayKeys.experience, relayKeys.outcomes],
|
|
710
|
+
"attempt.review": [relayKeys.experience, relayKeys.outcomes],
|
|
711
|
+
"points.awarded": [
|
|
712
|
+
relayKeys.balances,
|
|
713
|
+
relayKeys.leaderboards,
|
|
714
|
+
relayKeys.offers,
|
|
715
|
+
rewardKeys.deliveries
|
|
716
|
+
],
|
|
717
|
+
"entitlement.granted": [relayKeys.experience, relayKeys.rewards],
|
|
718
|
+
"entitlement.collected": [relayKeys.experience, relayKeys.rewards],
|
|
719
|
+
"delivery.updated": [rewardKeys.deliveries],
|
|
720
|
+
"referral.qualified": [relayKeys.referrals, relayKeys.profiles],
|
|
721
|
+
unknown: [relayKeys.experience]
|
|
722
|
+
};
|
|
723
|
+
|
|
476
724
|
// src/react/role-delivery.ts
|
|
477
725
|
function sanitizeDeliveries(deliveries) {
|
|
478
726
|
return deliveries.map(({ quest, status, revokedAt, reconciliation }) => ({
|
|
@@ -578,113 +826,6 @@ function watchRoleDeliveries(options) {
|
|
|
578
826
|
};
|
|
579
827
|
}
|
|
580
828
|
|
|
581
|
-
// src/react/use-role-deliveries.ts
|
|
582
|
-
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
583
|
-
var NONE = Object.freeze([]);
|
|
584
|
-
function useRoleDeliveries(relay, member, completions) {
|
|
585
|
-
const [state, setState] = useState3(null);
|
|
586
|
-
useEffect2(() => {
|
|
587
|
-
if (!member || !completions) {
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
590
|
-
const watch = watchRoleDeliveries({
|
|
591
|
-
read: async () => (await relay.me.rewardDeliveries()).deliveries,
|
|
592
|
-
onChange: (deliveries) => setState({ member, deliveries })
|
|
593
|
-
});
|
|
594
|
-
const wake = () => {
|
|
595
|
-
if (document.visibilityState === "visible") {
|
|
596
|
-
watch.wake();
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
window.addEventListener("focus", wake);
|
|
600
|
-
document.addEventListener("visibilitychange", wake);
|
|
601
|
-
return () => {
|
|
602
|
-
watch.dispose();
|
|
603
|
-
window.removeEventListener("focus", wake);
|
|
604
|
-
document.removeEventListener("visibilitychange", wake);
|
|
605
|
-
};
|
|
606
|
-
}, [relay, member, completions]);
|
|
607
|
-
return member && completions && state?.member === member ? state.deliveries : NONE;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
// src/react/experience.tsx
|
|
611
|
-
import { jsx } from "react/jsx-runtime";
|
|
612
|
-
var Deliveries = createContext2(Object.freeze([]));
|
|
613
|
-
function useExperienceSnapshot() {
|
|
614
|
-
const store = useStore();
|
|
615
|
-
const get = () => store.experience;
|
|
616
|
-
return useSyncExternalStore2(store.subscribe, get, get);
|
|
617
|
-
}
|
|
618
|
-
function DeliveriesProvider({ children }) {
|
|
619
|
-
const store = useStore();
|
|
620
|
-
const experience = useExperienceSnapshot();
|
|
621
|
-
const member = useSyncExternalStore2(
|
|
622
|
-
store.subscribe,
|
|
623
|
-
() => store.scope?.member ?? null,
|
|
624
|
-
() => null
|
|
625
|
-
);
|
|
626
|
-
const ready = experience.status === "ready";
|
|
627
|
-
const deliveries = useRoleDeliveries(
|
|
628
|
-
store.client,
|
|
629
|
-
ready ? member : null,
|
|
630
|
-
ready ? completionMark([
|
|
631
|
-
...experience.data.quests,
|
|
632
|
-
...experience.data.collections.flatMap((c) => c.quests)
|
|
633
|
-
]) : ""
|
|
634
|
-
);
|
|
635
|
-
return /* @__PURE__ */ jsx(Deliveries, { value: deliveries, children });
|
|
636
|
-
}
|
|
637
|
-
function useExperience() {
|
|
638
|
-
const store = useStore();
|
|
639
|
-
const experience = useExperienceSnapshot();
|
|
640
|
-
const deliveries = useContext2(Deliveries);
|
|
641
|
-
const refresh = useCallback3(() => store.refreshExperience(), [store]);
|
|
642
|
-
return useMemo(
|
|
643
|
-
() => ({ ...experience, refresh, deliveries }),
|
|
644
|
-
[experience, refresh, deliveries]
|
|
645
|
-
);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// src/react/keys.ts
|
|
649
|
-
var relayKeys = {
|
|
650
|
-
/** `useExperience`: invalidating it reads the quest experience again. */
|
|
651
|
-
experience: ["experience"],
|
|
652
|
-
/** `useMe`. */
|
|
653
|
-
me: ["me"],
|
|
654
|
-
/** `useAccounts`. */
|
|
655
|
-
accounts: ["accounts"],
|
|
656
|
-
/** `useWallets`. */
|
|
657
|
-
wallets: ["wallets"],
|
|
658
|
-
/** `useMyProfile`, `useProfile`, `useProfileCompletions`, `useProfileReferral`. */
|
|
659
|
-
profiles: ["profiles"],
|
|
660
|
-
/** `useLeaderboard`, `useLeaderboardPlacement`. */
|
|
661
|
-
leaderboards: ["leaderboards"],
|
|
662
|
-
/** `useReferralSummary`. */
|
|
663
|
-
referrals: ["referrals"],
|
|
664
|
-
/** `usePointLedgers`. */
|
|
665
|
-
pointLedgers: ["point-ledgers"],
|
|
666
|
-
/** `useTieredRewards`. */
|
|
667
|
-
tieredRewards: ["tiered-rewards"],
|
|
668
|
-
/** `useSignInMethods`. */
|
|
669
|
-
signInMethods: ["sign-in-methods"],
|
|
670
|
-
/** `useEntitlements`, `useDeliveries`. */
|
|
671
|
-
rewards: ["rewards"],
|
|
672
|
-
/** `useBalances`, `usePointHistory`. */
|
|
673
|
-
balances: ["balances"],
|
|
674
|
-
/** `useQuestOutcomes`. */
|
|
675
|
-
outcomes: ["outcomes"],
|
|
676
|
-
/** `useOffers`, `useRedeemOffer`. */
|
|
677
|
-
offers: ["offers"]
|
|
678
|
-
};
|
|
679
|
-
var completionChanges = [
|
|
680
|
-
relayKeys.rewards,
|
|
681
|
-
relayKeys.balances,
|
|
682
|
-
relayKeys.leaderboards,
|
|
683
|
-
relayKeys.profiles,
|
|
684
|
-
relayKeys.referrals,
|
|
685
|
-
relayKeys.offers
|
|
686
|
-
];
|
|
687
|
-
|
|
688
829
|
// src/react/status.ts
|
|
689
830
|
function isFinished(view) {
|
|
690
831
|
return view.availability.kind === "completed" || view.completion.kind !== "keyed" && view.completion.kind !== "progress" && view.completed;
|
|
@@ -956,6 +1097,9 @@ function scopeKey(session) {
|
|
|
956
1097
|
function isVisible() {
|
|
957
1098
|
return typeof document === "undefined" || document.visibilityState !== "hidden";
|
|
958
1099
|
}
|
|
1100
|
+
var ACTIVITY_MS = 5e3;
|
|
1101
|
+
var SNAPSHOT_MS = 3e4;
|
|
1102
|
+
var FOCUS_GAP_MS = 2e3;
|
|
959
1103
|
var RelayStore = class {
|
|
960
1104
|
client;
|
|
961
1105
|
#session = LOADING;
|
|
@@ -971,8 +1115,28 @@ var RelayStore = class {
|
|
|
971
1115
|
#sessionRead = null;
|
|
972
1116
|
/** The completions the experience last showed, and for whom. */
|
|
973
1117
|
#completions = null;
|
|
974
|
-
|
|
1118
|
+
#polling;
|
|
1119
|
+
#feed = null;
|
|
1120
|
+
/** Relay answered that it has no activity feed: the experience observer carries on alone. */
|
|
1121
|
+
#feedMissing = false;
|
|
1122
|
+
/**
|
|
1123
|
+
* The experience read in flight was asked for by an `attempt.accepted` event, which already
|
|
1124
|
+
* read what a completion changes.
|
|
1125
|
+
*/
|
|
1126
|
+
#readForAcceptance = false;
|
|
1127
|
+
/** The latest experience read the store asked for. */
|
|
1128
|
+
#experienceRead = Promise.resolve();
|
|
1129
|
+
#shownAt = 0;
|
|
1130
|
+
#focusReadAt = 0;
|
|
1131
|
+
/** The first cache of this mount: a public read's `initialData` seeds only it. */
|
|
1132
|
+
#firstCache = null;
|
|
1133
|
+
#settled = null;
|
|
1134
|
+
constructor(client, polling = {}) {
|
|
975
1135
|
this.client = client;
|
|
1136
|
+
this.#polling = {
|
|
1137
|
+
activityMs: polling.activityMs ?? ACTIVITY_MS,
|
|
1138
|
+
snapshotMs: polling.snapshotMs ?? SNAPSHOT_MS
|
|
1139
|
+
};
|
|
976
1140
|
}
|
|
977
1141
|
/** `refreshSession` with one identity per store, for hooks to hand out as `refresh`. */
|
|
978
1142
|
rereadSession = () => this.refreshSession();
|
|
@@ -991,23 +1155,41 @@ var RelayStore = class {
|
|
|
991
1155
|
get experience() {
|
|
992
1156
|
return this.#experienceView;
|
|
993
1157
|
}
|
|
1158
|
+
/** The first query cache of this mount, the only one a public read's `initialData` seeds. */
|
|
1159
|
+
get firstCache() {
|
|
1160
|
+
return this.#firstCache;
|
|
1161
|
+
}
|
|
1162
|
+
/** Settles once the session is known (or failed to read), for a component that suspends. */
|
|
1163
|
+
settled() {
|
|
1164
|
+
if (this.#session.status !== "loading") {
|
|
1165
|
+
return Promise.resolve();
|
|
1166
|
+
}
|
|
1167
|
+
if (!this.#settled) {
|
|
1168
|
+
let resolve = () => {
|
|
1169
|
+
};
|
|
1170
|
+
const promise = new Promise((done) => {
|
|
1171
|
+
resolve = done;
|
|
1172
|
+
});
|
|
1173
|
+
this.#settled = { promise, resolve };
|
|
1174
|
+
}
|
|
1175
|
+
return this.#settled.promise;
|
|
1176
|
+
}
|
|
994
1177
|
/** Starts observing; the returned function stops every read, timer and listener. */
|
|
995
1178
|
mount() {
|
|
996
1179
|
this.#mounted = true;
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
}
|
|
1180
|
+
this.#feedMissing = false;
|
|
1181
|
+
this.#startObserver();
|
|
1000
1182
|
void this.refreshSession();
|
|
1001
1183
|
const onVisibility = () => {
|
|
1002
1184
|
if (isVisible()) {
|
|
1003
|
-
this.#
|
|
1185
|
+
this.#shownAt = Date.now();
|
|
1004
1186
|
this.#scope?.cache.resume();
|
|
1005
|
-
} else {
|
|
1006
|
-
this.#observer?.dispose();
|
|
1007
|
-
this.#observer = null;
|
|
1008
1187
|
}
|
|
1009
1188
|
};
|
|
1010
|
-
const onFocus = () =>
|
|
1189
|
+
const onFocus = () => {
|
|
1190
|
+
this.#scope?.cache.focus();
|
|
1191
|
+
this.#readOnFocus();
|
|
1192
|
+
};
|
|
1011
1193
|
if (typeof window !== "undefined") {
|
|
1012
1194
|
document.addEventListener("visibilitychange", onVisibility);
|
|
1013
1195
|
window.addEventListener("focus", onFocus);
|
|
@@ -1020,11 +1202,13 @@ var RelayStore = class {
|
|
|
1020
1202
|
}
|
|
1021
1203
|
this.#observer?.dispose();
|
|
1022
1204
|
this.#observer = null;
|
|
1205
|
+
this.#stopFeed();
|
|
1023
1206
|
this.#sessionRead?.abort();
|
|
1024
1207
|
this.#sessionRead = null;
|
|
1025
1208
|
this.#sessionVersion++;
|
|
1026
1209
|
this.#scope?.cache.dispose();
|
|
1027
1210
|
this.#scope = null;
|
|
1211
|
+
this.#firstCache = null;
|
|
1028
1212
|
this.#session = LOADING;
|
|
1029
1213
|
this.#experience = { owner: null, state: LOADING };
|
|
1030
1214
|
this.#emit();
|
|
@@ -1078,8 +1262,21 @@ var RelayStore = class {
|
|
|
1078
1262
|
this.#setSession({ status: "ready", data: null, error: null });
|
|
1079
1263
|
this.#emit();
|
|
1080
1264
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1265
|
+
/**
|
|
1266
|
+
* Reads the experience again. With a feed, it is read first: the events it finds read the
|
|
1267
|
+
* experience and whatever else they changed, so a change the participant just made shows its
|
|
1268
|
+
* effects at once, and the experience is read only once.
|
|
1269
|
+
*/
|
|
1270
|
+
async refreshExperience() {
|
|
1271
|
+
const feed = this.#feed;
|
|
1272
|
+
if (feed?.ready) {
|
|
1273
|
+
const before = this.#experienceRead;
|
|
1274
|
+
await feed.refresh();
|
|
1275
|
+
if (this.#experienceRead !== before) {
|
|
1276
|
+
return this.#experienceRead;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
return this.#readExperience(false);
|
|
1083
1280
|
}
|
|
1084
1281
|
/**
|
|
1085
1282
|
* Marks queries out of date (see `QueryCache.invalidate`). The `["experience"]` key, or no keys at
|
|
@@ -1094,90 +1291,179 @@ var RelayStore = class {
|
|
|
1094
1291
|
return Promise.all(reads).then(() => {
|
|
1095
1292
|
});
|
|
1096
1293
|
}
|
|
1294
|
+
#readExperience(forAcceptance) {
|
|
1295
|
+
this.#readForAcceptance = forAcceptance && isVisible();
|
|
1296
|
+
this.#experienceRead = this.#observer?.refresh() ?? Promise.resolve();
|
|
1297
|
+
return this.#experienceRead;
|
|
1298
|
+
}
|
|
1299
|
+
/** The window regained focus: read for changes, unless that just happened. */
|
|
1300
|
+
#readOnFocus() {
|
|
1301
|
+
const now = Date.now();
|
|
1302
|
+
const last = Math.max(
|
|
1303
|
+
this.#shownAt,
|
|
1304
|
+
this.#focusReadAt,
|
|
1305
|
+
this.#feed?.settledAt ?? 0
|
|
1306
|
+
);
|
|
1307
|
+
if (now - last < FOCUS_GAP_MS || !this.#scope) {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
this.#focusReadAt = now;
|
|
1311
|
+
if (this.#feed) {
|
|
1312
|
+
void this.#feed.refresh();
|
|
1313
|
+
} else if (!this.#scope.member) {
|
|
1314
|
+
void this.refreshSession();
|
|
1315
|
+
}
|
|
1316
|
+
if (this.#scope.member && (!this.#feed || this.#experience.state.error)) {
|
|
1317
|
+
void this.#readExperience(false);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
/** Follows the signed-in member's activity feed while there is one; stops it otherwise. */
|
|
1321
|
+
#syncFeed() {
|
|
1322
|
+
const scope = this.#scope;
|
|
1323
|
+
const available = typeof this.client.me?.activity?.observe === "function";
|
|
1324
|
+
const wanted = this.#mounted && available && !this.#feedMissing && scope?.member ? scope : null;
|
|
1325
|
+
const previous = this.#feed;
|
|
1326
|
+
if (previous && previous.scope === wanted?.key) {
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
this.#stopFeed();
|
|
1330
|
+
if (!wanted?.session) {
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
const feed = new ActivityFeed(
|
|
1334
|
+
this.client,
|
|
1335
|
+
wanted.session,
|
|
1336
|
+
{
|
|
1337
|
+
scope: wanted.key,
|
|
1338
|
+
intervalMs: this.#polling.activityMs,
|
|
1339
|
+
// The same member's new session carries on where the last one left off.
|
|
1340
|
+
cursor: previous?.owner === feedOwner(wanted.session) ? previous.cursor : void 0
|
|
1341
|
+
},
|
|
1342
|
+
{
|
|
1343
|
+
events: (events) => this.#applyEvents(events),
|
|
1344
|
+
session: () => void this.refreshSession(),
|
|
1345
|
+
missing: () => {
|
|
1346
|
+
this.#feedMissing = true;
|
|
1347
|
+
this.#stopFeed();
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
);
|
|
1351
|
+
this.#feed = feed;
|
|
1352
|
+
}
|
|
1353
|
+
#stopFeed() {
|
|
1354
|
+
const feed = this.#feed;
|
|
1355
|
+
this.#feed = null;
|
|
1356
|
+
feed?.dispose();
|
|
1357
|
+
}
|
|
1358
|
+
/** Reads again, once each, the queries the events change. */
|
|
1359
|
+
#applyEvents(events) {
|
|
1360
|
+
const keys = /* @__PURE__ */ new Map();
|
|
1361
|
+
for (const event of events) {
|
|
1362
|
+
for (const key of activityChanges[event.kind] ?? activityChanges.unknown) {
|
|
1363
|
+
keys.set(hashKey(key), key);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
if (keys.delete(hashKey(relayKeys.experience))) {
|
|
1367
|
+
void this.#readExperience(
|
|
1368
|
+
events.some((event) => event.kind === "attempt.accepted")
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
if (keys.size > 0) {
|
|
1372
|
+
void this.#scope?.cache.invalidate([...keys.values()]);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1097
1375
|
#startObserver() {
|
|
1098
1376
|
if (this.#observer || !this.#mounted) {
|
|
1099
1377
|
return;
|
|
1100
1378
|
}
|
|
1101
1379
|
this.#starting = true;
|
|
1380
|
+
const { snapshotMs } = this.#polling;
|
|
1102
1381
|
try {
|
|
1103
|
-
this.#observer = this.client.quests.observe(
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1382
|
+
this.#observer = this.client.quests.observe(
|
|
1383
|
+
(observation) => {
|
|
1384
|
+
switch (observation.kind) {
|
|
1385
|
+
case "loading":
|
|
1386
|
+
this.#readForAcceptance = false;
|
|
1387
|
+
if (this.#starting) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
this.#sessionVersion++;
|
|
1391
|
+
this.#sessionRead?.abort();
|
|
1107
1392
|
return;
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
break;
|
|
1120
|
-
case "ready":
|
|
1121
|
-
this.#sessionVersion++;
|
|
1122
|
-
this.#setSession({
|
|
1123
|
-
status: "ready",
|
|
1124
|
-
data: observation.session,
|
|
1125
|
-
error: null
|
|
1126
|
-
});
|
|
1127
|
-
this.#completed(observation.progress);
|
|
1128
|
-
this.#experience = {
|
|
1129
|
-
owner: observation.progress.member,
|
|
1130
|
-
state: {
|
|
1393
|
+
case "session":
|
|
1394
|
+
this.#sessionVersion++;
|
|
1395
|
+
this.#setSession({
|
|
1396
|
+
status: "ready",
|
|
1397
|
+
data: observation.session,
|
|
1398
|
+
error: null
|
|
1399
|
+
});
|
|
1400
|
+
break;
|
|
1401
|
+
case "ready":
|
|
1402
|
+
this.#sessionVersion++;
|
|
1403
|
+
this.#setSession({
|
|
1131
1404
|
status: "ready",
|
|
1132
|
-
|
|
1133
|
-
data: {
|
|
1134
|
-
entitlements: observation.progress.entitlements,
|
|
1135
|
-
quests: visibleQuests(observation.progress.quests),
|
|
1136
|
-
collections: observation.progress.collections.map(
|
|
1137
|
-
(collection) => ({
|
|
1138
|
-
...collection,
|
|
1139
|
-
quests: visibleQuests(collection.quests)
|
|
1140
|
-
})
|
|
1141
|
-
)
|
|
1142
|
-
},
|
|
1405
|
+
data: observation.session,
|
|
1143
1406
|
error: null
|
|
1407
|
+
});
|
|
1408
|
+
this.#completed(observation.progress, this.#readForAcceptance);
|
|
1409
|
+
this.#readForAcceptance = false;
|
|
1410
|
+
this.#experience = {
|
|
1411
|
+
owner: observation.progress.member,
|
|
1412
|
+
state: {
|
|
1413
|
+
status: "ready",
|
|
1414
|
+
// Hidden quests never reach the UI, on any poll.
|
|
1415
|
+
data: {
|
|
1416
|
+
entitlements: observation.progress.entitlements,
|
|
1417
|
+
quests: visibleQuests(observation.progress.quests),
|
|
1418
|
+
collections: observation.progress.collections.map(
|
|
1419
|
+
(collection) => ({
|
|
1420
|
+
...collection,
|
|
1421
|
+
quests: visibleQuests(collection.quests)
|
|
1422
|
+
})
|
|
1423
|
+
)
|
|
1424
|
+
},
|
|
1425
|
+
error: null
|
|
1426
|
+
}
|
|
1427
|
+
};
|
|
1428
|
+
break;
|
|
1429
|
+
case "error": {
|
|
1430
|
+
const error = relayError(observation.error);
|
|
1431
|
+
const previous = this.#experience;
|
|
1432
|
+
this.#experience = previous.state.status === "ready" ? {
|
|
1433
|
+
owner: previous.owner,
|
|
1434
|
+
state: { ...previous.state, error }
|
|
1435
|
+
} : {
|
|
1436
|
+
owner: this.#scope?.member ?? null,
|
|
1437
|
+
state: { status: "error", data: void 0, error }
|
|
1438
|
+
};
|
|
1439
|
+
if (this.#session.status === "loading") {
|
|
1440
|
+
void this.refreshSession();
|
|
1144
1441
|
}
|
|
1145
|
-
|
|
1146
|
-
break;
|
|
1147
|
-
case "error": {
|
|
1148
|
-
const error = relayError(observation.error);
|
|
1149
|
-
const previous = this.#experience;
|
|
1150
|
-
this.#experience = previous.state.status === "ready" ? {
|
|
1151
|
-
owner: previous.owner,
|
|
1152
|
-
state: { ...previous.state, error }
|
|
1153
|
-
} : {
|
|
1154
|
-
owner: this.#scope?.member ?? null,
|
|
1155
|
-
state: { status: "error", data: void 0, error }
|
|
1156
|
-
};
|
|
1157
|
-
if (this.#session.status === "loading") {
|
|
1158
|
-
void this.refreshSession();
|
|
1442
|
+
break;
|
|
1159
1443
|
}
|
|
1160
|
-
break;
|
|
1161
1444
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1445
|
+
this.#emit();
|
|
1446
|
+
},
|
|
1447
|
+
// A failed read retries within seconds, not after the slow interval.
|
|
1448
|
+
{ intervalMs: snapshotMs, maxBackoffMs: snapshotMs, retryMs: 3e3 }
|
|
1449
|
+
);
|
|
1165
1450
|
} finally {
|
|
1166
1451
|
this.#starting = false;
|
|
1167
1452
|
}
|
|
1168
1453
|
}
|
|
1169
1454
|
/**
|
|
1170
1455
|
* A new completion changes points, scores, profile completions and referral progress, whether
|
|
1171
|
-
* the participant submitted it or Domino completed it by itself: read them again
|
|
1456
|
+
* the participant submitted it or Domino completed it by itself: read them again, unless the
|
|
1457
|
+
* `attempt.accepted` event that asked for this read already did.
|
|
1172
1458
|
*/
|
|
1173
|
-
#completed(progress) {
|
|
1459
|
+
#completed(progress, alreadyRead) {
|
|
1174
1460
|
const mark = completionMark([
|
|
1175
1461
|
...progress.quests,
|
|
1176
1462
|
...progress.collections.flatMap((collection) => collection.quests)
|
|
1177
1463
|
]);
|
|
1178
1464
|
const previous = this.#completions;
|
|
1179
1465
|
this.#completions = { member: progress.member, mark };
|
|
1180
|
-
if (previous?.member === progress.member && previous.mark !== mark) {
|
|
1466
|
+
if (previous?.member === progress.member && previous.mark !== mark && !alreadyRead) {
|
|
1181
1467
|
void this.#scope?.cache.invalidate(completionChanges);
|
|
1182
1468
|
}
|
|
1183
1469
|
}
|
|
@@ -1195,6 +1481,7 @@ var RelayStore = class {
|
|
|
1195
1481
|
this.#scope?.cache.dispose();
|
|
1196
1482
|
if (key === null) {
|
|
1197
1483
|
this.#scope = null;
|
|
1484
|
+
this.#syncFeed();
|
|
1198
1485
|
return;
|
|
1199
1486
|
}
|
|
1200
1487
|
const session = next.status === "ready" ? next.data : null;
|
|
@@ -1204,6 +1491,8 @@ var RelayStore = class {
|
|
|
1204
1491
|
member: sessionMember(session),
|
|
1205
1492
|
cache: new QueryCache(session?.id, () => void this.refreshSession())
|
|
1206
1493
|
};
|
|
1494
|
+
this.#firstCache ??= this.#scope.cache;
|
|
1495
|
+
this.#syncFeed();
|
|
1207
1496
|
}
|
|
1208
1497
|
#deriveExperience() {
|
|
1209
1498
|
const session = this.#session;
|
|
@@ -1221,6 +1510,10 @@ var RelayStore = class {
|
|
|
1221
1510
|
}
|
|
1222
1511
|
#emit() {
|
|
1223
1512
|
const experience = this.#deriveExperience();
|
|
1513
|
+
if (this.#settled && this.#session.status !== "loading") {
|
|
1514
|
+
this.#settled.resolve();
|
|
1515
|
+
this.#settled = null;
|
|
1516
|
+
}
|
|
1224
1517
|
if (experience !== this.#experienceView) {
|
|
1225
1518
|
this.#experienceView = experience;
|
|
1226
1519
|
}
|
|
@@ -1230,35 +1523,7 @@ var RelayStore = class {
|
|
|
1230
1523
|
}
|
|
1231
1524
|
};
|
|
1232
1525
|
|
|
1233
|
-
// src/react/provider.tsx
|
|
1234
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1235
|
-
function RelayProvider({
|
|
1236
|
-
client,
|
|
1237
|
-
baseUrl = "/relay",
|
|
1238
|
-
children
|
|
1239
|
-
}) {
|
|
1240
|
-
const origin = client ? null : baseUrl;
|
|
1241
|
-
const store = useMemo2(
|
|
1242
|
-
() => new RelayStore(
|
|
1243
|
-
client ?? createBrowserRelayClient({ baseUrl: origin ?? baseUrl })
|
|
1244
|
-
),
|
|
1245
|
-
// A given client ignores `baseUrl`.
|
|
1246
|
-
[client, origin]
|
|
1247
|
-
);
|
|
1248
|
-
useEffect3(() => store.mount(), [store]);
|
|
1249
|
-
return /* @__PURE__ */ jsx2(StoreContext, { value: store, children: /* @__PURE__ */ jsx2(DeliveriesProvider, { children }) });
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
1526
|
// src/react/query.ts
|
|
1253
|
-
import {
|
|
1254
|
-
useCallback as useCallback4,
|
|
1255
|
-
useEffect as useEffect4,
|
|
1256
|
-
useLayoutEffect as useLayoutEffect2,
|
|
1257
|
-
useMemo as useMemo3,
|
|
1258
|
-
useRef as useRef3,
|
|
1259
|
-
useState as useState4,
|
|
1260
|
-
useSyncExternalStore as useSyncExternalStore3
|
|
1261
|
-
} from "react";
|
|
1262
1527
|
function useLatest(value) {
|
|
1263
1528
|
const ref = useRef3(value);
|
|
1264
1529
|
useLayoutEffect2(() => {
|
|
@@ -1268,17 +1533,34 @@ function useLatest(value) {
|
|
|
1268
1533
|
}
|
|
1269
1534
|
function useSessionSnapshot(store) {
|
|
1270
1535
|
const get = () => store.session;
|
|
1271
|
-
return
|
|
1536
|
+
return useSyncExternalStore2(store.subscribe, get, get);
|
|
1272
1537
|
}
|
|
1273
1538
|
function useScope(store) {
|
|
1274
1539
|
const get = () => store.scope;
|
|
1275
|
-
return
|
|
1540
|
+
return useSyncExternalStore2(store.subscribe, get, get);
|
|
1541
|
+
}
|
|
1542
|
+
function isInitializer(value) {
|
|
1543
|
+
return typeof value === "function";
|
|
1276
1544
|
}
|
|
1277
|
-
function
|
|
1545
|
+
function useSeed(key, initialData) {
|
|
1278
1546
|
const hash = key ? hashKey(key) : null;
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1547
|
+
return useMemo(() => {
|
|
1548
|
+
if (initialData === void 0) {
|
|
1549
|
+
return null;
|
|
1550
|
+
}
|
|
1551
|
+
const data = isInitializer(initialData) ? initialData() : initialData;
|
|
1552
|
+
return {
|
|
1553
|
+
seed: { data, at: Date.now() },
|
|
1554
|
+
shown: { status: "ready", data, error: null }
|
|
1555
|
+
};
|
|
1556
|
+
}, [hash]);
|
|
1557
|
+
}
|
|
1558
|
+
function useCached(cache, key, read, options, seeded = null) {
|
|
1559
|
+
const { intervalMs, refetchOnFocus, staleMs } = options;
|
|
1560
|
+
const active = options.enabled === false ? null : key;
|
|
1561
|
+
const hash = active ? hashKey(active) : null;
|
|
1562
|
+
const latest = useLatest({ key: active, read });
|
|
1563
|
+
const subscribe = useCallback3(
|
|
1282
1564
|
(listener) => {
|
|
1283
1565
|
const { key: current } = latest.current;
|
|
1284
1566
|
if (!cache || !current) {
|
|
@@ -1288,41 +1570,89 @@ function useCached(cache, key, read, options) {
|
|
|
1288
1570
|
return cache.subscribe(
|
|
1289
1571
|
current,
|
|
1290
1572
|
(context) => latest.current.read(context),
|
|
1291
|
-
{ intervalMs, refetchOnFocus },
|
|
1292
|
-
listener
|
|
1573
|
+
{ intervalMs, refetchOnFocus, staleMs },
|
|
1574
|
+
listener,
|
|
1575
|
+
seeded?.seed
|
|
1293
1576
|
);
|
|
1294
1577
|
},
|
|
1295
1578
|
// `hash` stands for the key.
|
|
1296
|
-
[cache, hash, intervalMs, refetchOnFocus]
|
|
1579
|
+
[cache, hash, intervalMs, refetchOnFocus, staleMs, seeded]
|
|
1297
1580
|
);
|
|
1298
|
-
const get = () =>
|
|
1299
|
-
|
|
1300
|
-
|
|
1581
|
+
const get = () => {
|
|
1582
|
+
const fallback = seeded?.shown ?? LOADING;
|
|
1583
|
+
return cache && active ? cache.snapshot(active, fallback) : fallback;
|
|
1584
|
+
};
|
|
1585
|
+
const snapshot = useSyncExternalStore2(subscribe, get, get);
|
|
1586
|
+
const refresh = useCallback3(
|
|
1301
1587
|
() => cache && latest.current.key ? cache.refresh(latest.current.key) : Promise.resolve(),
|
|
1302
1588
|
[cache, hash]
|
|
1303
1589
|
);
|
|
1304
|
-
return
|
|
1590
|
+
return useMemo(() => ({ ...snapshot, refresh }), [snapshot, refresh]);
|
|
1591
|
+
}
|
|
1592
|
+
function selected(query, select) {
|
|
1593
|
+
return query.status === "ready" ? { ...query, data: select(query.data) } : query;
|
|
1594
|
+
}
|
|
1595
|
+
function suspend(query, store, cache, key, read, seed) {
|
|
1596
|
+
if (query.status === "error") {
|
|
1597
|
+
throw query.error;
|
|
1598
|
+
}
|
|
1599
|
+
if (query.status !== "loading" || !key) {
|
|
1600
|
+
return;
|
|
1601
|
+
}
|
|
1602
|
+
if (typeof window === "undefined") {
|
|
1603
|
+
throw new Error("Domino suspense queries read in the browser");
|
|
1604
|
+
}
|
|
1605
|
+
throw cache ? cache.ensure(key, read, seed) : store.settled();
|
|
1305
1606
|
}
|
|
1306
1607
|
function useRelayQuery(key, read, options = {}) {
|
|
1307
1608
|
const store = useStore();
|
|
1308
1609
|
const scope = useScope(store);
|
|
1309
|
-
|
|
1610
|
+
const cache = scope?.cache ?? null;
|
|
1611
|
+
const seeded = useSeed(key, options.initialData);
|
|
1612
|
+
const seed = !cache || cache === store.firstCache ? seeded : null;
|
|
1613
|
+
const query = useCached(cache, key, read, options, seed);
|
|
1614
|
+
const { select } = options;
|
|
1615
|
+
if (options.suspense) {
|
|
1616
|
+
suspend(
|
|
1617
|
+
query,
|
|
1618
|
+
store,
|
|
1619
|
+
cache,
|
|
1620
|
+
options.enabled === false ? null : key,
|
|
1621
|
+
read,
|
|
1622
|
+
seed?.seed
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
return useMemo(
|
|
1626
|
+
() => select ? selected(query, select) : query,
|
|
1627
|
+
[query, select]
|
|
1628
|
+
);
|
|
1310
1629
|
}
|
|
1311
1630
|
function useMemberQuery(key, read, options = {}) {
|
|
1312
1631
|
const store = useStore();
|
|
1313
1632
|
const scope = useScope(store);
|
|
1314
1633
|
const member = scope?.member ?? null;
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1634
|
+
const cache = member ? scope.cache : null;
|
|
1635
|
+
const query = useCached(cache, member ? key : null, read, options);
|
|
1636
|
+
const gated = useMemberGate(store, member, query);
|
|
1637
|
+
if (options.suspense) {
|
|
1638
|
+
suspend(
|
|
1639
|
+
gated,
|
|
1640
|
+
store,
|
|
1641
|
+
cache,
|
|
1642
|
+
options.enabled === false ? null : key,
|
|
1643
|
+
read,
|
|
1644
|
+
void 0
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
const { select } = options;
|
|
1648
|
+
return useMemo(
|
|
1649
|
+
() => select ? selected(gated, select) : gated,
|
|
1650
|
+
[gated, select]
|
|
1320
1651
|
);
|
|
1321
|
-
return useMemberGate(store, member, query);
|
|
1322
1652
|
}
|
|
1323
1653
|
function useMemberGate(store, member, query) {
|
|
1324
1654
|
const session = useSessionSnapshot(store);
|
|
1325
|
-
return
|
|
1655
|
+
return useMemo(() => {
|
|
1326
1656
|
if (session.status === "loading") {
|
|
1327
1657
|
return { ...LOADING, refresh: query.refresh };
|
|
1328
1658
|
}
|
|
@@ -1337,7 +1667,8 @@ function useMemberGate(store, member, query) {
|
|
|
1337
1667
|
return member ? query : { ...SIGNED_OUT, refresh: query.refresh };
|
|
1338
1668
|
}, [session, member, query, store]);
|
|
1339
1669
|
}
|
|
1340
|
-
function usePages(cache,
|
|
1670
|
+
function usePages(cache, requested, read, options) {
|
|
1671
|
+
const key = options.enabled === false ? null : requested;
|
|
1341
1672
|
const hash = key ? hashKey(key) : null;
|
|
1342
1673
|
const query = useCached(
|
|
1343
1674
|
cache,
|
|
@@ -1345,17 +1676,17 @@ function usePages(cache, key, read, options) {
|
|
|
1345
1676
|
(context) => read(context),
|
|
1346
1677
|
options
|
|
1347
1678
|
);
|
|
1348
|
-
const [more, setMore] =
|
|
1679
|
+
const [more, setMore] = useState3(null);
|
|
1349
1680
|
const busy = useRef3(null);
|
|
1350
1681
|
const latest = useLatest({ key, read, query });
|
|
1351
|
-
|
|
1682
|
+
useEffect2(
|
|
1352
1683
|
() => () => {
|
|
1353
1684
|
busy.current?.abort();
|
|
1354
1685
|
busy.current = null;
|
|
1355
1686
|
},
|
|
1356
1687
|
[cache, hash]
|
|
1357
1688
|
);
|
|
1358
|
-
const loadMore =
|
|
1689
|
+
const loadMore = useCallback3(async () => {
|
|
1359
1690
|
const { key: current, read: reader, query: shown } = latest.current;
|
|
1360
1691
|
if (!cache || !current || busy.current || shown.status !== "ready" || shown.data.nextCursor === null) {
|
|
1361
1692
|
return;
|
|
@@ -1391,7 +1722,7 @@ function usePages(cache, key, read, options) {
|
|
|
1391
1722
|
}
|
|
1392
1723
|
}, [cache, hash]);
|
|
1393
1724
|
const mine = more && more.owner.cache === cache && more.owner.hash === hash ? more : null;
|
|
1394
|
-
return
|
|
1725
|
+
return useMemo(
|
|
1395
1726
|
() => ({
|
|
1396
1727
|
...query,
|
|
1397
1728
|
loadMore,
|
|
@@ -1417,7 +1748,7 @@ function useMemberPages(key, read, options = {}) {
|
|
|
1417
1748
|
options
|
|
1418
1749
|
);
|
|
1419
1750
|
const gate = useMemberGate(store, member, pages);
|
|
1420
|
-
return
|
|
1751
|
+
return useMemo(
|
|
1421
1752
|
() => gate === pages ? pages : {
|
|
1422
1753
|
...gate,
|
|
1423
1754
|
loadMore: pages.loadMore,
|
|
@@ -1429,13 +1760,33 @@ function useMemberPages(key, read, options = {}) {
|
|
|
1429
1760
|
}
|
|
1430
1761
|
function useInvalidate() {
|
|
1431
1762
|
const store = useStore();
|
|
1432
|
-
return
|
|
1763
|
+
return useCallback3((keys = []) => store.invalidate(keys), [store]);
|
|
1764
|
+
}
|
|
1765
|
+
function isUpdater(update) {
|
|
1766
|
+
return typeof update === "function";
|
|
1767
|
+
}
|
|
1768
|
+
function useSetQueryData() {
|
|
1769
|
+
const store = useStore();
|
|
1770
|
+
return useCallback3(
|
|
1771
|
+
(key, update) => {
|
|
1772
|
+
const cache = store.scope?.cache;
|
|
1773
|
+
if (!cache) {
|
|
1774
|
+
return false;
|
|
1775
|
+
}
|
|
1776
|
+
const current = cache.snapshot(key);
|
|
1777
|
+
return cache.set(
|
|
1778
|
+
key,
|
|
1779
|
+
isUpdater(update) ? update(current.status === "ready" ? current.data : void 0) : update
|
|
1780
|
+
);
|
|
1781
|
+
},
|
|
1782
|
+
[store]
|
|
1783
|
+
);
|
|
1433
1784
|
}
|
|
1434
1785
|
function useSession() {
|
|
1435
1786
|
const store = useStore();
|
|
1436
1787
|
const session = useSessionSnapshot(store);
|
|
1437
1788
|
const refresh = store.rereadSession;
|
|
1438
|
-
return
|
|
1789
|
+
return useMemo(
|
|
1439
1790
|
() => ({
|
|
1440
1791
|
...session,
|
|
1441
1792
|
refresh,
|
|
@@ -1447,41 +1798,227 @@ function useSession() {
|
|
|
1447
1798
|
function useAction() {
|
|
1448
1799
|
const session = useScopeSession();
|
|
1449
1800
|
const store = useStore();
|
|
1450
|
-
const scope =
|
|
1801
|
+
const scope = useMemo(() => ({ store, session }), [store, session]);
|
|
1451
1802
|
const {
|
|
1452
1803
|
run: execute,
|
|
1453
1804
|
retry: replay,
|
|
1454
|
-
|
|
1455
|
-
error:
|
|
1456
|
-
settle
|
|
1805
|
+
isPending,
|
|
1806
|
+
error: actionError2,
|
|
1807
|
+
settle,
|
|
1808
|
+
reset: resetAction
|
|
1457
1809
|
} = useRelayAction(scope);
|
|
1458
|
-
const run =
|
|
1810
|
+
const run = useCallback3(
|
|
1459
1811
|
async (task) => (await execute(task)).ok,
|
|
1460
1812
|
[execute]
|
|
1461
1813
|
);
|
|
1462
|
-
const retry =
|
|
1463
|
-
return {
|
|
1814
|
+
const retry = useCallback3(async () => (await replay()).ok, [replay]);
|
|
1815
|
+
return { isPending, actionError: actionError2, resetAction, run, retry, settle };
|
|
1464
1816
|
}
|
|
1465
1817
|
function useScopeSession() {
|
|
1466
1818
|
const store = useStore();
|
|
1467
1819
|
return useScope(store)?.session?.id;
|
|
1468
1820
|
}
|
|
1469
1821
|
|
|
1822
|
+
// src/react/mutation.ts
|
|
1823
|
+
function useMutation(mutation, options = {}) {
|
|
1824
|
+
const store = useStore();
|
|
1825
|
+
const invalidate = useInvalidate();
|
|
1826
|
+
const session = useScopeSession();
|
|
1827
|
+
const scope = useMemo2(() => ({ store, session }), [store, session]);
|
|
1828
|
+
const action = useRelayAction(scope);
|
|
1829
|
+
const { run, retry, reset, settle } = action;
|
|
1830
|
+
const latest = useRef4({ mutation, options });
|
|
1831
|
+
const ran = useRef4(null);
|
|
1832
|
+
useLayoutEffect3(() => {
|
|
1833
|
+
latest.current = { mutation, options };
|
|
1834
|
+
});
|
|
1835
|
+
const after = useCallback4(
|
|
1836
|
+
async (result) => {
|
|
1837
|
+
if (!result.ok) {
|
|
1838
|
+
throw result.error ?? clientError(
|
|
1839
|
+
"Another change is still running; wait for it to finish",
|
|
1840
|
+
RelayErrorCode.InvalidInput
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
const { invalidates } = latest.current.options;
|
|
1844
|
+
const keys = typeof invalidates === "function" ? ran.current ? invalidates(result.value, ran.current.variables) : [] : invalidates;
|
|
1845
|
+
if (keys?.length) {
|
|
1846
|
+
await invalidate(keys);
|
|
1847
|
+
}
|
|
1848
|
+
return result.value;
|
|
1849
|
+
},
|
|
1850
|
+
[invalidate]
|
|
1851
|
+
);
|
|
1852
|
+
const mutateAsync = useCallback4(
|
|
1853
|
+
async (variables) => {
|
|
1854
|
+
const write = latest.current.mutation;
|
|
1855
|
+
const result = await run((actionId) => {
|
|
1856
|
+
ran.current = { variables };
|
|
1857
|
+
return write(variables, { actionId, session });
|
|
1858
|
+
});
|
|
1859
|
+
return after(result);
|
|
1860
|
+
},
|
|
1861
|
+
[run, after, session]
|
|
1862
|
+
);
|
|
1863
|
+
const mutate = useCallback4(
|
|
1864
|
+
(variables) => {
|
|
1865
|
+
mutateAsync(variables).catch(() => {
|
|
1866
|
+
});
|
|
1867
|
+
},
|
|
1868
|
+
[mutateAsync]
|
|
1869
|
+
);
|
|
1870
|
+
const replay = useCallback4(async () => {
|
|
1871
|
+
try {
|
|
1872
|
+
return await after(await retry());
|
|
1873
|
+
} catch {
|
|
1874
|
+
return null;
|
|
1875
|
+
}
|
|
1876
|
+
}, [retry, after]);
|
|
1877
|
+
const shape = useMemo2(
|
|
1878
|
+
() => ({
|
|
1879
|
+
mutate,
|
|
1880
|
+
mutateAsync,
|
|
1881
|
+
status: action.status,
|
|
1882
|
+
isPending: action.isPending,
|
|
1883
|
+
data: action.data,
|
|
1884
|
+
error: action.error,
|
|
1885
|
+
reset,
|
|
1886
|
+
settle
|
|
1887
|
+
}),
|
|
1888
|
+
[
|
|
1889
|
+
mutate,
|
|
1890
|
+
mutateAsync,
|
|
1891
|
+
action.status,
|
|
1892
|
+
action.isPending,
|
|
1893
|
+
action.data,
|
|
1894
|
+
action.error,
|
|
1895
|
+
reset,
|
|
1896
|
+
settle
|
|
1897
|
+
]
|
|
1898
|
+
);
|
|
1899
|
+
return { mutation: shape, replay };
|
|
1900
|
+
}
|
|
1901
|
+
function useRelayMutation(mutation, options = {}) {
|
|
1902
|
+
return useMutation(mutation, options).mutation;
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
// src/react/provider.tsx
|
|
1906
|
+
import { useEffect as useEffect4, useMemo as useMemo4 } from "react";
|
|
1907
|
+
|
|
1908
|
+
// src/react/experience.tsx
|
|
1909
|
+
import {
|
|
1910
|
+
createContext as createContext2,
|
|
1911
|
+
useCallback as useCallback5,
|
|
1912
|
+
useContext as useContext2,
|
|
1913
|
+
useMemo as useMemo3,
|
|
1914
|
+
useSyncExternalStore as useSyncExternalStore3
|
|
1915
|
+
} from "react";
|
|
1916
|
+
|
|
1917
|
+
// src/react/use-role-deliveries.ts
|
|
1918
|
+
import { useEffect as useEffect3, useState as useState4 } from "react";
|
|
1919
|
+
var NONE = Object.freeze([]);
|
|
1920
|
+
function useRoleDeliveries(relay, member, completions) {
|
|
1921
|
+
const [state, setState] = useState4(null);
|
|
1922
|
+
useEffect3(() => {
|
|
1923
|
+
if (!member || !completions) {
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
const watch = watchRoleDeliveries({
|
|
1927
|
+
read: async () => (await relay.me.rewardDeliveries()).deliveries,
|
|
1928
|
+
onChange: (deliveries) => setState({ member, deliveries })
|
|
1929
|
+
});
|
|
1930
|
+
const wake = () => {
|
|
1931
|
+
if (document.visibilityState === "visible") {
|
|
1932
|
+
watch.wake();
|
|
1933
|
+
}
|
|
1934
|
+
};
|
|
1935
|
+
window.addEventListener("focus", wake);
|
|
1936
|
+
document.addEventListener("visibilitychange", wake);
|
|
1937
|
+
return () => {
|
|
1938
|
+
watch.dispose();
|
|
1939
|
+
window.removeEventListener("focus", wake);
|
|
1940
|
+
document.removeEventListener("visibilitychange", wake);
|
|
1941
|
+
};
|
|
1942
|
+
}, [relay, member, completions]);
|
|
1943
|
+
return member && completions && state?.member === member ? state.deliveries : NONE;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
// src/react/experience.tsx
|
|
1947
|
+
import { jsx } from "react/jsx-runtime";
|
|
1948
|
+
var Deliveries = createContext2(Object.freeze([]));
|
|
1949
|
+
function useExperienceSnapshot() {
|
|
1950
|
+
const store = useStore();
|
|
1951
|
+
const get = () => store.experience;
|
|
1952
|
+
return useSyncExternalStore3(store.subscribe, get, get);
|
|
1953
|
+
}
|
|
1954
|
+
function DeliveriesProvider({ children }) {
|
|
1955
|
+
const store = useStore();
|
|
1956
|
+
const experience = useExperienceSnapshot();
|
|
1957
|
+
const member = useSyncExternalStore3(
|
|
1958
|
+
store.subscribe,
|
|
1959
|
+
() => store.scope?.member ?? null,
|
|
1960
|
+
() => null
|
|
1961
|
+
);
|
|
1962
|
+
const ready = experience.status === "ready";
|
|
1963
|
+
const deliveries = useRoleDeliveries(
|
|
1964
|
+
store.client,
|
|
1965
|
+
ready ? member : null,
|
|
1966
|
+
ready ? completionMark([
|
|
1967
|
+
...experience.data.quests,
|
|
1968
|
+
...experience.data.collections.flatMap((c) => c.quests)
|
|
1969
|
+
]) : ""
|
|
1970
|
+
);
|
|
1971
|
+
return /* @__PURE__ */ jsx(Deliveries, { value: deliveries, children });
|
|
1972
|
+
}
|
|
1973
|
+
function useExperience() {
|
|
1974
|
+
const store = useStore();
|
|
1975
|
+
const experience = useExperienceSnapshot();
|
|
1976
|
+
const deliveries = useContext2(Deliveries);
|
|
1977
|
+
const refresh = useCallback5(() => store.refreshExperience(), [store]);
|
|
1978
|
+
return useMemo3(
|
|
1979
|
+
() => ({ ...experience, refresh, deliveries }),
|
|
1980
|
+
[experience, refresh, deliveries]
|
|
1981
|
+
);
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
// src/react/provider.tsx
|
|
1985
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1986
|
+
function RelayProvider({
|
|
1987
|
+
client,
|
|
1988
|
+
baseUrl = "/relay",
|
|
1989
|
+
polling,
|
|
1990
|
+
children
|
|
1991
|
+
}) {
|
|
1992
|
+
const origin = client ? null : baseUrl;
|
|
1993
|
+
const activityMs = polling?.activityMs;
|
|
1994
|
+
const snapshotMs = polling?.snapshotMs;
|
|
1995
|
+
const store = useMemo4(
|
|
1996
|
+
() => new RelayStore(
|
|
1997
|
+
client ?? createBrowserRelayClient({ baseUrl: origin ?? baseUrl }),
|
|
1998
|
+
{ activityMs, snapshotMs }
|
|
1999
|
+
),
|
|
2000
|
+
// A given client ignores `baseUrl`; `polling` is compared by value.
|
|
2001
|
+
[client, origin, activityMs, snapshotMs]
|
|
2002
|
+
);
|
|
2003
|
+
useEffect4(() => store.mount(), [store]);
|
|
2004
|
+
return /* @__PURE__ */ jsx2(StoreContext, { value: store, children: /* @__PURE__ */ jsx2(DeliveriesProvider, { children }) });
|
|
2005
|
+
}
|
|
2006
|
+
|
|
1470
2007
|
// src/react/rewards.ts
|
|
1471
2008
|
function useEntitlements(options = {}) {
|
|
1472
2009
|
const relay = useRelay();
|
|
1473
2010
|
return useMemberQuery(
|
|
1474
|
-
|
|
2011
|
+
rewardKeys.entitlements,
|
|
1475
2012
|
(context) => relay.rewards.entitlements(context),
|
|
1476
|
-
{ intervalMs:
|
|
2013
|
+
{ intervalMs: 3e4, ...options }
|
|
1477
2014
|
);
|
|
1478
2015
|
}
|
|
1479
2016
|
function useDeliveries(options = {}) {
|
|
1480
2017
|
const relay = useRelay();
|
|
1481
2018
|
return useMemberQuery(
|
|
1482
|
-
|
|
2019
|
+
rewardKeys.deliveries,
|
|
1483
2020
|
(context) => relay.rewards.deliveries(context),
|
|
1484
|
-
{ intervalMs:
|
|
2021
|
+
{ intervalMs: 3e4, ...options }
|
|
1485
2022
|
);
|
|
1486
2023
|
}
|
|
1487
2024
|
|
|
@@ -1507,11 +2044,11 @@ function questGroups(experience, order = []) {
|
|
|
1507
2044
|
|
|
1508
2045
|
// src/react/use-quest.ts
|
|
1509
2046
|
import {
|
|
1510
|
-
useCallback as
|
|
2047
|
+
useCallback as useCallback6,
|
|
1511
2048
|
useEffect as useEffect5,
|
|
1512
|
-
useLayoutEffect as
|
|
1513
|
-
useMemo as
|
|
1514
|
-
useRef as
|
|
2049
|
+
useLayoutEffect as useLayoutEffect4,
|
|
2050
|
+
useMemo as useMemo5,
|
|
2051
|
+
useRef as useRef5,
|
|
1515
2052
|
useState as useState5
|
|
1516
2053
|
} from "react";
|
|
1517
2054
|
function useQuest(observed) {
|
|
@@ -1522,7 +2059,7 @@ function useQuest(observed) {
|
|
|
1522
2059
|
const [notice, setNotice] = useState5(null);
|
|
1523
2060
|
const [error, setError] = useState5(null);
|
|
1524
2061
|
const [busy, setBusy] = useState5(false);
|
|
1525
|
-
const lock =
|
|
2062
|
+
const lock = useRef5(false);
|
|
1526
2063
|
const [discardedAttempt, setDiscardedAttempt] = useState5(null);
|
|
1527
2064
|
const [saved, setSaved] = useState5("none");
|
|
1528
2065
|
const [recoveryRevision, setRecoveryRevision] = useState5(0);
|
|
@@ -1551,7 +2088,7 @@ function useQuest(observed) {
|
|
|
1551
2088
|
active = false;
|
|
1552
2089
|
};
|
|
1553
2090
|
}, [relay, quest, release, completed, attempt, busy, recoveryRevision]);
|
|
1554
|
-
const run =
|
|
2091
|
+
const run = useCallback6(
|
|
1555
2092
|
async (action) => {
|
|
1556
2093
|
if (lock.current) {
|
|
1557
2094
|
return;
|
|
@@ -1582,11 +2119,11 @@ function useQuest(observed) {
|
|
|
1582
2119
|
},
|
|
1583
2120
|
[store]
|
|
1584
2121
|
);
|
|
1585
|
-
const shown =
|
|
1586
|
-
|
|
2122
|
+
const shown = useRef5(view);
|
|
2123
|
+
useLayoutEffect4(() => {
|
|
1587
2124
|
shown.current = view;
|
|
1588
2125
|
});
|
|
1589
|
-
const actions =
|
|
2126
|
+
const actions = useMemo5(
|
|
1590
2127
|
() => ({
|
|
1591
2128
|
restart: async () => {
|
|
1592
2129
|
if (lock.current) {
|
|
@@ -1659,7 +2196,7 @@ function useQuest(observed) {
|
|
|
1659
2196
|
[relay, run]
|
|
1660
2197
|
);
|
|
1661
2198
|
const startingFresh = view.attempt?.id === discardedAttempt && view.attempt?.status === "failed";
|
|
1662
|
-
return
|
|
2199
|
+
return useMemo5(
|
|
1663
2200
|
() => ({
|
|
1664
2201
|
/** The newest known version of the quest. Render this, not the prop. */
|
|
1665
2202
|
view,
|
|
@@ -1667,6 +2204,9 @@ function useQuest(observed) {
|
|
|
1667
2204
|
draft,
|
|
1668
2205
|
notice,
|
|
1669
2206
|
error,
|
|
2207
|
+
/** True while `submit`, `resume`, `retry` or `restart` runs. */
|
|
2208
|
+
isPending: busy,
|
|
2209
|
+
/** @deprecated Use `isPending`. Removed in 2.0.0. */
|
|
1670
2210
|
busy,
|
|
1671
2211
|
saved,
|
|
1672
2212
|
/** Review and explicitly restart this terminally retired saved submission. */
|
|
@@ -1692,10 +2232,10 @@ function useQuest(observed) {
|
|
|
1692
2232
|
}
|
|
1693
2233
|
|
|
1694
2234
|
// src/react/auth.ts
|
|
1695
|
-
import { useCallback as
|
|
2235
|
+
import { useCallback as useCallback7, useMemo as useMemo7, useRef as useRef6, useState as useState7 } from "react";
|
|
1696
2236
|
|
|
1697
2237
|
// src/react/wallets.ts
|
|
1698
|
-
import { useEffect as useEffect6, useMemo as
|
|
2238
|
+
import { useEffect as useEffect6, useMemo as useMemo6, useState as useState6 } from "react";
|
|
1699
2239
|
function useWallets() {
|
|
1700
2240
|
const relay = useRelay();
|
|
1701
2241
|
const invalidate = useInvalidate();
|
|
@@ -1705,8 +2245,8 @@ function useWallets() {
|
|
|
1705
2245
|
(options) => relay.wallets.list(options),
|
|
1706
2246
|
{ refetchOnFocus: true }
|
|
1707
2247
|
);
|
|
1708
|
-
const {
|
|
1709
|
-
const actions =
|
|
2248
|
+
const { isPending, actionError: actionError2, resetAction, run, retry, settle } = useAction();
|
|
2249
|
+
const actions = useMemo6(() => {
|
|
1710
2250
|
const changed = () => void invalidate([relayKeys.wallets, relayKeys.experience]);
|
|
1711
2251
|
return {
|
|
1712
2252
|
/** Links the wallet to the member the list was read for; another session is refused. */
|
|
@@ -1723,9 +2263,19 @@ function useWallets() {
|
|
|
1723
2263
|
})
|
|
1724
2264
|
};
|
|
1725
2265
|
}, [relay, invalidate, session, run]);
|
|
1726
|
-
return
|
|
1727
|
-
() => ({
|
|
1728
|
-
|
|
2266
|
+
return useMemo6(
|
|
2267
|
+
() => ({
|
|
2268
|
+
...query,
|
|
2269
|
+
isPending,
|
|
2270
|
+
/** @deprecated Use `isPending`. Removed in 2.0.0. */
|
|
2271
|
+
busy: isPending,
|
|
2272
|
+
actionError: actionError2,
|
|
2273
|
+
resetAction,
|
|
2274
|
+
retry,
|
|
2275
|
+
settle,
|
|
2276
|
+
...actions
|
|
2277
|
+
}),
|
|
2278
|
+
[query, isPending, actionError2, resetAction, retry, settle, actions]
|
|
1729
2279
|
);
|
|
1730
2280
|
}
|
|
1731
2281
|
function discoverChains(key) {
|
|
@@ -1793,15 +2343,15 @@ function useMe() {
|
|
|
1793
2343
|
function useSignIn() {
|
|
1794
2344
|
const relay = useRelay();
|
|
1795
2345
|
const [challenge, setChallengeState] = useState7(null);
|
|
1796
|
-
const latest =
|
|
2346
|
+
const latest = useRef6(null);
|
|
1797
2347
|
const [busy, setBusy] = useState7(false);
|
|
1798
|
-
const lock =
|
|
2348
|
+
const lock = useRef6(false);
|
|
1799
2349
|
const [error, setError] = useState7(null);
|
|
1800
|
-
const setChallenge =
|
|
2350
|
+
const setChallenge = useCallback7((value) => {
|
|
1801
2351
|
latest.current = value;
|
|
1802
2352
|
setChallengeState(value);
|
|
1803
2353
|
}, []);
|
|
1804
|
-
const run =
|
|
2354
|
+
const run = useCallback7(
|
|
1805
2355
|
async (task, fallback) => {
|
|
1806
2356
|
if (lock.current) {
|
|
1807
2357
|
return;
|
|
@@ -1820,14 +2370,14 @@ function useSignIn() {
|
|
|
1820
2370
|
},
|
|
1821
2371
|
[]
|
|
1822
2372
|
);
|
|
1823
|
-
const sendCode =
|
|
2373
|
+
const sendCode = useCallback7(
|
|
1824
2374
|
(email) => run(async () => {
|
|
1825
2375
|
setChallenge(null);
|
|
1826
2376
|
setChallenge((await relay.auth.emailStart(email)).challenge);
|
|
1827
2377
|
}, "Couldn't send a code. Check the address and try again."),
|
|
1828
2378
|
[relay, run, setChallenge]
|
|
1829
2379
|
);
|
|
1830
|
-
const verifyCode =
|
|
2380
|
+
const verifyCode = useCallback7(
|
|
1831
2381
|
(code) => run(async () => {
|
|
1832
2382
|
const sent = latest.current;
|
|
1833
2383
|
if (!sent) {
|
|
@@ -1838,18 +2388,19 @@ function useSignIn() {
|
|
|
1838
2388
|
}, "That code didn't work. Check it, or request a new one."),
|
|
1839
2389
|
[relay, run, setChallenge]
|
|
1840
2390
|
);
|
|
1841
|
-
const startOver =
|
|
2391
|
+
const startOver = useCallback7(() => {
|
|
1842
2392
|
setChallenge(null);
|
|
1843
2393
|
setError(null);
|
|
1844
2394
|
}, [setChallenge]);
|
|
1845
|
-
const
|
|
2395
|
+
const reset = useCallback7(() => setError(null), []);
|
|
2396
|
+
const withProvider = useCallback7(
|
|
1846
2397
|
(provider) => run(async () => {
|
|
1847
2398
|
const { url } = await relay.auth.start(provider, "sign-in");
|
|
1848
2399
|
window.location.assign(url);
|
|
1849
2400
|
}, "Couldn't start sign-in. Try again."),
|
|
1850
2401
|
[relay, run]
|
|
1851
2402
|
);
|
|
1852
|
-
const withWallet =
|
|
2403
|
+
const withWallet = useCallback7(
|
|
1853
2404
|
(signer) => run(async () => {
|
|
1854
2405
|
await relay.auth.wallet.signIn(signer);
|
|
1855
2406
|
setChallenge(null);
|
|
@@ -1857,10 +2408,15 @@ function useSignIn() {
|
|
|
1857
2408
|
[relay, run, setChallenge]
|
|
1858
2409
|
);
|
|
1859
2410
|
const codeSent = challenge !== null;
|
|
1860
|
-
return
|
|
2411
|
+
return useMemo7(
|
|
1861
2412
|
() => ({
|
|
2413
|
+
/** True while a sign-in action runs. */
|
|
2414
|
+
isPending: busy,
|
|
2415
|
+
/** @deprecated Use `isPending`. Removed in 2.0.0. */
|
|
1862
2416
|
busy,
|
|
1863
2417
|
error,
|
|
2418
|
+
/** Clears `error`, keeping a code already sent. */
|
|
2419
|
+
reset,
|
|
1864
2420
|
/** True once a code was sent and the form should ask for it. */
|
|
1865
2421
|
codeSent,
|
|
1866
2422
|
sendCode,
|
|
@@ -1873,6 +2429,7 @@ function useSignIn() {
|
|
|
1873
2429
|
[
|
|
1874
2430
|
busy,
|
|
1875
2431
|
error,
|
|
2432
|
+
reset,
|
|
1876
2433
|
codeSent,
|
|
1877
2434
|
sendCode,
|
|
1878
2435
|
verifyCode,
|
|
@@ -1884,26 +2441,28 @@ function useSignIn() {
|
|
|
1884
2441
|
}
|
|
1885
2442
|
function useSignOut() {
|
|
1886
2443
|
const store = useStore();
|
|
1887
|
-
const
|
|
1888
|
-
const
|
|
1889
|
-
const
|
|
2444
|
+
const { mutation } = useMutation(() => store.signOut());
|
|
2445
|
+
const { mutateAsync } = mutation;
|
|
2446
|
+
const lock = useRef6(false);
|
|
2447
|
+
const signOut = useCallback7(async () => {
|
|
1890
2448
|
if (lock.current) {
|
|
1891
2449
|
return;
|
|
1892
2450
|
}
|
|
1893
2451
|
lock.current = true;
|
|
1894
|
-
setBusy(true);
|
|
1895
2452
|
try {
|
|
1896
|
-
await
|
|
2453
|
+
await mutateAsync();
|
|
1897
2454
|
} finally {
|
|
1898
2455
|
lock.current = false;
|
|
1899
|
-
setBusy(false);
|
|
1900
2456
|
}
|
|
1901
|
-
}, [
|
|
1902
|
-
return
|
|
2457
|
+
}, [mutateAsync]);
|
|
2458
|
+
return useMemo7(
|
|
2459
|
+
() => ({ ...mutation, signOut, busy: mutation.isPending }),
|
|
2460
|
+
[mutation, signOut]
|
|
2461
|
+
);
|
|
1903
2462
|
}
|
|
1904
2463
|
function useSignInOptions(input = {}) {
|
|
1905
2464
|
const chains = JSON.stringify(cosmosChainList(input.cosmos));
|
|
1906
|
-
const cosmos =
|
|
2465
|
+
const cosmos = useMemo7(
|
|
1907
2466
|
() => JSON.parse(chains),
|
|
1908
2467
|
[chains]
|
|
1909
2468
|
);
|
|
@@ -1912,6 +2471,7 @@ function useSignInOptions(input = {}) {
|
|
|
1912
2471
|
const {
|
|
1913
2472
|
busy,
|
|
1914
2473
|
error,
|
|
2474
|
+
reset,
|
|
1915
2475
|
codeSent,
|
|
1916
2476
|
startOver,
|
|
1917
2477
|
sendCode,
|
|
@@ -1919,7 +2479,7 @@ function useSignInOptions(input = {}) {
|
|
|
1919
2479
|
withProvider,
|
|
1920
2480
|
withWallet
|
|
1921
2481
|
} = useSignIn();
|
|
1922
|
-
const built =
|
|
2482
|
+
const built = useMemo7(() => {
|
|
1923
2483
|
if (!methods) {
|
|
1924
2484
|
return null;
|
|
1925
2485
|
}
|
|
@@ -1938,22 +2498,24 @@ function useSignInOptions(input = {}) {
|
|
|
1938
2498
|
});
|
|
1939
2499
|
}, [methods, wallets, cosmos, withProvider, sendCode, verifyCode, withWallet]);
|
|
1940
2500
|
const methodsError = methods?.error ?? null;
|
|
1941
|
-
return
|
|
2501
|
+
return useMemo7(
|
|
1942
2502
|
() => ({
|
|
1943
2503
|
options: built?.options ?? null,
|
|
1944
2504
|
unavailable: built?.unavailable ?? NONE_UNAVAILABLE,
|
|
1945
2505
|
methodsError,
|
|
2506
|
+
isPending: busy,
|
|
1946
2507
|
busy,
|
|
1947
2508
|
error,
|
|
2509
|
+
reset,
|
|
1948
2510
|
codeSent,
|
|
1949
2511
|
startOver
|
|
1950
2512
|
}),
|
|
1951
|
-
[built, methodsError, busy, error, codeSent, startOver]
|
|
2513
|
+
[built, methodsError, busy, error, reset, codeSent, startOver]
|
|
1952
2514
|
);
|
|
1953
2515
|
}
|
|
1954
2516
|
|
|
1955
2517
|
// src/react/accounts.ts
|
|
1956
|
-
import { useMemo as
|
|
2518
|
+
import { useMemo as useMemo8 } from "react";
|
|
1957
2519
|
function isConnected(accounts, provider) {
|
|
1958
2520
|
return Boolean(
|
|
1959
2521
|
accounts?.some(
|
|
@@ -1970,8 +2532,8 @@ function useAccounts() {
|
|
|
1970
2532
|
(options) => relay.auth.accounts(options),
|
|
1971
2533
|
{ refetchOnFocus: true }
|
|
1972
2534
|
);
|
|
1973
|
-
const {
|
|
1974
|
-
const actions =
|
|
2535
|
+
const { isPending, actionError: actionError2, resetAction, run, retry, settle } = useAction();
|
|
2536
|
+
const actions = useMemo8(
|
|
1975
2537
|
() => ({
|
|
1976
2538
|
connect: (provider) => run(async () => {
|
|
1977
2539
|
const { url } = await relay.auth.start(provider, "connect", {
|
|
@@ -1991,22 +2553,34 @@ function useAccounts() {
|
|
|
1991
2553
|
[relay, invalidate, session, run]
|
|
1992
2554
|
);
|
|
1993
2555
|
const accounts = query.data;
|
|
1994
|
-
return
|
|
2556
|
+
return useMemo8(
|
|
1995
2557
|
() => ({
|
|
1996
2558
|
...query,
|
|
1997
|
-
|
|
1998
|
-
|
|
2559
|
+
isPending,
|
|
2560
|
+
/** @deprecated Use `isPending`. Removed in 2.0.0. */
|
|
2561
|
+
busy: isPending,
|
|
2562
|
+
actionError: actionError2,
|
|
2563
|
+
resetAction,
|
|
1999
2564
|
retry,
|
|
2000
2565
|
settle,
|
|
2001
2566
|
isConnected: (provider) => isConnected(accounts, provider),
|
|
2002
2567
|
...actions
|
|
2003
2568
|
}),
|
|
2004
|
-
[
|
|
2569
|
+
[
|
|
2570
|
+
query,
|
|
2571
|
+
isPending,
|
|
2572
|
+
actionError2,
|
|
2573
|
+
resetAction,
|
|
2574
|
+
retry,
|
|
2575
|
+
settle,
|
|
2576
|
+
accounts,
|
|
2577
|
+
actions
|
|
2578
|
+
]
|
|
2005
2579
|
);
|
|
2006
2580
|
}
|
|
2007
2581
|
|
|
2008
2582
|
// src/react/profiles.ts
|
|
2009
|
-
import { useMemo as
|
|
2583
|
+
import { useMemo as useMemo9 } from "react";
|
|
2010
2584
|
var MINE = [...relayKeys.profiles, "mine"];
|
|
2011
2585
|
function useMyProfile() {
|
|
2012
2586
|
const relay = useRelay();
|
|
@@ -2017,8 +2591,8 @@ function useMyProfile() {
|
|
|
2017
2591
|
(options) => relay.profiles.mine(options),
|
|
2018
2592
|
{ refetchOnFocus: true }
|
|
2019
2593
|
);
|
|
2020
|
-
const {
|
|
2021
|
-
const actions =
|
|
2594
|
+
const { isPending, actionError: actionError2, resetAction, run, retry, settle } = useAction();
|
|
2595
|
+
const actions = useMemo9(() => {
|
|
2022
2596
|
const change = (task) => run(async (actionId) => {
|
|
2023
2597
|
const cache = store.scope?.cache;
|
|
2024
2598
|
const saved = await task(actionId);
|
|
@@ -2041,9 +2615,19 @@ function useMyProfile() {
|
|
|
2041
2615
|
)
|
|
2042
2616
|
};
|
|
2043
2617
|
}, [relay, store, session, run]);
|
|
2044
|
-
return
|
|
2045
|
-
() => ({
|
|
2046
|
-
|
|
2618
|
+
return useMemo9(
|
|
2619
|
+
() => ({
|
|
2620
|
+
...query,
|
|
2621
|
+
isPending,
|
|
2622
|
+
/** @deprecated Use `isPending`. Removed in 2.0.0. */
|
|
2623
|
+
busy: isPending,
|
|
2624
|
+
actionError: actionError2,
|
|
2625
|
+
resetAction,
|
|
2626
|
+
retry,
|
|
2627
|
+
settle,
|
|
2628
|
+
...actions
|
|
2629
|
+
}),
|
|
2630
|
+
[query, isPending, actionError2, resetAction, retry, settle, actions]
|
|
2047
2631
|
);
|
|
2048
2632
|
}
|
|
2049
2633
|
function useProfile(id, options = {}) {
|
|
@@ -2084,7 +2668,7 @@ function useProfileCompletions(profile, options = {}) {
|
|
|
2084
2668
|
}
|
|
2085
2669
|
|
|
2086
2670
|
// src/react/referrals.ts
|
|
2087
|
-
import { useCallback as
|
|
2671
|
+
import { useCallback as useCallback8, useEffect as useEffect7, useMemo as useMemo10, useRef as useRef7, useState as useState8 } from "react";
|
|
2088
2672
|
var PENDING = "domino:pending-referral";
|
|
2089
2673
|
var CODE = /^[a-zA-Z0-9_-]{1,100}$/;
|
|
2090
2674
|
function captureReferralCode(param = "ref") {
|
|
@@ -2117,8 +2701,8 @@ function useInvitation(param = "ref") {
|
|
|
2117
2701
|
const code = captureReferralCode(param);
|
|
2118
2702
|
return code ? { status: "pending", code } : { status: "none" };
|
|
2119
2703
|
});
|
|
2120
|
-
const started =
|
|
2121
|
-
const pending =
|
|
2704
|
+
const started = useRef7(null);
|
|
2705
|
+
const pending = useRef7({
|
|
2122
2706
|
member,
|
|
2123
2707
|
relay,
|
|
2124
2708
|
session,
|
|
@@ -2134,7 +2718,7 @@ function useInvitation(param = "ref") {
|
|
|
2134
2718
|
action: createRelayAction()
|
|
2135
2719
|
};
|
|
2136
2720
|
}
|
|
2137
|
-
const accept =
|
|
2721
|
+
const accept = useCallback8(
|
|
2138
2722
|
async (code) => {
|
|
2139
2723
|
const owner = pending.current;
|
|
2140
2724
|
if (owner.action.busy) {
|
|
@@ -2179,7 +2763,7 @@ function useInvitation(param = "ref") {
|
|
|
2179
2763
|
void accept(state.code);
|
|
2180
2764
|
}
|
|
2181
2765
|
}, [member, state, accept]);
|
|
2182
|
-
return
|
|
2766
|
+
return useMemo10(() => ({ invitation: state, accept }), [state, accept]);
|
|
2183
2767
|
}
|
|
2184
2768
|
function useReferralSummary(options = {}) {
|
|
2185
2769
|
const relay = useRelay();
|
|
@@ -2189,7 +2773,7 @@ function useReferralSummary(options = {}) {
|
|
|
2189
2773
|
(request) => relay.referrals.summary(request),
|
|
2190
2774
|
{ intervalMs }
|
|
2191
2775
|
);
|
|
2192
|
-
return
|
|
2776
|
+
return useMemo10(() => {
|
|
2193
2777
|
let link = null;
|
|
2194
2778
|
if (query.data && typeof window !== "undefined") {
|
|
2195
2779
|
const url = new URL(path, window.location.origin);
|
|
@@ -2246,7 +2830,7 @@ function useQuestOutcomes(query = {}) {
|
|
|
2246
2830
|
}
|
|
2247
2831
|
|
|
2248
2832
|
// src/react/offers.ts
|
|
2249
|
-
import { useCallback as
|
|
2833
|
+
import { useCallback as useCallback9, useMemo as useMemo11 } from "react";
|
|
2250
2834
|
function useOffers() {
|
|
2251
2835
|
const relay = useRelay();
|
|
2252
2836
|
return useRelayQuery(
|
|
@@ -2256,34 +2840,19 @@ function useOffers() {
|
|
|
2256
2840
|
}
|
|
2257
2841
|
function useRedeemOffer() {
|
|
2258
2842
|
const relay = useRelay();
|
|
2259
|
-
const
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
error
|
|
2268
|
-
} = useRelayAction(scope);
|
|
2269
|
-
const refresh = useCallback8(
|
|
2270
|
-
async (result) => {
|
|
2271
|
-
const redemption = result.ok ? result.value : null;
|
|
2272
|
-
if (redemption) {
|
|
2273
|
-
await invalidate([relayKeys.offers, relayKeys.balances]);
|
|
2274
|
-
}
|
|
2275
|
-
return redemption;
|
|
2276
|
-
},
|
|
2277
|
-
[invalidate]
|
|
2843
|
+
const { mutation, replay } = useMutation(
|
|
2844
|
+
(offer, { actionId, session }) => relay.offers.redeem(offer, { actionId }, { session }),
|
|
2845
|
+
{ invalidates: [relayKeys.offers, relayKeys.balances] }
|
|
2846
|
+
);
|
|
2847
|
+
const { mutateAsync } = mutation;
|
|
2848
|
+
const redeem = useCallback9(
|
|
2849
|
+
(offer) => mutateAsync(offer).catch(() => null),
|
|
2850
|
+
[mutateAsync]
|
|
2278
2851
|
);
|
|
2279
|
-
|
|
2280
|
-
(
|
|
2281
|
-
|
|
2282
|
-
).then(refresh),
|
|
2283
|
-
[run, relay, session, refresh]
|
|
2852
|
+
return useMemo11(
|
|
2853
|
+
() => ({ ...mutation, redeem, retry: replay, busy: mutation.isPending }),
|
|
2854
|
+
[mutation, redeem, replay]
|
|
2284
2855
|
);
|
|
2285
|
-
const retry = useCallback8(() => replay().then(refresh), [replay, refresh]);
|
|
2286
|
-
return { redeem, retry, settle, busy, error };
|
|
2287
2856
|
}
|
|
2288
2857
|
|
|
2289
2858
|
// src/react/references.ts
|
|
@@ -2343,9 +2912,11 @@ export {
|
|
|
2343
2912
|
useReferralSummary,
|
|
2344
2913
|
useRelay,
|
|
2345
2914
|
useRelayAction,
|
|
2915
|
+
useRelayMutation,
|
|
2346
2916
|
useRelayPages,
|
|
2347
2917
|
useRelayQuery,
|
|
2348
2918
|
useSession,
|
|
2919
|
+
useSetQueryData,
|
|
2349
2920
|
useSignIn,
|
|
2350
2921
|
useSignInMethods,
|
|
2351
2922
|
useSignInOptions,
|