@domino-sdk/relay 0.14.1 → 0.15.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.
@@ -0,0 +1,3847 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import * as zod from 'zod';
4
+ import { z } from 'zod';
5
+ import { QuestView, QuestController, ProgressObservation, questExperienceSchema, ProgressObserver, ExchangeInput, PhotoSubmission, QuizSubmission, ClaimSubmission, SubmissionDraft } from '../index.js';
6
+ import { r as referralAcceptSchema, L as LeaderboardQuery, w as walletChallengeInputSchema, i as walletProofSchema, j as AuthProvider, k as AccountConnection, l as referralSummarySchema, m as LeaderboardPage } from '../settings-e0nHA0JA.js';
7
+ import { SubmitInput, ReviewListOptions, MemberListOptions, ReleaseInput, beginHandoverSchema } from '../schema.js';
8
+ import { createBrowserRelayClient } from '../browser.js';
9
+
10
+ type RelayClient = ReturnType<typeof createBrowserRelayClient>;
11
+ /** The participant client, for calls no hook covers. */
12
+ declare function useRelay(): {
13
+ referrals: {
14
+ list: () => Promise<{
15
+ id: string;
16
+ title: string;
17
+ enabled: boolean;
18
+ qualification: {
19
+ kind: "signup";
20
+ } | {
21
+ kind: "quest";
22
+ quest: string;
23
+ } | {
24
+ kind: "external";
25
+ };
26
+ rewards: {
27
+ inviter: ({
28
+ kind: "tier";
29
+ reward: {
30
+ id: string;
31
+ title: string;
32
+ tiers: {
33
+ id: string;
34
+ title: string;
35
+ }[];
36
+ inventory: {
37
+ kind: "untracked";
38
+ };
39
+ fulfillment: {
40
+ kind: "staff-handover";
41
+ };
42
+ };
43
+ tier: string;
44
+ } | {
45
+ kind: "points";
46
+ balance: string;
47
+ amount: number;
48
+ })[];
49
+ invitee: ({
50
+ kind: "tier";
51
+ reward: {
52
+ id: string;
53
+ title: string;
54
+ tiers: {
55
+ id: string;
56
+ title: string;
57
+ }[];
58
+ inventory: {
59
+ kind: "untracked";
60
+ };
61
+ fulfillment: {
62
+ kind: "staff-handover";
63
+ };
64
+ };
65
+ tier: string;
66
+ } | {
67
+ kind: "points";
68
+ balance: string;
69
+ amount: number;
70
+ })[];
71
+ };
72
+ milestones: {
73
+ id: string;
74
+ count: number;
75
+ rewards: ({
76
+ kind: "tier";
77
+ reward: {
78
+ id: string;
79
+ title: string;
80
+ tiers: {
81
+ id: string;
82
+ title: string;
83
+ }[];
84
+ inventory: {
85
+ kind: "untracked";
86
+ };
87
+ fulfillment: {
88
+ kind: "staff-handover";
89
+ };
90
+ };
91
+ tier: string;
92
+ } | {
93
+ kind: "points";
94
+ balance: string;
95
+ amount: number;
96
+ })[];
97
+ }[];
98
+ bonuses: {
99
+ id: string;
100
+ balance: string;
101
+ basisPoints: number;
102
+ external: boolean;
103
+ quests?: string[] | undefined;
104
+ durationDays?: number | undefined;
105
+ maxPoints?: number | undefined;
106
+ }[];
107
+ key?: string | undefined;
108
+ inviterGroup?: string | undefined;
109
+ }[]>;
110
+ summary: () => Promise<{
111
+ code: string;
112
+ attributed: number;
113
+ programs: {
114
+ definition: {
115
+ id: string;
116
+ title: string;
117
+ enabled: boolean;
118
+ qualification: {
119
+ kind: "signup";
120
+ } | {
121
+ kind: "quest";
122
+ quest: string;
123
+ } | {
124
+ kind: "external";
125
+ };
126
+ rewards: {
127
+ inviter: ({
128
+ kind: "tier";
129
+ reward: {
130
+ id: string;
131
+ title: string;
132
+ tiers: {
133
+ id: string;
134
+ title: string;
135
+ }[];
136
+ inventory: {
137
+ kind: "untracked";
138
+ };
139
+ fulfillment: {
140
+ kind: "staff-handover";
141
+ };
142
+ };
143
+ tier: string;
144
+ } | {
145
+ kind: "points";
146
+ balance: string;
147
+ amount: number;
148
+ })[];
149
+ invitee: ({
150
+ kind: "tier";
151
+ reward: {
152
+ id: string;
153
+ title: string;
154
+ tiers: {
155
+ id: string;
156
+ title: string;
157
+ }[];
158
+ inventory: {
159
+ kind: "untracked";
160
+ };
161
+ fulfillment: {
162
+ kind: "staff-handover";
163
+ };
164
+ };
165
+ tier: string;
166
+ } | {
167
+ kind: "points";
168
+ balance: string;
169
+ amount: number;
170
+ })[];
171
+ };
172
+ milestones: {
173
+ id: string;
174
+ count: number;
175
+ rewards: ({
176
+ kind: "tier";
177
+ reward: {
178
+ id: string;
179
+ title: string;
180
+ tiers: {
181
+ id: string;
182
+ title: string;
183
+ }[];
184
+ inventory: {
185
+ kind: "untracked";
186
+ };
187
+ fulfillment: {
188
+ kind: "staff-handover";
189
+ };
190
+ };
191
+ tier: string;
192
+ } | {
193
+ kind: "points";
194
+ balance: string;
195
+ amount: number;
196
+ })[];
197
+ }[];
198
+ bonuses: {
199
+ id: string;
200
+ balance: string;
201
+ basisPoints: number;
202
+ external: boolean;
203
+ quests?: string[] | undefined;
204
+ durationDays?: number | undefined;
205
+ maxPoints?: number | undefined;
206
+ }[];
207
+ key?: string | undefined;
208
+ inviterGroup?: string | undefined;
209
+ };
210
+ qualified: number;
211
+ milestones: {
212
+ id: string;
213
+ count: number;
214
+ reached: boolean;
215
+ }[];
216
+ }[];
217
+ accounts: {
218
+ id: string;
219
+ program: string;
220
+ kind: "milestone" | "fixed" | "bonus";
221
+ balance: string;
222
+ earned: number;
223
+ settled: number;
224
+ outstanding: number;
225
+ }[];
226
+ }>;
227
+ history: (before?: number) => Promise<{
228
+ items: {
229
+ id: number;
230
+ program: string;
231
+ balance: string;
232
+ amount: number;
233
+ at: number;
234
+ reason: string;
235
+ }[];
236
+ next: number | null;
237
+ }>;
238
+ accept: (input: zod.input<typeof referralAcceptSchema>) => Promise<{
239
+ ok: true;
240
+ }>;
241
+ };
242
+ leaderboards: {
243
+ list: () => Promise<{
244
+ id: string;
245
+ title: string;
246
+ balance: string;
247
+ score: {
248
+ kind: "balance";
249
+ } | {
250
+ window: {
251
+ kind: "fixed";
252
+ start: number;
253
+ end: number;
254
+ } | {
255
+ kind: "all-time";
256
+ } | {
257
+ kind: "rolling";
258
+ days: number;
259
+ } | {
260
+ kind: "calendar";
261
+ period: "day" | "week" | "month";
262
+ timeZone: string;
263
+ };
264
+ kind: "earned";
265
+ quests?: string[] | undefined;
266
+ } | {
267
+ kind: "net";
268
+ window: {
269
+ kind: "fixed";
270
+ start: number;
271
+ end: number;
272
+ } | {
273
+ kind: "all-time";
274
+ } | {
275
+ kind: "rolling";
276
+ days: number;
277
+ } | {
278
+ kind: "calendar";
279
+ period: "day" | "week" | "month";
280
+ timeZone: string;
281
+ };
282
+ };
283
+ access: "participants" | "public";
284
+ key?: string | undefined;
285
+ group?: string | undefined;
286
+ }[]>;
287
+ standings: (board: string, options?: LeaderboardQuery) => Promise<{
288
+ leaderboard: string;
289
+ title: string;
290
+ version: string;
291
+ calculation: "balance" | "earned" | "net";
292
+ period: {
293
+ start: number | null;
294
+ end: number | null;
295
+ };
296
+ calculatedAt: number;
297
+ lastEntryAt: number | null;
298
+ total: number;
299
+ items: {
300
+ participant: string;
301
+ name: string;
302
+ score: number;
303
+ rank: number;
304
+ member?: string | undefined;
305
+ }[];
306
+ me: {
307
+ participant: string;
308
+ name: string;
309
+ score: number;
310
+ rank: number;
311
+ member?: string | undefined;
312
+ } | null;
313
+ nearby: {
314
+ participant: string;
315
+ name: string;
316
+ score: number;
317
+ rank: number;
318
+ member?: string | undefined;
319
+ }[];
320
+ nextCursor: string | null;
321
+ }>;
322
+ };
323
+ quests: {
324
+ get: (id: string) => Promise<{
325
+ quest: string;
326
+ title: string;
327
+ presentation: {
328
+ quiz?: {
329
+ id: string;
330
+ prompt: string;
331
+ choices: {
332
+ id: string;
333
+ label: string;
334
+ }[];
335
+ }[] | undefined;
336
+ instructions?: string | undefined;
337
+ video?: {
338
+ url: string;
339
+ poster?: string | undefined;
340
+ captions?: {
341
+ url: string;
342
+ language: string;
343
+ label: string;
344
+ } | undefined;
345
+ } | undefined;
346
+ };
347
+ connections: ("discord" | "google" | "apple" | "x")[];
348
+ trigger: {
349
+ kind: "manual";
350
+ input: "quiz" | "photo" | "none";
351
+ actor?: "member" | "staff" | undefined;
352
+ } | {
353
+ kind: "automatic";
354
+ observation?: {
355
+ source: string;
356
+ type: string;
357
+ } | undefined;
358
+ };
359
+ availability: {
360
+ kind: "available";
361
+ input: "quiz" | "photo" | "none";
362
+ } | {
363
+ kind: "completed";
364
+ } | {
365
+ kind: "locked";
366
+ missing: {
367
+ quest: string;
368
+ title: string;
369
+ }[];
370
+ } | {
371
+ kind: "staff-required";
372
+ } | {
373
+ kind: "automatic";
374
+ observation?: {
375
+ source: string;
376
+ type: string;
377
+ } | undefined;
378
+ } | {
379
+ kind: "checking";
380
+ attempt: string;
381
+ } | {
382
+ kind: "needs-review";
383
+ attempt: string;
384
+ } | {
385
+ kind: "retryable";
386
+ attempt: string;
387
+ };
388
+ completed: boolean;
389
+ completion: {
390
+ kind: "streak";
391
+ days: number;
392
+ timeZone: string;
393
+ } | {
394
+ kind: "once";
395
+ } | {
396
+ kind: "keyed";
397
+ };
398
+ completionCount: number;
399
+ visibility: "visible" | "hidden";
400
+ missing: {
401
+ quest: string;
402
+ title: string;
403
+ }[];
404
+ attempt: {
405
+ id: string;
406
+ release: string;
407
+ quest: string;
408
+ member: string;
409
+ evidence: string | null;
410
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
411
+ reason: string | null;
412
+ retries: number;
413
+ generation: number;
414
+ completion: string | null;
415
+ reviewRewards: ({
416
+ kind: "tier";
417
+ reward: {
418
+ id: string;
419
+ title: string;
420
+ tiers: {
421
+ id: string;
422
+ title: string;
423
+ }[];
424
+ inventory: {
425
+ kind: "untracked";
426
+ };
427
+ fulfillment: {
428
+ kind: "staff-handover";
429
+ };
430
+ };
431
+ tier: string;
432
+ } | {
433
+ kind: "points";
434
+ balance: string;
435
+ amount: number;
436
+ } | {
437
+ kind: "integration";
438
+ provider: "discord";
439
+ action: "grant-role";
440
+ roleId: string;
441
+ })[] | null;
442
+ createdAt: number;
443
+ input?: {
444
+ kind: "quiz";
445
+ answers: {
446
+ [k: string]: string;
447
+ };
448
+ release?: string | undefined;
449
+ } | undefined;
450
+ } | null;
451
+ release: string;
452
+ interaction: "quiz" | "photo" | "staff" | "automatic" | "claim";
453
+ lifecycle: "paused" | "active" | "archived";
454
+ rewards: {
455
+ label: string;
456
+ }[];
457
+ key?: string | undefined;
458
+ streak?: {
459
+ goal: number;
460
+ current: number;
461
+ best: number;
462
+ today: string;
463
+ todayQualified: boolean;
464
+ timeZone: string;
465
+ nextBoundary: number;
466
+ pendingTimeZone: {
467
+ timeZone: string;
468
+ effectiveAt: number;
469
+ } | null;
470
+ days: {
471
+ day: number;
472
+ date: string;
473
+ timeZone: string;
474
+ occurredAt: number;
475
+ }[];
476
+ milestone: {
477
+ status: "pending";
478
+ } | {
479
+ status: "awarded";
480
+ completion: string;
481
+ achievedAt: number;
482
+ } | {
483
+ status: "budget-exhausted";
484
+ budget: string;
485
+ achievedAt: number;
486
+ };
487
+ } | null | undefined;
488
+ }>;
489
+ retry: (view: QuestView) => Promise<{
490
+ id: string;
491
+ release: string;
492
+ quest: string;
493
+ member: string;
494
+ evidence: string | null;
495
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
496
+ reason: string | null;
497
+ retries: number;
498
+ generation: number;
499
+ completion: string | null;
500
+ reviewRewards: ({
501
+ kind: "tier";
502
+ reward: {
503
+ id: string;
504
+ title: string;
505
+ tiers: {
506
+ id: string;
507
+ title: string;
508
+ }[];
509
+ inventory: {
510
+ kind: "untracked";
511
+ };
512
+ fulfillment: {
513
+ kind: "staff-handover";
514
+ };
515
+ };
516
+ tier: string;
517
+ } | {
518
+ kind: "points";
519
+ balance: string;
520
+ amount: number;
521
+ } | {
522
+ kind: "integration";
523
+ provider: "discord";
524
+ action: "grant-role";
525
+ roleId: string;
526
+ })[] | null;
527
+ createdAt: number;
528
+ input?: {
529
+ kind: "quiz";
530
+ answers: {
531
+ [k: string]: string;
532
+ };
533
+ release?: string | undefined;
534
+ } | undefined;
535
+ }>;
536
+ experience: () => Promise<{
537
+ member: string;
538
+ quests: {
539
+ quest: string;
540
+ title: string;
541
+ presentation: {
542
+ quiz?: {
543
+ id: string;
544
+ prompt: string;
545
+ choices: {
546
+ id: string;
547
+ label: string;
548
+ }[];
549
+ }[] | undefined;
550
+ instructions?: string | undefined;
551
+ video?: {
552
+ url: string;
553
+ poster?: string | undefined;
554
+ captions?: {
555
+ url: string;
556
+ language: string;
557
+ label: string;
558
+ } | undefined;
559
+ } | undefined;
560
+ };
561
+ connections: ("discord" | "google" | "apple" | "x")[];
562
+ trigger: {
563
+ kind: "manual";
564
+ input: "quiz" | "photo" | "none";
565
+ actor?: "member" | "staff" | undefined;
566
+ } | {
567
+ kind: "automatic";
568
+ observation?: {
569
+ source: string;
570
+ type: string;
571
+ } | undefined;
572
+ };
573
+ availability: {
574
+ kind: "available";
575
+ input: "quiz" | "photo" | "none";
576
+ } | {
577
+ kind: "completed";
578
+ } | {
579
+ kind: "locked";
580
+ missing: {
581
+ quest: string;
582
+ title: string;
583
+ }[];
584
+ } | {
585
+ kind: "staff-required";
586
+ } | {
587
+ kind: "automatic";
588
+ observation?: {
589
+ source: string;
590
+ type: string;
591
+ } | undefined;
592
+ } | {
593
+ kind: "checking";
594
+ attempt: string;
595
+ } | {
596
+ kind: "needs-review";
597
+ attempt: string;
598
+ } | {
599
+ kind: "retryable";
600
+ attempt: string;
601
+ };
602
+ completed: boolean;
603
+ completion: {
604
+ kind: "streak";
605
+ days: number;
606
+ timeZone: string;
607
+ } | {
608
+ kind: "once";
609
+ } | {
610
+ kind: "keyed";
611
+ };
612
+ completionCount: number;
613
+ visibility: "visible" | "hidden";
614
+ missing: {
615
+ quest: string;
616
+ title: string;
617
+ }[];
618
+ attempt: {
619
+ id: string;
620
+ release: string;
621
+ quest: string;
622
+ member: string;
623
+ evidence: string | null;
624
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
625
+ reason: string | null;
626
+ retries: number;
627
+ generation: number;
628
+ completion: string | null;
629
+ reviewRewards: ({
630
+ kind: "tier";
631
+ reward: {
632
+ id: string;
633
+ title: string;
634
+ tiers: {
635
+ id: string;
636
+ title: string;
637
+ }[];
638
+ inventory: {
639
+ kind: "untracked";
640
+ };
641
+ fulfillment: {
642
+ kind: "staff-handover";
643
+ };
644
+ };
645
+ tier: string;
646
+ } | {
647
+ kind: "points";
648
+ balance: string;
649
+ amount: number;
650
+ } | {
651
+ kind: "integration";
652
+ provider: "discord";
653
+ action: "grant-role";
654
+ roleId: string;
655
+ })[] | null;
656
+ createdAt: number;
657
+ input?: {
658
+ kind: "quiz";
659
+ answers: {
660
+ [k: string]: string;
661
+ };
662
+ release?: string | undefined;
663
+ } | undefined;
664
+ } | null;
665
+ release: string;
666
+ interaction: "quiz" | "photo" | "staff" | "automatic" | "claim";
667
+ lifecycle: "paused" | "active" | "archived";
668
+ rewards: {
669
+ label: string;
670
+ }[];
671
+ key?: string | undefined;
672
+ streak?: {
673
+ goal: number;
674
+ current: number;
675
+ best: number;
676
+ today: string;
677
+ todayQualified: boolean;
678
+ timeZone: string;
679
+ nextBoundary: number;
680
+ pendingTimeZone: {
681
+ timeZone: string;
682
+ effectiveAt: number;
683
+ } | null;
684
+ days: {
685
+ day: number;
686
+ date: string;
687
+ timeZone: string;
688
+ occurredAt: number;
689
+ }[];
690
+ milestone: {
691
+ status: "pending";
692
+ } | {
693
+ status: "awarded";
694
+ completion: string;
695
+ achievedAt: number;
696
+ } | {
697
+ status: "budget-exhausted";
698
+ budget: string;
699
+ achievedAt: number;
700
+ };
701
+ } | null | undefined;
702
+ }[];
703
+ collections: {
704
+ id: string;
705
+ title: string;
706
+ quests: {
707
+ quest: string;
708
+ title: string;
709
+ presentation: {
710
+ quiz?: {
711
+ id: string;
712
+ prompt: string;
713
+ choices: {
714
+ id: string;
715
+ label: string;
716
+ }[];
717
+ }[] | undefined;
718
+ instructions?: string | undefined;
719
+ video?: {
720
+ url: string;
721
+ poster?: string | undefined;
722
+ captions?: {
723
+ url: string;
724
+ language: string;
725
+ label: string;
726
+ } | undefined;
727
+ } | undefined;
728
+ };
729
+ connections: ("discord" | "google" | "apple" | "x")[];
730
+ trigger: {
731
+ kind: "manual";
732
+ input: "quiz" | "photo" | "none";
733
+ actor?: "member" | "staff" | undefined;
734
+ } | {
735
+ kind: "automatic";
736
+ observation?: {
737
+ source: string;
738
+ type: string;
739
+ } | undefined;
740
+ };
741
+ availability: {
742
+ kind: "available";
743
+ input: "quiz" | "photo" | "none";
744
+ } | {
745
+ kind: "completed";
746
+ } | {
747
+ kind: "locked";
748
+ missing: {
749
+ quest: string;
750
+ title: string;
751
+ }[];
752
+ } | {
753
+ kind: "staff-required";
754
+ } | {
755
+ kind: "automatic";
756
+ observation?: {
757
+ source: string;
758
+ type: string;
759
+ } | undefined;
760
+ } | {
761
+ kind: "checking";
762
+ attempt: string;
763
+ } | {
764
+ kind: "needs-review";
765
+ attempt: string;
766
+ } | {
767
+ kind: "retryable";
768
+ attempt: string;
769
+ };
770
+ completed: boolean;
771
+ completion: {
772
+ kind: "streak";
773
+ days: number;
774
+ timeZone: string;
775
+ } | {
776
+ kind: "once";
777
+ } | {
778
+ kind: "keyed";
779
+ };
780
+ completionCount: number;
781
+ visibility: "visible" | "hidden";
782
+ missing: {
783
+ quest: string;
784
+ title: string;
785
+ }[];
786
+ attempt: {
787
+ id: string;
788
+ release: string;
789
+ quest: string;
790
+ member: string;
791
+ evidence: string | null;
792
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
793
+ reason: string | null;
794
+ retries: number;
795
+ generation: number;
796
+ completion: string | null;
797
+ reviewRewards: ({
798
+ kind: "tier";
799
+ reward: {
800
+ id: string;
801
+ title: string;
802
+ tiers: {
803
+ id: string;
804
+ title: string;
805
+ }[];
806
+ inventory: {
807
+ kind: "untracked";
808
+ };
809
+ fulfillment: {
810
+ kind: "staff-handover";
811
+ };
812
+ };
813
+ tier: string;
814
+ } | {
815
+ kind: "points";
816
+ balance: string;
817
+ amount: number;
818
+ } | {
819
+ kind: "integration";
820
+ provider: "discord";
821
+ action: "grant-role";
822
+ roleId: string;
823
+ })[] | null;
824
+ createdAt: number;
825
+ input?: {
826
+ kind: "quiz";
827
+ answers: {
828
+ [k: string]: string;
829
+ };
830
+ release?: string | undefined;
831
+ } | undefined;
832
+ } | null;
833
+ release: string;
834
+ interaction: "quiz" | "photo" | "staff" | "automatic" | "claim";
835
+ lifecycle: "paused" | "active" | "archived";
836
+ rewards: {
837
+ label: string;
838
+ }[];
839
+ key?: string | undefined;
840
+ streak?: {
841
+ goal: number;
842
+ current: number;
843
+ best: number;
844
+ today: string;
845
+ todayQualified: boolean;
846
+ timeZone: string;
847
+ nextBoundary: number;
848
+ pendingTimeZone: {
849
+ timeZone: string;
850
+ effectiveAt: number;
851
+ } | null;
852
+ days: {
853
+ day: number;
854
+ date: string;
855
+ timeZone: string;
856
+ occurredAt: number;
857
+ }[];
858
+ milestone: {
859
+ status: "pending";
860
+ } | {
861
+ status: "awarded";
862
+ completion: string;
863
+ achievedAt: number;
864
+ } | {
865
+ status: "budget-exhausted";
866
+ budget: string;
867
+ achievedAt: number;
868
+ };
869
+ } | null | undefined;
870
+ }[];
871
+ key?: string | undefined;
872
+ }[];
873
+ }>;
874
+ collection: (id: string) => Promise<{
875
+ id: string;
876
+ title: string;
877
+ quests: {
878
+ quest: string;
879
+ title: string;
880
+ presentation: {
881
+ quiz?: {
882
+ id: string;
883
+ prompt: string;
884
+ choices: {
885
+ id: string;
886
+ label: string;
887
+ }[];
888
+ }[] | undefined;
889
+ instructions?: string | undefined;
890
+ video?: {
891
+ url: string;
892
+ poster?: string | undefined;
893
+ captions?: {
894
+ url: string;
895
+ language: string;
896
+ label: string;
897
+ } | undefined;
898
+ } | undefined;
899
+ };
900
+ connections: ("discord" | "google" | "apple" | "x")[];
901
+ trigger: {
902
+ kind: "manual";
903
+ input: "quiz" | "photo" | "none";
904
+ actor?: "member" | "staff" | undefined;
905
+ } | {
906
+ kind: "automatic";
907
+ observation?: {
908
+ source: string;
909
+ type: string;
910
+ } | undefined;
911
+ };
912
+ availability: {
913
+ kind: "available";
914
+ input: "quiz" | "photo" | "none";
915
+ } | {
916
+ kind: "completed";
917
+ } | {
918
+ kind: "locked";
919
+ missing: {
920
+ quest: string;
921
+ title: string;
922
+ }[];
923
+ } | {
924
+ kind: "staff-required";
925
+ } | {
926
+ kind: "automatic";
927
+ observation?: {
928
+ source: string;
929
+ type: string;
930
+ } | undefined;
931
+ } | {
932
+ kind: "checking";
933
+ attempt: string;
934
+ } | {
935
+ kind: "needs-review";
936
+ attempt: string;
937
+ } | {
938
+ kind: "retryable";
939
+ attempt: string;
940
+ };
941
+ completed: boolean;
942
+ completion: {
943
+ kind: "streak";
944
+ days: number;
945
+ timeZone: string;
946
+ } | {
947
+ kind: "once";
948
+ } | {
949
+ kind: "keyed";
950
+ };
951
+ completionCount: number;
952
+ visibility: "visible" | "hidden";
953
+ missing: {
954
+ quest: string;
955
+ title: string;
956
+ }[];
957
+ attempt: {
958
+ id: string;
959
+ release: string;
960
+ quest: string;
961
+ member: string;
962
+ evidence: string | null;
963
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
964
+ reason: string | null;
965
+ retries: number;
966
+ generation: number;
967
+ completion: string | null;
968
+ reviewRewards: ({
969
+ kind: "tier";
970
+ reward: {
971
+ id: string;
972
+ title: string;
973
+ tiers: {
974
+ id: string;
975
+ title: string;
976
+ }[];
977
+ inventory: {
978
+ kind: "untracked";
979
+ };
980
+ fulfillment: {
981
+ kind: "staff-handover";
982
+ };
983
+ };
984
+ tier: string;
985
+ } | {
986
+ kind: "points";
987
+ balance: string;
988
+ amount: number;
989
+ } | {
990
+ kind: "integration";
991
+ provider: "discord";
992
+ action: "grant-role";
993
+ roleId: string;
994
+ })[] | null;
995
+ createdAt: number;
996
+ input?: {
997
+ kind: "quiz";
998
+ answers: {
999
+ [k: string]: string;
1000
+ };
1001
+ release?: string | undefined;
1002
+ } | undefined;
1003
+ } | null;
1004
+ release: string;
1005
+ interaction: "quiz" | "photo" | "staff" | "automatic" | "claim";
1006
+ lifecycle: "paused" | "active" | "archived";
1007
+ rewards: {
1008
+ label: string;
1009
+ }[];
1010
+ key?: string | undefined;
1011
+ streak?: {
1012
+ goal: number;
1013
+ current: number;
1014
+ best: number;
1015
+ today: string;
1016
+ todayQualified: boolean;
1017
+ timeZone: string;
1018
+ nextBoundary: number;
1019
+ pendingTimeZone: {
1020
+ timeZone: string;
1021
+ effectiveAt: number;
1022
+ } | null;
1023
+ days: {
1024
+ day: number;
1025
+ date: string;
1026
+ timeZone: string;
1027
+ occurredAt: number;
1028
+ }[];
1029
+ milestone: {
1030
+ status: "pending";
1031
+ } | {
1032
+ status: "awarded";
1033
+ completion: string;
1034
+ achievedAt: number;
1035
+ } | {
1036
+ status: "budget-exhausted";
1037
+ budget: string;
1038
+ achievedAt: number;
1039
+ };
1040
+ } | null | undefined;
1041
+ }[];
1042
+ key?: string | undefined;
1043
+ }>;
1044
+ open: (view: QuestView) => Promise<QuestController>;
1045
+ observe: (listener: (value: ProgressObservation<zod.infer<typeof questExperienceSchema>>) => void, options?: {
1046
+ intervalMs?: number;
1047
+ maxBackoffMs?: number;
1048
+ }) => ProgressObserver;
1049
+ };
1050
+ wallet: {
1051
+ connection: () => Promise<{
1052
+ chain: "solana";
1053
+ address: string;
1054
+ verifiedAt: number;
1055
+ revision: number;
1056
+ } | null>;
1057
+ challenge: (input: zod.input<typeof walletChallengeInputSchema>, session: string) => Promise<{
1058
+ chain: "solana";
1059
+ address: string;
1060
+ id: string;
1061
+ message: string;
1062
+ expiresAt: number;
1063
+ }>;
1064
+ verify: (input: zod.input<typeof walletProofSchema>, session: string) => Promise<{
1065
+ chain: "solana";
1066
+ address: string;
1067
+ verifiedAt: number;
1068
+ revision: number;
1069
+ }>;
1070
+ };
1071
+ auth: {
1072
+ providers: () => Promise<{
1073
+ providers: {
1074
+ provider: "discord" | "google" | "apple" | "x";
1075
+ configured: boolean;
1076
+ }[];
1077
+ email: boolean;
1078
+ demo: boolean;
1079
+ }>;
1080
+ start: (provider: AuthProvider, mode: "sign-in" | "connect") => Promise<{
1081
+ url: string;
1082
+ }>;
1083
+ emailStart: (email: string) => Promise<{
1084
+ challenge: string;
1085
+ }>;
1086
+ emailVerify: (challenge: string, code: string) => Promise<{
1087
+ organization: string;
1088
+ project: string;
1089
+ environment: "test" | "live";
1090
+ id: string;
1091
+ principal: {
1092
+ kind: "member";
1093
+ member: string;
1094
+ } | {
1095
+ kind: "staff";
1096
+ subject: string;
1097
+ } | {
1098
+ kind: "operator";
1099
+ subject: string;
1100
+ };
1101
+ expiresAt: number;
1102
+ }>;
1103
+ accounts: () => Promise<{
1104
+ provider: "discord" | "google" | "apple" | "x";
1105
+ configured: boolean;
1106
+ status: "disconnected" | "connected" | "reconnect";
1107
+ subject: string | null;
1108
+ revision: number;
1109
+ }[]>;
1110
+ disconnect: (provider: AuthProvider) => Promise<{
1111
+ ok: boolean;
1112
+ }>;
1113
+ connections: () => Promise<{
1114
+ provider: string;
1115
+ subject: string;
1116
+ signInEnabled: boolean;
1117
+ }[]>;
1118
+ session: () => Promise<{
1119
+ organization: string;
1120
+ project: string;
1121
+ environment: "test" | "live";
1122
+ id: string;
1123
+ principal: {
1124
+ kind: "member";
1125
+ member: string;
1126
+ } | {
1127
+ kind: "staff";
1128
+ subject: string;
1129
+ } | {
1130
+ kind: "operator";
1131
+ subject: string;
1132
+ };
1133
+ expiresAt: number;
1134
+ } | null>;
1135
+ signOut: () => Promise<{
1136
+ ok: boolean;
1137
+ }>;
1138
+ exchange: (input: ExchangeInput) => Promise<{
1139
+ token: string;
1140
+ session: {
1141
+ organization: string;
1142
+ project: string;
1143
+ environment: "test" | "live";
1144
+ id: string;
1145
+ principal: {
1146
+ kind: "member";
1147
+ member: string;
1148
+ } | {
1149
+ kind: "staff";
1150
+ subject: string;
1151
+ } | {
1152
+ kind: "operator";
1153
+ subject: string;
1154
+ };
1155
+ expiresAt: number;
1156
+ };
1157
+ }>;
1158
+ };
1159
+ me: {
1160
+ observeProgress: (listener: (value: ProgressObservation) => void, options?: {
1161
+ intervalMs?: number;
1162
+ maxBackoffMs?: number;
1163
+ }) => ProgressObserver;
1164
+ submission: {
1165
+ (quest: string, options?: {
1166
+ input: "photo";
1167
+ release?: string;
1168
+ recoverPrevious?: boolean;
1169
+ repeatable?: boolean;
1170
+ }): Promise<PhotoSubmission>;
1171
+ (quest: string, options: {
1172
+ input: "quiz";
1173
+ release?: string;
1174
+ recoverPrevious?: boolean;
1175
+ repeatable?: boolean;
1176
+ }): Promise<QuizSubmission>;
1177
+ (quest: string, options: {
1178
+ input: "none";
1179
+ release?: string;
1180
+ recoverPrevious?: boolean;
1181
+ repeatable?: boolean;
1182
+ }): Promise<ClaimSubmission>;
1183
+ };
1184
+ collectionPass: (entitlement: string, session: string) => Promise<{
1185
+ code: string;
1186
+ expiresAt: number;
1187
+ entitlement: string;
1188
+ }>;
1189
+ linkPass: (code: string) => Promise<{
1190
+ id: string;
1191
+ release: string;
1192
+ quest: string;
1193
+ member: string;
1194
+ evidence: string | null;
1195
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
1196
+ reason: string | null;
1197
+ retries: number;
1198
+ generation: number;
1199
+ completion: string | null;
1200
+ reviewRewards: ({
1201
+ kind: "tier";
1202
+ reward: {
1203
+ id: string;
1204
+ title: string;
1205
+ tiers: {
1206
+ id: string;
1207
+ title: string;
1208
+ }[];
1209
+ inventory: {
1210
+ kind: "untracked";
1211
+ };
1212
+ fulfillment: {
1213
+ kind: "staff-handover";
1214
+ };
1215
+ };
1216
+ tier: string;
1217
+ } | {
1218
+ kind: "points";
1219
+ balance: string;
1220
+ amount: number;
1221
+ } | {
1222
+ kind: "integration";
1223
+ provider: "discord";
1224
+ action: "grant-role";
1225
+ roleId: string;
1226
+ })[] | null;
1227
+ createdAt: number;
1228
+ input?: {
1229
+ kind: "quiz";
1230
+ answers: {
1231
+ [k: string]: string;
1232
+ };
1233
+ release?: string | undefined;
1234
+ } | undefined;
1235
+ }>;
1236
+ progress: () => Promise<{
1237
+ member: string;
1238
+ quests: {
1239
+ quest: string;
1240
+ title: string;
1241
+ presentation: {
1242
+ quiz?: {
1243
+ id: string;
1244
+ prompt: string;
1245
+ choices: {
1246
+ id: string;
1247
+ label: string;
1248
+ }[];
1249
+ }[] | undefined;
1250
+ instructions?: string | undefined;
1251
+ video?: {
1252
+ url: string;
1253
+ poster?: string | undefined;
1254
+ captions?: {
1255
+ url: string;
1256
+ language: string;
1257
+ label: string;
1258
+ } | undefined;
1259
+ } | undefined;
1260
+ };
1261
+ connections: ("discord" | "google" | "apple" | "x")[];
1262
+ trigger: {
1263
+ kind: "manual";
1264
+ input: "quiz" | "photo" | "none";
1265
+ actor?: "member" | "staff" | undefined;
1266
+ } | {
1267
+ kind: "automatic";
1268
+ observation?: {
1269
+ source: string;
1270
+ type: string;
1271
+ } | undefined;
1272
+ };
1273
+ availability: {
1274
+ kind: "available";
1275
+ input: "quiz" | "photo" | "none";
1276
+ } | {
1277
+ kind: "completed";
1278
+ } | {
1279
+ kind: "locked";
1280
+ missing: {
1281
+ quest: string;
1282
+ title: string;
1283
+ }[];
1284
+ } | {
1285
+ kind: "staff-required";
1286
+ } | {
1287
+ kind: "automatic";
1288
+ observation?: {
1289
+ source: string;
1290
+ type: string;
1291
+ } | undefined;
1292
+ } | {
1293
+ kind: "checking";
1294
+ attempt: string;
1295
+ } | {
1296
+ kind: "needs-review";
1297
+ attempt: string;
1298
+ } | {
1299
+ kind: "retryable";
1300
+ attempt: string;
1301
+ };
1302
+ completed: boolean;
1303
+ completion: {
1304
+ kind: "streak";
1305
+ days: number;
1306
+ timeZone: string;
1307
+ } | {
1308
+ kind: "once";
1309
+ } | {
1310
+ kind: "keyed";
1311
+ };
1312
+ completionCount: number;
1313
+ visibility: "visible" | "hidden";
1314
+ missing: {
1315
+ quest: string;
1316
+ title: string;
1317
+ }[];
1318
+ attempt: {
1319
+ id: string;
1320
+ release: string;
1321
+ quest: string;
1322
+ member: string;
1323
+ evidence: string | null;
1324
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
1325
+ reason: string | null;
1326
+ retries: number;
1327
+ generation: number;
1328
+ completion: string | null;
1329
+ reviewRewards: ({
1330
+ kind: "tier";
1331
+ reward: {
1332
+ id: string;
1333
+ title: string;
1334
+ tiers: {
1335
+ id: string;
1336
+ title: string;
1337
+ }[];
1338
+ inventory: {
1339
+ kind: "untracked";
1340
+ };
1341
+ fulfillment: {
1342
+ kind: "staff-handover";
1343
+ };
1344
+ };
1345
+ tier: string;
1346
+ } | {
1347
+ kind: "points";
1348
+ balance: string;
1349
+ amount: number;
1350
+ } | {
1351
+ kind: "integration";
1352
+ provider: "discord";
1353
+ action: "grant-role";
1354
+ roleId: string;
1355
+ })[] | null;
1356
+ createdAt: number;
1357
+ input?: {
1358
+ kind: "quiz";
1359
+ answers: {
1360
+ [k: string]: string;
1361
+ };
1362
+ release?: string | undefined;
1363
+ } | undefined;
1364
+ } | null;
1365
+ key?: string | undefined;
1366
+ release?: string | undefined;
1367
+ streak?: {
1368
+ goal: number;
1369
+ current: number;
1370
+ best: number;
1371
+ today: string;
1372
+ todayQualified: boolean;
1373
+ timeZone: string;
1374
+ nextBoundary: number;
1375
+ pendingTimeZone: {
1376
+ timeZone: string;
1377
+ effectiveAt: number;
1378
+ } | null;
1379
+ days: {
1380
+ day: number;
1381
+ date: string;
1382
+ timeZone: string;
1383
+ occurredAt: number;
1384
+ }[];
1385
+ milestone: {
1386
+ status: "pending";
1387
+ } | {
1388
+ status: "awarded";
1389
+ completion: string;
1390
+ achievedAt: number;
1391
+ } | {
1392
+ status: "budget-exhausted";
1393
+ budget: string;
1394
+ achievedAt: number;
1395
+ };
1396
+ } | null | undefined;
1397
+ }[];
1398
+ entitlements: ({
1399
+ status: "available";
1400
+ id: string;
1401
+ member: string;
1402
+ reward: {
1403
+ id: string;
1404
+ title: string;
1405
+ tiers: {
1406
+ id: string;
1407
+ title: string;
1408
+ }[];
1409
+ inventory: {
1410
+ kind: "untracked";
1411
+ };
1412
+ fulfillment: {
1413
+ kind: "staff-handover";
1414
+ };
1415
+ };
1416
+ earnedTier: string;
1417
+ tier: string;
1418
+ revision: number;
1419
+ } | {
1420
+ status: "handing-over";
1421
+ handover: string;
1422
+ startedAt: number;
1423
+ id: string;
1424
+ member: string;
1425
+ reward: {
1426
+ id: string;
1427
+ title: string;
1428
+ tiers: {
1429
+ id: string;
1430
+ title: string;
1431
+ }[];
1432
+ inventory: {
1433
+ kind: "untracked";
1434
+ };
1435
+ fulfillment: {
1436
+ kind: "staff-handover";
1437
+ };
1438
+ };
1439
+ earnedTier: string;
1440
+ tier: string;
1441
+ revision: number;
1442
+ allocation?: {
1443
+ item: string;
1444
+ label: string;
1445
+ } | undefined;
1446
+ } | {
1447
+ status: "collected";
1448
+ handover: string;
1449
+ startedAt: number;
1450
+ collectedAt: number;
1451
+ id: string;
1452
+ member: string;
1453
+ reward: {
1454
+ id: string;
1455
+ title: string;
1456
+ tiers: {
1457
+ id: string;
1458
+ title: string;
1459
+ }[];
1460
+ inventory: {
1461
+ kind: "untracked";
1462
+ };
1463
+ fulfillment: {
1464
+ kind: "staff-handover";
1465
+ };
1466
+ };
1467
+ earnedTier: string;
1468
+ tier: string;
1469
+ revision: number;
1470
+ allocation?: {
1471
+ item: string;
1472
+ label: string;
1473
+ } | undefined;
1474
+ })[];
1475
+ }>;
1476
+ rewardDeliveries: () => Promise<{
1477
+ deliveries: {
1478
+ id: string;
1479
+ quest: string;
1480
+ completion: string;
1481
+ member: string;
1482
+ provider: "discord";
1483
+ action: "grant-role";
1484
+ roleId: string;
1485
+ status: "pending" | "delivered" | "failed";
1486
+ attempts: number;
1487
+ nextAt: number;
1488
+ lastError: string | null;
1489
+ createdAt: number;
1490
+ deliveredAt: number | null;
1491
+ }[];
1492
+ }>;
1493
+ claim: (input: Omit<SubmitInput, "member">, options?: {
1494
+ session: string;
1495
+ }) => Promise<{
1496
+ id: string;
1497
+ release: string;
1498
+ quest: string;
1499
+ member: string;
1500
+ evidence: string | null;
1501
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
1502
+ reason: string | null;
1503
+ retries: number;
1504
+ generation: number;
1505
+ completion: string | null;
1506
+ reviewRewards: ({
1507
+ kind: "tier";
1508
+ reward: {
1509
+ id: string;
1510
+ title: string;
1511
+ tiers: {
1512
+ id: string;
1513
+ title: string;
1514
+ }[];
1515
+ inventory: {
1516
+ kind: "untracked";
1517
+ };
1518
+ fulfillment: {
1519
+ kind: "staff-handover";
1520
+ };
1521
+ };
1522
+ tier: string;
1523
+ } | {
1524
+ kind: "points";
1525
+ balance: string;
1526
+ amount: number;
1527
+ } | {
1528
+ kind: "integration";
1529
+ provider: "discord";
1530
+ action: "grant-role";
1531
+ roleId: string;
1532
+ })[] | null;
1533
+ createdAt: number;
1534
+ input?: {
1535
+ kind: "quiz";
1536
+ answers: {
1537
+ [k: string]: string;
1538
+ };
1539
+ release?: string | undefined;
1540
+ } | undefined;
1541
+ }>;
1542
+ upload: (file: File) => Promise<{
1543
+ id: string;
1544
+ member: string;
1545
+ type: "image/jpeg" | "image/png";
1546
+ size: number;
1547
+ }>;
1548
+ };
1549
+ reviews: {
1550
+ list: (options?: ReviewListOptions, requestOptions?: {
1551
+ signal?: AbortSignal;
1552
+ }) => Promise<{
1553
+ items: {
1554
+ attempt: {
1555
+ id: string;
1556
+ release: string;
1557
+ quest: string;
1558
+ member: string;
1559
+ evidence: string | null;
1560
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
1561
+ reason: string | null;
1562
+ retries: number;
1563
+ generation: number;
1564
+ completion: string | null;
1565
+ reviewRewards: ({
1566
+ kind: "tier";
1567
+ reward: {
1568
+ id: string;
1569
+ title: string;
1570
+ tiers: {
1571
+ id: string;
1572
+ title: string;
1573
+ }[];
1574
+ inventory: {
1575
+ kind: "untracked";
1576
+ };
1577
+ fulfillment: {
1578
+ kind: "staff-handover";
1579
+ };
1580
+ };
1581
+ tier: string;
1582
+ } | {
1583
+ kind: "points";
1584
+ balance: string;
1585
+ amount: number;
1586
+ } | {
1587
+ kind: "integration";
1588
+ provider: "discord";
1589
+ action: "grant-role";
1590
+ roleId: string;
1591
+ })[] | null;
1592
+ createdAt: number;
1593
+ input?: {
1594
+ kind: "quiz";
1595
+ answers: {
1596
+ [k: string]: string;
1597
+ };
1598
+ release?: string | undefined;
1599
+ } | undefined;
1600
+ };
1601
+ title: string;
1602
+ checks: {
1603
+ criteria: string;
1604
+ result: {
1605
+ kind: "pass" | "fail" | "unclear";
1606
+ reason: string;
1607
+ };
1608
+ }[];
1609
+ }[];
1610
+ nextCursor: string | null;
1611
+ }>;
1612
+ };
1613
+ members: {
1614
+ list: (options?: MemberListOptions, requestOptions?: {
1615
+ signal?: AbortSignal;
1616
+ }) => Promise<{
1617
+ items: {
1618
+ member: string;
1619
+ }[];
1620
+ nextCursor: string | null;
1621
+ }>;
1622
+ };
1623
+ evidence: {
1624
+ download(id: string, requestOptions?: {
1625
+ signal?: AbortSignal;
1626
+ }): Promise<Blob>;
1627
+ };
1628
+ lookupMember: (issuer: string, subject: string) => Promise<{
1629
+ member: string;
1630
+ }>;
1631
+ journeyTemplate: () => Promise<{
1632
+ code: string;
1633
+ definition: {
1634
+ quest: string;
1635
+ runtimeVersion: 1 | 2;
1636
+ title: string;
1637
+ presentation: {
1638
+ quiz?: {
1639
+ id: string;
1640
+ prompt: string;
1641
+ choices: {
1642
+ id: string;
1643
+ label: string;
1644
+ }[];
1645
+ }[] | undefined;
1646
+ instructions?: string | undefined;
1647
+ video?: {
1648
+ url: string;
1649
+ poster?: string | undefined;
1650
+ captions?: {
1651
+ url: string;
1652
+ language: string;
1653
+ label: string;
1654
+ } | undefined;
1655
+ } | undefined;
1656
+ };
1657
+ integrations: "discord"[];
1658
+ fields: Record<string, {
1659
+ kind: "point-ledger";
1660
+ default: string;
1661
+ label: string;
1662
+ description?: string | undefined;
1663
+ } | {
1664
+ kind: "datetime";
1665
+ default: string;
1666
+ label: string;
1667
+ description?: string | undefined;
1668
+ } | {
1669
+ kind: "resource";
1670
+ default: string;
1671
+ source: {
1672
+ provider: "discord";
1673
+ resource: "channel";
1674
+ types: ("text" | "announcement")[];
1675
+ } | {
1676
+ provider: "domino";
1677
+ resource: "point-ledger";
1678
+ } | {
1679
+ provider: "discord";
1680
+ resource: "role";
1681
+ assignable: boolean;
1682
+ };
1683
+ label: string;
1684
+ description?: string | undefined;
1685
+ } | {
1686
+ kind: "quiz";
1687
+ default: {
1688
+ id: string;
1689
+ prompt: string;
1690
+ choices: {
1691
+ id: string;
1692
+ label: string;
1693
+ }[];
1694
+ correct: string;
1695
+ }[];
1696
+ label: string;
1697
+ description?: string | undefined;
1698
+ } | {
1699
+ kind: "text";
1700
+ default: string;
1701
+ minLength: number;
1702
+ maxLength: number;
1703
+ multiline: boolean;
1704
+ label: string;
1705
+ description?: string | undefined;
1706
+ } | {
1707
+ kind: "integer";
1708
+ default: number;
1709
+ min: number;
1710
+ max: number;
1711
+ label: string;
1712
+ description?: string | undefined;
1713
+ } | {
1714
+ kind: "boolean";
1715
+ default: boolean;
1716
+ label: string;
1717
+ description?: string | undefined;
1718
+ } | {
1719
+ kind: "choice";
1720
+ default: string;
1721
+ options: string[];
1722
+ label: string;
1723
+ description?: string | undefined;
1724
+ }>;
1725
+ values: Record<string, string | number | boolean | {
1726
+ id: string;
1727
+ prompt: string;
1728
+ choices: {
1729
+ id: string;
1730
+ label: string;
1731
+ }[];
1732
+ correct: string;
1733
+ }[]>;
1734
+ rewards: ({
1735
+ kind: "tier";
1736
+ reward: {
1737
+ id: string;
1738
+ title: string;
1739
+ tiers: {
1740
+ id: string;
1741
+ title: string;
1742
+ }[];
1743
+ inventory: {
1744
+ kind: "untracked";
1745
+ };
1746
+ fulfillment: {
1747
+ kind: "staff-handover";
1748
+ };
1749
+ };
1750
+ tier: string;
1751
+ } | {
1752
+ kind: "points";
1753
+ balance: string;
1754
+ amount: number;
1755
+ } | {
1756
+ kind: "integration";
1757
+ provider: "discord";
1758
+ action: "grant-role";
1759
+ roleId: string;
1760
+ })[];
1761
+ humanReview: boolean;
1762
+ trigger: {
1763
+ kind: "manual";
1764
+ input: "quiz" | "photo" | "none";
1765
+ actor?: "member" | "staff" | undefined;
1766
+ } | {
1767
+ kind: "automatic";
1768
+ observation?: {
1769
+ source: string;
1770
+ type: string;
1771
+ } | undefined;
1772
+ };
1773
+ requires: {
1774
+ quest: string;
1775
+ scope: "ever";
1776
+ }[];
1777
+ completion: {
1778
+ kind: "streak";
1779
+ days: number;
1780
+ timeZone: string;
1781
+ } | {
1782
+ kind: "once";
1783
+ } | {
1784
+ kind: "keyed";
1785
+ };
1786
+ visibility: "visible" | "hidden";
1787
+ budgets: {
1788
+ id: string;
1789
+ scope: "member" | "project";
1790
+ period: "day" | "lifetime";
1791
+ limit: number;
1792
+ cost: number | {
1793
+ balance: string;
1794
+ };
1795
+ }[];
1796
+ };
1797
+ }[]>;
1798
+ template: () => Promise<{
1799
+ code: string;
1800
+ definition: {
1801
+ quest: string;
1802
+ runtimeVersion: 1 | 2;
1803
+ title: string;
1804
+ presentation: {
1805
+ quiz?: {
1806
+ id: string;
1807
+ prompt: string;
1808
+ choices: {
1809
+ id: string;
1810
+ label: string;
1811
+ }[];
1812
+ }[] | undefined;
1813
+ instructions?: string | undefined;
1814
+ video?: {
1815
+ url: string;
1816
+ poster?: string | undefined;
1817
+ captions?: {
1818
+ url: string;
1819
+ language: string;
1820
+ label: string;
1821
+ } | undefined;
1822
+ } | undefined;
1823
+ };
1824
+ integrations: "discord"[];
1825
+ fields: Record<string, {
1826
+ kind: "point-ledger";
1827
+ default: string;
1828
+ label: string;
1829
+ description?: string | undefined;
1830
+ } | {
1831
+ kind: "datetime";
1832
+ default: string;
1833
+ label: string;
1834
+ description?: string | undefined;
1835
+ } | {
1836
+ kind: "resource";
1837
+ default: string;
1838
+ source: {
1839
+ provider: "discord";
1840
+ resource: "channel";
1841
+ types: ("text" | "announcement")[];
1842
+ } | {
1843
+ provider: "domino";
1844
+ resource: "point-ledger";
1845
+ } | {
1846
+ provider: "discord";
1847
+ resource: "role";
1848
+ assignable: boolean;
1849
+ };
1850
+ label: string;
1851
+ description?: string | undefined;
1852
+ } | {
1853
+ kind: "quiz";
1854
+ default: {
1855
+ id: string;
1856
+ prompt: string;
1857
+ choices: {
1858
+ id: string;
1859
+ label: string;
1860
+ }[];
1861
+ correct: string;
1862
+ }[];
1863
+ label: string;
1864
+ description?: string | undefined;
1865
+ } | {
1866
+ kind: "text";
1867
+ default: string;
1868
+ minLength: number;
1869
+ maxLength: number;
1870
+ multiline: boolean;
1871
+ label: string;
1872
+ description?: string | undefined;
1873
+ } | {
1874
+ kind: "integer";
1875
+ default: number;
1876
+ min: number;
1877
+ max: number;
1878
+ label: string;
1879
+ description?: string | undefined;
1880
+ } | {
1881
+ kind: "boolean";
1882
+ default: boolean;
1883
+ label: string;
1884
+ description?: string | undefined;
1885
+ } | {
1886
+ kind: "choice";
1887
+ default: string;
1888
+ options: string[];
1889
+ label: string;
1890
+ description?: string | undefined;
1891
+ }>;
1892
+ values: Record<string, string | number | boolean | {
1893
+ id: string;
1894
+ prompt: string;
1895
+ choices: {
1896
+ id: string;
1897
+ label: string;
1898
+ }[];
1899
+ correct: string;
1900
+ }[]>;
1901
+ rewards: ({
1902
+ kind: "tier";
1903
+ reward: {
1904
+ id: string;
1905
+ title: string;
1906
+ tiers: {
1907
+ id: string;
1908
+ title: string;
1909
+ }[];
1910
+ inventory: {
1911
+ kind: "untracked";
1912
+ };
1913
+ fulfillment: {
1914
+ kind: "staff-handover";
1915
+ };
1916
+ };
1917
+ tier: string;
1918
+ } | {
1919
+ kind: "points";
1920
+ balance: string;
1921
+ amount: number;
1922
+ } | {
1923
+ kind: "integration";
1924
+ provider: "discord";
1925
+ action: "grant-role";
1926
+ roleId: string;
1927
+ })[];
1928
+ humanReview: boolean;
1929
+ trigger: {
1930
+ kind: "manual";
1931
+ input: "quiz" | "photo" | "none";
1932
+ actor?: "member" | "staff" | undefined;
1933
+ } | {
1934
+ kind: "automatic";
1935
+ observation?: {
1936
+ source: string;
1937
+ type: string;
1938
+ } | undefined;
1939
+ };
1940
+ requires: {
1941
+ quest: string;
1942
+ scope: "ever";
1943
+ }[];
1944
+ completion: {
1945
+ kind: "streak";
1946
+ days: number;
1947
+ timeZone: string;
1948
+ } | {
1949
+ kind: "once";
1950
+ } | {
1951
+ kind: "keyed";
1952
+ };
1953
+ visibility: "visible" | "hidden";
1954
+ budgets: {
1955
+ id: string;
1956
+ scope: "member" | "project";
1957
+ period: "day" | "lifetime";
1958
+ limit: number;
1959
+ cost: number | {
1960
+ balance: string;
1961
+ };
1962
+ }[];
1963
+ };
1964
+ }>;
1965
+ snapshot: () => Promise<{
1966
+ releases: {
1967
+ quest: string;
1968
+ runtimeVersion: 1 | 2;
1969
+ title: string;
1970
+ presentation: {
1971
+ quiz?: {
1972
+ id: string;
1973
+ prompt: string;
1974
+ choices: {
1975
+ id: string;
1976
+ label: string;
1977
+ }[];
1978
+ }[] | undefined;
1979
+ instructions?: string | undefined;
1980
+ video?: {
1981
+ url: string;
1982
+ poster?: string | undefined;
1983
+ captions?: {
1984
+ url: string;
1985
+ language: string;
1986
+ label: string;
1987
+ } | undefined;
1988
+ } | undefined;
1989
+ };
1990
+ integrations: "discord"[];
1991
+ fields: Record<string, {
1992
+ kind: "point-ledger";
1993
+ default: string;
1994
+ label: string;
1995
+ description?: string | undefined;
1996
+ } | {
1997
+ kind: "datetime";
1998
+ default: string;
1999
+ label: string;
2000
+ description?: string | undefined;
2001
+ } | {
2002
+ kind: "resource";
2003
+ default: string;
2004
+ source: {
2005
+ provider: "discord";
2006
+ resource: "channel";
2007
+ types: ("text" | "announcement")[];
2008
+ } | {
2009
+ provider: "domino";
2010
+ resource: "point-ledger";
2011
+ } | {
2012
+ provider: "discord";
2013
+ resource: "role";
2014
+ assignable: boolean;
2015
+ };
2016
+ label: string;
2017
+ description?: string | undefined;
2018
+ } | {
2019
+ kind: "quiz";
2020
+ default: {
2021
+ id: string;
2022
+ prompt: string;
2023
+ choices: {
2024
+ id: string;
2025
+ label: string;
2026
+ }[];
2027
+ correct: string;
2028
+ }[];
2029
+ label: string;
2030
+ description?: string | undefined;
2031
+ } | {
2032
+ kind: "text";
2033
+ default: string;
2034
+ minLength: number;
2035
+ maxLength: number;
2036
+ multiline: boolean;
2037
+ label: string;
2038
+ description?: string | undefined;
2039
+ } | {
2040
+ kind: "integer";
2041
+ default: number;
2042
+ min: number;
2043
+ max: number;
2044
+ label: string;
2045
+ description?: string | undefined;
2046
+ } | {
2047
+ kind: "boolean";
2048
+ default: boolean;
2049
+ label: string;
2050
+ description?: string | undefined;
2051
+ } | {
2052
+ kind: "choice";
2053
+ default: string;
2054
+ options: string[];
2055
+ label: string;
2056
+ description?: string | undefined;
2057
+ }>;
2058
+ values: Record<string, string | number | boolean | {
2059
+ id: string;
2060
+ prompt: string;
2061
+ choices: {
2062
+ id: string;
2063
+ label: string;
2064
+ }[];
2065
+ correct: string;
2066
+ }[]>;
2067
+ rewards: ({
2068
+ kind: "tier";
2069
+ reward: {
2070
+ id: string;
2071
+ title: string;
2072
+ tiers: {
2073
+ id: string;
2074
+ title: string;
2075
+ }[];
2076
+ inventory: {
2077
+ kind: "untracked";
2078
+ };
2079
+ fulfillment: {
2080
+ kind: "staff-handover";
2081
+ };
2082
+ };
2083
+ tier: string;
2084
+ } | {
2085
+ kind: "points";
2086
+ balance: string;
2087
+ amount: number;
2088
+ } | {
2089
+ kind: "integration";
2090
+ provider: "discord";
2091
+ action: "grant-role";
2092
+ roleId: string;
2093
+ })[];
2094
+ humanReview: boolean;
2095
+ trigger: {
2096
+ kind: "manual";
2097
+ input: "quiz" | "photo" | "none";
2098
+ actor?: "member" | "staff" | undefined;
2099
+ } | {
2100
+ kind: "automatic";
2101
+ observation?: {
2102
+ source: string;
2103
+ type: string;
2104
+ } | undefined;
2105
+ };
2106
+ requires: {
2107
+ quest: string;
2108
+ scope: "ever";
2109
+ }[];
2110
+ completion: {
2111
+ kind: "streak";
2112
+ days: number;
2113
+ timeZone: string;
2114
+ } | {
2115
+ kind: "once";
2116
+ } | {
2117
+ kind: "keyed";
2118
+ };
2119
+ visibility: "visible" | "hidden";
2120
+ budgets: {
2121
+ id: string;
2122
+ scope: "member" | "project";
2123
+ period: "day" | "lifetime";
2124
+ limit: number;
2125
+ cost: number | {
2126
+ balance: string;
2127
+ };
2128
+ }[];
2129
+ code: string;
2130
+ provider: "workers-ai" | "fixture-pass" | "fixture-fail" | "fixture-unclear" | "fixture-error";
2131
+ id: string;
2132
+ createdAt: number;
2133
+ legacy: boolean;
2134
+ lifecycle: "paused" | "active" | "archived";
2135
+ key?: string | undefined;
2136
+ origin?: {
2137
+ typeVersion: string;
2138
+ } | undefined;
2139
+ configuration?: {
2140
+ defaults: Record<string, string | number | boolean | {
2141
+ id: string;
2142
+ prompt: string;
2143
+ choices: {
2144
+ id: string;
2145
+ label: string;
2146
+ }[];
2147
+ correct: string;
2148
+ }[]>;
2149
+ overrides: Record<string, string | number | boolean | {
2150
+ id: string;
2151
+ prompt: string;
2152
+ choices: {
2153
+ id: string;
2154
+ label: string;
2155
+ }[];
2156
+ correct: string;
2157
+ }[]>;
2158
+ preserved: string[];
2159
+ } | undefined;
2160
+ }[];
2161
+ completions: {
2162
+ key: string;
2163
+ id: string;
2164
+ quest: string;
2165
+ member: string;
2166
+ }[];
2167
+ entitlements: ({
2168
+ status: "available";
2169
+ id: string;
2170
+ member: string;
2171
+ reward: {
2172
+ id: string;
2173
+ title: string;
2174
+ tiers: {
2175
+ id: string;
2176
+ title: string;
2177
+ }[];
2178
+ inventory: {
2179
+ kind: "untracked";
2180
+ };
2181
+ fulfillment: {
2182
+ kind: "staff-handover";
2183
+ };
2184
+ };
2185
+ earnedTier: string;
2186
+ tier: string;
2187
+ revision: number;
2188
+ } | {
2189
+ status: "handing-over";
2190
+ handover: string;
2191
+ startedAt: number;
2192
+ id: string;
2193
+ member: string;
2194
+ reward: {
2195
+ id: string;
2196
+ title: string;
2197
+ tiers: {
2198
+ id: string;
2199
+ title: string;
2200
+ }[];
2201
+ inventory: {
2202
+ kind: "untracked";
2203
+ };
2204
+ fulfillment: {
2205
+ kind: "staff-handover";
2206
+ };
2207
+ };
2208
+ earnedTier: string;
2209
+ tier: string;
2210
+ revision: number;
2211
+ allocation?: {
2212
+ item: string;
2213
+ label: string;
2214
+ } | undefined;
2215
+ } | {
2216
+ status: "collected";
2217
+ handover: string;
2218
+ startedAt: number;
2219
+ collectedAt: number;
2220
+ id: string;
2221
+ member: string;
2222
+ reward: {
2223
+ id: string;
2224
+ title: string;
2225
+ tiers: {
2226
+ id: string;
2227
+ title: string;
2228
+ }[];
2229
+ inventory: {
2230
+ kind: "untracked";
2231
+ };
2232
+ fulfillment: {
2233
+ kind: "staff-handover";
2234
+ };
2235
+ };
2236
+ earnedTier: string;
2237
+ tier: string;
2238
+ revision: number;
2239
+ allocation?: {
2240
+ item: string;
2241
+ label: string;
2242
+ } | undefined;
2243
+ })[];
2244
+ attempts: {
2245
+ id: string;
2246
+ release: string;
2247
+ quest: string;
2248
+ member: string;
2249
+ evidence: string | null;
2250
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
2251
+ reason: string | null;
2252
+ retries: number;
2253
+ generation: number;
2254
+ completion: string | null;
2255
+ reviewRewards: ({
2256
+ kind: "tier";
2257
+ reward: {
2258
+ id: string;
2259
+ title: string;
2260
+ tiers: {
2261
+ id: string;
2262
+ title: string;
2263
+ }[];
2264
+ inventory: {
2265
+ kind: "untracked";
2266
+ };
2267
+ fulfillment: {
2268
+ kind: "staff-handover";
2269
+ };
2270
+ };
2271
+ tier: string;
2272
+ } | {
2273
+ kind: "points";
2274
+ balance: string;
2275
+ amount: number;
2276
+ } | {
2277
+ kind: "integration";
2278
+ provider: "discord";
2279
+ action: "grant-role";
2280
+ roleId: string;
2281
+ })[] | null;
2282
+ createdAt: number;
2283
+ input?: {
2284
+ kind: "quiz";
2285
+ answers: {
2286
+ [k: string]: string;
2287
+ };
2288
+ release?: string | undefined;
2289
+ } | undefined;
2290
+ }[];
2291
+ balances: {
2292
+ member: string;
2293
+ balance: string;
2294
+ earned: number;
2295
+ held: number;
2296
+ available: number;
2297
+ }[];
2298
+ events: {
2299
+ id: number;
2300
+ attempt: string | null;
2301
+ kind: string;
2302
+ detail: string;
2303
+ actor: string | null;
2304
+ at: number;
2305
+ }[];
2306
+ }>;
2307
+ publish: (release: ReleaseInput) => Promise<{
2308
+ quest: string;
2309
+ runtimeVersion: 1 | 2;
2310
+ title: string;
2311
+ presentation: {
2312
+ quiz?: {
2313
+ id: string;
2314
+ prompt: string;
2315
+ choices: {
2316
+ id: string;
2317
+ label: string;
2318
+ }[];
2319
+ }[] | undefined;
2320
+ instructions?: string | undefined;
2321
+ video?: {
2322
+ url: string;
2323
+ poster?: string | undefined;
2324
+ captions?: {
2325
+ url: string;
2326
+ language: string;
2327
+ label: string;
2328
+ } | undefined;
2329
+ } | undefined;
2330
+ };
2331
+ integrations: "discord"[];
2332
+ fields: Record<string, {
2333
+ kind: "point-ledger";
2334
+ default: string;
2335
+ label: string;
2336
+ description?: string | undefined;
2337
+ } | {
2338
+ kind: "datetime";
2339
+ default: string;
2340
+ label: string;
2341
+ description?: string | undefined;
2342
+ } | {
2343
+ kind: "resource";
2344
+ default: string;
2345
+ source: {
2346
+ provider: "discord";
2347
+ resource: "channel";
2348
+ types: ("text" | "announcement")[];
2349
+ } | {
2350
+ provider: "domino";
2351
+ resource: "point-ledger";
2352
+ } | {
2353
+ provider: "discord";
2354
+ resource: "role";
2355
+ assignable: boolean;
2356
+ };
2357
+ label: string;
2358
+ description?: string | undefined;
2359
+ } | {
2360
+ kind: "quiz";
2361
+ default: {
2362
+ id: string;
2363
+ prompt: string;
2364
+ choices: {
2365
+ id: string;
2366
+ label: string;
2367
+ }[];
2368
+ correct: string;
2369
+ }[];
2370
+ label: string;
2371
+ description?: string | undefined;
2372
+ } | {
2373
+ kind: "text";
2374
+ default: string;
2375
+ minLength: number;
2376
+ maxLength: number;
2377
+ multiline: boolean;
2378
+ label: string;
2379
+ description?: string | undefined;
2380
+ } | {
2381
+ kind: "integer";
2382
+ default: number;
2383
+ min: number;
2384
+ max: number;
2385
+ label: string;
2386
+ description?: string | undefined;
2387
+ } | {
2388
+ kind: "boolean";
2389
+ default: boolean;
2390
+ label: string;
2391
+ description?: string | undefined;
2392
+ } | {
2393
+ kind: "choice";
2394
+ default: string;
2395
+ options: string[];
2396
+ label: string;
2397
+ description?: string | undefined;
2398
+ }>;
2399
+ values: Record<string, string | number | boolean | {
2400
+ id: string;
2401
+ prompt: string;
2402
+ choices: {
2403
+ id: string;
2404
+ label: string;
2405
+ }[];
2406
+ correct: string;
2407
+ }[]>;
2408
+ rewards: ({
2409
+ kind: "tier";
2410
+ reward: {
2411
+ id: string;
2412
+ title: string;
2413
+ tiers: {
2414
+ id: string;
2415
+ title: string;
2416
+ }[];
2417
+ inventory: {
2418
+ kind: "untracked";
2419
+ };
2420
+ fulfillment: {
2421
+ kind: "staff-handover";
2422
+ };
2423
+ };
2424
+ tier: string;
2425
+ } | {
2426
+ kind: "points";
2427
+ balance: string;
2428
+ amount: number;
2429
+ } | {
2430
+ kind: "integration";
2431
+ provider: "discord";
2432
+ action: "grant-role";
2433
+ roleId: string;
2434
+ })[];
2435
+ humanReview: boolean;
2436
+ trigger: {
2437
+ kind: "manual";
2438
+ input: "quiz" | "photo" | "none";
2439
+ actor?: "member" | "staff" | undefined;
2440
+ } | {
2441
+ kind: "automatic";
2442
+ observation?: {
2443
+ source: string;
2444
+ type: string;
2445
+ } | undefined;
2446
+ };
2447
+ requires: {
2448
+ quest: string;
2449
+ scope: "ever";
2450
+ }[];
2451
+ completion: {
2452
+ kind: "streak";
2453
+ days: number;
2454
+ timeZone: string;
2455
+ } | {
2456
+ kind: "once";
2457
+ } | {
2458
+ kind: "keyed";
2459
+ };
2460
+ visibility: "visible" | "hidden";
2461
+ budgets: {
2462
+ id: string;
2463
+ scope: "member" | "project";
2464
+ period: "day" | "lifetime";
2465
+ limit: number;
2466
+ cost: number | {
2467
+ balance: string;
2468
+ };
2469
+ }[];
2470
+ code: string;
2471
+ provider: "workers-ai" | "fixture-pass" | "fixture-fail" | "fixture-unclear" | "fixture-error";
2472
+ id: string;
2473
+ createdAt: number;
2474
+ legacy: boolean;
2475
+ lifecycle: "paused" | "active" | "archived";
2476
+ key?: string | undefined;
2477
+ origin?: {
2478
+ typeVersion: string;
2479
+ } | undefined;
2480
+ configuration?: {
2481
+ defaults: Record<string, string | number | boolean | {
2482
+ id: string;
2483
+ prompt: string;
2484
+ choices: {
2485
+ id: string;
2486
+ label: string;
2487
+ }[];
2488
+ correct: string;
2489
+ }[]>;
2490
+ overrides: Record<string, string | number | boolean | {
2491
+ id: string;
2492
+ prompt: string;
2493
+ choices: {
2494
+ id: string;
2495
+ label: string;
2496
+ }[];
2497
+ correct: string;
2498
+ }[]>;
2499
+ preserved: string[];
2500
+ } | undefined;
2501
+ }>;
2502
+ publishBatch: (releases: ReleaseInput[]) => Promise<{
2503
+ quest: string;
2504
+ runtimeVersion: 1 | 2;
2505
+ title: string;
2506
+ presentation: {
2507
+ quiz?: {
2508
+ id: string;
2509
+ prompt: string;
2510
+ choices: {
2511
+ id: string;
2512
+ label: string;
2513
+ }[];
2514
+ }[] | undefined;
2515
+ instructions?: string | undefined;
2516
+ video?: {
2517
+ url: string;
2518
+ poster?: string | undefined;
2519
+ captions?: {
2520
+ url: string;
2521
+ language: string;
2522
+ label: string;
2523
+ } | undefined;
2524
+ } | undefined;
2525
+ };
2526
+ integrations: "discord"[];
2527
+ fields: Record<string, {
2528
+ kind: "point-ledger";
2529
+ default: string;
2530
+ label: string;
2531
+ description?: string | undefined;
2532
+ } | {
2533
+ kind: "datetime";
2534
+ default: string;
2535
+ label: string;
2536
+ description?: string | undefined;
2537
+ } | {
2538
+ kind: "resource";
2539
+ default: string;
2540
+ source: {
2541
+ provider: "discord";
2542
+ resource: "channel";
2543
+ types: ("text" | "announcement")[];
2544
+ } | {
2545
+ provider: "domino";
2546
+ resource: "point-ledger";
2547
+ } | {
2548
+ provider: "discord";
2549
+ resource: "role";
2550
+ assignable: boolean;
2551
+ };
2552
+ label: string;
2553
+ description?: string | undefined;
2554
+ } | {
2555
+ kind: "quiz";
2556
+ default: {
2557
+ id: string;
2558
+ prompt: string;
2559
+ choices: {
2560
+ id: string;
2561
+ label: string;
2562
+ }[];
2563
+ correct: string;
2564
+ }[];
2565
+ label: string;
2566
+ description?: string | undefined;
2567
+ } | {
2568
+ kind: "text";
2569
+ default: string;
2570
+ minLength: number;
2571
+ maxLength: number;
2572
+ multiline: boolean;
2573
+ label: string;
2574
+ description?: string | undefined;
2575
+ } | {
2576
+ kind: "integer";
2577
+ default: number;
2578
+ min: number;
2579
+ max: number;
2580
+ label: string;
2581
+ description?: string | undefined;
2582
+ } | {
2583
+ kind: "boolean";
2584
+ default: boolean;
2585
+ label: string;
2586
+ description?: string | undefined;
2587
+ } | {
2588
+ kind: "choice";
2589
+ default: string;
2590
+ options: string[];
2591
+ label: string;
2592
+ description?: string | undefined;
2593
+ }>;
2594
+ values: Record<string, string | number | boolean | {
2595
+ id: string;
2596
+ prompt: string;
2597
+ choices: {
2598
+ id: string;
2599
+ label: string;
2600
+ }[];
2601
+ correct: string;
2602
+ }[]>;
2603
+ rewards: ({
2604
+ kind: "tier";
2605
+ reward: {
2606
+ id: string;
2607
+ title: string;
2608
+ tiers: {
2609
+ id: string;
2610
+ title: string;
2611
+ }[];
2612
+ inventory: {
2613
+ kind: "untracked";
2614
+ };
2615
+ fulfillment: {
2616
+ kind: "staff-handover";
2617
+ };
2618
+ };
2619
+ tier: string;
2620
+ } | {
2621
+ kind: "points";
2622
+ balance: string;
2623
+ amount: number;
2624
+ } | {
2625
+ kind: "integration";
2626
+ provider: "discord";
2627
+ action: "grant-role";
2628
+ roleId: string;
2629
+ })[];
2630
+ humanReview: boolean;
2631
+ trigger: {
2632
+ kind: "manual";
2633
+ input: "quiz" | "photo" | "none";
2634
+ actor?: "member" | "staff" | undefined;
2635
+ } | {
2636
+ kind: "automatic";
2637
+ observation?: {
2638
+ source: string;
2639
+ type: string;
2640
+ } | undefined;
2641
+ };
2642
+ requires: {
2643
+ quest: string;
2644
+ scope: "ever";
2645
+ }[];
2646
+ completion: {
2647
+ kind: "streak";
2648
+ days: number;
2649
+ timeZone: string;
2650
+ } | {
2651
+ kind: "once";
2652
+ } | {
2653
+ kind: "keyed";
2654
+ };
2655
+ visibility: "visible" | "hidden";
2656
+ budgets: {
2657
+ id: string;
2658
+ scope: "member" | "project";
2659
+ period: "day" | "lifetime";
2660
+ limit: number;
2661
+ cost: number | {
2662
+ balance: string;
2663
+ };
2664
+ }[];
2665
+ code: string;
2666
+ provider: "workers-ai" | "fixture-pass" | "fixture-fail" | "fixture-unclear" | "fixture-error";
2667
+ id: string;
2668
+ createdAt: number;
2669
+ legacy: boolean;
2670
+ lifecycle: "paused" | "active" | "archived";
2671
+ key?: string | undefined;
2672
+ origin?: {
2673
+ typeVersion: string;
2674
+ } | undefined;
2675
+ configuration?: {
2676
+ defaults: Record<string, string | number | boolean | {
2677
+ id: string;
2678
+ prompt: string;
2679
+ choices: {
2680
+ id: string;
2681
+ label: string;
2682
+ }[];
2683
+ correct: string;
2684
+ }[]>;
2685
+ overrides: Record<string, string | number | boolean | {
2686
+ id: string;
2687
+ prompt: string;
2688
+ choices: {
2689
+ id: string;
2690
+ label: string;
2691
+ }[];
2692
+ correct: string;
2693
+ }[]>;
2694
+ preserved: string[];
2695
+ } | undefined;
2696
+ }[]>;
2697
+ progress: (member: string) => Promise<{
2698
+ member: string;
2699
+ quests: {
2700
+ quest: string;
2701
+ title: string;
2702
+ presentation: {
2703
+ quiz?: {
2704
+ id: string;
2705
+ prompt: string;
2706
+ choices: {
2707
+ id: string;
2708
+ label: string;
2709
+ }[];
2710
+ }[] | undefined;
2711
+ instructions?: string | undefined;
2712
+ video?: {
2713
+ url: string;
2714
+ poster?: string | undefined;
2715
+ captions?: {
2716
+ url: string;
2717
+ language: string;
2718
+ label: string;
2719
+ } | undefined;
2720
+ } | undefined;
2721
+ };
2722
+ connections: ("discord" | "google" | "apple" | "x")[];
2723
+ trigger: {
2724
+ kind: "manual";
2725
+ input: "quiz" | "photo" | "none";
2726
+ actor?: "member" | "staff" | undefined;
2727
+ } | {
2728
+ kind: "automatic";
2729
+ observation?: {
2730
+ source: string;
2731
+ type: string;
2732
+ } | undefined;
2733
+ };
2734
+ availability: {
2735
+ kind: "available";
2736
+ input: "quiz" | "photo" | "none";
2737
+ } | {
2738
+ kind: "completed";
2739
+ } | {
2740
+ kind: "locked";
2741
+ missing: {
2742
+ quest: string;
2743
+ title: string;
2744
+ }[];
2745
+ } | {
2746
+ kind: "staff-required";
2747
+ } | {
2748
+ kind: "automatic";
2749
+ observation?: {
2750
+ source: string;
2751
+ type: string;
2752
+ } | undefined;
2753
+ } | {
2754
+ kind: "checking";
2755
+ attempt: string;
2756
+ } | {
2757
+ kind: "needs-review";
2758
+ attempt: string;
2759
+ } | {
2760
+ kind: "retryable";
2761
+ attempt: string;
2762
+ };
2763
+ completed: boolean;
2764
+ completion: {
2765
+ kind: "streak";
2766
+ days: number;
2767
+ timeZone: string;
2768
+ } | {
2769
+ kind: "once";
2770
+ } | {
2771
+ kind: "keyed";
2772
+ };
2773
+ completionCount: number;
2774
+ visibility: "visible" | "hidden";
2775
+ missing: {
2776
+ quest: string;
2777
+ title: string;
2778
+ }[];
2779
+ attempt: {
2780
+ id: string;
2781
+ release: string;
2782
+ quest: string;
2783
+ member: string;
2784
+ evidence: string | null;
2785
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
2786
+ reason: string | null;
2787
+ retries: number;
2788
+ generation: number;
2789
+ completion: string | null;
2790
+ reviewRewards: ({
2791
+ kind: "tier";
2792
+ reward: {
2793
+ id: string;
2794
+ title: string;
2795
+ tiers: {
2796
+ id: string;
2797
+ title: string;
2798
+ }[];
2799
+ inventory: {
2800
+ kind: "untracked";
2801
+ };
2802
+ fulfillment: {
2803
+ kind: "staff-handover";
2804
+ };
2805
+ };
2806
+ tier: string;
2807
+ } | {
2808
+ kind: "points";
2809
+ balance: string;
2810
+ amount: number;
2811
+ } | {
2812
+ kind: "integration";
2813
+ provider: "discord";
2814
+ action: "grant-role";
2815
+ roleId: string;
2816
+ })[] | null;
2817
+ createdAt: number;
2818
+ input?: {
2819
+ kind: "quiz";
2820
+ answers: {
2821
+ [k: string]: string;
2822
+ };
2823
+ release?: string | undefined;
2824
+ } | undefined;
2825
+ } | null;
2826
+ key?: string | undefined;
2827
+ release?: string | undefined;
2828
+ streak?: {
2829
+ goal: number;
2830
+ current: number;
2831
+ best: number;
2832
+ today: string;
2833
+ todayQualified: boolean;
2834
+ timeZone: string;
2835
+ nextBoundary: number;
2836
+ pendingTimeZone: {
2837
+ timeZone: string;
2838
+ effectiveAt: number;
2839
+ } | null;
2840
+ days: {
2841
+ day: number;
2842
+ date: string;
2843
+ timeZone: string;
2844
+ occurredAt: number;
2845
+ }[];
2846
+ milestone: {
2847
+ status: "pending";
2848
+ } | {
2849
+ status: "awarded";
2850
+ completion: string;
2851
+ achievedAt: number;
2852
+ } | {
2853
+ status: "budget-exhausted";
2854
+ budget: string;
2855
+ achievedAt: number;
2856
+ };
2857
+ } | null | undefined;
2858
+ }[];
2859
+ entitlements: ({
2860
+ status: "available";
2861
+ id: string;
2862
+ member: string;
2863
+ reward: {
2864
+ id: string;
2865
+ title: string;
2866
+ tiers: {
2867
+ id: string;
2868
+ title: string;
2869
+ }[];
2870
+ inventory: {
2871
+ kind: "untracked";
2872
+ };
2873
+ fulfillment: {
2874
+ kind: "staff-handover";
2875
+ };
2876
+ };
2877
+ earnedTier: string;
2878
+ tier: string;
2879
+ revision: number;
2880
+ } | {
2881
+ status: "handing-over";
2882
+ handover: string;
2883
+ startedAt: number;
2884
+ id: string;
2885
+ member: string;
2886
+ reward: {
2887
+ id: string;
2888
+ title: string;
2889
+ tiers: {
2890
+ id: string;
2891
+ title: string;
2892
+ }[];
2893
+ inventory: {
2894
+ kind: "untracked";
2895
+ };
2896
+ fulfillment: {
2897
+ kind: "staff-handover";
2898
+ };
2899
+ };
2900
+ earnedTier: string;
2901
+ tier: string;
2902
+ revision: number;
2903
+ allocation?: {
2904
+ item: string;
2905
+ label: string;
2906
+ } | undefined;
2907
+ } | {
2908
+ status: "collected";
2909
+ handover: string;
2910
+ startedAt: number;
2911
+ collectedAt: number;
2912
+ id: string;
2913
+ member: string;
2914
+ reward: {
2915
+ id: string;
2916
+ title: string;
2917
+ tiers: {
2918
+ id: string;
2919
+ title: string;
2920
+ }[];
2921
+ inventory: {
2922
+ kind: "untracked";
2923
+ };
2924
+ fulfillment: {
2925
+ kind: "staff-handover";
2926
+ };
2927
+ };
2928
+ earnedTier: string;
2929
+ tier: string;
2930
+ revision: number;
2931
+ allocation?: {
2932
+ item: string;
2933
+ label: string;
2934
+ } | undefined;
2935
+ })[];
2936
+ }>;
2937
+ beginHandover: (id: string, input: zod.input<typeof beginHandoverSchema>) => Promise<{
2938
+ status: "available";
2939
+ id: string;
2940
+ member: string;
2941
+ reward: {
2942
+ id: string;
2943
+ title: string;
2944
+ tiers: {
2945
+ id: string;
2946
+ title: string;
2947
+ }[];
2948
+ inventory: {
2949
+ kind: "untracked";
2950
+ };
2951
+ fulfillment: {
2952
+ kind: "staff-handover";
2953
+ };
2954
+ };
2955
+ earnedTier: string;
2956
+ tier: string;
2957
+ revision: number;
2958
+ } | {
2959
+ status: "handing-over";
2960
+ handover: string;
2961
+ startedAt: number;
2962
+ id: string;
2963
+ member: string;
2964
+ reward: {
2965
+ id: string;
2966
+ title: string;
2967
+ tiers: {
2968
+ id: string;
2969
+ title: string;
2970
+ }[];
2971
+ inventory: {
2972
+ kind: "untracked";
2973
+ };
2974
+ fulfillment: {
2975
+ kind: "staff-handover";
2976
+ };
2977
+ };
2978
+ earnedTier: string;
2979
+ tier: string;
2980
+ revision: number;
2981
+ allocation?: {
2982
+ item: string;
2983
+ label: string;
2984
+ } | undefined;
2985
+ } | {
2986
+ status: "collected";
2987
+ handover: string;
2988
+ startedAt: number;
2989
+ collectedAt: number;
2990
+ id: string;
2991
+ member: string;
2992
+ reward: {
2993
+ id: string;
2994
+ title: string;
2995
+ tiers: {
2996
+ id: string;
2997
+ title: string;
2998
+ }[];
2999
+ inventory: {
3000
+ kind: "untracked";
3001
+ };
3002
+ fulfillment: {
3003
+ kind: "staff-handover";
3004
+ };
3005
+ };
3006
+ earnedTier: string;
3007
+ tier: string;
3008
+ revision: number;
3009
+ allocation?: {
3010
+ item: string;
3011
+ label: string;
3012
+ } | undefined;
3013
+ }>;
3014
+ confirmHandover: (id: string, input: {
3015
+ actionId: string;
3016
+ handover: string;
3017
+ }) => Promise<{
3018
+ status: "available";
3019
+ id: string;
3020
+ member: string;
3021
+ reward: {
3022
+ id: string;
3023
+ title: string;
3024
+ tiers: {
3025
+ id: string;
3026
+ title: string;
3027
+ }[];
3028
+ inventory: {
3029
+ kind: "untracked";
3030
+ };
3031
+ fulfillment: {
3032
+ kind: "staff-handover";
3033
+ };
3034
+ };
3035
+ earnedTier: string;
3036
+ tier: string;
3037
+ revision: number;
3038
+ } | {
3039
+ status: "handing-over";
3040
+ handover: string;
3041
+ startedAt: number;
3042
+ id: string;
3043
+ member: string;
3044
+ reward: {
3045
+ id: string;
3046
+ title: string;
3047
+ tiers: {
3048
+ id: string;
3049
+ title: string;
3050
+ }[];
3051
+ inventory: {
3052
+ kind: "untracked";
3053
+ };
3054
+ fulfillment: {
3055
+ kind: "staff-handover";
3056
+ };
3057
+ };
3058
+ earnedTier: string;
3059
+ tier: string;
3060
+ revision: number;
3061
+ allocation?: {
3062
+ item: string;
3063
+ label: string;
3064
+ } | undefined;
3065
+ } | {
3066
+ status: "collected";
3067
+ handover: string;
3068
+ startedAt: number;
3069
+ collectedAt: number;
3070
+ id: string;
3071
+ member: string;
3072
+ reward: {
3073
+ id: string;
3074
+ title: string;
3075
+ tiers: {
3076
+ id: string;
3077
+ title: string;
3078
+ }[];
3079
+ inventory: {
3080
+ kind: "untracked";
3081
+ };
3082
+ fulfillment: {
3083
+ kind: "staff-handover";
3084
+ };
3085
+ };
3086
+ earnedTier: string;
3087
+ tier: string;
3088
+ revision: number;
3089
+ allocation?: {
3090
+ item: string;
3091
+ label: string;
3092
+ } | undefined;
3093
+ }>;
3094
+ upload: (member: string, file: File) => Promise<{
3095
+ id: string;
3096
+ member: string;
3097
+ type: "image/jpeg" | "image/png";
3098
+ size: number;
3099
+ }>;
3100
+ submit: (input: SubmitInput) => Promise<{
3101
+ id: string;
3102
+ release: string;
3103
+ quest: string;
3104
+ member: string;
3105
+ evidence: string | null;
3106
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
3107
+ reason: string | null;
3108
+ retries: number;
3109
+ generation: number;
3110
+ completion: string | null;
3111
+ reviewRewards: ({
3112
+ kind: "tier";
3113
+ reward: {
3114
+ id: string;
3115
+ title: string;
3116
+ tiers: {
3117
+ id: string;
3118
+ title: string;
3119
+ }[];
3120
+ inventory: {
3121
+ kind: "untracked";
3122
+ };
3123
+ fulfillment: {
3124
+ kind: "staff-handover";
3125
+ };
3126
+ };
3127
+ tier: string;
3128
+ } | {
3129
+ kind: "points";
3130
+ balance: string;
3131
+ amount: number;
3132
+ } | {
3133
+ kind: "integration";
3134
+ provider: "discord";
3135
+ action: "grant-role";
3136
+ roleId: string;
3137
+ })[] | null;
3138
+ createdAt: number;
3139
+ input?: {
3140
+ kind: "quiz";
3141
+ answers: {
3142
+ [k: string]: string;
3143
+ };
3144
+ release?: string | undefined;
3145
+ } | undefined;
3146
+ }>;
3147
+ retry: (id: string) => Promise<{
3148
+ id: string;
3149
+ release: string;
3150
+ quest: string;
3151
+ member: string;
3152
+ evidence: string | null;
3153
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
3154
+ reason: string | null;
3155
+ retries: number;
3156
+ generation: number;
3157
+ completion: string | null;
3158
+ reviewRewards: ({
3159
+ kind: "tier";
3160
+ reward: {
3161
+ id: string;
3162
+ title: string;
3163
+ tiers: {
3164
+ id: string;
3165
+ title: string;
3166
+ }[];
3167
+ inventory: {
3168
+ kind: "untracked";
3169
+ };
3170
+ fulfillment: {
3171
+ kind: "staff-handover";
3172
+ };
3173
+ };
3174
+ tier: string;
3175
+ } | {
3176
+ kind: "points";
3177
+ balance: string;
3178
+ amount: number;
3179
+ } | {
3180
+ kind: "integration";
3181
+ provider: "discord";
3182
+ action: "grant-role";
3183
+ roleId: string;
3184
+ })[] | null;
3185
+ createdAt: number;
3186
+ input?: {
3187
+ kind: "quiz";
3188
+ answers: {
3189
+ [k: string]: string;
3190
+ };
3191
+ release?: string | undefined;
3192
+ } | undefined;
3193
+ }>;
3194
+ decide: (id: string, input: {
3195
+ actionId: string;
3196
+ generation: number;
3197
+ decision: "accept" | "reject";
3198
+ reason: string;
3199
+ }) => Promise<{
3200
+ id: string;
3201
+ release: string;
3202
+ quest: string;
3203
+ member: string;
3204
+ evidence: string | null;
3205
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
3206
+ reason: string | null;
3207
+ retries: number;
3208
+ generation: number;
3209
+ completion: string | null;
3210
+ reviewRewards: ({
3211
+ kind: "tier";
3212
+ reward: {
3213
+ id: string;
3214
+ title: string;
3215
+ tiers: {
3216
+ id: string;
3217
+ title: string;
3218
+ }[];
3219
+ inventory: {
3220
+ kind: "untracked";
3221
+ };
3222
+ fulfillment: {
3223
+ kind: "staff-handover";
3224
+ };
3225
+ };
3226
+ tier: string;
3227
+ } | {
3228
+ kind: "points";
3229
+ balance: string;
3230
+ amount: number;
3231
+ } | {
3232
+ kind: "integration";
3233
+ provider: "discord";
3234
+ action: "grant-role";
3235
+ roleId: string;
3236
+ })[] | null;
3237
+ createdAt: number;
3238
+ input?: {
3239
+ kind: "quiz";
3240
+ answers: {
3241
+ [k: string]: string;
3242
+ };
3243
+ release?: string | undefined;
3244
+ } | undefined;
3245
+ }>;
3246
+ };
3247
+
3248
+ /**
3249
+ * One participant client and one quest observer for the whole app.
3250
+ *
3251
+ * `baseUrl` defaults to `/relay`, the participant proxy that `domino dev` and
3252
+ * Domino hosting provide. Pass `client` to share a client created elsewhere.
3253
+ */
3254
+ declare function RelayProvider({ client, baseUrl, children, }: {
3255
+ client?: RelayClient;
3256
+ baseUrl?: string;
3257
+ children: ReactNode;
3258
+ }): react.JSX.Element;
3259
+
3260
+ /**
3261
+ * All a participant sees of a reward Domino delivers elsewhere, such as a
3262
+ * Discord role. Attempts, errors, and role IDs stay out of the page.
3263
+ */
3264
+ type RoleDelivery = {
3265
+ quest: string;
3266
+ status: "pending" | "delivered" | "failed";
3267
+ };
3268
+ declare function sanitizeDeliveries(deliveries: RoleDelivery[]): RoleDelivery[];
3269
+ /**
3270
+ * Changes whenever the participant completes something, which is the only time
3271
+ * a new delivery can appear. Empty until the first completion, so participants
3272
+ * with nothing to deliver never ask.
3273
+ */
3274
+ declare function completionMark(quests: Pick<QuestView, "quest" | "completed" | "completionCount">[]): string;
3275
+ declare function hasPending(deliveries: RoleDelivery[]): boolean;
3276
+ /**
3277
+ * The words for one quest, or null when it delivers nothing. This never
3278
+ * changes whether the quest is completed: the role follows the completion.
3279
+ */
3280
+ declare function roleDeliveryLabel(deliveries: RoleDelivery[], quest: string): "Role delivery pending" | "Role delivery failed" | "Role granted" | null;
3281
+ /** Waits between reads: while a role is pending, then after each failure. */
3282
+ declare const PENDING_POLL_MS = 5000;
3283
+ declare const RETRY_DELAYS_MS: number[];
3284
+ type Schedule = (run: () => void, ms: number) => () => void;
3285
+ /**
3286
+ * Follows one participant's role deliveries until there is nothing to wait for.
3287
+ *
3288
+ * - A read that succeeds with nothing pending ends the watch: no empty polling.
3289
+ * - A pending role is read again every few seconds.
3290
+ * - A failed read, including the very first, is retried with a short backoff.
3291
+ * After the last retry the watch rests until `wake()`, which the page calls
3292
+ * when it becomes visible or focused again.
3293
+ * - Failures never report anything, so a pending role stays pending on screen.
3294
+ */
3295
+ declare function watchRoleDeliveries(options: {
3296
+ read: () => Promise<RoleDelivery[]>;
3297
+ onChange: (deliveries: RoleDelivery[]) => void;
3298
+ schedule?: Schedule;
3299
+ }): {
3300
+ wake(): void;
3301
+ dispose(): void;
3302
+ };
3303
+
3304
+ type Collection = {
3305
+ id: string;
3306
+ title: string;
3307
+ quests: QuestView[];
3308
+ };
3309
+ type Experience = {
3310
+ status: "loading";
3311
+ } | {
3312
+ status: "signed-out";
3313
+ } | {
3314
+ status: "error";
3315
+ message: string;
3316
+ } | {
3317
+ status: "ready";
3318
+ quests: QuestView[];
3319
+ collections: Collection[];
3320
+ /** Set when a refresh failed; the last good data stays on screen. */
3321
+ stale: string | null;
3322
+ };
3323
+ /**
3324
+ * Everything to list, in display order: collections as Console arranged them,
3325
+ * then any quest nobody has placed yet, sorted by `order`: authoring keys
3326
+ * (the `key` in quests/*.quest.ts), or quest IDs for quests without one.
3327
+ * Archived quests are left out.
3328
+ */
3329
+ declare function questGroups(experience: Extract<Experience, {
3330
+ status: "ready";
3331
+ }>, order?: string[]): Collection[];
3332
+
3333
+ type ExperienceContext = {
3334
+ experience: Experience;
3335
+ /** The signed-in participant's member ID, or null. */
3336
+ member: string | null;
3337
+ /** Discord roles earned from quests, and whether each has arrived yet. */
3338
+ deliveries: RoleDelivery[];
3339
+ /** Read again now instead of waiting for the next poll. */
3340
+ refresh(): Promise<void>;
3341
+ };
3342
+ /** The participant's quests and collections, polled for the whole app. */
3343
+ declare function useExperience(): ExperienceContext;
3344
+
3345
+ type QuestInput = {
3346
+ kind: "claim";
3347
+ } | {
3348
+ kind: "quiz";
3349
+ answers: Record<string, string>;
3350
+ } | {
3351
+ kind: "photo";
3352
+ file: File;
3353
+ };
3354
+ /** A submission saved in this browser that never got a final answer. */
3355
+ type SavedSubmission = "none" | "interrupted" | "outdated";
3356
+ type QuestNotice = "received" | "quest-updated" | null;
3357
+ /**
3358
+ * Submission state for one quest, built on the SDK's quest controller.
3359
+ *
3360
+ * The rules this hook protects:
3361
+ * - Receipt is not completion. After "received", the observed experience
3362
+ * reports checking, review, acceptance, or rejection.
3363
+ * - When the quest changed underneath the participant, nothing is resubmitted
3364
+ * for them. They see the latest version with whatever draft still applies.
3365
+ * - An interrupted submission is resumed, never duplicated.
3366
+ */
3367
+ declare function useQuest(observed: QuestView): {
3368
+ /** The newest known version of the quest. Render this, not the prop. */
3369
+ view: {
3370
+ quest: string;
3371
+ title: string;
3372
+ presentation: {
3373
+ quiz?: {
3374
+ id: string;
3375
+ prompt: string;
3376
+ choices: {
3377
+ id: string;
3378
+ label: string;
3379
+ }[];
3380
+ }[] | undefined;
3381
+ instructions?: string | undefined;
3382
+ video?: {
3383
+ url: string;
3384
+ poster?: string | undefined;
3385
+ captions?: {
3386
+ url: string;
3387
+ language: string;
3388
+ label: string;
3389
+ } | undefined;
3390
+ } | undefined;
3391
+ };
3392
+ connections: ("discord" | "google" | "apple" | "x")[];
3393
+ trigger: {
3394
+ kind: "manual";
3395
+ input: "quiz" | "photo" | "none";
3396
+ actor?: "member" | "staff" | undefined;
3397
+ } | {
3398
+ kind: "automatic";
3399
+ observation?: {
3400
+ source: string;
3401
+ type: string;
3402
+ } | undefined;
3403
+ };
3404
+ availability: {
3405
+ kind: "available";
3406
+ input: "quiz" | "photo" | "none";
3407
+ } | {
3408
+ kind: "completed";
3409
+ } | {
3410
+ kind: "locked";
3411
+ missing: {
3412
+ quest: string;
3413
+ title: string;
3414
+ }[];
3415
+ } | {
3416
+ kind: "staff-required";
3417
+ } | {
3418
+ kind: "automatic";
3419
+ observation?: {
3420
+ source: string;
3421
+ type: string;
3422
+ } | undefined;
3423
+ } | {
3424
+ kind: "checking";
3425
+ attempt: string;
3426
+ } | {
3427
+ kind: "needs-review";
3428
+ attempt: string;
3429
+ } | {
3430
+ kind: "retryable";
3431
+ attempt: string;
3432
+ };
3433
+ completed: boolean;
3434
+ completion: {
3435
+ kind: "streak";
3436
+ days: number;
3437
+ timeZone: string;
3438
+ } | {
3439
+ kind: "once";
3440
+ } | {
3441
+ kind: "keyed";
3442
+ };
3443
+ completionCount: number;
3444
+ visibility: "visible" | "hidden";
3445
+ missing: {
3446
+ quest: string;
3447
+ title: string;
3448
+ }[];
3449
+ attempt: {
3450
+ id: string;
3451
+ release: string;
3452
+ quest: string;
3453
+ member: string;
3454
+ evidence: string | null;
3455
+ status: "failed" | "queued" | "evaluating" | "accepted" | "progressed" | "rejected" | "needs-review";
3456
+ reason: string | null;
3457
+ retries: number;
3458
+ generation: number;
3459
+ completion: string | null;
3460
+ reviewRewards: ({
3461
+ kind: "tier";
3462
+ reward: {
3463
+ id: string;
3464
+ title: string;
3465
+ tiers: {
3466
+ id: string;
3467
+ title: string;
3468
+ }[];
3469
+ inventory: {
3470
+ kind: "untracked";
3471
+ };
3472
+ fulfillment: {
3473
+ kind: "staff-handover";
3474
+ };
3475
+ };
3476
+ tier: string;
3477
+ } | {
3478
+ kind: "points";
3479
+ balance: string;
3480
+ amount: number;
3481
+ } | {
3482
+ kind: "integration";
3483
+ provider: "discord";
3484
+ action: "grant-role";
3485
+ roleId: string;
3486
+ })[] | null;
3487
+ createdAt: number;
3488
+ input?: {
3489
+ kind: "quiz";
3490
+ answers: {
3491
+ [k: string]: string;
3492
+ };
3493
+ release?: string | undefined;
3494
+ } | undefined;
3495
+ } | null;
3496
+ release: string;
3497
+ interaction: "quiz" | "photo" | "staff" | "automatic" | "claim";
3498
+ lifecycle: "paused" | "active" | "archived";
3499
+ rewards: {
3500
+ label: string;
3501
+ }[];
3502
+ key?: string | undefined;
3503
+ streak?: {
3504
+ goal: number;
3505
+ current: number;
3506
+ best: number;
3507
+ today: string;
3508
+ todayQualified: boolean;
3509
+ timeZone: string;
3510
+ nextBoundary: number;
3511
+ pendingTimeZone: {
3512
+ timeZone: string;
3513
+ effectiveAt: number;
3514
+ } | null;
3515
+ days: {
3516
+ day: number;
3517
+ date: string;
3518
+ timeZone: string;
3519
+ occurredAt: number;
3520
+ }[];
3521
+ milestone: {
3522
+ status: "pending";
3523
+ } | {
3524
+ status: "awarded";
3525
+ completion: string;
3526
+ achievedAt: number;
3527
+ } | {
3528
+ status: "budget-exhausted";
3529
+ budget: string;
3530
+ achievedAt: number;
3531
+ };
3532
+ } | null | undefined;
3533
+ };
3534
+ /** Input recovered after the quest changed. Prefill the form with it. */
3535
+ draft: SubmissionDraft | null;
3536
+ notice: QuestNotice;
3537
+ error: string | null;
3538
+ busy: boolean;
3539
+ saved: SavedSubmission;
3540
+ /** The attempt the last "received" notice is about. */
3541
+ receipt: string | null;
3542
+ startingFresh: boolean;
3543
+ restart: () => Promise<void>;
3544
+ submit: (input: QuestInput) => Promise<void>;
3545
+ /** Finish an interrupted submission, or reopen an outdated draft. */
3546
+ resume: () => Promise<void>;
3547
+ /**
3548
+ * Re-run verification that failed to run. Never creates a new attempt.
3549
+ * Domino refuses this for automatic quests, so never offer it for them.
3550
+ */
3551
+ retry: () => Promise<void>;
3552
+ };
3553
+
3554
+ type QuestTone = "open" | "done" | "waiting" | "attention" | "locked" | "off";
3555
+ type QuestStatus = {
3556
+ tone: QuestTone;
3557
+ label: string;
3558
+ detail?: string;
3559
+ };
3560
+ /**
3561
+ * True when nothing more can happen on this quest for the participant.
3562
+ * `completed` only says it was ever completed; a repeatable (keyed) quest
3563
+ * keeps running after that, so it is never finished.
3564
+ */
3565
+ declare function isFinished(view: QuestView): boolean;
3566
+ /**
3567
+ * True for every quest Domino runs by itself. The server or an operator owns
3568
+ * each run, including a retry after a failure, so the participant gets a
3569
+ * status and nothing to press.
3570
+ */
3571
+ declare function isAutomatic(view: QuestView): boolean;
3572
+ /**
3573
+ * True for automatic quests driven by observed activity, possibly many times
3574
+ * and without telling the participant. They read "Automatic", not "In progress".
3575
+ */
3576
+ declare function runsSilently(view: QuestView): boolean;
3577
+ /** "Completed 3 times" for repeatable quests, otherwise nothing. */
3578
+ declare function completionCountLabel(view: QuestView): string | null;
3579
+ /**
3580
+ * True when a repeatable quest's latest submission was accepted. The quest is
3581
+ * open again, so show the normal submit action rather than a finished state.
3582
+ */
3583
+ declare function canRepeat(view: QuestView): boolean;
3584
+ /** Hidden quests run in the background and are never listed. */
3585
+ declare function visibleQuests<T extends Pick<QuestView, "visibility">>(quests: T[]): T[];
3586
+ /** Turns a QuestView into words. Pure, so copy changes stay in one place. */
3587
+ declare function questStatus(view: QuestView): QuestStatus;
3588
+ /** True when the participant can submit something right now. */
3589
+ declare function canSubmit(view: QuestView): boolean;
3590
+ declare function progressOf(quests: QuestView[]): {
3591
+ total: number;
3592
+ done: number;
3593
+ };
3594
+
3595
+ type OAuthProvider = AuthProvider;
3596
+ type SignInMethods = {
3597
+ providers: OAuthProvider[];
3598
+ email: boolean;
3599
+ };
3600
+ /** Sign-in methods this project has configured in Console. */
3601
+ declare function useSignInMethods(): SignInMethods | null;
3602
+ /** Email codes and OAuth consent always happen in the participant's browser. */
3603
+ declare function useSignIn(): {
3604
+ busy: boolean;
3605
+ error: string | null;
3606
+ /** True once a code was sent and the form should ask for it. */
3607
+ codeSent: boolean;
3608
+ sendCode: (email: string) => Promise<void>;
3609
+ verifyCode: (code: string) => Promise<void>;
3610
+ startOver: () => void;
3611
+ withProvider: (provider: OAuthProvider) => Promise<void>;
3612
+ };
3613
+ declare function useSignOut(): {
3614
+ busy: boolean;
3615
+ signOut: () => Promise<void>;
3616
+ };
3617
+
3618
+ /** True when the account can be used to verify quests right now. */
3619
+ declare function isConnected(accounts: AccountConnection[] | null, provider: AuthProvider): boolean;
3620
+ /**
3621
+ * The signed-in participant's connected accounts (X, Discord, Google, Apple).
3622
+ *
3623
+ * Connecting leaves the page for the provider's consent screen and comes back
3624
+ * connected. The list is read again when the window regains focus and after
3625
+ * any disconnect in this tab, so every component using it stays in step.
3626
+ */
3627
+ declare function useAccounts(): {
3628
+ /** Null until read, and while nobody is signed in. */
3629
+ accounts: {
3630
+ provider: "discord" | "google" | "apple" | "x";
3631
+ configured: boolean;
3632
+ status: "disconnected" | "connected" | "reconnect";
3633
+ subject: string | null;
3634
+ revision: number;
3635
+ }[] | null;
3636
+ error: string | null;
3637
+ busy: boolean;
3638
+ refresh: () => Promise<void>;
3639
+ isConnected: (provider: AuthProvider) => boolean;
3640
+ connect: (provider: AuthProvider) => Promise<void>;
3641
+ disconnect: (provider: AuthProvider) => Promise<void>;
3642
+ };
3643
+
3644
+ type ReferralSummary = z.infer<typeof referralSummarySchema>;
3645
+ /**
3646
+ * Keeps an invitation code from the landing URL (`?ref=CODE` by default)
3647
+ * through sign-in, including the round trip to an OAuth provider.
3648
+ * Returns the code waiting to be accepted, if any.
3649
+ */
3650
+ declare function captureReferralCode(param?: string): string | null;
3651
+ type Invitation = {
3652
+ status: "none";
3653
+ } | {
3654
+ status: "pending";
3655
+ code: string;
3656
+ } | {
3657
+ status: "accepting";
3658
+ code: string;
3659
+ } | {
3660
+ status: "accepted";
3661
+ code: string;
3662
+ } | {
3663
+ status: "rejected";
3664
+ code: string;
3665
+ reason: string;
3666
+ } | {
3667
+ status: "failed";
3668
+ code: string;
3669
+ reason: string;
3670
+ };
3671
+ /**
3672
+ * Accepts the invitation the participant arrived with, as soon as they are
3673
+ * signed in. Render it once near the app root so the code survives sign-in.
3674
+ *
3675
+ * Domino rejects self-referrals, cycles, codes from another project, and
3676
+ * invitations accepted after the participant's first completion. Show the
3677
+ * reason; `accept(code)` also serves a manual "Have a code?" input.
3678
+ */
3679
+ declare function useInvitation(param?: string): {
3680
+ invitation: Invitation;
3681
+ accept: (code: string) => Promise<void>;
3682
+ };
3683
+ /**
3684
+ * The signed-in participant's invitation code, share link, and progress:
3685
+ * attributed friends, qualified friends per program, milestones, and points.
3686
+ */
3687
+ declare function useReferralSummary(options?: {
3688
+ path?: string;
3689
+ param?: string;
3690
+ }): {
3691
+ summary: {
3692
+ code: string;
3693
+ attributed: number;
3694
+ programs: {
3695
+ definition: {
3696
+ id: string;
3697
+ title: string;
3698
+ enabled: boolean;
3699
+ qualification: {
3700
+ kind: "signup";
3701
+ } | {
3702
+ kind: "quest";
3703
+ quest: string;
3704
+ } | {
3705
+ kind: "external";
3706
+ };
3707
+ rewards: {
3708
+ inviter: ({
3709
+ kind: "tier";
3710
+ reward: {
3711
+ id: string;
3712
+ title: string;
3713
+ tiers: {
3714
+ id: string;
3715
+ title: string;
3716
+ }[];
3717
+ inventory: {
3718
+ kind: "untracked";
3719
+ };
3720
+ fulfillment: {
3721
+ kind: "staff-handover";
3722
+ };
3723
+ };
3724
+ tier: string;
3725
+ } | {
3726
+ kind: "points";
3727
+ balance: string;
3728
+ amount: number;
3729
+ })[];
3730
+ invitee: ({
3731
+ kind: "tier";
3732
+ reward: {
3733
+ id: string;
3734
+ title: string;
3735
+ tiers: {
3736
+ id: string;
3737
+ title: string;
3738
+ }[];
3739
+ inventory: {
3740
+ kind: "untracked";
3741
+ };
3742
+ fulfillment: {
3743
+ kind: "staff-handover";
3744
+ };
3745
+ };
3746
+ tier: string;
3747
+ } | {
3748
+ kind: "points";
3749
+ balance: string;
3750
+ amount: number;
3751
+ })[];
3752
+ };
3753
+ milestones: {
3754
+ id: string;
3755
+ count: number;
3756
+ rewards: ({
3757
+ kind: "tier";
3758
+ reward: {
3759
+ id: string;
3760
+ title: string;
3761
+ tiers: {
3762
+ id: string;
3763
+ title: string;
3764
+ }[];
3765
+ inventory: {
3766
+ kind: "untracked";
3767
+ };
3768
+ fulfillment: {
3769
+ kind: "staff-handover";
3770
+ };
3771
+ };
3772
+ tier: string;
3773
+ } | {
3774
+ kind: "points";
3775
+ balance: string;
3776
+ amount: number;
3777
+ })[];
3778
+ }[];
3779
+ bonuses: {
3780
+ id: string;
3781
+ balance: string;
3782
+ basisPoints: number;
3783
+ external: boolean;
3784
+ quests?: string[] | undefined;
3785
+ durationDays?: number | undefined;
3786
+ maxPoints?: number | undefined;
3787
+ }[];
3788
+ key?: string | undefined;
3789
+ inviterGroup?: string | undefined;
3790
+ };
3791
+ qualified: number;
3792
+ milestones: {
3793
+ id: string;
3794
+ count: number;
3795
+ reached: boolean;
3796
+ }[];
3797
+ }[];
3798
+ accounts: {
3799
+ id: string;
3800
+ program: string;
3801
+ kind: "milestone" | "fixed" | "bonus";
3802
+ balance: string;
3803
+ earned: number;
3804
+ settled: number;
3805
+ outstanding: number;
3806
+ }[];
3807
+ } | null;
3808
+ link: string | null;
3809
+ error: string | null;
3810
+ refresh: () => Promise<void>;
3811
+ };
3812
+
3813
+ type LeaderboardState = {
3814
+ status: "loading";
3815
+ } | {
3816
+ status: "error";
3817
+ message: string;
3818
+ } | {
3819
+ status: "ready";
3820
+ page: LeaderboardPage;
3821
+ stale: string | null;
3822
+ };
3823
+ /**
3824
+ * One leaderboard's top rows plus the participant's own row and neighbours.
3825
+ *
3826
+ * Read again every `intervalMs` while the page is visible, and when the
3827
+ * participant signs in or out. Boards default to participants-only access:
3828
+ * signed-out visitors see an error unless the board is published as public.
3829
+ */
3830
+ declare function useLeaderboard(board: string, options?: {
3831
+ limit?: number;
3832
+ intervalMs?: number;
3833
+ }): {
3834
+ refresh: () => Promise<void>;
3835
+ status: "loading";
3836
+ } | {
3837
+ refresh: () => Promise<void>;
3838
+ status: "error";
3839
+ message: string;
3840
+ } | {
3841
+ refresh: () => Promise<void>;
3842
+ status: "ready";
3843
+ page: LeaderboardPage;
3844
+ stale: string | null;
3845
+ };
3846
+
3847
+ export { type Collection, type Experience, type Invitation, type LeaderboardState, type OAuthProvider, PENDING_POLL_MS, type QuestInput, type QuestNotice, type QuestStatus, type QuestTone, RETRY_DELAYS_MS, type ReferralSummary, type RelayClient, RelayProvider, type RoleDelivery, type SavedSubmission, canRepeat, canSubmit, captureReferralCode, completionCountLabel, completionMark, hasPending, isAutomatic, isConnected, isFinished, progressOf, questGroups, questStatus, roleDeliveryLabel, runsSilently, sanitizeDeliveries, useAccounts, useExperience, useInvitation, useLeaderboard, useQuest, useReferralSummary, useRelay, useSignIn, useSignInMethods, useSignOut, visibleQuests, watchRoleDeliveries };