@domino-sdk/relay 0.14.1 → 0.16.1

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