@domino-sdk/relay 0.17.2 → 0.18.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,1511 @@
1
+ // src/content.ts
2
+ import { z as z3 } from "zod";
3
+
4
+ // src/identifier.ts
5
+ import { z } from "zod";
6
+ var identifier = z.string().min(1).max(100).regex(/^[a-zA-Z0-9_-]+$/);
7
+
8
+ // src/trackers.ts
9
+ import { z as z2 } from "zod";
10
+ var timestamp = z2.number().int().safe().nonnegative().max(864e13);
11
+ var count = z2.number().int().safe().nonnegative();
12
+ var externalId = z2.string().min(1).max(256);
13
+ var metric = count.nullable().default(null);
14
+ var xTweetSchema = z2.looseObject({
15
+ id: externalId,
16
+ userId: externalId,
17
+ content: z2.string(),
18
+ createdAt: z2.iso.datetime({ offset: true }),
19
+ author: z2.looseObject({
20
+ id: externalId,
21
+ username: z2.string(),
22
+ name: z2.string(),
23
+ verified: z2.boolean().nullable().default(null)
24
+ }),
25
+ likeCount: metric,
26
+ replyCount: metric,
27
+ retweetCount: metric,
28
+ quoteCount: metric,
29
+ viewCount: metric,
30
+ bookmarkCount: metric,
31
+ isReply: z2.boolean(),
32
+ isRetweet: z2.boolean(),
33
+ isQuoteTweet: z2.boolean()
34
+ });
35
+ var xContentBodySchema = z2.strictObject({
36
+ version: z2.literal(1),
37
+ id: z2.string().min(1),
38
+ authorId: z2.string().min(1),
39
+ publishedAt: timestamp,
40
+ text: z2.string(),
41
+ isReply: z2.boolean(),
42
+ isRetweet: z2.boolean(),
43
+ isQuoteTweet: z2.boolean(),
44
+ media: z2.array(z2.strictObject({ type: z2.string(), url: z2.string() })).nullable(),
45
+ mentionedAuthorIds: z2.array(z2.string().min(1)).nullable(),
46
+ videoLengthSeconds: z2.number().nonnegative().nullable(),
47
+ references: z2.strictObject({
48
+ replyId: z2.string().nullable(),
49
+ replyAuthorId: z2.string().nullable(),
50
+ quoteId: z2.string().nullable(),
51
+ quoteAuthorId: z2.string().nullable(),
52
+ repostId: z2.string().nullable(),
53
+ repostAuthorId: z2.string().nullable()
54
+ })
55
+ });
56
+ var trackerContentQuerySchema = z2.strictObject({
57
+ id: externalId,
58
+ observation: z2.string().regex(/^observation_[a-f0-9]{64}$/)
59
+ });
60
+ var trackerContentReadSchema = trackerContentQuerySchema.extend({
61
+ member: identifier
62
+ });
63
+ var attributionContext = { member: identifier, capturedAt: timestamp };
64
+ var trackerEvidenceSchema = z2.strictObject({
65
+ contentRevision: identifier,
66
+ observation: identifier
67
+ });
68
+ var trackerContentSchema = z2.strictObject({
69
+ tracker: identifier,
70
+ source: z2.literal("x"),
71
+ evidence: trackerEvidenceSchema,
72
+ content: xContentBodySchema,
73
+ observedAt: timestamp,
74
+ removed: z2.boolean(),
75
+ attribution: z2.discriminatedUnion("kind", [
76
+ z2.strictObject({
77
+ ...attributionContext,
78
+ kind: z2.literal("linked"),
79
+ account: z2.strictObject({
80
+ provider: z2.literal("x"),
81
+ issuer: z2.string().min(1),
82
+ subject: externalId,
83
+ revision: count,
84
+ linkedAt: timestamp.nullable()
85
+ })
86
+ }),
87
+ z2.strictObject({ ...attributionContext, kind: z2.literal("unlinked") }),
88
+ z2.strictObject({
89
+ ...attributionContext,
90
+ kind: z2.literal("different-author")
91
+ })
92
+ ])
93
+ });
94
+ var trackerSourceSchema = z2.discriminatedUnion("kind", [
95
+ z2.object({
96
+ kind: z2.literal("x-search"),
97
+ query: z2.string().trim().min(1).max(2e3)
98
+ }).strict(),
99
+ z2.object({ kind: z2.literal("custom"), namespace: identifier }).strict()
100
+ ]);
101
+ var x = {
102
+ search: (input) => trackerSourceSchema.options[0].parse({ kind: "x-search", ...input })
103
+ };
104
+ var customSource = (namespace) => trackerSourceSchema.options[1].parse({ kind: "custom", namespace });
105
+ var windowSchema = z2.object({ start: timestamp, end: timestamp.optional() }).strict().refine(
106
+ (w) => w.end === void 0 || w.end > w.start,
107
+ "End must follow start"
108
+ );
109
+ var trackerDefinitionSchema = z2.object({
110
+ key: identifier,
111
+ title: z2.string().trim().min(1).max(120),
112
+ source: trackerSourceSchema,
113
+ window: windowSchema,
114
+ refreshSeconds: z2.number().int().min(300).max(86400).default(21600),
115
+ maxPages: z2.number().int().min(1).max(1e3).default(60)
116
+ }).strict();
117
+ var trackerArtifactSchema = z2.union([
118
+ trackerDefinitionSchema,
119
+ z2.object({ code: z2.string().min(1).max(2e6) }).strict()
120
+ ]);
121
+ function defineTracker(input) {
122
+ return trackerDefinitionSchema.parse(input);
123
+ }
124
+ var publishedTrackerSchema = z2.object({
125
+ id: identifier,
126
+ version: identifier,
127
+ definition: trackerDefinitionSchema,
128
+ publishedAt: timestamp,
129
+ actor: z2.string().nullable()
130
+ });
131
+ var trackerStatusSchema = z2.object({
132
+ published: publishedTrackerSchema,
133
+ paused: z2.boolean(),
134
+ state: z2.enum(["idle", "syncing", "error", "complete"]),
135
+ lastStartedAt: timestamp.nullable(),
136
+ lastCompletedAt: timestamp.nullable(),
137
+ nextSyncAt: timestamp.nullable(),
138
+ coverage: z2.enum(["unknown", "partial", "complete"]),
139
+ error: z2.string().nullable(),
140
+ records: count
141
+ });
142
+ var trackerControlSchema = z2.object({
143
+ actionId: identifier,
144
+ action: z2.enum(["pause", "resume", "refresh"])
145
+ }).strict();
146
+ var trackerRecordInputSchema = z2.object({
147
+ id: externalId,
148
+ occurredAt: timestamp,
149
+ observedAt: timestamp,
150
+ author: z2.object({
151
+ id: externalId,
152
+ verified: z2.boolean().nullable().default(null)
153
+ }).strict().nullable().default(null),
154
+ data: z2.record(z2.string(), z2.json()),
155
+ removed: z2.boolean().default(false)
156
+ }).strict().refine(
157
+ (v) => new TextEncoder().encode(JSON.stringify(v.data)).byteLength <= 131072,
158
+ "Record exceeds 128 KB"
159
+ );
160
+ var trackerRecordSchema = trackerRecordInputSchema.safeExtend({
161
+ source: z2.string(),
162
+ firstSeenAt: timestamp,
163
+ /** Present only when includeEvidence is true; custom sources have no X evidence. */
164
+ evidence: trackerEvidenceSchema.nullable().optional()
165
+ });
166
+ var trackerIngestSchema = z2.object({
167
+ actionId: identifier,
168
+ records: z2.array(trackerRecordInputSchema).min(1).max(100)
169
+ }).strict();
170
+ var trackerIngestResultSchema = z2.object({ stored: count });
171
+ var booleanQuery = z2.union([
172
+ z2.boolean(),
173
+ z2.enum(["true", "false"]).transform((v) => v === "true")
174
+ ]);
175
+ var trackerQuerySchema = z2.object({
176
+ author: externalId.optional(),
177
+ member: identifier.optional(),
178
+ verified: booleanQuery.optional(),
179
+ since: z2.coerce.number().int().safe().nonnegative().optional(),
180
+ until: z2.coerce.number().int().safe().nonnegative().optional(),
181
+ removed: booleanQuery.default(false),
182
+ minLikes: z2.coerce.number().int().safe().nonnegative().optional(),
183
+ minViews: z2.coerce.number().int().safe().nonnegative().optional(),
184
+ limit: z2.coerce.number().int().min(1).max(100).default(25),
185
+ cursor: z2.string().max(2048).optional(),
186
+ includeEvidence: booleanQuery.optional()
187
+ }).strict().refine(
188
+ (q) => q.since === void 0 || q.until === void 0 || q.until > q.since,
189
+ "Until must follow since"
190
+ );
191
+ var trackerPageSchema = z2.object({
192
+ tracker: identifier,
193
+ items: z2.array(trackerRecordSchema),
194
+ nextCursor: z2.string().nullable(),
195
+ total: count,
196
+ status: trackerStatusSchema
197
+ });
198
+ var trackerSummarySchema = z2.object({
199
+ records: count,
200
+ authors: count,
201
+ metrics: z2.object({
202
+ likes: count,
203
+ replies: count,
204
+ reposts: count,
205
+ quotes: count,
206
+ views: count,
207
+ bookmarks: count
208
+ }),
209
+ missingMetrics: count,
210
+ status: trackerStatusSchema
211
+ });
212
+ var trackerPreviewLimits = {
213
+ pages: 3,
214
+ posts: 100,
215
+ days: 30
216
+ };
217
+ var trackerPreviewInputSchema = z2.object({
218
+ query: trackerSourceSchema.options[0].shape.query,
219
+ /** Start of the searched window. The window ends when the sample is fetched. */
220
+ since: timestamp
221
+ }).strict();
222
+ var trackerPreviewSchema = z2.object({
223
+ query: z2.string(),
224
+ since: timestamp,
225
+ fetchedAt: timestamp,
226
+ pages: count,
227
+ /** Every match in the sample, newest first, verified or not. */
228
+ posts: z2.array(xTweetSchema).max(trackerPreviewLimits.posts),
229
+ /** X had more matches than the sample holds. */
230
+ more: z2.boolean()
231
+ });
232
+
233
+ // src/content.ts
234
+ var timestamp2 = z3.number().int().safe().nonnegative().max(864e13);
235
+ var contentPolicySchema = z3.strictObject({
236
+ tracker: identifier,
237
+ window: trackerDefinitionSchema.shape.window,
238
+ enrollment: z3.enum(["none", "required"]).default("none"),
239
+ posts: z3.enum(["after-enrollment", "since-start"]).default("after-enrollment"),
240
+ historical: z3.enum(["automatic", "claim", "staff"]).default("claim")
241
+ });
242
+ function content(tracker, policy = {}) {
243
+ if (tracker.source.kind !== "x-search") {
244
+ throw new Error("Content quests require an X tracker");
245
+ }
246
+ return {
247
+ kind: "automatic",
248
+ content: contentPolicySchema.parse({
249
+ tracker: tracker.key,
250
+ window: tracker.window,
251
+ ...policy
252
+ })
253
+ };
254
+ }
255
+ var admittedContentSchema = xContentBodySchema.extend({
256
+ tracker: identifier,
257
+ revision: identifier,
258
+ observation: identifier,
259
+ attribution: trackerContentSchema.shape.attribution.options[0],
260
+ enrolledAt: timestamp2.nullable(),
261
+ completionKey: z3.string().min(1).max(200)
262
+ });
263
+ function perContent() {
264
+ return {
265
+ kind: "keyed",
266
+ perContent: true,
267
+ key: (ctx) => {
268
+ if (!ctx.content) {
269
+ throw new Error("perContent requires an admitted content item");
270
+ }
271
+ return ctx.content.completionKey;
272
+ }
273
+ };
274
+ }
275
+ var contentEnrollmentInputSchema = z3.strictObject({
276
+ actionId: identifier,
277
+ quest: identifier,
278
+ member: identifier
279
+ });
280
+ var contentEnrollmentSchema = z3.strictObject({
281
+ quest: identifier,
282
+ member: identifier,
283
+ enrolledAt: timestamp2
284
+ });
285
+ var contentReleaseInputSchema = contentEnrollmentInputSchema.extend({
286
+ content: z3.string().min(1).max(256)
287
+ });
288
+ var contentAdmissionSchema = z3.strictObject({
289
+ quest: identifier,
290
+ content: z3.string().min(1).max(256),
291
+ release: identifier,
292
+ state: z3.enum(["pending", "admitted", "excluded"]),
293
+ reason: z3.string().nullable(),
294
+ attempt: identifier.nullable()
295
+ });
296
+ var contentAdmissionQuerySchema = z3.strictObject({
297
+ quest: identifier,
298
+ member: identifier.optional(),
299
+ content: z3.string().min(1).max(256).optional(),
300
+ after: z3.string().min(1).max(256).optional()
301
+ });
302
+ var contentAdmissionPageSchema = z3.strictObject({
303
+ items: z3.array(contentAdmissionSchema),
304
+ next: z3.string().nullable()
305
+ });
306
+ function isContentParticipantRoute(path, method) {
307
+ return method === "GET" && (path === "/v1/content/admissions" || path === "/v1/content/qualifications" || path === "/v1/content/performance" || path === "/v1/engagement/history" || path === "/v1/engagement/boundaries") || method === "POST" && (path === "/v1/content/enrollments" || path === "/v1/content/claims");
308
+ }
309
+ var contentQualificationDecisionSchema = z3.strictObject({
310
+ kind: z3.enum(["accept", "reject", "review", "superseded"]),
311
+ reason: z3.string().nullable()
312
+ });
313
+ var contentQualificationQuerySchema = z3.strictObject({
314
+ quest: identifier,
315
+ member: identifier.optional(),
316
+ content: z3.string().min(1).max(256).optional(),
317
+ before: z3.coerce.number().int().positive().safe().optional()
318
+ });
319
+ var contentQualificationSchema = z3.strictObject({
320
+ quest: identifier,
321
+ content: z3.string(),
322
+ member: identifier,
323
+ release: identifier,
324
+ attempt: identifier,
325
+ revision: identifier,
326
+ observation: identifier,
327
+ current: z3.boolean(),
328
+ state: z3.enum([
329
+ "pending",
330
+ "qualified",
331
+ "unqualified",
332
+ "needs-review",
333
+ "failed",
334
+ "superseded",
335
+ "stale",
336
+ "blocked",
337
+ "unavailable"
338
+ ]),
339
+ reason: z3.string().nullable(),
340
+ reward: z3.strictObject({
341
+ attempt: identifier.nullable(),
342
+ completion: identifier.nullable(),
343
+ state: z3.enum(["unresolved", "awarded", "excluded"])
344
+ })
345
+ });
346
+ var contentQualificationPageSchema = z3.strictObject({
347
+ items: z3.array(contentQualificationSchema),
348
+ next: z3.number().int().positive().safe().nullable()
349
+ });
350
+ var contentMetricSchema = z3.enum([
351
+ "likes",
352
+ "replies",
353
+ "reposts",
354
+ "quotes",
355
+ "views",
356
+ "bookmarks"
357
+ ]);
358
+ var contentMetricsSchema = z3.partialRecord(
359
+ contentMetricSchema,
360
+ z3.number().int().safe().nonnegative()
361
+ );
362
+ var contentPerformancePolicySchema = z3.strictObject({
363
+ metrics: z3.array(contentMetricSchema).min(1).max(6).refine(
364
+ (values) => new Set(values).size === values.length,
365
+ "Metrics must be unique"
366
+ ),
367
+ maxAgeMs: z3.number().int().positive().max(864e5).default(36e5)
368
+ });
369
+
370
+ // src/streaks.ts
371
+ import { z as z4 } from "zod";
372
+ var communityTimeZoneSchema = z4.string().min(1).max(100).refine((zone) => {
373
+ try {
374
+ if (/^[+-]/.test(zone)) {
375
+ return false;
376
+ }
377
+ new Intl.DateTimeFormat("en", { timeZone: zone });
378
+ return true;
379
+ } catch {
380
+ return false;
381
+ }
382
+ }, "Use an IANA community timezone, such as Europe/Budapest");
383
+ var streakPolicySchema = z4.object({
384
+ kind: z4.literal("streak"),
385
+ days: z4.number().int().min(1).max(3650),
386
+ timeZone: communityTimeZoneSchema
387
+ }).strict();
388
+ var streak = (options) => streakPolicySchema.parse({ kind: "streak", ...options });
389
+ var streakProgressSchema = z4.object({
390
+ goal: z4.number().int().positive(),
391
+ current: z4.number().int().nonnegative(),
392
+ best: z4.number().int().nonnegative(),
393
+ today: z4.string(),
394
+ todayQualified: z4.boolean(),
395
+ timeZone: communityTimeZoneSchema,
396
+ nextBoundary: z4.number().int(),
397
+ pendingTimeZone: z4.object({
398
+ timeZone: communityTimeZoneSchema,
399
+ effectiveAt: z4.number().int()
400
+ }).nullable(),
401
+ days: z4.array(
402
+ z4.object({
403
+ day: z4.number().int(),
404
+ date: z4.string(),
405
+ timeZone: communityTimeZoneSchema,
406
+ occurredAt: z4.number().int()
407
+ })
408
+ ),
409
+ milestone: z4.discriminatedUnion("status", [
410
+ z4.object({ status: z4.literal("pending") }),
411
+ z4.object({
412
+ status: z4.literal("awarded"),
413
+ completion: z4.string(),
414
+ achievedAt: z4.number().int()
415
+ }),
416
+ z4.object({
417
+ status: z4.literal("budget-exhausted"),
418
+ budget: z4.string(),
419
+ achievedAt: z4.number().int()
420
+ })
421
+ ])
422
+ });
423
+
424
+ // src/observations.ts
425
+ import { z as z5 } from "zod";
426
+ var name = z5.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,199}$/);
427
+ var observationInputSchema = z5.object({
428
+ id: name,
429
+ source: name,
430
+ type: name,
431
+ member: identifier,
432
+ actor: z5.object({ provider: identifier, subject: z5.string().min(1).max(200) }).strict().optional(),
433
+ occurredAt: z5.number().int().nonnegative().max(864e13),
434
+ data: z5.record(z5.string(), z5.json())
435
+ }).strict().refine(
436
+ (value) => JSON.stringify(value.data).length <= 32768,
437
+ "Observation data exceeds 32 KB"
438
+ );
439
+ var observationSchema = observationInputSchema.safeExtend({
440
+ receivedAt: z5.number().int().nonnegative()
441
+ });
442
+ var observationTriggerSchema = z5.object({ source: name, type: name }).strict();
443
+ var completionPolicySchema = z5.discriminatedUnion("kind", [
444
+ streakPolicySchema,
445
+ z5.object({ kind: z5.literal("once") }).strict(),
446
+ z5.object({ kind: z5.literal("keyed") }).strict()
447
+ ]);
448
+ var completionKeySchema = z5.string().min(1).max(500);
449
+ var budgetSchema = z5.object({
450
+ id: name,
451
+ scope: z5.enum(["member", "project"]),
452
+ period: z5.enum(["lifetime", "day"]),
453
+ limit: z5.number().int().positive().max(Number.MAX_SAFE_INTEGER),
454
+ cost: z5.union([
455
+ z5.number().int().positive().max(Number.MAX_SAFE_INTEGER),
456
+ z5.object({ balance: name }).strict()
457
+ ])
458
+ }).strict();
459
+ var observationReceiptSchema = z5.object({
460
+ id: name,
461
+ source: name,
462
+ attempts: z5.array(z5.string()),
463
+ receivedAt: z5.number()
464
+ });
465
+ var discordReactionSchema = z5.object({
466
+ guildId: z5.string(),
467
+ channelId: z5.string(),
468
+ messageId: z5.string(),
469
+ userId: z5.string(),
470
+ messageAuthorId: z5.string().nullable().default(null),
471
+ actorRoles: z5.array(z5.string()).default([]),
472
+ emoji: z5.object({ id: z5.string().nullable(), name: z5.string() }),
473
+ messagePublishedAt: z5.number()
474
+ }).strict();
475
+ var discordMessageSchema = z5.object({
476
+ guildId: z5.string(),
477
+ channelId: z5.string(),
478
+ messageId: z5.string(),
479
+ userId: z5.string(),
480
+ content: z5.string().nullable(),
481
+ replyTo: z5.string().nullable(),
482
+ publishedAt: z5.number()
483
+ }).strict();
484
+
485
+ // src/integrations.ts
486
+ import { z as z6 } from "zod";
487
+ var integrationProviderSchema = z6.enum(["discord"]);
488
+ var discordServerSchema = z6.object({
489
+ id: z6.string().regex(/^[0-9]{1,20}$/),
490
+ name: z6.string().min(1),
491
+ icon: z6.string().nullable()
492
+ });
493
+ var projectIntegrationSchema = z6.object({
494
+ provider: integrationProviderSchema,
495
+ configured: z6.boolean(),
496
+ status: z6.enum(["disconnected", "ready", "attention"]),
497
+ revision: z6.number().int().nonnegative(),
498
+ server: discordServerSchema.nullable(),
499
+ issue: z6.string().nullable(),
500
+ connectedAt: z6.number().default(0)
501
+ });
502
+
503
+ // src/accounts.ts
504
+ import { z as z7 } from "zod";
505
+ var authProviderSchema = z7.enum(["google", "apple", "x", "discord"]);
506
+ var accountConnectionSchema = z7.object({
507
+ provider: authProviderSchema,
508
+ configured: z7.boolean(),
509
+ status: z7.enum(["disconnected", "connected", "reconnect"]),
510
+ subject: z7.string().nullable(),
511
+ revision: z7.number().int().nonnegative()
512
+ });
513
+ var discordMemberInputSchema = z7.object({}).strict();
514
+ var discordMessageInputSchema = z7.object({
515
+ channelId: z7.string().regex(/^[0-9]{1,20}$/),
516
+ messageId: z7.string().regex(/^[0-9]{1,20}$/)
517
+ }).strict();
518
+ var discordMemberSchema = z7.object({
519
+ userId: z7.string().regex(/^[0-9]{1,20}$/).nullable().default(null),
520
+ nickname: z7.string().nullable().default(null),
521
+ displayName: z7.string().nullable().default(null),
522
+ boostingSince: z7.string().datetime({ offset: true }).nullable().default(null),
523
+ roles: z7.array(z7.string().regex(/^[0-9]{1,20}$/)),
524
+ joinedAt: z7.string().datetime({ offset: true }).nullable(),
525
+ pending: z7.boolean()
526
+ });
527
+
528
+ // src/submission-input.ts
529
+ import { z as z8 } from "zod";
530
+ var textOptionsSchema = z8.object({
531
+ required: z8.boolean().default(true),
532
+ minLength: z8.number().int().min(0).max(1e4).default(1),
533
+ maxLength: z8.number().int().min(1).max(1e4).default(1e4)
534
+ }).strict().refine(
535
+ (v) => v.minLength <= v.maxLength,
536
+ "minLength must not exceed maxLength"
537
+ );
538
+ var hostSchema = z8.string().min(1).max(253).refine((host) => {
539
+ if (!/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/i.test(host) || host.includes("..")) {
540
+ return false;
541
+ }
542
+ try {
543
+ const url = new URL(`https://${host}`);
544
+ return url.hostname === host.toLowerCase() && !url.port && !url.username && !url.password && url.pathname === "/" && !url.search && !url.hash;
545
+ } catch {
546
+ return false;
547
+ }
548
+ }, "Use a hostname without a scheme, path, port, or wildcard");
549
+ var urlOptionsSchema = z8.object({
550
+ required: z8.boolean().default(true),
551
+ allowedHosts: z8.array(hostSchema).min(1).max(100).optional()
552
+ }).strict();
553
+ var textEvidenceSchema = z8.object({ kind: z8.literal("text"), value: z8.string().max(1e4) }).strict();
554
+ var urlEvidenceSchema = z8.object({ kind: z8.literal("url"), value: z8.string().max(2048) }).strict();
555
+ var valueEvidenceSchema = z8.discriminatedUnion("kind", [
556
+ textEvidenceSchema,
557
+ urlEvidenceSchema
558
+ ]);
559
+ function validateSubmissionValue(input, contract) {
560
+ const maximum = input.kind === "text" ? 1e4 : 2048;
561
+ if (input.value.length > maximum) {
562
+ return `Enter no more than ${maximum} characters`;
563
+ }
564
+ if (input.kind !== contract.input) {
565
+ return `This quest requires ${contract.input} input`;
566
+ }
567
+ if (!input.value.trim()) {
568
+ return contract.constraints.required ? "This field is required" : null;
569
+ }
570
+ if (contract.input === "text") {
571
+ if (input.value.length < contract.constraints.minLength) {
572
+ return `Enter at least ${contract.constraints.minLength} characters`;
573
+ }
574
+ if (input.value.length > contract.constraints.maxLength) {
575
+ return `Enter no more than ${contract.constraints.maxLength} characters`;
576
+ }
577
+ return null;
578
+ }
579
+ const url = parseHttpUrl(input.value);
580
+ if (!url) {
581
+ return "Enter a valid HTTP or HTTPS URL without credentials";
582
+ }
583
+ if (contract.constraints.allowedHosts && !contract.constraints.allowedHosts.some(
584
+ (host) => host.toLowerCase() === url.hostname.toLowerCase()
585
+ )) {
586
+ return `Use a URL hosted on: ${contract.constraints.allowedHosts.join(", ")}`;
587
+ }
588
+ return null;
589
+ }
590
+ function parseHttpUrl(value) {
591
+ if (value !== value.trim() || /[\\\s]/.test(value) || !/^https?:\/\//i.test(value)) {
592
+ return null;
593
+ }
594
+ try {
595
+ const url = new URL(value);
596
+ return ["http:", "https:"].includes(url.protocol) && !url.username && !url.password ? url : null;
597
+ } catch {
598
+ return null;
599
+ }
600
+ }
601
+ function xPostId(value) {
602
+ const url = parseHttpUrl(value);
603
+ if (!url || url.port || ![
604
+ "x.com",
605
+ "www.x.com",
606
+ "twitter.com",
607
+ "www.twitter.com",
608
+ "mobile.twitter.com"
609
+ ].includes(url.hostname)) {
610
+ return null;
611
+ }
612
+ return /^\/(?:[A-Za-z0-9_]+|i\/web)\/status\/([0-9]{1,20})\/?$/.exec(
613
+ url.pathname
614
+ )?.[1] ?? null;
615
+ }
616
+
617
+ // src/quiz.ts
618
+ import { z as z9 } from "zod";
619
+ var quizId = z9.string().regex(/^[a-zA-Z0-9_-]+$/).max(100);
620
+ var quizChoiceSchema = z9.object({ id: quizId, label: z9.string().trim().min(1).max(500) }).strict();
621
+ var quizQuestionSchema = z9.object({
622
+ id: quizId,
623
+ prompt: z9.string().trim().min(1).max(1e3),
624
+ choices: z9.array(quizChoiceSchema).min(2).max(8).refine(
625
+ (choices) => new Set(choices.map((choice) => choice.id)).size === choices.length,
626
+ "Choice IDs must be unique"
627
+ )
628
+ }).strict();
629
+ var quizQuestionsSchema = z9.array(quizQuestionSchema).min(1).max(20).refine(
630
+ (questions) => new Set(questions.map((question) => question.id)).size === questions.length,
631
+ "Question IDs must be unique"
632
+ );
633
+ var quizContentSchema = z9.array(
634
+ quizQuestionSchema.extend({ correct: quizId }).refine(
635
+ (question) => question.choices.some((choice) => choice.id === question.correct),
636
+ "Choose a correct answer from the available choices"
637
+ )
638
+ ).min(1).max(20).refine(
639
+ (questions) => new Set(questions.map((question) => question.id)).size === questions.length,
640
+ "Question IDs must be unique"
641
+ );
642
+
643
+ // src/schema.ts
644
+ import { z as z12 } from "zod";
645
+
646
+ // src/settings.ts
647
+ import { z as z11 } from "zod";
648
+
649
+ // src/resources.ts
650
+ import { z as z10 } from "zod";
651
+ var channelSourceSchema = z10.object({
652
+ provider: z10.literal("discord"),
653
+ resource: z10.literal("channel"),
654
+ types: z10.array(z10.enum(["text", "announcement"])).min(1)
655
+ }).strict();
656
+ var resourceSourceSchema = z10.union([
657
+ z10.object({
658
+ provider: z10.literal("domino"),
659
+ resource: z10.literal("point-ledger")
660
+ }).strict(),
661
+ channelSourceSchema,
662
+ z10.object({
663
+ provider: z10.literal("discord"),
664
+ resource: z10.literal("role"),
665
+ assignable: z10.boolean().default(false)
666
+ }).strict()
667
+ ]);
668
+ var resourceRequestSchema = z10.object({
669
+ source: resourceSourceSchema,
670
+ query: z10.string().max(100).optional(),
671
+ cursor: z10.string().regex(/^\d{1,6}$/).optional(),
672
+ ids: z10.array(z10.string().min(1).max(100)).max(50).optional()
673
+ }).strict();
674
+ var resourceOptionsSchema = z10.object({
675
+ revision: z10.number().int(),
676
+ options: z10.array(
677
+ z10.object({
678
+ id: z10.string(),
679
+ label: z10.string(),
680
+ description: z10.string().optional(),
681
+ group: z10.string().optional(),
682
+ disabledReason: z10.string().optional()
683
+ })
684
+ ),
685
+ cursor: z10.string().nullable()
686
+ });
687
+ var discord = {
688
+ roles(options = {}) {
689
+ return resourceSourceSchema.parse({
690
+ provider: "discord",
691
+ resource: "role",
692
+ assignable: options.assignable ?? false
693
+ });
694
+ },
695
+ channels(options = {}) {
696
+ return resourceSourceSchema.parse({
697
+ provider: "discord",
698
+ resource: "channel",
699
+ types: options.types ?? ["text", "announcement"]
700
+ });
701
+ }
702
+ };
703
+ var pointLedgers = () => ({
704
+ provider: "domino",
705
+ resource: "point-ledger"
706
+ });
707
+
708
+ // src/settings.ts
709
+ var instant = z11.iso.datetime({ offset: true }).transform((value) => new Date(value).toISOString());
710
+ var resourceId = z11.union([z11.literal(""), z11.string().regex(/^\S{1,200}$/)]);
711
+ var base = { label: z11.string().min(1), description: z11.string().optional() };
712
+ var settingFieldSchema = z11.discriminatedUnion("kind", [
713
+ z11.object({ ...base, kind: z11.literal("point-ledger"), default: identifier }).strict(),
714
+ z11.object({ ...base, kind: z11.literal("datetime"), default: instant }).strict(),
715
+ z11.object({
716
+ ...base,
717
+ kind: z11.literal("resource"),
718
+ default: resourceId,
719
+ source: resourceSourceSchema
720
+ }).strict(),
721
+ z11.object({ ...base, kind: z11.literal("quiz"), default: quizContentSchema }).strict(),
722
+ z11.object({
723
+ ...base,
724
+ kind: z11.literal("text"),
725
+ default: z11.string(),
726
+ minLength: z11.number().int().nonnegative(),
727
+ maxLength: z11.number().int().positive(),
728
+ multiline: z11.boolean()
729
+ }).strict(),
730
+ z11.object({
731
+ ...base,
732
+ kind: z11.literal("integer"),
733
+ default: z11.number().int(),
734
+ min: z11.number().int(),
735
+ max: z11.number().int()
736
+ }).strict(),
737
+ z11.object({ ...base, kind: z11.literal("boolean"), default: z11.boolean() }).strict(),
738
+ z11.object({
739
+ ...base,
740
+ kind: z11.literal("choice"),
741
+ default: z11.string(),
742
+ options: z11.array(z11.string().min(1)).min(1)
743
+ }).strict()
744
+ ]);
745
+ var settingsFieldsSchema = z11.record(
746
+ z11.string().regex(/^[a-zA-Z][a-zA-Z0-9_]*$/),
747
+ settingFieldSchema
748
+ );
749
+ var settingsValuesSchema = z11.record(
750
+ z11.string(),
751
+ z11.union([z11.string(), z11.number().finite(), z11.boolean(), quizContentSchema])
752
+ );
753
+ var settings = {
754
+ pointLedger(options) {
755
+ const field = {
756
+ ...options,
757
+ kind: "point-ledger",
758
+ default: identifier.parse(options.default)
759
+ };
760
+ return identifier.default(field.default).meta(field);
761
+ },
762
+ datetime(options) {
763
+ const field = {
764
+ ...options,
765
+ kind: "datetime",
766
+ default: instant.parse(options.default)
767
+ };
768
+ return instant.default(field.default).meta(field);
769
+ },
770
+ resource(options) {
771
+ const field = {
772
+ ...options,
773
+ source: resourceSourceSchema.parse(options.source),
774
+ kind: "resource",
775
+ default: resourceId.parse(options.default ?? "")
776
+ };
777
+ return resourceId.default(field.default).meta(field);
778
+ },
779
+ quiz(options) {
780
+ const value = quizContentSchema.parse(options.default);
781
+ return quizContentSchema.default(value).meta({ ...options, default: value, kind: "quiz" });
782
+ },
783
+ text(options) {
784
+ const field = {
785
+ ...options,
786
+ kind: "text",
787
+ minLength: options.minLength ?? 1,
788
+ maxLength: options.maxLength ?? 2e3,
789
+ multiline: options.multiline ?? false
790
+ };
791
+ return z11.string().min(field.minLength).max(field.maxLength).default(field.default).meta(field);
792
+ },
793
+ integer(options) {
794
+ return z11.number().int().min(options.min).max(options.max).default(options.default).meta({ ...options, kind: "integer" });
795
+ },
796
+ boolean(options) {
797
+ return z11.boolean().default(options.default).meta({ ...options, kind: "boolean" });
798
+ },
799
+ choice(options) {
800
+ return z11.enum(options.options).default(options.default).meta({ ...options, kind: "choice" });
801
+ },
802
+ object(shape) {
803
+ return z11.object(shape).strict();
804
+ }
805
+ };
806
+ function parseSettings(fields, input) {
807
+ const shape = {};
808
+ for (const [key, field] of Object.entries(fields)) {
809
+ switch (field.kind) {
810
+ case "point-ledger":
811
+ shape[key] = identifier.default(field.default);
812
+ break;
813
+ case "datetime":
814
+ shape[key] = instant.default(field.default);
815
+ break;
816
+ case "resource":
817
+ shape[key] = resourceId.default(field.default);
818
+ break;
819
+ case "quiz":
820
+ shape[key] = quizContentSchema.default(field.default);
821
+ break;
822
+ case "text":
823
+ shape[key] = z11.string().min(field.minLength).max(field.maxLength).default(field.default);
824
+ break;
825
+ case "integer":
826
+ shape[key] = z11.number().int().min(field.min).max(field.max).default(field.default);
827
+ break;
828
+ case "boolean":
829
+ shape[key] = z11.boolean().default(field.default);
830
+ break;
831
+ case "choice":
832
+ shape[key] = z11.enum(field.options).default(field.default);
833
+ break;
834
+ }
835
+ }
836
+ return settingsValuesSchema.parse(z11.object(shape).strict().parse(input));
837
+ }
838
+ function missingResourceSettings(fields, values) {
839
+ return Object.entries(fields).filter(([key, field]) => field.kind === "resource" && !values[key]).map(([key]) => key);
840
+ }
841
+ function compatibleSettingKinds(previous, next) {
842
+ return previous.kind === next.kind || previous.kind === "text" && (next.kind === "resource" || next.kind === "datetime" || next.kind === "point-ledger");
843
+ }
844
+
845
+ // src/schema.ts
846
+ var pointsRewardSchema = z12.object({
847
+ kind: z12.literal("points").default("points"),
848
+ balance: identifier,
849
+ amount: z12.number().int().min(0).max(1e4)
850
+ }).strict();
851
+ var tieredRewardDefinitionSchema = z12.object({
852
+ id: identifier,
853
+ title: z12.string().min(1).max(120),
854
+ tiers: z12.array(
855
+ z12.object({ id: identifier, title: z12.string().min(1).max(120) }).strict()
856
+ ).min(1).max(20).refine(
857
+ (tiers) => new Set(tiers.map((t) => t.id)).size === tiers.length,
858
+ "Tier IDs must be unique"
859
+ ),
860
+ inventory: z12.object({ kind: z12.literal("untracked") }).strict(),
861
+ fulfillment: z12.object({ kind: z12.literal("staff-handover") }).strict()
862
+ }).strict();
863
+ var tierRewardSchema = z12.object({
864
+ kind: z12.literal("tier"),
865
+ reward: tieredRewardDefinitionSchema,
866
+ tier: identifier
867
+ }).strict().refine(
868
+ (value) => value.reward.tiers.some((t) => t.id === value.tier),
869
+ "Unknown reward tier"
870
+ );
871
+ var integrationRewardSchema = z12.object({
872
+ kind: z12.literal("integration"),
873
+ provider: z12.literal("discord"),
874
+ action: z12.literal("grant-role"),
875
+ roleId: z12.string().regex(/^[0-9]{1,20}$/)
876
+ }).strict();
877
+ var rewardSchema = z12.union([
878
+ pointsRewardSchema,
879
+ tierRewardSchema,
880
+ integrationRewardSchema
881
+ ]);
882
+ function rewardKey(reward) {
883
+ if (reward.kind === "integration") {
884
+ return `integration:${reward.provider}:${reward.action}:${reward.roleId}`;
885
+ }
886
+ return reward.kind === "points" ? "points:" + reward.balance : "tier:" + reward.reward.id;
887
+ }
888
+ var triggerSchema = z12.union([
889
+ z12.object({
890
+ kind: z12.literal("manual"),
891
+ input: z12.literal("text"),
892
+ constraints: textOptionsSchema,
893
+ actor: z12.enum(["member", "staff"]).optional()
894
+ }).strict(),
895
+ z12.object({
896
+ kind: z12.literal("manual"),
897
+ input: z12.literal("url"),
898
+ constraints: urlOptionsSchema,
899
+ actor: z12.enum(["member", "staff"]).optional()
900
+ }).strict(),
901
+ z12.object({
902
+ kind: z12.literal("manual"),
903
+ input: z12.enum(["photo", "quiz", "none"]),
904
+ actor: z12.enum(["member", "staff"]).optional()
905
+ }).strict(),
906
+ z12.object({
907
+ kind: z12.literal("automatic"),
908
+ observation: observationTriggerSchema.optional(),
909
+ content: contentPolicySchema.optional()
910
+ }).strict().refine(
911
+ (value) => !(value.observation && value.content),
912
+ "Choose one automatic trigger source"
913
+ )
914
+ ]);
915
+ var prerequisiteSchema = z12.object({ quest: identifier, scope: z12.literal("ever") }).strict();
916
+ var photoResultSchema = z12.object({
917
+ kind: z12.enum(["pass", "fail", "unclear"]),
918
+ reason: z12.string().min(1).max(2e3)
919
+ }).strict();
920
+ var textReviewInputSchema = z12.object({
921
+ text: z12.string().min(1).max(16e3).refine((value) => value.trim().length > 0, "Text must not be blank"),
922
+ criteria: z12.string().trim().min(1).max(2e3)
923
+ }).strict();
924
+ var textResultSchema = photoResultSchema;
925
+ var decisionSchema = z12.discriminatedUnion("kind", [
926
+ z12.object({
927
+ kind: z12.literal("accept"),
928
+ rewards: z12.array(rewardSchema).max(10),
929
+ completionKey: completionKeySchema.optional()
930
+ }).strict(),
931
+ z12.object({ kind: z12.literal("reject"), reason: z12.string().min(1).max(2e3) }).strict(),
932
+ z12.object({
933
+ kind: z12.literal("review"),
934
+ reason: z12.string().min(1).max(2e3),
935
+ rewards: z12.array(rewardSchema).max(10).optional(),
936
+ completionKey: completionKeySchema.optional()
937
+ }).strict()
938
+ ]);
939
+ var reviewModeSchema = z12.enum(["workers-ai"]);
940
+ var storedReviewModeSchema = z12.enum([
941
+ "fixture-pass",
942
+ "fixture-fail",
943
+ "fixture-unclear",
944
+ "fixture-error",
945
+ "workers-ai"
946
+ ]);
947
+ var rewardBundleSchema = z12.array(rewardSchema).max(10).refine(
948
+ (rewards) => new Set(rewards.map(rewardKey)).size === rewards.length,
949
+ "Use one entry per balance or shared reward"
950
+ );
951
+ var mediaUrlSchema = z12.string().max(2e3).refine((value) => {
952
+ if (/^\/(?!\/)[^\\\s]*$/.test(value)) {
953
+ return true;
954
+ }
955
+ try {
956
+ return new URL(value).protocol === "https:";
957
+ } catch {
958
+ return false;
959
+ }
960
+ }, "Use an HTTPS URL or a same-site path beginning with /");
961
+ var questPresentationSchema = z12.object({
962
+ quiz: quizQuestionsSchema.optional(),
963
+ instructions: z12.string().max(4e3).optional(),
964
+ video: z12.object({
965
+ url: mediaUrlSchema,
966
+ poster: mediaUrlSchema.optional(),
967
+ captions: z12.object({
968
+ url: mediaUrlSchema,
969
+ language: z12.string().min(2).max(20),
970
+ label: z12.string().min(1).max(80)
971
+ }).strict().optional()
972
+ }).strict().optional()
973
+ }).strict();
974
+ var questDescriptionSchema = z12.object({
975
+ quest: identifier,
976
+ runtimeVersion: z12.union([z12.literal(1), z12.literal(2)]).default(1),
977
+ title: z12.string().min(1).max(120),
978
+ presentation: questPresentationSchema.default({}),
979
+ integrations: z12.array(integrationProviderSchema).max(10).default([]),
980
+ fields: settingsFieldsSchema,
981
+ values: settingsValuesSchema,
982
+ rewards: rewardBundleSchema,
983
+ humanReview: z12.boolean(),
984
+ trigger: triggerSchema,
985
+ performance: contentPerformancePolicySchema.optional(),
986
+ requires: z12.array(prerequisiteSchema).max(30).default([]),
987
+ completion: completionPolicySchema,
988
+ visibility: z12.enum(["visible", "hidden"]).default("visible"),
989
+ budgets: z12.array(budgetSchema).max(20).default([])
990
+ }).strict();
991
+ var artifactSchema = z12.object({ code: z12.string().min(1).max(1e6) }).strict();
992
+ var releaseSchema = artifactSchema.extend({
993
+ settings: settingsValuesSchema,
994
+ provider: reviewModeSchema,
995
+ expectedRelease: identifier.nullable().optional(),
996
+ settingRenames: z12.record(z12.string(), z12.string()).optional()
997
+ }).strict();
998
+ var batchReleaseSchema = z12.object({ releases: z12.array(releaseSchema).min(1).max(50) }).strict();
999
+ var questSettingsInputSchema = z12.object({
1000
+ quest: identifier,
1001
+ expectedRelease: identifier,
1002
+ set: settingsValuesSchema,
1003
+ reset: z12.array(z12.string())
1004
+ }).strict();
1005
+ var storedReleaseSchema = questDescriptionSchema.extend({
1006
+ key: identifier.optional(),
1007
+ code: z12.string(),
1008
+ provider: storedReviewModeSchema,
1009
+ id: identifier,
1010
+ createdAt: z12.number(),
1011
+ legacy: z12.boolean().default(false),
1012
+ origin: z12.object({ typeVersion: identifier }).strict().optional(),
1013
+ lifecycle: z12.enum(["active", "paused", "archived"]).default("active"),
1014
+ configuration: z12.object({
1015
+ defaults: settingsValuesSchema,
1016
+ overrides: settingsValuesSchema,
1017
+ preserved: z12.array(z12.string())
1018
+ }).strict().optional()
1019
+ });
1020
+ var legacyReleaseSchema = z12.object({
1021
+ quest: identifier,
1022
+ title: z12.string(),
1023
+ criteria: z12.string(),
1024
+ humanReview: z12.boolean(),
1025
+ rewards: rewardBundleSchema,
1026
+ code: z12.string(),
1027
+ provider: storedReviewModeSchema,
1028
+ id: identifier,
1029
+ createdAt: z12.number()
1030
+ }).transform((r) => {
1031
+ const { criteria, ...stored } = r;
1032
+ return storedReleaseSchema.parse({
1033
+ ...stored,
1034
+ fields: {},
1035
+ values: { criteria, humanReview: r.humanReview },
1036
+ trigger: { kind: "manual", input: "photo" },
1037
+ completion: { kind: "once" },
1038
+ legacy: true
1039
+ });
1040
+ });
1041
+ var publishedReleaseSchema = z12.union([
1042
+ storedReleaseSchema,
1043
+ legacyReleaseSchema
1044
+ ]);
1045
+ var templateSchema = z12.object({
1046
+ code: z12.string(),
1047
+ definition: questDescriptionSchema
1048
+ });
1049
+ var quizAnswersSchema = z12.record(identifier, identifier).refine(
1050
+ (answers) => Object.keys(answers).length > 0 && Object.keys(answers).length <= 50,
1051
+ "Provide between 1 and 50 answers"
1052
+ ).transform(
1053
+ (answers) => Object.fromEntries(
1054
+ Object.entries(answers).sort(([a], [b]) => a.localeCompare(b))
1055
+ )
1056
+ );
1057
+ var quizEvidenceSchema = z12.object({
1058
+ kind: z12.literal("quiz"),
1059
+ release: identifier.optional(),
1060
+ answers: quizAnswersSchema
1061
+ }).strict();
1062
+ var submissionEvidenceSchema = z12.union([
1063
+ quizEvidenceSchema,
1064
+ textEvidenceSchema,
1065
+ urlEvidenceSchema
1066
+ ]);
1067
+ var submitSchema = z12.object({
1068
+ actionId: identifier,
1069
+ quest: identifier,
1070
+ member: identifier,
1071
+ evidence: identifier.optional(),
1072
+ input: submissionEvidenceSchema.optional(),
1073
+ release: identifier.optional(),
1074
+ faultAfterReview: z12.boolean().optional()
1075
+ }).strict();
1076
+ var attemptSchema = z12.object({
1077
+ id: identifier,
1078
+ release: identifier,
1079
+ quest: identifier,
1080
+ member: identifier,
1081
+ evidence: identifier.nullable(),
1082
+ input: submissionEvidenceSchema.optional(),
1083
+ status: z12.enum([
1084
+ "queued",
1085
+ "evaluating",
1086
+ "accepted",
1087
+ "progressed",
1088
+ "rejected",
1089
+ "needs-review",
1090
+ "failed"
1091
+ ]),
1092
+ reason: z12.string().nullable(),
1093
+ retries: z12.number(),
1094
+ generation: z12.number(),
1095
+ completion: z12.string().nullable(),
1096
+ reviewRewards: rewardBundleSchema.nullable().default(null),
1097
+ createdAt: z12.number()
1098
+ });
1099
+ var eventSchema = z12.object({
1100
+ id: z12.number(),
1101
+ attempt: z12.string().nullable(),
1102
+ kind: z12.string(),
1103
+ detail: z12.string(),
1104
+ actor: z12.string().nullable().default(null),
1105
+ at: z12.number()
1106
+ });
1107
+ var pickupSelectionSchema = z12.object({
1108
+ item: identifier,
1109
+ revision: z12.number().int().nonnegative()
1110
+ }).strict();
1111
+ var pickupAllocationSchema = z12.object({
1112
+ item: identifier,
1113
+ label: z12.string().min(1).max(80)
1114
+ }).strict();
1115
+ var pickupPolicySchema = z12.discriminatedUnion("kind", [
1116
+ z12.object({ kind: z12.literal("untracked") }).strict(),
1117
+ z12.object({
1118
+ kind: z12.literal("at-pickup"),
1119
+ tiers: z12.array(
1120
+ z12.object({
1121
+ tier: identifier,
1122
+ variants: z12.array(pickupAllocationSchema).min(1).max(100)
1123
+ }).strict()
1124
+ ).min(1).max(100)
1125
+ }).strict()
1126
+ ]);
1127
+ var pickupCatalogSchema = z12.object({
1128
+ reward: tieredRewardDefinitionSchema,
1129
+ revision: z12.number().int().nonnegative(),
1130
+ policy: pickupPolicySchema
1131
+ });
1132
+ var pickupAvailabilitySchema = z12.discriminatedUnion("kind", [
1133
+ z12.object({ kind: z12.literal("untracked") }).strict(),
1134
+ z12.object({
1135
+ kind: z12.literal("at-pickup"),
1136
+ revision: z12.number().int().nonnegative(),
1137
+ variants: z12.array(
1138
+ pickupAllocationSchema.extend({
1139
+ available: z12.number().int().nonnegative()
1140
+ })
1141
+ )
1142
+ }).strict()
1143
+ ]);
1144
+ var configurePickupSchema = z12.object({
1145
+ reward: identifier,
1146
+ revision: z12.number().int().nonnegative(),
1147
+ actionId: identifier,
1148
+ policy: z12.discriminatedUnion("kind", [
1149
+ z12.object({ kind: z12.literal("untracked") }).strict(),
1150
+ z12.object({
1151
+ kind: z12.literal("at-pickup"),
1152
+ tiers: z12.array(
1153
+ z12.object({
1154
+ tier: identifier,
1155
+ variants: z12.array(
1156
+ pickupAllocationSchema.extend({
1157
+ item: identifier.optional()
1158
+ })
1159
+ ).min(1).max(100)
1160
+ }).strict()
1161
+ ).min(1).max(100)
1162
+ }).strict()
1163
+ ])
1164
+ }).strict();
1165
+ var entitlementBase = {
1166
+ id: identifier,
1167
+ member: identifier,
1168
+ reward: tieredRewardDefinitionSchema,
1169
+ earnedTier: identifier,
1170
+ tier: identifier,
1171
+ revision: z12.number().int().positive()
1172
+ };
1173
+ var entitlementSchema = z12.discriminatedUnion("status", [
1174
+ z12.object({ ...entitlementBase, status: z12.literal("available") }).strict(),
1175
+ z12.object({
1176
+ ...entitlementBase,
1177
+ status: z12.literal("handing-over"),
1178
+ handover: identifier,
1179
+ startedAt: z12.number(),
1180
+ allocation: pickupAllocationSchema.optional()
1181
+ }).strict(),
1182
+ z12.object({
1183
+ ...entitlementBase,
1184
+ status: z12.literal("collected"),
1185
+ handover: identifier,
1186
+ startedAt: z12.number(),
1187
+ allocation: pickupAllocationSchema.optional(),
1188
+ collectedAt: z12.number()
1189
+ }).strict()
1190
+ ]);
1191
+ var beginHandoverSchema = z12.object({
1192
+ actionId: identifier,
1193
+ revision: z12.number().int().positive(),
1194
+ selection: pickupSelectionSchema.optional()
1195
+ }).strict();
1196
+ var confirmHandoverSchema = z12.object({ actionId: identifier, handover: identifier }).strict();
1197
+ var completionRecordSchema = z12.object({
1198
+ key: z12.string().default("once"),
1199
+ id: identifier,
1200
+ quest: identifier,
1201
+ member: identifier
1202
+ });
1203
+ var questAvailabilitySchema = z12.discriminatedUnion("kind", [
1204
+ z12.object({
1205
+ kind: z12.literal("available"),
1206
+ input: z12.enum(["photo", "quiz", "none", "text", "url"])
1207
+ }).strict(),
1208
+ z12.object({ kind: z12.literal("completed") }).strict(),
1209
+ z12.object({
1210
+ kind: z12.literal("locked"),
1211
+ missing: z12.array(z12.object({ quest: identifier, title: z12.string() })).min(1)
1212
+ }).strict(),
1213
+ z12.object({ kind: z12.literal("staff-required") }).strict(),
1214
+ z12.object({
1215
+ kind: z12.literal("automatic"),
1216
+ observation: observationTriggerSchema.optional()
1217
+ }).strict(),
1218
+ z12.object({ kind: z12.literal("checking"), attempt: identifier }).strict(),
1219
+ z12.object({ kind: z12.literal("needs-review"), attempt: identifier }).strict(),
1220
+ z12.object({ kind: z12.literal("retryable"), attempt: identifier }).strict()
1221
+ ]);
1222
+ var memberProgressSchema = z12.object({
1223
+ member: identifier,
1224
+ quests: z12.array(
1225
+ z12.object({
1226
+ quest: identifier,
1227
+ key: identifier.optional(),
1228
+ release: identifier.optional(),
1229
+ title: z12.string(),
1230
+ presentation: questPresentationSchema.default({}),
1231
+ connections: z12.array(authProviderSchema).default([]),
1232
+ trigger: triggerSchema,
1233
+ availability: questAvailabilitySchema,
1234
+ completed: z12.boolean(),
1235
+ completion: completionPolicySchema.default({ kind: "once" }),
1236
+ streak: streakProgressSchema.nullable().optional(),
1237
+ completionCount: z12.number().int().nonnegative().default(0),
1238
+ visibility: z12.enum(["visible", "hidden"]).default("visible"),
1239
+ missing: z12.array(z12.object({ quest: identifier, title: z12.string() })),
1240
+ attempt: attemptSchema.nullable()
1241
+ })
1242
+ ),
1243
+ entitlements: z12.array(entitlementSchema)
1244
+ });
1245
+ var snapshotSchema = z12.object({
1246
+ releases: z12.array(publishedReleaseSchema),
1247
+ completions: z12.array(completionRecordSchema),
1248
+ entitlements: z12.array(entitlementSchema),
1249
+ attempts: z12.array(attemptSchema),
1250
+ balances: z12.array(
1251
+ z12.object({
1252
+ member: z12.string(),
1253
+ balance: z12.string(),
1254
+ earned: z12.number(),
1255
+ held: z12.number(),
1256
+ available: z12.number()
1257
+ })
1258
+ ),
1259
+ events: z12.array(eventSchema)
1260
+ });
1261
+ var evidenceSchema = z12.object({
1262
+ id: identifier,
1263
+ member: identifier,
1264
+ type: z12.enum(["image/jpeg", "image/png"]),
1265
+ size: z12.number()
1266
+ });
1267
+ var errorSchema = z12.object({
1268
+ error: z12.string(),
1269
+ code: z12.enum(["stale-quiz", "quest-updated", "invalid-submission"]).optional(),
1270
+ missing: z12.array(z12.object({ quest: identifier, title: z12.string() })).optional()
1271
+ });
1272
+ var staffDecisionSchema = z12.object({
1273
+ actionId: identifier,
1274
+ generation: z12.number().int().nonnegative(),
1275
+ decision: z12.enum(["accept", "reject"]),
1276
+ reason: z12.string().trim().min(1).max(2e3)
1277
+ }).strict();
1278
+ var stockSchema = z12.object({ item: identifier, quantity: z12.number().int().min(0).max(1e4) }).strict();
1279
+ var reservationSchema = z12.object({
1280
+ actionId: identifier,
1281
+ member: identifier,
1282
+ item: identifier,
1283
+ balance: identifier,
1284
+ price: z12.number().int().positive().max(1e4)
1285
+ }).strict();
1286
+ var pageOptions = {
1287
+ limit: z12.number().int().min(1).max(100).default(25),
1288
+ cursor: z12.string().min(1).max(4096).optional()
1289
+ };
1290
+ var reviewListSchema = z12.object({
1291
+ ...pageOptions,
1292
+ member: identifier.optional(),
1293
+ quest: identifier.optional()
1294
+ }).strict();
1295
+ var memberListSchema = z12.object({
1296
+ ...pageOptions,
1297
+ prefix: identifier.optional()
1298
+ }).strict();
1299
+ var reviewItemSchema = z12.object({
1300
+ attempt: attemptSchema,
1301
+ title: z12.string(),
1302
+ checks: z12.array(
1303
+ z12.object({ criteria: z12.string(), result: photoResultSchema })
1304
+ )
1305
+ });
1306
+ var reviewPageSchema = z12.object({
1307
+ items: z12.array(reviewItemSchema).max(100),
1308
+ nextCursor: z12.string().nullable()
1309
+ });
1310
+ var memberPageSchema = z12.object({
1311
+ items: z12.array(z12.object({ member: identifier })).max(100),
1312
+ nextCursor: z12.string().nullable()
1313
+ });
1314
+ var createStockItemSchema = z12.object({ actionId: identifier, name: z12.string().trim().min(1).max(80) }).strict();
1315
+ var stockItemSchema = z12.object({ id: identifier, name: z12.string() });
1316
+ var contentPerformanceSnapshotSchema = z12.strictObject({
1317
+ contentAttempt: identifier,
1318
+ observation: identifier,
1319
+ observedAt: z12.number().int().safe().nonnegative(),
1320
+ metrics: contentMetricsSchema,
1321
+ rewards: rewardBundleSchema
1322
+ });
1323
+ var contentPerformanceQuerySchema = contentQualificationQuerySchema.extend({
1324
+ content: z12.string().min(1).max(256)
1325
+ });
1326
+ var contentPerformancePageSchema = z12.strictObject({
1327
+ current: z12.strictObject({
1328
+ state: z12.enum([
1329
+ "content-pending",
1330
+ "content-unqualified",
1331
+ "waiting",
1332
+ "pending",
1333
+ "qualified",
1334
+ "unqualified",
1335
+ "needs-review",
1336
+ "failed",
1337
+ "superseded"
1338
+ ]),
1339
+ reason: z12.string().nullable(),
1340
+ contentAttempt: identifier,
1341
+ attempt: identifier.nullable(),
1342
+ reward: contentQualificationSchema.shape.reward
1343
+ }),
1344
+ items: z12.array(
1345
+ z12.strictObject({
1346
+ attempt: identifier,
1347
+ contentAttempt: identifier,
1348
+ observation: identifier,
1349
+ observedAt: z12.number(),
1350
+ metrics: contentMetricsSchema,
1351
+ state: z12.enum([
1352
+ "pending",
1353
+ "qualified",
1354
+ "unqualified",
1355
+ "needs-review",
1356
+ "failed",
1357
+ "superseded"
1358
+ ]),
1359
+ reason: z12.string().nullable()
1360
+ })
1361
+ ),
1362
+ next: z12.number().int().positive().safe().nullable()
1363
+ });
1364
+
1365
+ export {
1366
+ identifier,
1367
+ xTweetSchema,
1368
+ xContentBodySchema,
1369
+ trackerContentQuerySchema,
1370
+ trackerContentReadSchema,
1371
+ trackerContentSchema,
1372
+ trackerSourceSchema,
1373
+ x,
1374
+ customSource,
1375
+ trackerDefinitionSchema,
1376
+ trackerArtifactSchema,
1377
+ defineTracker,
1378
+ publishedTrackerSchema,
1379
+ trackerStatusSchema,
1380
+ trackerControlSchema,
1381
+ trackerRecordInputSchema,
1382
+ trackerRecordSchema,
1383
+ trackerIngestSchema,
1384
+ trackerIngestResultSchema,
1385
+ trackerQuerySchema,
1386
+ trackerPageSchema,
1387
+ trackerSummarySchema,
1388
+ trackerPreviewLimits,
1389
+ trackerPreviewInputSchema,
1390
+ trackerPreviewSchema,
1391
+ contentPolicySchema,
1392
+ content,
1393
+ admittedContentSchema,
1394
+ perContent,
1395
+ contentEnrollmentInputSchema,
1396
+ contentEnrollmentSchema,
1397
+ contentReleaseInputSchema,
1398
+ contentAdmissionSchema,
1399
+ contentAdmissionQuerySchema,
1400
+ contentAdmissionPageSchema,
1401
+ isContentParticipantRoute,
1402
+ contentQualificationDecisionSchema,
1403
+ contentQualificationQuerySchema,
1404
+ contentQualificationSchema,
1405
+ contentQualificationPageSchema,
1406
+ contentMetricSchema,
1407
+ contentMetricsSchema,
1408
+ contentPerformancePolicySchema,
1409
+ communityTimeZoneSchema,
1410
+ streakPolicySchema,
1411
+ streak,
1412
+ streakProgressSchema,
1413
+ observationInputSchema,
1414
+ observationSchema,
1415
+ observationTriggerSchema,
1416
+ completionPolicySchema,
1417
+ completionKeySchema,
1418
+ budgetSchema,
1419
+ observationReceiptSchema,
1420
+ discordReactionSchema,
1421
+ discordMessageSchema,
1422
+ integrationProviderSchema,
1423
+ discordServerSchema,
1424
+ projectIntegrationSchema,
1425
+ authProviderSchema,
1426
+ accountConnectionSchema,
1427
+ discordMemberInputSchema,
1428
+ discordMessageInputSchema,
1429
+ discordMemberSchema,
1430
+ textOptionsSchema,
1431
+ urlOptionsSchema,
1432
+ textEvidenceSchema,
1433
+ urlEvidenceSchema,
1434
+ valueEvidenceSchema,
1435
+ validateSubmissionValue,
1436
+ xPostId,
1437
+ quizChoiceSchema,
1438
+ quizQuestionSchema,
1439
+ quizQuestionsSchema,
1440
+ quizContentSchema,
1441
+ resourceSourceSchema,
1442
+ resourceRequestSchema,
1443
+ resourceOptionsSchema,
1444
+ discord,
1445
+ pointLedgers,
1446
+ settingFieldSchema,
1447
+ settingsFieldsSchema,
1448
+ settingsValuesSchema,
1449
+ settings,
1450
+ parseSettings,
1451
+ missingResourceSettings,
1452
+ compatibleSettingKinds,
1453
+ pointsRewardSchema,
1454
+ tieredRewardDefinitionSchema,
1455
+ tierRewardSchema,
1456
+ integrationRewardSchema,
1457
+ rewardSchema,
1458
+ rewardKey,
1459
+ triggerSchema,
1460
+ prerequisiteSchema,
1461
+ photoResultSchema,
1462
+ textReviewInputSchema,
1463
+ textResultSchema,
1464
+ decisionSchema,
1465
+ reviewModeSchema,
1466
+ storedReviewModeSchema,
1467
+ rewardBundleSchema,
1468
+ mediaUrlSchema,
1469
+ questPresentationSchema,
1470
+ questDescriptionSchema,
1471
+ artifactSchema,
1472
+ releaseSchema,
1473
+ batchReleaseSchema,
1474
+ questSettingsInputSchema,
1475
+ publishedReleaseSchema,
1476
+ templateSchema,
1477
+ quizAnswersSchema,
1478
+ quizEvidenceSchema,
1479
+ submissionEvidenceSchema,
1480
+ submitSchema,
1481
+ attemptSchema,
1482
+ eventSchema,
1483
+ pickupSelectionSchema,
1484
+ pickupAllocationSchema,
1485
+ pickupPolicySchema,
1486
+ pickupCatalogSchema,
1487
+ pickupAvailabilitySchema,
1488
+ configurePickupSchema,
1489
+ entitlementSchema,
1490
+ beginHandoverSchema,
1491
+ confirmHandoverSchema,
1492
+ completionRecordSchema,
1493
+ questAvailabilitySchema,
1494
+ memberProgressSchema,
1495
+ snapshotSchema,
1496
+ evidenceSchema,
1497
+ errorSchema,
1498
+ staffDecisionSchema,
1499
+ stockSchema,
1500
+ reservationSchema,
1501
+ reviewListSchema,
1502
+ memberListSchema,
1503
+ reviewItemSchema,
1504
+ reviewPageSchema,
1505
+ memberPageSchema,
1506
+ createStockItemSchema,
1507
+ stockItemSchema,
1508
+ contentPerformanceSnapshotSchema,
1509
+ contentPerformanceQuerySchema,
1510
+ contentPerformancePageSchema
1511
+ };