@domino-sdk/relay 1.0.0-next.13 → 1.0.0-next.14

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.
@@ -1,19 +1,87 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { a6 as referralAcceptSchema, c as LeaderboardQuery, G as engagementPageQuerySchema, s as contentQualificationQuerySchema, i as contentAdmissionQuerySchema, k as contentEnrollmentInputSchema, u as contentReleaseInputSchema, af as referralSummarySchema, a as LeaderboardPage } from '../referrals-KQfP4pBf.js';
3
+ import { a6 as referralAcceptSchema, c as LeaderboardQuery, G as engagementPageQuerySchema, s as contentQualificationQuerySchema, i as contentAdmissionQuerySchema, k as contentEnrollmentInputSchema, u as contentReleaseInputSchema, b as LeaderboardPlacement, af as referralSummarySchema, a as LeaderboardPage } from '../referrals-KQfP4pBf.js';
4
4
  import { ao as submitSchema, x as contentPerformanceQuerySchema, T as TieredRewardReference } from '../schema-BF_TQsmT.js';
5
- import { a as PageQuery, f as exchangeSchema } from '../pages-KYK1L60W.js';
5
+ import { a as PageQuery, f as exchangeSchema, P as Page, c as ParticipantSession, M as MemberSummary } from '../pages-KYK1L60W.js';
6
6
  import { x as walletAddressInputSchema, M as walletSignatureSchema, L as LinkedWallet, f as WalletSigner, d as WalletSignInNetwork } from '../wallet-BtiG0Xhr.js';
7
- import { h as QuestView, J as questExperienceSchema, e as PointHistoryQuery, c as PointEntryKind, P as PointBalance, b as PointEntry, f as PointLedgerReference } from '../catalog-C85V1NgW.js';
8
- import { F as profileUpdateSchema, c as ProfileCompletionQuery, a as ProfileCompletion, e as ProfileSummary, f as ProfileUpdate } from '../profiles-BtOXMGcC.js';
7
+ import { h as QuestView, J as questExperienceSchema, e as PointHistoryQuery, c as PointEntryKind, a as PointBalances, b as PointEntry, f as PointLedgerReference } from '../catalog-C85V1NgW.js';
8
+ import { F as profileUpdateSchema, c as ProfileCompletionQuery, f as ProfileUpdate, e as ProfileSummary, a as ProfileCompletion, d as ProfileReferral } from '../profiles-BtOXMGcC.js';
9
9
  import * as zod from 'zod';
10
10
  import { z } from 'zod';
11
- import { k as RelayRequestOptions, c as QuestController, a as ProgressObservation, b as ProgressObserver, P as PhotoSubmission, e as QuizSubmission, C as ClaimSubmission, V as ValueSubmission, S as SubmissionDraft } from '../client-Bf9PNUIi.js';
11
+ import { g as RelayError, k as RelayRequestOptions, c as QuestController, a as ProgressObservation, b as ProgressObserver, P as PhotoSubmission, e as QuizSubmission, C as ClaimSubmission, V as ValueSubmission, S as SubmissionDraft } from '../client-Bf9PNUIi.js';
12
12
  import { a as AuthProvider, A as AccountConnection } from '../submission-input-CccwAl5Z.js';
13
13
  import { createBrowserRelayClient, SignInMethods, CosmosChains, SignInOption, SignInUnavailable, SignInWallet, DiscoveredWallet } from '../browser.js';
14
14
  export { EmailSignInOption, OAuthSignInOption, SignInIcon, WalletSignInOption } from '../browser.js';
15
15
  import '../request-error-VnTiMXc3.js';
16
16
 
17
+ /**
18
+ * A query's identity: plain JSON values, outermost group first, such as
19
+ * `["leaderboards", "weekly", 25]`. `invalidate(["leaderboards"])` matches every key that starts
20
+ * with those values.
21
+ */
22
+ type QueryKey = readonly (string | number | boolean | null)[];
23
+ /**
24
+ * What every read hook returns, besides `refresh`.
25
+ *
26
+ * - `loading`: nothing read yet for this participant.
27
+ * - `ready`: `data` is the last good value. `error` is set while the latest refresh failed and the
28
+ * value on screen may be out of date; the next successful read clears it.
29
+ * - `error`: the first read failed, or the thing is gone (a 404).
30
+ * - `signed-out`: the hook needs a signed-in member and there is none.
31
+ */
32
+ type QuerySnapshot<T> = {
33
+ status: "loading";
34
+ data: undefined;
35
+ error: null;
36
+ } | {
37
+ status: "ready";
38
+ data: T;
39
+ error: RelayError | null;
40
+ } | {
41
+ status: "error";
42
+ data: undefined;
43
+ error: RelayError;
44
+ };
45
+ type MemberSnapshot<T> = QuerySnapshot<T> | {
46
+ status: "signed-out";
47
+ data: undefined;
48
+ error: null;
49
+ };
50
+ /** What a query's read function receives: pass it on as the client method's last argument. */
51
+ type QueryContext = {
52
+ /** Aborted when the read is superseded, invalidated, or the participant changes. */
53
+ signal: AbortSignal;
54
+ /** The session the cache belongs to. Relay refuses a read for another session (`stale-session`). */
55
+ session?: string;
56
+ };
57
+ type QueryRead<T> = (context: QueryContext) => Promise<T>;
58
+ type QueryOptions = {
59
+ /** Read again this often while the page is visible. Polling pauses while the tab is hidden. */
60
+ intervalMs?: number;
61
+ /** Read again when the window regains focus. */
62
+ refetchOnFocus?: boolean;
63
+ };
64
+
65
+ type Collection = {
66
+ id: string;
67
+ /** The collection's authoring key, when it has one. */
68
+ key?: string;
69
+ title: string;
70
+ quests: QuestView[];
71
+ };
72
+ /** The participant's quests and collections, as `useExperience().data` holds them. */
73
+ type ExperienceData = {
74
+ quests: QuestView[];
75
+ collections: Collection[];
76
+ };
77
+ /**
78
+ * Everything to list, in display order: collections as Console arranged them,
79
+ * then any quest nobody has placed yet, sorted by `order`: authoring keys
80
+ * (the `key` in quests/*.quest.ts), or quest IDs for quests without one.
81
+ * Archived quests are left out.
82
+ */
83
+ declare function questGroups(experience: ExperienceData, order?: string[]): Collection[];
84
+
17
85
  type RelayClient = ReturnType<typeof createBrowserRelayClient>;
18
86
  /** The participant client, for calls no hook covers. */
19
87
  declare function useRelay(): {
@@ -2437,10 +2505,12 @@ declare function useRelay(): {
2437
2505
  };
2438
2506
 
2439
2507
  /**
2440
- * One participant client and one quest observer for the whole app.
2508
+ * One participant client, one quest observer and one query cache for the whole app.
2441
2509
  *
2442
- * `baseUrl` defaults to `/relay`, the participant proxy that `domino dev` and
2443
- * Domino hosting provide. Pass `client` to share a client created elsewhere.
2510
+ * `baseUrl` defaults to `/relay`, the participant proxy that `domino dev` and Domino hosting
2511
+ * provide. Pass `client` to share a client created elsewhere. A new `client` or `baseUrl` takes
2512
+ * effect at once: the old observer stops, reads in flight are cancelled, and the hooks start again
2513
+ * from an empty cache. Safe to render on the server; nothing is read until it mounts.
2444
2514
  */
2445
2515
  declare function RelayProvider({ client, baseUrl, children, }: {
2446
2516
  client?: RelayClient;
@@ -2448,90 +2518,139 @@ declare function RelayProvider({ client, baseUrl, children, }: {
2448
2518
  children: ReactNode;
2449
2519
  }): react.JSX.Element;
2450
2520
 
2521
+ /** What every read hook returns: `{ status, data, error, refresh }`. */
2522
+ type Query<T> = QuerySnapshot<T> & {
2523
+ /** Reads again now, replacing a read in flight. Never rejects: a failure lands in `error`. */
2524
+ refresh(): Promise<void>;
2525
+ };
2526
+ /** A read that needs a signed-in member: a `Query`, or `signed-out` while nobody is. */
2527
+ type MemberQuery<T> = MemberSnapshot<T> & {
2528
+ refresh(): Promise<void>;
2529
+ };
2530
+
2531
+ /** What a paged read adds to its query: the next page. */
2532
+ type PageLoader = {
2533
+ /** Appends the next page; does nothing while one loads, or when there is none. */
2534
+ loadMore(): Promise<void>;
2535
+ /** True while `loadMore()` reads. */
2536
+ loadingMore: boolean;
2537
+ /** Why the last `loadMore()` failed, until the next one starts. */
2538
+ loadMoreError: RelayError | null;
2539
+ };
2540
+ /** A paged read as one growing list: `data.items` and `data.nextCursor`, and `loadMore()`. */
2541
+ type PagedQuery<T> = Query<Page<T>> & PageLoader;
2542
+ /** A paged read that needs a signed-in member: a `PagedQuery`, or `signed-out` while nobody is. */
2543
+ type MemberPagedQuery<T> = MemberQuery<Page<T>> & PageLoader;
2544
+ /** A paged read: `read` receives `cursor` (absent for the first page) with `signal` and `session`. */
2545
+ type PageRead<T> = (context: QueryContext & {
2546
+ cursor?: string;
2547
+ }) => Promise<Page<T>>;
2451
2548
  /**
2452
- * All a participant sees of a reward Domino delivers elsewhere, such as a
2453
- * Discord role. Attempts, errors, and role IDs stay out of the page.
2549
+ * A cached read through the participant client, for calls no hook covers.
2550
+ *
2551
+ * Every component that asks for the same `key` shares one read and one value; `useInvalidate()`
2552
+ * marks it out of date after a change. `read` receives `{ signal, session }`: pass them as the
2553
+ * client method's last argument, so a superseded read is cancelled and Relay refuses one for
2554
+ * another session. The value belongs to the participant signed in when it was read, and is
2555
+ * dropped when they sign out or another member signs in.
2556
+ *
2557
+ * ```tsx
2558
+ * const boards = useRelayQuery(["leaderboards", "list"], (options) =>
2559
+ * relay.leaderboards.list(options)
2560
+ * )
2561
+ * ```
2454
2562
  */
2455
- type RoleDelivery = {
2456
- quest: string;
2457
- status: "pending" | "delivered" | "failed";
2458
- };
2459
- declare function sanitizeDeliveries(deliveries: RoleDelivery[]): RoleDelivery[];
2563
+ declare function useRelayQuery<T>(key: QueryKey, read: QueryRead<T>, options?: QueryOptions): Query<T>;
2460
2564
  /**
2461
- * Changes whenever the participant completes something, which is the only time
2462
- * a new delivery can appear. Empty until the first completion, so participants
2463
- * with nothing to deliver never ask.
2565
+ * `useRelayQuery` for reads that need a signed-in member. Nothing is read while nobody is signed
2566
+ * in, and `status` is then `signed-out`.
2464
2567
  */
2465
- declare function completionMark(quests: Pick<QuestView, "quest" | "completed" | "completionCount">[]): string;
2466
- declare function hasPending(deliveries: RoleDelivery[]): boolean;
2568
+ declare function useMemberQuery<T>(key: QueryKey, read: QueryRead<T>, options?: QueryOptions): MemberQuery<T>;
2467
2569
  /**
2468
- * The words for one quest, or null when it delivers nothing. This never
2469
- * changes whether the quest is completed: the role follows the completion.
2570
+ * A paged read (`{ cursor }` in, `{ items, nextCursor }` out) as one growing list, for pages a
2571
+ * signed-out visitor can read too. `refresh()` and an invalidation start again from the first
2572
+ * page; a page that arrives after that, or for another key or participant, is dropped rather than
2573
+ * appended.
2470
2574
  */
2471
- declare function roleDeliveryLabel(deliveries: RoleDelivery[], quest: string): "Role delivery pending" | "Role delivery failed" | "Role granted" | null;
2472
- /** Waits between reads: while a role is pending, then after each failure. */
2473
- declare const PENDING_POLL_MS = 5000;
2474
- declare const RETRY_DELAYS_MS: number[];
2475
- type Schedule = (run: () => void, ms: number) => () => void;
2575
+ declare function useRelayPages<T>(key: QueryKey, read: PageRead<T>, options?: QueryOptions): PagedQuery<T>;
2576
+ /** `useRelayPages` for pages that need a signed-in member: `signed-out` while nobody is. */
2577
+ declare function useMemberPages<T>(key: QueryKey, read: PageRead<T>, options?: QueryOptions): MemberPagedQuery<T>;
2476
2578
  /**
2477
- * Follows one participant's role deliveries until there is nothing to wait for.
2579
+ * Marks cached reads out of date after a change. Each key is a prefix: `[["leaderboards"]]`
2580
+ * reads every leaderboard on screen again and forgets the rest. With no keys, everything.
2478
2581
  *
2479
- * - A read that succeeds with nothing pending ends the watch: no empty polling.
2480
- * - A pending role is read again every few seconds.
2481
- * - A failed read, including the very first, is retried with a short backoff.
2482
- * After the last retry the watch rests until `wake()`, which the page calls
2483
- * when it becomes visible or focused again.
2484
- * - Failures never report anything, so a pending role stays pending on screen.
2582
+ * The SDK's own mutating hooks call it; call it after a change made with `useRelay()` directly.
2583
+ * `["experience"]` reads the quest experience again.
2485
2584
  */
2486
- declare function watchRoleDeliveries(options: {
2487
- read: () => Promise<RoleDelivery[]>;
2488
- onChange: (deliveries: RoleDelivery[]) => void;
2489
- schedule?: Schedule;
2490
- }): {
2491
- wake(): void;
2492
- dispose(): void;
2585
+ declare function useInvalidate(): (keys?: QueryKey[]) => Promise<void>;
2586
+ /**
2587
+ * Who is signed in: the session (`data`, null for a signed-out visitor) and its `member`.
2588
+ * Independent of the quest experience: a failing experience read signs nobody out.
2589
+ */
2590
+ declare function useSession(): Query<ParticipantSession | null> & {
2591
+ /** The signed-in member's ID, or null. */
2592
+ member: string | null;
2493
2593
  };
2494
2594
 
2495
- type Collection = {
2496
- id: string;
2497
- title: string;
2498
- quests: QuestView[];
2595
+ /**
2596
+ * The key prefixes the SDK's hooks cache under, for `useInvalidate()`: after a change made with
2597
+ * `useRelay()` directly, `invalidate([relayKeys.leaderboards])` reads every leaderboard on screen
2598
+ * again. Keys of your own `useRelayQuery` calls must not start with these.
2599
+ */
2600
+ declare const relayKeys: {
2601
+ /** `useExperience`: invalidating it reads the quest experience again. */
2602
+ readonly experience: readonly ["experience"];
2603
+ /** `useMe`. */
2604
+ readonly me: readonly ["me"];
2605
+ /** `useAccounts`. */
2606
+ readonly accounts: readonly ["accounts"];
2607
+ /** `useWallets`. */
2608
+ readonly wallets: readonly ["wallets"];
2609
+ /** `useMyProfile`, `useProfile`, `useProfileCompletions`, `useProfileReferral`. */
2610
+ readonly profiles: readonly ["profiles"];
2611
+ /** `useLeaderboard`, `useLeaderboardPlacement`. */
2612
+ readonly leaderboards: readonly ["leaderboards"];
2613
+ /** `useReferralSummary`. */
2614
+ readonly referrals: readonly ["referrals"];
2615
+ /** `usePointLedgers`. */
2616
+ readonly pointLedgers: readonly ["point-ledgers"];
2617
+ /** `useTieredRewards`. */
2618
+ readonly tieredRewards: readonly ["tiered-rewards"];
2619
+ /** `useSignInMethods`. */
2620
+ readonly signInMethods: readonly ["sign-in-methods"];
2621
+ /** `useBalances`, `usePointHistory`. */
2622
+ readonly balances: readonly ["balances"];
2499
2623
  };
2500
- type Experience = {
2501
- status: "loading";
2502
- } | {
2503
- status: "signed-out";
2504
- } | {
2505
- status: "error";
2506
- message: string;
2507
- } | {
2508
- status: "ready";
2509
- quests: QuestView[];
2510
- collections: Collection[];
2511
- /** Set when a refresh failed; the last good data stays on screen. */
2512
- stale: string | null;
2624
+
2625
+ /**
2626
+ * All a participant sees of a reward Domino delivers elsewhere, such as a
2627
+ * Discord role. Attempts, errors, and role IDs stay out of the page.
2628
+ */
2629
+ type RoleDelivery = {
2630
+ quest: string;
2631
+ status: "pending" | "delivered" | "failed";
2513
2632
  };
2633
+ type KnownRoleDeliveryStatus = "pending" | "failed" | "granted";
2634
+ /** Where one quest's role deliveries stand, as a code an app can localize; open for new codes. */
2635
+ type RoleDeliveryStatus = KnownRoleDeliveryStatus | (string & {});
2514
2636
  /**
2515
- * Everything to list, in display order: collections as Console arranged them,
2516
- * then any quest nobody has placed yet, sorted by `order`: authoring keys
2517
- * (the `key` in quests/*.quest.ts), or quest IDs for quests without one.
2518
- * Archived quests are left out.
2637
+ * Where one quest's roles stand, or null when it delivers nothing. This never
2638
+ * changes whether the quest is completed: the role follows the completion.
2639
+ * `failed` means Domino gave up; only the organizer can grant the role now.
2519
2640
  */
2520
- declare function questGroups(experience: Extract<Experience, {
2521
- status: "ready";
2522
- }>, order?: string[]): Collection[];
2641
+ declare function roleDeliveryStatus(deliveries: RoleDelivery[], quest: string): KnownRoleDeliveryStatus | null;
2642
+ /** `roleDeliveryStatus` in English, or null for null. */
2643
+ declare function roleDeliveryLabel(status: RoleDeliveryStatus | null): "Role delivery pending" | "Role delivery failed" | "Role granted" | null;
2523
2644
 
2524
- type ExperienceContext = {
2525
- experience: Experience;
2526
- /** The signed-in participant's member ID, or null. */
2527
- member: string | null;
2528
- /** Discord roles earned from quests, and whether each has arrived yet. */
2645
+ /**
2646
+ * The signed-in participant's quests and collections, polled for the whole app by one observer,
2647
+ * which pauses while the tab is hidden. `data` holds `quests` and `collections`; `signed-out`
2648
+ * means nobody is signed in. `deliveries` lists Discord roles earned from quests and whether each
2649
+ * has arrived yet.
2650
+ */
2651
+ declare function useExperience(): MemberQuery<ExperienceData> & {
2529
2652
  deliveries: RoleDelivery[];
2530
- /** Read again now instead of waiting for the next poll. */
2531
- refresh(): Promise<void>;
2532
2653
  };
2533
- /** The participant's quests and collections, polled for the whole app. */
2534
- declare function useExperience(): ExperienceContext;
2535
2654
 
2536
2655
  type QuestInput = {
2537
2656
  kind: "text" | "url";
@@ -2821,7 +2940,7 @@ declare function useQuest(observed: QuestView): {
2821
2940
  /** Input recovered after the quest changed. Prefill the form with it. */
2822
2941
  draft: SubmissionDraft | null;
2823
2942
  notice: QuestNotice;
2824
- error: string | null;
2943
+ error: RelayError | null;
2825
2944
  busy: boolean;
2826
2945
  saved: SavedSubmission;
2827
2946
  /** The attempt the last "received" notice is about. */
@@ -2839,8 +2958,37 @@ declare function useQuest(observed: QuestView): {
2839
2958
  };
2840
2959
 
2841
2960
  type QuestTone = "open" | "done" | "waiting" | "attention" | "locked" | "off";
2961
+ /**
2962
+ * Why a quest shows the way it does, as a stable code an app can localize. `questStatusText` turns
2963
+ * it into English.
2964
+ *
2965
+ * - `completed`: nothing more to do.
2966
+ * - `paused`, `closed`: the operator paused or archived the quest.
2967
+ * - `streak`: a streak in progress; `view.streak` has the counts and when the next day starts.
2968
+ * - `streak-budget-exhausted`: the streak reached a milestone whose reward budget ran out.
2969
+ * - `automatic`: Domino counts this by itself whenever the participant qualifies.
2970
+ * - `in-progress`: an automatic quest Domino is running.
2971
+ * - `locked`: prerequisites first; `view.availability.missing` lists them.
2972
+ * - `checking`, `in-review`: a submission is being verified, or reviewed by a person.
2973
+ * - `retryable`: verification could not run; the participant can retry.
2974
+ * - `staff-required`: a staff member confirms it.
2975
+ * - `rejected`: the last submission was not accepted; the participant can try again.
2976
+ * - `ready`: the participant can act now.
2977
+ */
2978
+ type KnownQuestStatusCode = "completed" | "paused" | "closed" | "streak" | "streak-budget-exhausted" | "automatic" | "in-progress" | "locked" | "checking" | "in-review" | "retryable" | "staff-required" | "rejected" | "ready";
2979
+ /** A known code, or one a newer SDK adds: render unknown codes with a neutral fallback. */
2980
+ type QuestStatusCode = KnownQuestStatusCode | (string & {});
2842
2981
  type QuestStatus = {
2843
2982
  tone: QuestTone;
2983
+ code: QuestStatusCode;
2984
+ /**
2985
+ * Set when the participant's last submission was rejected: the evaluator's reason, or an empty
2986
+ * string when it gave none.
2987
+ */
2988
+ reason?: string;
2989
+ };
2990
+ /** `QuestStatus` in English: a short `label`, and a sentence of `detail` when there is more. */
2991
+ type QuestStatusText = QuestStatus & {
2844
2992
  label: string;
2845
2993
  detail?: string;
2846
2994
  };
@@ -2856,11 +3004,6 @@ declare function isFinished(view: QuestView): boolean;
2856
3004
  * status and nothing to press.
2857
3005
  */
2858
3006
  declare function isAutomatic(view: QuestView): boolean;
2859
- /**
2860
- * True for automatic quests driven by observed activity, possibly many times
2861
- * and without telling the participant. They read "Automatic", not "In progress".
2862
- */
2863
- declare function runsSilently(view: QuestView): boolean;
2864
3007
  /** "Completed 3 times" for repeatable quests, otherwise nothing. */
2865
3008
  declare function completionCountLabel(view: QuestView): string | null;
2866
3009
  /**
@@ -2868,10 +3011,18 @@ declare function completionCountLabel(view: QuestView): string | null;
2868
3011
  * open again, so show the normal submit action rather than a finished state.
2869
3012
  */
2870
3013
  declare function canRepeat(view: QuestView): boolean;
2871
- /** Hidden quests run in the background and are never listed. */
2872
- declare function visibleQuests<T extends Pick<QuestView, "visibility">>(quests: T[]): T[];
2873
- /** Turns a QuestView into words. Pure, so copy changes stay in one place. */
2874
- declare function questStatus(view: QuestView): QuestStatus;
3014
+ /**
3015
+ * What a QuestView means for the participant, as a tone and a code. Pure and free of copy: render
3016
+ * the code in your own words, or call `questStatusText` for English.
3017
+ */
3018
+ declare function questStatus(view: QuestView): QuestStatus & {
3019
+ code: KnownQuestStatusCode;
3020
+ };
3021
+ /**
3022
+ * `questStatus` in English, for apps that do not localize: a `label` such as "In review", and a
3023
+ * `detail` sentence when there is more to say.
3024
+ */
3025
+ declare function questStatusText(view: QuestView): QuestStatusText;
2875
3026
  /** True when the participant can submit something right now. */
2876
3027
  declare function canSubmit(view: QuestView): boolean;
2877
3028
  declare function progressOf(quests: QuestView[]): {
@@ -2882,25 +3033,24 @@ declare function progressOf(quests: QuestView[]): {
2882
3033
  type OAuthProvider = AuthProvider;
2883
3034
  /**
2884
3035
  * The sign-in methods participants can use here: the OAuth providers and email Domino configured
2885
- * for the platform, and the wallet sign-in this project enabled in Console.
3036
+ * for the platform, and the wallet sign-in this project enabled in Console, in `data`. When they
3037
+ * cannot be read, `data` offers email alone and `data.error` says why; the server still has the
3038
+ * final say.
2886
3039
  */
2887
- declare function useSignInMethods(): SignInMethods | null;
3040
+ declare function useSignInMethods(): Query<SignInMethods>;
2888
3041
  /**
2889
- * The signed-in member and the seed of their generated avatar, or null while signed out or
2890
- * loading: `<img src={defaultAvatar(me.avatarSeed)} />`. The seed is derived from the member and
3042
+ * The signed-in member and the seed of their generated avatar, in `data`:
3043
+ * `<img src={defaultAvatar(me.data.avatarSeed)} />`. The seed is derived from the member and
2891
3044
  * reveals nothing about them; linking wallets or accounts does not change it.
2892
3045
  */
2893
- declare function useMe(): {
2894
- member: string;
2895
- avatarSeed: string;
2896
- } | null;
3046
+ declare function useMe(): MemberQuery<MemberSummary>;
2897
3047
  /**
2898
3048
  * Email codes, OAuth consent and wallet signatures always happen in the participant's browser.
2899
3049
  * The actions keep their identity across renders, and never reject: a failure lands in `error`.
2900
3050
  */
2901
3051
  declare function useSignIn(): {
2902
3052
  busy: boolean;
2903
- error: string | null;
3053
+ error: RelayError | null;
2904
3054
  /** True once a code was sent and the form should ask for it. */
2905
3055
  codeSent: boolean;
2906
3056
  sendCode: (email: string) => Promise<void>;
@@ -2937,9 +3087,10 @@ declare function useSignInOptions(input?: {
2937
3087
  options: SignInOption[] | null;
2938
3088
  unavailable: SignInUnavailable[];
2939
3089
  /** Why the project's methods could not be read; the options are then email alone. */
2940
- methodsError: string | null;
3090
+ methodsError: RelayError | null;
2941
3091
  busy: boolean;
2942
- error: string | null;
3092
+ /** Why the last sign-in action failed. */
3093
+ error: RelayError | null;
2943
3094
  /** True once an email code was sent and the form should ask for it. */
2944
3095
  codeSent: boolean;
2945
3096
  /** Forgets the email code sent, to use another address. */
@@ -2947,53 +3098,119 @@ declare function useSignInOptions(input?: {
2947
3098
  };
2948
3099
 
2949
3100
  /** True when the account can be used to verify quests right now. */
2950
- declare function isConnected(accounts: AccountConnection[] | null, provider: AuthProvider): boolean;
3101
+ declare function isConnected(accounts: AccountConnection[] | null | undefined, provider: AuthProvider): boolean;
2951
3102
  /**
2952
- * The signed-in participant's connected accounts (X, Discord, Google, Apple).
3103
+ * The signed-in participant's connected accounts (X, Discord, Google, Apple) in `data`.
2953
3104
  *
2954
3105
  * Connecting leaves the page for the provider's consent screen and comes back
2955
3106
  * connected. The list is read again when the window regains focus and after
2956
- * any disconnect in this tab, so every component using it stays in step.
3107
+ * a disconnect, in every component that uses it. `connect` and `disconnect`
3108
+ * never reject: they resolve whether they succeeded, and a failure lands in
3109
+ * `actionError`.
2957
3110
  */
2958
3111
  declare function useAccounts(): {
2959
- /** Null until read, and while nobody is signed in. */
2960
- accounts: {
3112
+ connect: (provider: AuthProvider) => Promise<boolean>;
3113
+ disconnect: (provider: AuthProvider) => Promise<boolean>;
3114
+ busy: boolean;
3115
+ actionError: RelayError | null;
3116
+ isConnected: (provider: AuthProvider) => boolean;
3117
+ status: "loading";
3118
+ data: undefined;
3119
+ error: null;
3120
+ refresh(): Promise<void>;
3121
+ } | {
3122
+ connect: (provider: AuthProvider) => Promise<boolean>;
3123
+ disconnect: (provider: AuthProvider) => Promise<boolean>;
3124
+ busy: boolean;
3125
+ actionError: RelayError | null;
3126
+ isConnected: (provider: AuthProvider) => boolean;
3127
+ status: "error";
3128
+ data: undefined;
3129
+ error: RelayError;
3130
+ refresh(): Promise<void>;
3131
+ } | {
3132
+ connect: (provider: AuthProvider) => Promise<boolean>;
3133
+ disconnect: (provider: AuthProvider) => Promise<boolean>;
3134
+ busy: boolean;
3135
+ actionError: RelayError | null;
3136
+ isConnected: (provider: AuthProvider) => boolean;
3137
+ status: "signed-out";
3138
+ data: undefined;
3139
+ error: null;
3140
+ refresh(): Promise<void>;
3141
+ } | {
3142
+ connect: (provider: AuthProvider) => Promise<boolean>;
3143
+ disconnect: (provider: AuthProvider) => Promise<boolean>;
3144
+ busy: boolean;
3145
+ actionError: RelayError | null;
3146
+ isConnected: (provider: AuthProvider) => boolean;
3147
+ status: "ready";
3148
+ data: {
2961
3149
  provider: "google" | "apple" | "x" | "discord";
2962
3150
  configured: boolean;
2963
3151
  status: "disconnected" | "connected" | "reconnect";
2964
3152
  subject: string | null;
2965
3153
  revision: number;
2966
- }[] | null;
2967
- error: string | null;
2968
- busy: boolean;
2969
- refresh: () => Promise<void>;
2970
- isConnected: (provider: AuthProvider) => boolean;
2971
- connect: (provider: AuthProvider) => Promise<void>;
2972
- disconnect: (provider: AuthProvider) => Promise<void>;
3154
+ }[];
3155
+ error: RelayError | null;
3156
+ refresh(): Promise<void>;
2973
3157
  };
2974
3158
 
2975
3159
  /**
2976
- * The signed-in participant's linked Solana, EVM and Cosmos wallets.
3160
+ * The signed-in participant's linked Solana, EVM and Cosmos wallets, in `data`.
2977
3161
  *
2978
3162
  * Linking asks the wallet to sign a one-time message. The list is read again
2979
- * when the window regains focus and after any link or unlink in this tab, so
2980
- * every component using it stays in step.
3163
+ * when the window regains focus and after a link or unlink, in every component
3164
+ * that uses it. `link` and `unlink` never reject: they resolve whether they
3165
+ * succeeded, and a failure lands in `actionError`.
2981
3166
  */
2982
3167
  declare function useWallets(): {
2983
- /** Null until read, and while nobody is signed in. */
2984
- wallets: {
3168
+ /** Links the wallet to the member the list was read for; another session is refused. */
3169
+ link: (signer: WalletSigner) => Promise<boolean>;
3170
+ unlink: (wallet: Pick<LinkedWallet, "chain" | "address">) => Promise<boolean>;
3171
+ busy: boolean;
3172
+ actionError: RelayError | null;
3173
+ status: "loading";
3174
+ data: undefined;
3175
+ error: null;
3176
+ refresh(): Promise<void>;
3177
+ } | {
3178
+ /** Links the wallet to the member the list was read for; another session is refused. */
3179
+ link: (signer: WalletSigner) => Promise<boolean>;
3180
+ unlink: (wallet: Pick<LinkedWallet, "chain" | "address">) => Promise<boolean>;
3181
+ busy: boolean;
3182
+ actionError: RelayError | null;
3183
+ status: "error";
3184
+ data: undefined;
3185
+ error: RelayError;
3186
+ refresh(): Promise<void>;
3187
+ } | {
3188
+ /** Links the wallet to the member the list was read for; another session is refused. */
3189
+ link: (signer: WalletSigner) => Promise<boolean>;
3190
+ unlink: (wallet: Pick<LinkedWallet, "chain" | "address">) => Promise<boolean>;
3191
+ busy: boolean;
3192
+ actionError: RelayError | null;
3193
+ status: "signed-out";
3194
+ data: undefined;
3195
+ error: null;
3196
+ refresh(): Promise<void>;
3197
+ } | {
3198
+ /** Links the wallet to the member the list was read for; another session is refused. */
3199
+ link: (signer: WalletSigner) => Promise<boolean>;
3200
+ unlink: (wallet: Pick<LinkedWallet, "chain" | "address">) => Promise<boolean>;
3201
+ busy: boolean;
3202
+ actionError: RelayError | null;
3203
+ status: "ready";
3204
+ data: {
2985
3205
  chain: "solana" | "eip155" | "cosmos";
2986
3206
  network: `cosmos:${string}` | null;
2987
3207
  address: string;
2988
3208
  verifiedAt: number;
2989
3209
  revision: number;
2990
3210
  signIn: boolean;
2991
- }[] | null;
2992
- error: string | null;
2993
- busy: boolean;
2994
- refresh: () => Promise<void>;
2995
- link: (signer: WalletSigner) => Promise<void>;
2996
- unlink: (wallet: Pick<LinkedWallet, "chain" | "address">) => Promise<void>;
3211
+ }[];
3212
+ error: RelayError | null;
3213
+ refresh(): Promise<void>;
2997
3214
  };
2998
3215
  /**
2999
3216
  * The EVM, Solana and Cosmos wallets installed in this browser. Empty during
@@ -3021,19 +3238,54 @@ declare function useSignInWallets(networks: readonly WalletSignInNetwork[] | nul
3021
3238
  cosmos?: CosmosChains;
3022
3239
  }): SignInWallet[] | null;
3023
3240
 
3024
- /** Dispatched on `window` after the member changes their profile in this tab. */
3025
- declare const PROFILE_CHANGED = "relay-profile-changed";
3026
3241
  /**
3027
- * The signed-in member's own profile, and changes to it: the name, the avatar (an uploaded
3028
- * picture, an account's picture or the generated one) and whether others see it.
3242
+ * The signed-in member's own profile in `data`, and changes to it: the name, the avatar (an
3243
+ * uploaded picture, an account's picture or the generated one) and whether others see it.
3029
3244
  *
3030
- * Read again when the window regains focus and after any change in this tab, so every component
3031
- * using it stays in step. Each change is bound to the session it was read with: a session that
3032
- * changed in between is refused rather than applied to another member.
3245
+ * Read again when the window regains focus and after a change, in every component that uses it,
3246
+ * with the leaderboards that show the name. Each change is bound to the session the profile was
3247
+ * read with: a session that changed in between is refused rather than applied to another member.
3248
+ * `update` and `uploadAvatar` never reject: they resolve true once saved, and a failure lands in
3249
+ * `actionError`.
3033
3250
  */
3034
3251
  declare function useMyProfile(): {
3035
- /** Null until read, and while nobody is signed in. */
3036
- profile: {
3252
+ update: (input: ProfileUpdate) => Promise<boolean>;
3253
+ /** Uploads a JPEG, PNG or WebP of at most 5 MB as the avatar. */
3254
+ uploadAvatar: (file: Blob) => Promise<boolean>;
3255
+ busy: boolean;
3256
+ actionError: RelayError | null;
3257
+ status: "loading";
3258
+ data: undefined;
3259
+ error: null;
3260
+ refresh(): Promise<void>;
3261
+ } | {
3262
+ update: (input: ProfileUpdate) => Promise<boolean>;
3263
+ /** Uploads a JPEG, PNG or WebP of at most 5 MB as the avatar. */
3264
+ uploadAvatar: (file: Blob) => Promise<boolean>;
3265
+ busy: boolean;
3266
+ actionError: RelayError | null;
3267
+ status: "error";
3268
+ data: undefined;
3269
+ error: RelayError;
3270
+ refresh(): Promise<void>;
3271
+ } | {
3272
+ update: (input: ProfileUpdate) => Promise<boolean>;
3273
+ /** Uploads a JPEG, PNG or WebP of at most 5 MB as the avatar. */
3274
+ uploadAvatar: (file: Blob) => Promise<boolean>;
3275
+ busy: boolean;
3276
+ actionError: RelayError | null;
3277
+ status: "signed-out";
3278
+ data: undefined;
3279
+ error: null;
3280
+ refresh(): Promise<void>;
3281
+ } | {
3282
+ update: (input: ProfileUpdate) => Promise<boolean>;
3283
+ /** Uploads a JPEG, PNG or WebP of at most 5 MB as the avatar. */
3284
+ uploadAvatar: (file: Blob) => Promise<boolean>;
3285
+ busy: boolean;
3286
+ actionError: RelayError | null;
3287
+ status: "ready";
3288
+ data: {
3037
3289
  id: string;
3038
3290
  name: string;
3039
3291
  avatar: {
@@ -3060,198 +3312,43 @@ declare function useMyProfile(): {
3060
3312
  name: string | null;
3061
3313
  imageUrl: string | null;
3062
3314
  }[];
3063
- } | null;
3064
- error: string | null;
3065
- busy: boolean;
3066
- refresh: () => Promise<void>;
3067
- /** Resolves true once saved; a failure sets `error`. */
3068
- update: (input: ProfileUpdate) => Promise<boolean>;
3069
- /** Uploads a JPEG, PNG or WebP of at most 5 MB as the avatar; resolves true once saved. */
3070
- uploadAvatar: (file: Blob) => Promise<boolean>;
3071
- };
3072
- /**
3073
- * A read keyed by a profile. `missing` is the uniform 404: a profile (or board, or program) that
3074
- * is missing, hidden by its member, or not visible to this viewer, on purpose indistinguishable.
3075
- */
3076
- type ProfileReadState<T> = {
3077
- status: "loading";
3078
- } | {
3079
- status: "error";
3080
- message: string;
3081
- } | {
3082
- status: "missing";
3083
- } | {
3084
- status: "ready";
3085
- value: T;
3086
- stale: string | null;
3087
- };
3088
- type ProfileState = {
3089
- status: "loading";
3090
- } | {
3091
- status: "error";
3092
- message: string;
3093
- }
3094
- /** Missing, hidden by its member, or not visible to this viewer: indistinguishable on purpose. */
3095
- | {
3096
- status: "missing";
3097
- } | {
3098
- status: "ready";
3099
- profile: ProfileSummary;
3100
- stale: string | null;
3315
+ };
3316
+ error: RelayError | null;
3317
+ refresh(): Promise<void>;
3101
3318
  };
3102
3319
  /**
3103
- * A profile's name and avatar by its public ID (`relay.profiles.get`), read again every
3104
- * `intervalMs` (default 60 seconds) while the page is visible and when the participant signs in
3105
- * or out.
3320
+ * A profile's name and avatar by its public ID (`relay.profiles.get`), in `data`. Read again every
3321
+ * `intervalMs` (default 60 seconds) while the page is visible. A profile that is missing, hidden by
3322
+ * its member or not visible to this viewer is an `error` with `status` 404, indistinguishable on
3323
+ * purpose.
3106
3324
  */
3107
3325
  declare function useProfile(id: string, options?: {
3108
3326
  intervalMs?: number;
3109
- }): {
3110
- refresh: () => Promise<void>;
3111
- status: "loading";
3112
- } | {
3113
- refresh: () => Promise<void>;
3114
- status: "error";
3115
- message: string;
3116
- } | {
3117
- refresh: () => Promise<void>;
3118
- status: "missing";
3119
- } | {
3120
- refresh: () => Promise<void>;
3121
- status: "ready";
3122
- profile: ProfileSummary;
3123
- stale: string | null;
3124
- };
3327
+ }): Query<ProfileSummary>;
3125
3328
  /**
3126
- * A profile's current rank and score on one board (`relay.leaderboards.placement`), read again
3127
- * every `intervalMs` (default 30 seconds) while the page is visible. Signed-out visitors get an
3128
- * error for boards without public access.
3329
+ * A profile's current rank and score on one board (`relay.leaderboards.placement`), in `data`.
3330
+ * Read again every `intervalMs` (default 30 seconds) while the page is visible. Signed-out
3331
+ * visitors get an error for boards without public access.
3129
3332
  */
3130
3333
  declare function useLeaderboardPlacement(board: string, profile: string, options?: {
3131
3334
  intervalMs?: number;
3132
- }): {
3133
- refresh: () => Promise<void>;
3134
- status: "loading";
3135
- } | {
3136
- refresh: () => Promise<void>;
3137
- status: "error";
3138
- message: string;
3139
- } | {
3140
- refresh: () => Promise<void>;
3141
- status: "missing";
3142
- } | {
3143
- refresh: () => Promise<void>;
3144
- status: "ready";
3145
- value: {
3146
- leaderboard: string;
3147
- title: string;
3148
- profile: string;
3149
- rank: number | null;
3150
- score: number | null;
3151
- total: number;
3152
- key?: string | undefined;
3153
- };
3154
- stale: string | null;
3155
- };
3335
+ }): Query<LeaderboardPlacement>;
3156
3336
  /**
3157
- * A profile's progress in one referral program (`relay.profiles.referral`), read again every
3158
- * `intervalMs` (default 60 seconds) while the page is visible. Needs a signed-in participant.
3337
+ * A profile's progress in one referral program (`relay.profiles.referral`), in `data`. Read again
3338
+ * every `intervalMs` (default 60 seconds) while the page is visible. Needs a signed-in participant.
3159
3339
  */
3160
3340
  declare function useProfileReferral(profile: string, program: string, options?: {
3161
3341
  intervalMs?: number;
3162
- }): {
3163
- refresh: () => Promise<void>;
3164
- status: "loading";
3165
- } | {
3166
- refresh: () => Promise<void>;
3167
- status: "error";
3168
- message: string;
3169
- } | {
3170
- refresh: () => Promise<void>;
3171
- status: "missing";
3172
- } | {
3173
- refresh: () => Promise<void>;
3174
- status: "ready";
3175
- value: {
3176
- program: string;
3177
- title: string;
3178
- invited: number;
3179
- qualified: number;
3180
- milestones: {
3181
- id: string;
3182
- count: number;
3183
- reached: boolean;
3184
- }[];
3185
- key?: string | undefined;
3186
- };
3187
- stale: string | null;
3188
- };
3189
- type ProfileCompletionsState = {
3190
- status: "loading";
3191
- } | {
3192
- status: "error";
3193
- message: string;
3194
- } | {
3195
- status: "missing";
3196
- } | {
3197
- status: "ready";
3198
- items: ProfileCompletion[];
3199
- /** More completions to load with `loadMore()`. */
3200
- more: boolean;
3201
- /** Loading the next page. */
3202
- loading: boolean;
3203
- /** Why the last `loadMore()` failed, until the next succeeds. */
3204
- error: string | null;
3205
- };
3342
+ }): MemberQuery<ProfileReferral>;
3206
3343
  /**
3207
3344
  * A profile's completions of quests that show on profiles (`relay.profiles.completions`), most
3208
- * recently completed first, `limit` quests at a time. `loadMore()` appends the next page;
3209
- * `refresh()` starts again from the first, as signing in or out and a profile change in this tab
3210
- * do.
3345
+ * recently completed first, `limit` quests at a time: `data.items`, and `data.nextCursor` while
3346
+ * there are more. `loadMore()` appends the next page; `refresh()` starts again from the first, as a
3347
+ * quest submission or a profile change does.
3211
3348
  */
3212
3349
  declare function useProfileCompletions(profile: string, options?: {
3213
3350
  limit?: number;
3214
- }): {
3215
- refresh: () => Promise<void>;
3216
- /**
3217
- * Appends the next page; does nothing while one loads, while the first page reloads, or when
3218
- * there is none.
3219
- */
3220
- loadMore: () => Promise<void>;
3221
- status: "loading";
3222
- } | {
3223
- refresh: () => Promise<void>;
3224
- /**
3225
- * Appends the next page; does nothing while one loads, while the first page reloads, or when
3226
- * there is none.
3227
- */
3228
- loadMore: () => Promise<void>;
3229
- status: "error";
3230
- message: string;
3231
- } | {
3232
- refresh: () => Promise<void>;
3233
- /**
3234
- * Appends the next page; does nothing while one loads, while the first page reloads, or when
3235
- * there is none.
3236
- */
3237
- loadMore: () => Promise<void>;
3238
- status: "missing";
3239
- } | {
3240
- refresh: () => Promise<void>;
3241
- /**
3242
- * Appends the next page; does nothing while one loads, while the first page reloads, or when
3243
- * there is none.
3244
- */
3245
- loadMore: () => Promise<void>;
3246
- status: "ready";
3247
- items: ProfileCompletion[];
3248
- /** More completions to load with `loadMore()`. */
3249
- more: boolean;
3250
- /** Loading the next page. */
3251
- loading: boolean;
3252
- /** Why the last `loadMore()` failed, until the next succeeds. */
3253
- error: string | null;
3254
- };
3351
+ }): PagedQuery<ProfileCompletion>;
3255
3352
 
3256
3353
  type ReferralSummary = z.infer<typeof referralSummarySchema>;
3257
3354
  /**
@@ -3271,14 +3368,18 @@ type Invitation = {
3271
3368
  } | {
3272
3369
  status: "accepted";
3273
3370
  code: string;
3274
- } | {
3371
+ }
3372
+ /** Domino refused the code, or it is malformed: `error` says why. Never retry it. */
3373
+ | {
3275
3374
  status: "rejected";
3276
3375
  code: string;
3277
- reason: string;
3278
- } | {
3376
+ error: RelayError;
3377
+ }
3378
+ /** Offline, a server error or a cut-off answer: `error` says why. Retry with `accept(code)`. */
3379
+ | {
3279
3380
  status: "failed";
3280
3381
  code: string;
3281
- reason: string;
3382
+ error: RelayError;
3282
3383
  };
3283
3384
  /**
3284
3385
  * Accepts the invitation the participant arrived with, as soon as they are
@@ -3286,334 +3387,67 @@ type Invitation = {
3286
3387
  *
3287
3388
  * Domino rejects self-referrals, cycles, codes from another project, and
3288
3389
  * invitations accepted after the participant's first completion. Show the
3289
- * reason; `accept(code)` also serves a manual "Have a code?" input.
3390
+ * reason; `accept(code)` also serves a manual "Have a code?" input. Once
3391
+ * accepted, the referral summary and referral progress are read again.
3290
3392
  */
3291
3393
  declare function useInvitation(param?: string): {
3292
3394
  invitation: Invitation;
3293
3395
  accept: (code: string) => Promise<void>;
3294
3396
  };
3295
3397
  /**
3296
- * The signed-in participant's invitation code, share link, and progress:
3297
- * attributed friends, qualified friends per program, milestones, and points.
3398
+ * The signed-in participant's invitation code and progress in `data`: attributed friends,
3399
+ * qualified friends per program, milestones, and points. `link` is the share link, null until the
3400
+ * summary is read. Read again after an invitation is accepted and after a quest submission.
3298
3401
  */
3299
3402
  declare function useReferralSummary(options?: {
3300
3403
  path?: string;
3301
3404
  param?: string;
3302
- }): {
3303
- summary: {
3304
- code: string;
3305
- attributed: number;
3306
- programs: {
3307
- definition: {
3308
- id: string;
3309
- title: string;
3310
- enabled: boolean;
3311
- qualification: {
3312
- kind: "signup";
3313
- } | {
3314
- kind: "quest";
3315
- quest: string;
3316
- } | {
3317
- kind: "external";
3318
- };
3319
- rewards: {
3320
- inviter: ({
3321
- kind: "tier";
3322
- reward: {
3323
- id: string;
3324
- title: string;
3325
- tiers: {
3326
- id: string;
3327
- title: string;
3328
- }[];
3329
- inventory: {
3330
- kind: "untracked";
3331
- };
3332
- fulfillment: {
3333
- kind: "staff-handover";
3334
- };
3335
- };
3336
- tier: string;
3337
- } | {
3338
- kind: "points";
3339
- balance: string;
3340
- amount: number;
3341
- })[];
3342
- invitee: ({
3343
- kind: "tier";
3344
- reward: {
3345
- id: string;
3346
- title: string;
3347
- tiers: {
3348
- id: string;
3349
- title: string;
3350
- }[];
3351
- inventory: {
3352
- kind: "untracked";
3353
- };
3354
- fulfillment: {
3355
- kind: "staff-handover";
3356
- };
3357
- };
3358
- tier: string;
3359
- } | {
3360
- kind: "points";
3361
- balance: string;
3362
- amount: number;
3363
- })[];
3364
- };
3365
- milestones: {
3366
- id: string;
3367
- count: number;
3368
- rewards: ({
3369
- kind: "tier";
3370
- reward: {
3371
- id: string;
3372
- title: string;
3373
- tiers: {
3374
- id: string;
3375
- title: string;
3376
- }[];
3377
- inventory: {
3378
- kind: "untracked";
3379
- };
3380
- fulfillment: {
3381
- kind: "staff-handover";
3382
- };
3383
- };
3384
- tier: string;
3385
- } | {
3386
- kind: "points";
3387
- balance: string;
3388
- amount: number;
3389
- })[];
3390
- }[];
3391
- bonuses: {
3392
- id: string;
3393
- balance: string;
3394
- basisPoints: number;
3395
- external: boolean;
3396
- quests?: string[] | undefined;
3397
- durationDays?: number | undefined;
3398
- maxPoints?: number | undefined;
3399
- }[];
3400
- key?: string | undefined;
3401
- inviterGroup?: string | undefined;
3402
- };
3403
- qualified: number;
3404
- milestones: {
3405
- id: string;
3406
- count: number;
3407
- reached: boolean;
3408
- }[];
3409
- }[];
3410
- accounts: {
3411
- id: string;
3412
- program: string;
3413
- kind: "fixed" | "milestone" | "bonus";
3414
- balance: string;
3415
- earned: number;
3416
- settled: number;
3417
- outstanding: number;
3418
- }[];
3419
- } | null;
3405
+ }): MemberQuery<ReferralSummary> & {
3420
3406
  link: string | null;
3421
- error: string | null;
3422
- refresh: () => Promise<void>;
3423
3407
  };
3424
3408
 
3425
- type LeaderboardState = {
3426
- status: "loading";
3427
- } | {
3428
- status: "error";
3429
- message: string;
3430
- } | {
3431
- status: "ready";
3432
- page: LeaderboardPage;
3433
- stale: string | null;
3434
- };
3435
3409
  /**
3436
- * One leaderboard's top rows plus the participant's own row and neighbours.
3410
+ * One leaderboard's top rows plus the participant's own row and neighbours, in `data`.
3437
3411
  *
3438
- * Read again every `intervalMs` while the page is visible, and when the
3439
- * participant signs in or out. Boards default to participants-only access:
3440
- * signed-out visitors see an error unless the board is published as public.
3412
+ * Read again every `intervalMs` while the page is visible, after a quest submission, and for each
3413
+ * participant who signs in. Boards default to participants-only access: signed-out visitors get
3414
+ * an error unless the board is published as public.
3441
3415
  */
3442
3416
  declare function useLeaderboard(board: string, options?: {
3443
3417
  limit?: number;
3444
3418
  intervalMs?: number;
3445
- }): {
3446
- refresh: () => Promise<void>;
3447
- status: "loading";
3448
- } | {
3449
- refresh: () => Promise<void>;
3450
- status: "error";
3451
- message: string;
3452
- } | {
3453
- refresh: () => Promise<void>;
3454
- status: "ready";
3455
- page: LeaderboardPage;
3456
- stale: string | null;
3457
- };
3419
+ }): Query<LeaderboardPage>;
3458
3420
 
3459
- type BalancesState = {
3460
- status: "loading";
3461
- } | {
3462
- status: "signed-out";
3463
- } | {
3464
- status: "error";
3465
- message: string;
3466
- } | {
3467
- status: "ready";
3468
- items: PointBalance[];
3469
- stale: string | null;
3470
- };
3471
- type PointHistoryState = {
3472
- status: "loading";
3473
- } | {
3474
- status: "signed-out";
3475
- }
3476
- /** No ledger has this key or ID in the project (`point-ledger-not-found`). */
3477
- | {
3478
- status: "missing";
3479
- }
3480
- /** The member has not joined this project, so it has no points here (`not-joined`). */
3481
- | {
3482
- status: "not-joined";
3483
- } | {
3484
- status: "error";
3485
- message: string;
3486
- } | {
3487
- status: "ready";
3488
- items: PointEntry[];
3489
- /** Whether `loadMore()` has another page to read. */
3490
- more: boolean;
3491
- /** A next page is loading. */
3492
- loading: boolean;
3493
- /** Why the last next page failed; the items read so far stay. */
3494
- error: string | null;
3495
- };
3496
3421
  /**
3497
- * The signed-in participant's balance in each of the project's point ledgers: `balance` counts
3498
- * every entry, `available` leaves out points reservations hold. Read again when the participant
3499
- * signs in or out and after a quest completes. Find a ledger by the key your app declared:
3500
- * `items.find((b) => b.ledger.key === "points")`.
3422
+ * The signed-in participant's balance in each of the project's point ledgers, as `data.items`:
3423
+ * `balance` counts every entry, `available` leaves out points reservations hold. Read again
3424
+ * whenever one of the participant's quests completes. Find a ledger by the key your app declared:
3425
+ * `data.items.find((b) => b.ledger.key === "points")`.
3501
3426
  */
3502
- declare function useBalances(): {
3503
- refresh: () => Promise<void>;
3504
- status: "loading";
3505
- } | {
3506
- refresh: () => Promise<void>;
3507
- status: "signed-out";
3508
- } | {
3509
- refresh: () => Promise<void>;
3510
- status: "error";
3511
- message: string;
3512
- } | {
3513
- refresh: () => Promise<void>;
3514
- status: "ready";
3515
- items: PointBalance[];
3516
- stale: string | null;
3517
- };
3427
+ declare function useBalances(): MemberQuery<PointBalances>;
3518
3428
  /**
3519
- * The signed-in participant's own entries in one ledger, by key or ID, most recently recorded first, a page at a
3520
- * time. Starts over when the participant signs in or out and after a quest completes.
3429
+ * The signed-in participant's own entries in one ledger, by key or ID, most recently recorded
3430
+ * first, a page at a time: `data.items`, and `loadMore()` while `data.nextCursor` is set. Starts
3431
+ * over whenever one of the participant's quests completes. An unknown ledger is an `error` with
3432
+ * code `point-ledger-not-found`; a member who has not joined the project, `not-joined`.
3521
3433
  */
3522
- declare function usePointHistory(ledger: string): {
3523
- refresh: () => Promise<void>;
3524
- /** Appends the next page; does nothing while a page loads or when there is none. */
3525
- loadMore: () => Promise<void>;
3526
- status: "loading";
3527
- } | {
3528
- refresh: () => Promise<void>;
3529
- /** Appends the next page; does nothing while a page loads or when there is none. */
3530
- loadMore: () => Promise<void>;
3531
- status: "signed-out";
3532
- } | {
3533
- refresh: () => Promise<void>;
3534
- /** Appends the next page; does nothing while a page loads or when there is none. */
3535
- loadMore: () => Promise<void>;
3536
- status: "missing";
3537
- } | {
3538
- refresh: () => Promise<void>;
3539
- /** Appends the next page; does nothing while a page loads or when there is none. */
3540
- loadMore: () => Promise<void>;
3541
- status: "not-joined";
3542
- } | {
3543
- refresh: () => Promise<void>;
3544
- /** Appends the next page; does nothing while a page loads or when there is none. */
3545
- loadMore: () => Promise<void>;
3546
- status: "error";
3547
- message: string;
3548
- } | {
3549
- refresh: () => Promise<void>;
3550
- /** Appends the next page; does nothing while a page loads or when there is none. */
3551
- loadMore: () => Promise<void>;
3552
- status: "ready";
3553
- items: PointEntry[];
3554
- /** Whether `loadMore()` has another page to read. */
3555
- more: boolean;
3556
- /** A next page is loading. */
3557
- loading: boolean;
3558
- /** Why the last next page failed; the items read so far stay. */
3559
- error: string | null;
3560
- };
3434
+ declare function usePointHistory(ledger: string): MemberPagedQuery<PointEntry>;
3561
3435
 
3562
- type ReferencesState<T> = {
3563
- status: "loading";
3564
- } | {
3565
- status: "error";
3566
- message: string;
3567
- } | {
3568
- status: "ready";
3569
- items: T[];
3570
- };
3571
- type PointLedgersState = ReferencesState<PointLedgerReference>;
3572
- type TieredRewardsState = ReferencesState<TieredRewardReference>;
3573
3436
  /**
3574
- * The project's point ledgers with their keys and names.
3437
+ * The project's point ledgers with their keys and names, in `data`.
3575
3438
  *
3576
3439
  * Reads such as referral summaries and history name ledgers by ID. Find a
3577
3440
  * ledger by the key your app declared, then compare IDs:
3578
- * `items.find((l) => l.key === "credits")?.id`.
3441
+ * `data.find((l) => l.key === "credits")?.id`.
3579
3442
  */
3580
- declare function usePointLedgers(): {
3581
- refresh: () => Promise<void>;
3582
- status: "loading";
3583
- } | {
3584
- refresh: () => Promise<void>;
3585
- status: "error";
3586
- message: string;
3587
- } | {
3588
- refresh: () => Promise<void>;
3589
- status: "ready";
3590
- items: {
3591
- id: string;
3592
- key: string | null;
3593
- name: string;
3594
- }[];
3595
- };
3443
+ declare function usePointLedgers(): Query<PointLedgerReference[]>;
3596
3444
  /**
3597
- * The project's tiered rewards with their keys.
3445
+ * The project's tiered rewards with their keys, in `data`.
3598
3446
  *
3599
3447
  * Entitlements and reward definitions name tiered rewards by ID. Find a reward
3600
3448
  * by the key you gave defineTieredReward, then compare IDs:
3601
- * `items.find((r) => r.key === "tote")?.id`.
3449
+ * `data.find((r) => r.key === "tote")?.id`.
3602
3450
  */
3603
- declare function useTieredRewards(): {
3604
- refresh: () => Promise<void>;
3605
- status: "loading";
3606
- } | {
3607
- refresh: () => Promise<void>;
3608
- status: "error";
3609
- message: string;
3610
- } | {
3611
- refresh: () => Promise<void>;
3612
- status: "ready";
3613
- items: {
3614
- id: string;
3615
- key: string | null;
3616
- }[];
3617
- };
3451
+ declare function useTieredRewards(): Query<TieredRewardReference[]>;
3618
3452
 
3619
- export { type BalancesState, type Collection, CosmosChains, DiscoveredWallet, type Experience, type Invitation, type LeaderboardState, type OAuthProvider, PENDING_POLL_MS, PROFILE_CHANGED, type PointHistoryState, type PointLedgersState, type ProfileCompletionsState, type ProfileReadState, type ProfileState, type QuestInput, type QuestNotice, type QuestStatus, type QuestTone, RETRY_DELAYS_MS, type ReferencesState, type ReferralSummary, type RelayClient, RelayProvider, type RoleDelivery, type SavedSubmission, SignInMethods, SignInOption, SignInUnavailable, SignInWallet, type TieredRewardsState, canRepeat, canSubmit, captureReferralCode, completionCountLabel, completionMark, hasPending, isAutomatic, isConnected, isFinished, progressOf, questGroups, questStatus, roleDeliveryLabel, runsSilently, sanitizeDeliveries, useAccounts, useBalances, useExperience, useInvitation, useLeaderboard, useLeaderboardPlacement, useMe, useMyProfile, usePointHistory, usePointLedgers, useProfile, useProfileCompletions, useProfileReferral, useQuest, useReferralSummary, useRelay, useSignIn, useSignInMethods, useSignInOptions, useSignInWallets, useSignOut, useTieredRewards, useWalletDiscovery, useWallets, visibleQuests, watchRoleDeliveries };
3453
+ export { type Collection, CosmosChains, DiscoveredWallet, type ExperienceData, type Invitation, type KnownQuestStatusCode, type KnownRoleDeliveryStatus, type MemberPagedQuery, type MemberQuery, type MemberSnapshot, type OAuthProvider, Page, type PageLoader, type PageRead, type PagedQuery, type Query, type QueryContext, type QueryKey, type QueryOptions, type QueryRead, type QuerySnapshot, type QuestInput, type QuestNotice, type QuestStatus, type QuestStatusCode, type QuestStatusText, type QuestTone, type ReferralSummary, type RelayClient, RelayProvider, type RoleDelivery, type RoleDeliveryStatus, type SavedSubmission, SignInMethods, SignInOption, SignInUnavailable, SignInWallet, canRepeat, canSubmit, captureReferralCode, completionCountLabel, isAutomatic, isConnected, isFinished, progressOf, questGroups, questStatus, questStatusText, relayKeys, roleDeliveryLabel, roleDeliveryStatus, useAccounts, useBalances, useExperience, useInvalidate, useInvitation, useLeaderboard, useLeaderboardPlacement, useMe, useMemberPages, useMemberQuery, useMyProfile, usePointHistory, usePointLedgers, useProfile, useProfileCompletions, useProfileReferral, useQuest, useReferralSummary, useRelay, useRelayPages, useRelayQuery, useSession, useSignIn, useSignInMethods, useSignInOptions, useSignInWallets, useSignOut, useTieredRewards, useWalletDiscovery, useWallets };