@domino-sdk/relay 1.16.0 → 1.18.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.
Files changed (50) hide show
  1. package/dist/{attempt-captures-DHwIVoRP.d.ts → attempt-captures-ByzZyggX.d.ts} +5 -1
  2. package/dist/authoring.d.ts +82 -9
  3. package/dist/authoring.js +14 -9
  4. package/dist/{automatic-outcomes-BcEn_L46.d.ts → automatic-outcomes-BBSdMf0R.d.ts} +2 -1
  5. package/dist/avatar.d.ts +1 -1
  6. package/dist/browser.d.ts +7 -7
  7. package/dist/browser.js +9 -11
  8. package/dist/{chunk-Y6SRF54G.js → chunk-4VWMY4II.js} +32 -25
  9. package/dist/{chunk-6QJ3LADK.js → chunk-5P5PTZ3T.js} +1 -1
  10. package/dist/{chunk-3YCCHTCU.js → chunk-BWW3XLEE.js} +2 -2
  11. package/dist/{chunk-W335CWYJ.js → chunk-CVQG2AZZ.js} +2 -2
  12. package/dist/{chunk-ZLYBUM7K.js → chunk-DQWRDRVO.js} +26 -14
  13. package/dist/{chunk-46C33ASD.js → chunk-EMLDFUTV.js} +1314 -908
  14. package/dist/{chunk-4OLQYRSA.js → chunk-GMKJPHN4.js} +1 -1
  15. package/dist/{chunk-NM3IYYPG.js → chunk-HQBCFU5G.js} +6 -8
  16. package/dist/{chunk-YT3QKV2L.js → chunk-I525XMUY.js} +1 -1
  17. package/dist/{chunk-LLMJ2SUT.js → chunk-IE4QOQUI.js} +21 -4
  18. package/dist/{chunk-ZGH6NEG6.js → chunk-JIQHUDVZ.js} +1 -1
  19. package/dist/{chunk-NIYCAW2I.js → chunk-NGP2NMZ4.js} +1 -1
  20. package/dist/{chunk-XMBM2XD5.js → chunk-T47OFHHX.js} +2 -4
  21. package/dist/{chunk-AXRMT33W.js → chunk-UIHPWC4C.js} +3 -0
  22. package/dist/{chunk-UJACD6K2.js → chunk-XSLRNFIY.js} +346 -304
  23. package/dist/{chunk-PT5STHFH.js → chunk-YXAK2637.js} +1 -1
  24. package/dist/{client-DFSCmf3H.d.ts → client-93pUw04R.d.ts} +182 -14
  25. package/dist/{deployments-DIbKJO_Y.d.ts → deployments-D0mrWCsp.d.ts} +817 -1
  26. package/dist/{groups-Bi7lc54m.d.ts → groups-jLLG7MML.d.ts} +27 -2
  27. package/dist/{images-Cb8QHGjn.d.ts → images-BPiPqVKn.d.ts} +1 -1
  28. package/dist/index.d.ts +8 -8
  29. package/dist/index.js +12 -16
  30. package/dist/internal.d.ts +10 -10
  31. package/dist/internal.js +9 -10
  32. package/dist/{offers-Catj06u7.d.ts → offers-CPqiF3dZ.d.ts} +92 -3
  33. package/dist/{pages-CpYt56Km.d.ts → pages-1h1387a3.d.ts} +757 -3
  34. package/dist/portal-proxy.js +4 -4
  35. package/dist/react/index.d.ts +47 -19
  36. package/dist/react/index.js +361 -340
  37. package/dist/{schema-BaVl2VBS.d.ts → schema-Br3c1GOu.d.ts} +508 -2
  38. package/dist/schema.d.ts +565 -24
  39. package/dist/schema.js +61 -32
  40. package/dist/server/index.d.ts +10 -10
  41. package/dist/server/index.js +82 -24
  42. package/dist/{sign-in-options-CU1ND6-y.d.ts → sign-in-options--25uHySG.d.ts} +1 -1
  43. package/dist/{submission-input-Bi4HipqI.d.ts → submission-input-BEJ9qENg.d.ts} +2 -2
  44. package/dist/testing.d.ts +3 -3
  45. package/dist/testing.js +10 -13
  46. package/dist/{transport-BdrcbKi_.d.ts → transport-C2cK-6wO.d.ts} +6411 -72
  47. package/package.json +1 -1
  48. package/dist/chunk-2UAVZCMH.js +0 -314
  49. package/dist/chunk-NPGENI7K.js +0 -37
  50. package/dist/{profiles-BHMVj0kM.d.ts → profiles-D29SS12z.d.ts} +1 -1
@@ -8,37 +8,205 @@ import {
8
8
  discoverSolanaWallets,
9
9
  readSignInMethods,
10
10
  signInOptionsFrom
11
- } from "../chunk-3YCCHTCU.js";
12
- import "../chunk-Y6SRF54G.js";
11
+ } from "../chunk-BWW3XLEE.js";
12
+ import "../chunk-4VWMY4II.js";
13
13
  import {
14
14
  createRelayAction
15
- } from "../chunk-XMBM2XD5.js";
16
- import "../chunk-LLMJ2SUT.js";
17
- import "../chunk-UJACD6K2.js";
15
+ } from "../chunk-T47OFHHX.js";
16
+ import "../chunk-IE4QOQUI.js";
17
+ import "../chunk-XSLRNFIY.js";
18
+ import "../chunk-5P5PTZ3T.js";
19
+ import "../chunk-I525XMUY.js";
20
+ import {
21
+ sessionMember
22
+ } from "../chunk-YXAK2637.js";
18
23
  import {
19
24
  RelayError,
20
25
  RelayErrorCode,
21
26
  asRelayError,
22
27
  clientError,
23
- isRelayError
24
- } from "../chunk-2UAVZCMH.js";
25
- import "../chunk-6QJ3LADK.js";
26
- import {
28
+ isRelayError,
27
29
  isRequestError
28
- } from "../chunk-NPGENI7K.js";
29
- import "../chunk-YT3QKV2L.js";
30
- import {
31
- sessionMember
32
- } from "../chunk-PT5STHFH.js";
33
- import "../chunk-46C33ASD.js";
30
+ } from "../chunk-EMLDFUTV.js";
34
31
 
35
- // src/react/activity.ts
32
+ // src/react/context.ts
33
+ import { createContext, useContext } from "react";
34
+ var StoreContext = createContext(null);
35
+ function useStore() {
36
+ const store = useContext(StoreContext);
37
+ if (!store) {
38
+ throw new Error("Domino hooks require <RelayProvider>");
39
+ }
40
+ return store;
41
+ }
42
+ function useRelay() {
43
+ return useStore().client;
44
+ }
45
+
46
+ // src/react/keys.ts
47
+ var relayKeys = {
48
+ /** `useExperience`: invalidating it reads the quest experience again. */
49
+ experience: ["experience"],
50
+ /** `useMe`. */
51
+ me: ["me"],
52
+ /** `useAccounts`. */
53
+ accounts: ["accounts"],
54
+ /** `useWallets`. */
55
+ wallets: ["wallets"],
56
+ /** `useMyProfile`, `useProfile`, `useProfileCompletions`, `useProfileReferral`. */
57
+ profiles: ["profiles"],
58
+ /** `useLeaderboard`, `useLeaderboardPlacement`. */
59
+ leaderboards: ["leaderboards"],
60
+ /** `useReferralSummary`. */
61
+ referrals: ["referrals"],
62
+ /** `usePointLedgers`. */
63
+ pointLedgers: ["point-ledgers"],
64
+ badges: ["badges"],
65
+ /** `useTieredRewards`. */
66
+ tieredRewards: ["tiered-rewards"],
67
+ /** `useSignInMethods`. */
68
+ signInMethods: ["sign-in-methods"],
69
+ /** `useEntitlements`, `useDeliveries`. */
70
+ rewards: ["rewards"],
71
+ /** `useBalances`, `usePointHistory`. */
72
+ balances: ["balances"],
73
+ /** `useQuestOutcomes`. */
74
+ outcomes: ["outcomes"],
75
+ /** `useOffers`, `useRedeemOffer`. */
76
+ offers: ["offers"]
77
+ };
78
+ var rewardKeys = {
79
+ entitlements: [...relayKeys.rewards, "entitlements"],
80
+ deliveries: [...relayKeys.rewards, "deliveries"]
81
+ };
82
+ var completionChanges = [
83
+ relayKeys.rewards,
84
+ relayKeys.balances,
85
+ relayKeys.badges,
86
+ relayKeys.leaderboards,
87
+ relayKeys.profiles,
88
+ relayKeys.referrals,
89
+ relayKeys.offers
90
+ ];
91
+ var activityChanges = {
92
+ "attempt.accepted": [
93
+ relayKeys.experience,
94
+ relayKeys.outcomes,
95
+ ...completionChanges
96
+ ],
97
+ "attempt.rejected": [relayKeys.experience, relayKeys.outcomes],
98
+ "attempt.review": [relayKeys.experience, relayKeys.outcomes],
99
+ "points.awarded": [
100
+ relayKeys.balances,
101
+ relayKeys.leaderboards,
102
+ relayKeys.offers,
103
+ rewardKeys.deliveries
104
+ ],
105
+ "entitlement.granted": [relayKeys.experience, relayKeys.rewards],
106
+ "entitlement.collected": [relayKeys.experience, relayKeys.rewards],
107
+ "delivery.updated": [rewardKeys.deliveries],
108
+ "referral.qualified": [relayKeys.referrals, relayKeys.profiles],
109
+ unknown: [relayKeys.experience]
110
+ };
111
+
112
+ // src/react/action.ts
113
+ import { useCallback, useRef, useState } from "react";
114
+ var IDLE = Object.freeze({
115
+ status: "idle",
116
+ data: void 0,
117
+ error: null
118
+ });
119
+ function actionError(cause) {
120
+ return isRequestError(cause) && !isRelayError(cause) ? new RelayError(cause.message, {
121
+ kind: cause.kind,
122
+ status: cause.status,
123
+ code: cause.code,
124
+ uncertain: cause.uncertain,
125
+ operationId: cause.operationId,
126
+ replaySafe: cause.recovery === "replay",
127
+ retryAfter: cause.retryAfter,
128
+ cause
129
+ }) : asRelayError(cause);
130
+ }
131
+ function useRelayAction(scope) {
132
+ const owner = useRef({ scope, action: createRelayAction() });
133
+ const [state, setState] = useState({ owner: owner.current, ...IDLE });
134
+ if (owner.current.scope !== scope) {
135
+ owner.current = { scope, action: createRelayAction() };
136
+ }
137
+ const execute = useCallback(
138
+ async (task) => {
139
+ const current2 = owner.current;
140
+ if (current2.action.busy) {
141
+ return { ok: false };
142
+ }
143
+ const result = task ? current2.action.run(task) : current2.action.retry();
144
+ setState({
145
+ owner: current2,
146
+ status: "pending",
147
+ data: void 0,
148
+ error: null
149
+ });
150
+ try {
151
+ const value = await result;
152
+ if (owner.current === current2) {
153
+ setState({
154
+ owner: current2,
155
+ status: "success",
156
+ data: value,
157
+ error: null
158
+ });
159
+ }
160
+ return { ok: true, value };
161
+ } catch (caught) {
162
+ const error = actionError(current2.action.error ?? caught);
163
+ if (owner.current === current2) {
164
+ setState({ owner: current2, status: "error", data: void 0, error });
165
+ }
166
+ return { ok: false, error };
167
+ }
168
+ },
169
+ []
170
+ );
171
+ const retry = useCallback(() => execute(), [execute]);
172
+ const settle = useCallback(() => {
173
+ const current2 = owner.current;
174
+ if (!current2.action.settle()) {
175
+ return false;
176
+ }
177
+ setState({ owner: current2, ...IDLE });
178
+ return true;
179
+ }, []);
180
+ const reset = useCallback(() => {
181
+ const current2 = owner.current;
182
+ if (!current2.action.busy && current2.action.actionId === void 0) {
183
+ setState({ owner: current2, ...IDLE });
184
+ }
185
+ }, []);
186
+ const current = state.owner === owner.current ? state : IDLE;
187
+ const isPending = current.status === "pending";
188
+ return {
189
+ run: execute,
190
+ retry,
191
+ settle,
192
+ reset,
193
+ status: current.status,
194
+ isPending,
195
+ data: current.data,
196
+ error: current.error,
197
+ /** @deprecated Use `isPending`. Removed in 2.0.0. */
198
+ busy: isPending
199
+ };
200
+ }
201
+
202
+ // src/react/query.ts
36
203
  import {
37
- useCallback,
204
+ useCallback as useCallback2,
38
205
  useEffect,
39
206
  useLayoutEffect,
40
- useRef,
41
- useState,
207
+ useMemo,
208
+ useRef as useRef2,
209
+ useState as useState2,
42
210
  useSyncExternalStore
43
211
  } from "react";
44
212
 
@@ -287,252 +455,47 @@ var QueryCache = class {
287
455
  entry.version++;
288
456
  this.#write(entry, { status: "ready", data, error: null });
289
457
  }
290
- } catch (cause) {
291
- if (!counts()) {
292
- return;
293
- }
294
- const error = relayError(cause);
295
- if (error.code === RelayErrorCode.StaleSession) {
296
- this.#onStaleSession();
297
- }
298
- const gone = error.kind === "http" && error.status === 404 || error.code === RelayErrorCode.StaleSession;
299
- entry.version++;
300
- this.#write(
301
- entry,
302
- entry.state.status === "ready" && !gone ? { status: "ready", data: entry.state.data, error } : { status: "error", data: void 0, error }
303
- );
304
- } finally {
305
- if (counts()) {
306
- entry.controller = null;
307
- entry.pending = null;
308
- entry.settledAt = Date.now();
309
- this.#schedule(entry);
310
- }
311
- }
312
- })();
313
- entry.pending = pending;
314
- return pending;
315
- }
316
- /** Arms the poll for the shortest interval anyone on screen asked for. */
317
- #schedule(entry) {
318
- clearTimeout(entry.timer);
319
- if (this.#disposed || entry.pending || entry.listeners.size === 0 || entry.intervals.size === 0) {
320
- return;
321
- }
322
- const interval = Math.min(...entry.intervals.values());
323
- const wait = Math.max(0, entry.settledAt + interval - Date.now());
324
- entry.timer = setTimeout(() => {
325
- if (visible()) {
326
- void this.#fetch(entry, false);
327
- }
328
- }, wait);
329
- }
330
- };
331
-
332
- // src/react/context.ts
333
- import { createContext, useContext } from "react";
334
- var StoreContext = createContext(null);
335
- function useStore() {
336
- const store = useContext(StoreContext);
337
- if (!store) {
338
- throw new Error("Domino hooks require <RelayProvider>");
339
- }
340
- return store;
341
- }
342
- function useRelay() {
343
- return useStore().client;
344
- }
345
-
346
- // src/react/activity.ts
347
- function useActivity(options = {}) {
348
- const store = useStore();
349
- const scope = useSyncExternalStore(
350
- store.subscribe,
351
- () => store.scope,
352
- () => null
353
- );
354
- const session = useSyncExternalStore(
355
- store.subscribe,
356
- () => store.session,
357
- () => LOADING
358
- );
359
- const callback = useRef(options.onEvent);
360
- useLayoutEffect(() => {
361
- callback.current = options.onEvent;
362
- }, [options.onEvent]);
363
- const observer = useRef(null);
364
- const [state, setState] = useState(null);
365
- const { cursor, intervalMs } = options;
366
- useEffect(() => {
367
- if (!scope?.member) {
368
- return;
369
- }
370
- let active = true;
371
- const watch = store.client.me.activity.observe(
372
- (event) => callback.current?.(event),
373
- {
374
- cursor,
375
- intervalMs,
376
- onState: (observation) => {
377
- if (!active) {
378
- return;
379
- }
380
- if (observation.kind === "ready") {
381
- setState((prior) => {
382
- const items = prior?.owner === scope.key && prior.value.status === "ready" ? prior.value.data.items : [];
383
- const combined = new Map(
384
- [...items, ...observation.progress.items].map((event) => [
385
- event.id,
386
- event
387
- ])
388
- );
389
- return {
390
- owner: scope.key,
391
- value: {
392
- status: "ready",
393
- data: {
394
- ...observation.progress,
395
- items: [...combined.values()].slice(-100)
396
- },
397
- error: null
398
- }
399
- };
400
- });
401
- } else if (observation.kind === "error") {
402
- setState((prior) => ({
403
- owner: scope.key,
404
- value: prior?.owner === scope.key && prior.value.status === "ready" ? { ...prior.value, error: relayError(observation.error) } : {
405
- status: "error",
406
- data: void 0,
407
- error: relayError(observation.error)
408
- }
409
- }));
410
- } else if (observation.kind === "loading") {
411
- setState({ owner: scope.key, value: LOADING });
412
- }
413
- }
414
- }
415
- );
416
- observer.current = watch;
417
- return () => {
418
- active = false;
419
- watch.dispose();
420
- if (observer.current === watch) {
421
- observer.current = null;
422
- }
423
- };
424
- }, [store, scope?.key, cursor, intervalMs]);
425
- const refresh = useCallback(
426
- () => observer.current?.refresh() ?? Promise.resolve(),
427
- []
428
- );
429
- const value = session.status === "error" ? session : !scope ? LOADING : !scope.member ? { status: "signed-out", data: void 0, error: null } : state?.owner === scope.key ? state.value : LOADING;
430
- return { ...value, refresh };
431
- }
432
-
433
- // src/react/action.ts
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
- }
452
- function useRelayAction(scope) {
453
- const owner = useRef2({ scope, action: createRelayAction() });
454
- const [state, setState] = useState2({ owner: owner.current, ...IDLE });
455
- if (owner.current.scope !== scope) {
456
- owner.current = { scope, action: createRelayAction() };
457
- }
458
- const execute = useCallback2(
459
- async (task) => {
460
- const current2 = owner.current;
461
- if (current2.action.busy) {
462
- return { ok: false };
463
- }
464
- const result = task ? current2.action.run(task) : current2.action.retry();
465
- setState({
466
- owner: current2,
467
- status: "pending",
468
- data: void 0,
469
- error: null
470
- });
471
- try {
472
- const value = await result;
473
- if (owner.current === current2) {
474
- setState({
475
- owner: current2,
476
- status: "success",
477
- data: value,
478
- error: null
479
- });
458
+ } catch (cause) {
459
+ if (!counts()) {
460
+ return;
480
461
  }
481
- return { ok: true, value };
482
- } catch (caught) {
483
- const error = actionError(current2.action.error ?? caught);
484
- if (owner.current === current2) {
485
- setState({ owner: current2, status: "error", data: void 0, error });
462
+ const error = relayError(cause);
463
+ if (error.code === RelayErrorCode.StaleSession) {
464
+ this.#onStaleSession();
465
+ }
466
+ const gone = error.kind === "http" && error.status === 404 || error.code === RelayErrorCode.StaleSession;
467
+ entry.version++;
468
+ this.#write(
469
+ entry,
470
+ entry.state.status === "ready" && !gone ? { status: "ready", data: entry.state.data, error } : { status: "error", data: void 0, error }
471
+ );
472
+ } finally {
473
+ if (counts()) {
474
+ entry.controller = null;
475
+ entry.pending = null;
476
+ entry.settledAt = Date.now();
477
+ this.#schedule(entry);
486
478
  }
487
- return { ok: false, error };
488
479
  }
489
- },
490
- []
491
- );
492
- const retry = useCallback2(() => execute(), [execute]);
493
- const settle = useCallback2(() => {
494
- const current2 = owner.current;
495
- if (!current2.action.settle()) {
496
- return false;
497
- }
498
- setState({ owner: current2, ...IDLE });
499
- return true;
500
- }, []);
501
- const reset = useCallback2(() => {
502
- const current2 = owner.current;
503
- if (!current2.action.busy && current2.action.actionId === void 0) {
504
- setState({ owner: current2, ...IDLE });
480
+ })();
481
+ entry.pending = pending;
482
+ return pending;
483
+ }
484
+ /** Arms the poll for the shortest interval anyone on screen asked for. */
485
+ #schedule(entry) {
486
+ clearTimeout(entry.timer);
487
+ if (this.#disposed || entry.pending || entry.listeners.size === 0 || entry.intervals.size === 0) {
488
+ return;
505
489
  }
506
- }, []);
507
- const current = state.owner === owner.current ? state : IDLE;
508
- const isPending = current.status === "pending";
509
- return {
510
- run: execute,
511
- retry,
512
- settle,
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
520
- };
521
- }
522
-
523
- // src/react/mutation.ts
524
- import { useCallback as useCallback4, useLayoutEffect as useLayoutEffect3, useMemo as useMemo2, useRef as useRef4 } from "react";
525
-
526
- // src/react/query.ts
527
- import {
528
- useCallback as useCallback3,
529
- useEffect as useEffect2,
530
- useLayoutEffect as useLayoutEffect2,
531
- useMemo,
532
- useRef as useRef3,
533
- useState as useState3,
534
- useSyncExternalStore as useSyncExternalStore2
535
- } from "react";
490
+ const interval = Math.min(...entry.intervals.values());
491
+ const wait = Math.max(0, entry.settledAt + interval - Date.now());
492
+ entry.timer = setTimeout(() => {
493
+ if (visible()) {
494
+ void this.#fetch(entry, false);
495
+ }
496
+ }, wait);
497
+ }
498
+ };
536
499
 
537
500
  // src/react/feed.ts
538
501
  function feedOwner(session) {
@@ -657,70 +620,6 @@ var ActivityFeed = class {
657
620
  }
658
621
  };
659
622
 
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
-
724
623
  // src/react/role-delivery.ts
725
624
  function sanitizeDeliveries(deliveries) {
726
625
  return deliveries.map(({ quest, status, revokedAt, reconciliation }) => ({
@@ -1525,19 +1424,19 @@ var RelayStore = class {
1525
1424
 
1526
1425
  // src/react/query.ts
1527
1426
  function useLatest(value) {
1528
- const ref = useRef3(value);
1529
- useLayoutEffect2(() => {
1427
+ const ref = useRef2(value);
1428
+ useLayoutEffect(() => {
1530
1429
  ref.current = value;
1531
1430
  });
1532
1431
  return ref;
1533
1432
  }
1534
1433
  function useSessionSnapshot(store) {
1535
1434
  const get = () => store.session;
1536
- return useSyncExternalStore2(store.subscribe, get, get);
1435
+ return useSyncExternalStore(store.subscribe, get, get);
1537
1436
  }
1538
1437
  function useScope(store) {
1539
1438
  const get = () => store.scope;
1540
- return useSyncExternalStore2(store.subscribe, get, get);
1439
+ return useSyncExternalStore(store.subscribe, get, get);
1541
1440
  }
1542
1441
  function isInitializer(value) {
1543
1442
  return typeof value === "function";
@@ -1560,7 +1459,7 @@ function useCached(cache, key, read, options, seeded = null) {
1560
1459
  const active = options.enabled === false ? null : key;
1561
1460
  const hash = active ? hashKey(active) : null;
1562
1461
  const latest = useLatest({ key: active, read });
1563
- const subscribe = useCallback3(
1462
+ const subscribe = useCallback2(
1564
1463
  (listener) => {
1565
1464
  const { key: current } = latest.current;
1566
1465
  if (!cache || !current) {
@@ -1582,8 +1481,8 @@ function useCached(cache, key, read, options, seeded = null) {
1582
1481
  const fallback = seeded?.shown ?? LOADING;
1583
1482
  return cache && active ? cache.snapshot(active, fallback) : fallback;
1584
1483
  };
1585
- const snapshot = useSyncExternalStore2(subscribe, get, get);
1586
- const refresh = useCallback3(
1484
+ const snapshot = useSyncExternalStore(subscribe, get, get);
1485
+ const refresh = useCallback2(
1587
1486
  () => cache && latest.current.key ? cache.refresh(latest.current.key) : Promise.resolve(),
1588
1487
  [cache, hash]
1589
1488
  );
@@ -1676,17 +1575,17 @@ function usePages(cache, requested, read, options) {
1676
1575
  (context) => read(context),
1677
1576
  options
1678
1577
  );
1679
- const [more, setMore] = useState3(null);
1680
- const busy = useRef3(null);
1578
+ const [more, setMore] = useState2(null);
1579
+ const busy = useRef2(null);
1681
1580
  const latest = useLatest({ key, read, query });
1682
- useEffect2(
1581
+ useEffect(
1683
1582
  () => () => {
1684
1583
  busy.current?.abort();
1685
1584
  busy.current = null;
1686
1585
  },
1687
1586
  [cache, hash]
1688
1587
  );
1689
- const loadMore = useCallback3(async () => {
1588
+ const loadMore = useCallback2(async () => {
1690
1589
  const { key: current, read: reader, query: shown } = latest.current;
1691
1590
  if (!cache || !current || busy.current || shown.status !== "ready" || shown.data.nextCursor === null) {
1692
1591
  return;
@@ -1760,14 +1659,14 @@ function useMemberPages(key, read, options = {}) {
1760
1659
  }
1761
1660
  function useInvalidate() {
1762
1661
  const store = useStore();
1763
- return useCallback3((keys = []) => store.invalidate(keys), [store]);
1662
+ return useCallback2((keys = []) => store.invalidate(keys), [store]);
1764
1663
  }
1765
1664
  function isUpdater(update) {
1766
1665
  return typeof update === "function";
1767
1666
  }
1768
1667
  function useSetQueryData() {
1769
1668
  const store = useStore();
1770
- return useCallback3(
1669
+ return useCallback2(
1771
1670
  (key, update) => {
1772
1671
  const cache = store.scope?.cache;
1773
1672
  if (!cache) {
@@ -1807,11 +1706,11 @@ function useAction() {
1807
1706
  settle,
1808
1707
  reset: resetAction
1809
1708
  } = useRelayAction(scope);
1810
- const run = useCallback3(
1709
+ const run = useCallback2(
1811
1710
  async (task) => (await execute(task)).ok,
1812
1711
  [execute]
1813
1712
  );
1814
- const retry = useCallback3(async () => (await replay()).ok, [replay]);
1713
+ const retry = useCallback2(async () => (await replay()).ok, [replay]);
1815
1714
  return { isPending, actionError: actionError2, resetAction, run, retry, settle };
1816
1715
  }
1817
1716
  function useScopeSession() {
@@ -1819,7 +1718,126 @@ function useScopeSession() {
1819
1718
  return useScope(store)?.session?.id;
1820
1719
  }
1821
1720
 
1721
+ // src/react/badges.ts
1722
+ function useBadgeCatalog() {
1723
+ const relay = useRelay();
1724
+ return useRelayQuery(
1725
+ [...relayKeys.badges, "catalog"],
1726
+ (options) => relay.badges.list(options)
1727
+ );
1728
+ }
1729
+ function useBadges() {
1730
+ const relay = useRelay();
1731
+ return useMemberQuery(
1732
+ [...relayKeys.badges, "mine"],
1733
+ (options) => relay.me.badges(options)
1734
+ );
1735
+ }
1736
+ function useProfileBadges(profile) {
1737
+ const relay = useRelay();
1738
+ return useRelayQuery(
1739
+ [...relayKeys.profiles, profile, "badges"],
1740
+ (options) => relay.profiles.badges(profile, options)
1741
+ );
1742
+ }
1743
+
1744
+ // src/react/activity.ts
1745
+ import {
1746
+ useCallback as useCallback3,
1747
+ useEffect as useEffect2,
1748
+ useLayoutEffect as useLayoutEffect2,
1749
+ useRef as useRef3,
1750
+ useState as useState3,
1751
+ useSyncExternalStore as useSyncExternalStore2
1752
+ } from "react";
1753
+ function useActivity(options = {}) {
1754
+ const store = useStore();
1755
+ const scope = useSyncExternalStore2(
1756
+ store.subscribe,
1757
+ () => store.scope,
1758
+ () => null
1759
+ );
1760
+ const session = useSyncExternalStore2(
1761
+ store.subscribe,
1762
+ () => store.session,
1763
+ () => LOADING
1764
+ );
1765
+ const callback = useRef3(options.onEvent);
1766
+ useLayoutEffect2(() => {
1767
+ callback.current = options.onEvent;
1768
+ }, [options.onEvent]);
1769
+ const observer = useRef3(null);
1770
+ const [state, setState] = useState3(null);
1771
+ const { cursor, intervalMs } = options;
1772
+ useEffect2(() => {
1773
+ if (!scope?.member) {
1774
+ return;
1775
+ }
1776
+ let active = true;
1777
+ const watch = store.client.me.activity.observe(
1778
+ (event) => callback.current?.(event),
1779
+ {
1780
+ cursor,
1781
+ intervalMs,
1782
+ onState: (observation) => {
1783
+ if (!active) {
1784
+ return;
1785
+ }
1786
+ if (observation.kind === "ready") {
1787
+ setState((prior) => {
1788
+ const items = prior?.owner === scope.key && prior.value.status === "ready" ? prior.value.data.items : [];
1789
+ const combined = new Map(
1790
+ [...items, ...observation.progress.items].map((event) => [
1791
+ event.id,
1792
+ event
1793
+ ])
1794
+ );
1795
+ return {
1796
+ owner: scope.key,
1797
+ value: {
1798
+ status: "ready",
1799
+ data: {
1800
+ ...observation.progress,
1801
+ items: [...combined.values()].slice(-100)
1802
+ },
1803
+ error: null
1804
+ }
1805
+ };
1806
+ });
1807
+ } else if (observation.kind === "error") {
1808
+ setState((prior) => ({
1809
+ owner: scope.key,
1810
+ value: prior?.owner === scope.key && prior.value.status === "ready" ? { ...prior.value, error: relayError(observation.error) } : {
1811
+ status: "error",
1812
+ data: void 0,
1813
+ error: relayError(observation.error)
1814
+ }
1815
+ }));
1816
+ } else if (observation.kind === "loading") {
1817
+ setState({ owner: scope.key, value: LOADING });
1818
+ }
1819
+ }
1820
+ }
1821
+ );
1822
+ observer.current = watch;
1823
+ return () => {
1824
+ active = false;
1825
+ watch.dispose();
1826
+ if (observer.current === watch) {
1827
+ observer.current = null;
1828
+ }
1829
+ };
1830
+ }, [store, scope?.key, cursor, intervalMs]);
1831
+ const refresh = useCallback3(
1832
+ () => observer.current?.refresh() ?? Promise.resolve(),
1833
+ []
1834
+ );
1835
+ const value = session.status === "error" ? session : !scope ? LOADING : !scope.member ? { status: "signed-out", data: void 0, error: null } : state?.owner === scope.key ? state.value : LOADING;
1836
+ return { ...value, refresh };
1837
+ }
1838
+
1822
1839
  // src/react/mutation.ts
1840
+ import { useCallback as useCallback4, useLayoutEffect as useLayoutEffect3, useMemo as useMemo2, useRef as useRef4 } from "react";
1823
1841
  function useMutation(mutation, options = {}) {
1824
1842
  const store = useStore();
1825
1843
  const invalidate = useInvalidate();
@@ -2888,6 +2906,8 @@ export {
2888
2906
  roleDeliveryStatus,
2889
2907
  useAccounts,
2890
2908
  useActivity,
2909
+ useBadgeCatalog,
2910
+ useBadges,
2891
2911
  useBalances,
2892
2912
  useDeliveries,
2893
2913
  useEntitlements,
@@ -2904,6 +2924,7 @@ export {
2904
2924
  usePointHistory,
2905
2925
  usePointLedgers,
2906
2926
  useProfile,
2927
+ useProfileBadges,
2907
2928
  useProfileCompletions,
2908
2929
  useProfileReferral,
2909
2930
  useQuest,