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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +1 -1
  2. package/dist/authoring.d.ts +58 -44
  3. package/dist/authoring.js +58 -45
  4. package/dist/browser.d.ts +111 -151
  5. package/dist/browser.js +6 -6
  6. package/dist/{catalog-C85V1NgW.d.ts → catalog-CVXUHxiO.d.ts} +12 -99
  7. package/dist/{chunk-M64XHC42.js → chunk-76F4LSFP.js} +2 -2
  8. package/dist/{chunk-II7DRZSL.js → chunk-CYD6QMHU.js} +1 -1
  9. package/dist/{chunk-KS33GOUL.js → chunk-EJWDAF7I.js} +4 -4
  10. package/dist/chunk-FJ6O44NE.js +51 -0
  11. package/dist/{chunk-WQ24ILGO.js → chunk-G3YSBMJH.js} +7 -3
  12. package/dist/{chunk-MNQI35OG.js → chunk-HWRBLM7E.js} +3 -3
  13. package/dist/{chunk-CRNQP7NV.js → chunk-J4OYDYJE.js} +693 -676
  14. package/dist/{chunk-OA2KMQVZ.js → chunk-J52HD4AA.js} +11 -1
  15. package/dist/{chunk-EZWNGI5B.js → chunk-RCBJBFLC.js} +4 -4
  16. package/dist/{chunk-FXYJ4OMX.js → chunk-WMTROSYF.js} +1 -1
  17. package/dist/{client-Bf9PNUIi.d.ts → client-dfXT6hhq.d.ts} +7 -47
  18. package/dist/{deployments-CNCP0JnD.d.ts → deployments-C9wkQ06n.d.ts} +109 -125
  19. package/dist/{images-BG4pdO4y.d.ts → images-CRxHUuG5.d.ts} +1 -1
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +5 -5
  22. package/dist/{integrations-EjQzIApL.d.ts → integrations-C1vB6Ry6.d.ts} +93 -1
  23. package/dist/internal.d.ts +13 -4
  24. package/dist/internal.js +10 -4
  25. package/dist/portal-proxy.js +2 -2
  26. package/dist/react/index.d.ts +441 -655
  27. package/dist/react/index.js +1190 -810
  28. package/dist/{schema-BF_TQsmT.d.ts → schema-C4F2K9cm.d.ts} +9 -74
  29. package/dist/schema.d.ts +6 -7
  30. package/dist/schema.js +18 -16
  31. package/dist/server/index.d.ts +125 -233
  32. package/dist/server/index.js +16 -22
  33. package/dist/{trackers-W7nRdRr7.d.ts → trackers-7lxSWp2g.d.ts} +56 -14
  34. package/package.json +4 -2
  35. package/dist/observations-CQ6IcNuQ.d.ts +0 -90
package/README.md CHANGED
@@ -13,7 +13,7 @@ pnpm add @domino-sdk/relay
13
13
  | `@domino-sdk/relay/react` | React hooks over the browser client |
14
14
  | `@domino-sdk/relay/avatar` | Generated default avatars (`avatarSrc`, `defaultAvatar`) |
15
15
  | `@domino-sdk/relay/authoring` | Quest, tracker, leaderboard, referral and engagement definitions, and evaluator types |
16
- | `@domino-sdk/relay/schema` | Zod schemas of Relay's API bodies, deployments, tracker records and observations |
16
+ | `@domino-sdk/relay/schema` | Zod schemas of Relay's API bodies, deployments and tracker records |
17
17
  | `@domino-sdk/relay/build` | Bundling authored modules; needs `esbuild` installed |
18
18
  | `@domino-sdk/relay/portal-proxy` | Server proxies and hosted app Workers |
19
19
  | `@domino-sdk/relay/vite` | The Vite plugin that keeps server code out of the browser build |
@@ -1,14 +1,13 @@
1
1
  import { z } from 'zod';
2
2
  export { z } from 'zod';
3
3
  import { e as ContentPolicy, C as ContentMetric, E as EngagementBudget, T as leaderboardDefinitionSchema, a9 as referralAuthoringSchema, A as AdmittedContent } from './referrals-KQfP4pBf.js';
4
+ import { r as discordMessagesSourceSchema, a as DiscordMessageData, b as DiscordMessageTextData, t as discordReactionsSourceSchema, c as DiscordReactionData, e as ResourceSource, S as Setting, j as XReader, D as DiscordMessage, B as Budget, I as IntegerSettings, d as IntegrationProvider } from './integrations-C1vB6Ry6.js';
4
5
  import { Q as QuizContent, a as StreakPolicy } from './streaks-CWyq8Px5.js';
5
- import { b as ResourceSource, S as Setting, g as XReader, I as IntegerSettings, a as IntegrationProvider } from './integrations-EjQzIApL.js';
6
- import { j as TrackerDefinition, I as IdentityKind, J as customSourceSchema, F as WithRecordData, t as TrackerSource, a1 as trackerDefinitionSchema, T as Tracker, g as TrackerData, au as xSearchSourceSchema, X as XTweet, v as TrackerTriggerContext, x as TrackerTriggerPolicy, q as TrackerReader, W as Where, w as TrackerTriggerMode, E as WhereSetting } from './trackers-W7nRdRr7.js';
7
- export { i as TrackerDataSchema, m as TrackerPage, aw as trackerDataSchema, ak as trackerTriggerContextSchema } from './trackers-W7nRdRr7.js';
8
- import { e as ImageReader } from './images-BG4pdO4y.js';
9
- import { O as Observation, D as DiscordMessage, h as observationTriggerSchema, B as Budget } from './observations-CQ6IcNuQ.js';
6
+ import { j as TrackerDefinition, I as IdentityKind, K as customSourceSchema, G as WithRecordData, t as TrackerSource, a2 as trackerDefinitionSchema, T as Tracker, g as TrackerData, aw as xSearchSourceSchema, X as XTweet, w as TrackerTriggerContext, y as TrackerTriggerPolicy, q as TrackerReader, W as Where, x as TrackerTriggerMode, F as WhereSetting } from './trackers-7lxSWp2g.js';
7
+ export { i as TrackerDataSchema, m as TrackerPage, ay as trackerDataSchema, am as trackerTriggerContextSchema } from './trackers-7lxSWp2g.js';
8
+ import { e as ImageReader } from './images-CRxHUuG5.js';
10
9
  import { D as DiscordMember, T as TextEvidence, U as UrlEvidence, b as TextOptions, c as UrlOptions } from './submission-input-CccwAl5Z.js';
11
- import { n as TextReviewInput, m as TextResult, P as PhotoResult, ag as rewardSchema, av as triggerSchema, Q as QuestPresentation, a as QuestProfile, b as QuizEvidence, D as Decision, o as TieredRewardDefinition } from './schema-BF_TQsmT.js';
10
+ import { n as TextReviewInput, m as TextResult, P as PhotoResult, ag as rewardSchema, av as triggerSchema, Q as QuestPresentation, a as QuestProfile, b as QuizEvidence, D as Decision, o as TieredRewardDefinition } from './schema-C4F2K9cm.js';
12
11
  import { k as WalletConnection, S as SolanaBalance, L as LinkedWallet, j as WalletBalanceQuery, i as WalletBalance } from './wallet-BtiG0Xhr.js';
13
12
  export { E as EvmChainId, r as isEvmChainId } from './wallet-BtiG0Xhr.js';
14
13
  export { f as formatUnits, p as parseUnits } from './units-CwgsPB_r.js';
@@ -33,7 +32,7 @@ declare function content(tracker: TrackerDefinition, policy?: Partial<Pick<Conte
33
32
  };
34
33
  enrollment: "required" | "none";
35
34
  posts: "after-enrollment" | "since-start";
36
- historical: "staff" | "automatic" | "claim";
35
+ historical: "automatic" | "claim" | "staff";
37
36
  };
38
37
  };
39
38
  declare function perContent(): {
@@ -80,8 +79,8 @@ declare function defineEngagementReward<const M extends readonly [ContentMetric,
80
79
  /**
81
80
  * One milestone per quest, after `days` consecutive project calendar days with an accepted
82
81
  * attempt. Multiple accepted attempts occupy one day. The day comes from the attempt's trusted
83
- * occurrence time: a tracker record's (or observation's) `occurredAt` for `automatic({ tracker })`,
84
- * and the submission's admission time for `manual()`, so a manual streak counts the days a member
82
+ * occurrence time: a tracker record's `occurredAt` for `automatic({ tracker })`, and the
83
+ * submission's admission time for `manual()`, so a manual streak counts the days a member
85
84
  * submitted. Days begin at midnight in the project timezone (`calendar.timeZone` in relay.json, or
86
85
  * Console settings). Not available on content quests or prerequisite-only `automatic()`.
87
86
  */
@@ -186,8 +185,8 @@ declare function defineReferral(input: Omit<z.input<typeof referralAuthoringSche
186
185
  };
187
186
  declare function defineLeaderboard(input: Omit<z.input<typeof leaderboardDefinitionSchema>, "key" | "id"> & AuthoringIdentity): {
188
187
  id: string;
189
- balance: string;
190
188
  title: string;
189
+ balance: string;
191
190
  group?: string | undefined;
192
191
  score: {
193
192
  kind: "balance";
@@ -252,7 +251,33 @@ declare function defineTracker<S extends TrackerSource>(input: Omit<z.input<type
252
251
  type ChannelTypes = Extract<ResourceSource, {
253
252
  resource: "channel";
254
253
  }>["types"];
254
+ type DiscordMessagesSource = z.output<typeof discordMessagesSourceSchema>;
255
+ /**
256
+ * Messages members post in the project's Discord server. The Discord gateway writes one record per
257
+ * message, keyed by the message ID: its `author` is the poster's Discord account, `occurredAt` is
258
+ * when the message arrived, and `data` holds the channel, the replied-to message and the post time.
259
+ * A record is stored only when its author has linked that Discord account in the project, and its
260
+ * text only with `text: true`.
261
+ */
262
+ declare function messages(options?: {
263
+ text?: false;
264
+ }): DiscordMessagesSource & WithRecordData<DiscordMessageData>;
265
+ declare function messages(options: {
266
+ text: true;
267
+ }): DiscordMessagesSource & WithRecordData<DiscordMessageTextData>;
268
+ /**
269
+ * Reactions members add in the project's Discord server. The Discord gateway writes one record per
270
+ * reaction, keyed by message, reactor and emoji: its `author` is the reactor's Discord account and
271
+ * its `messageAuthor` account the message's author, when Discord names it. `occurredAt` is when
272
+ * the reaction arrived. A record is stored only when the reactor or the message author has linked
273
+ * that Discord account in the project. Pay the message author with
274
+ * `automatic({ tracker, beneficiary: "messageAuthor" })`; reactions to one's own message are
275
+ * skipped.
276
+ */
277
+ declare function reactions(): z.output<typeof discordReactionsSourceSchema> & WithRecordData<DiscordReactionData>;
255
278
  declare const discord: {
279
+ messages: typeof messages;
280
+ reactions: typeof reactions;
256
281
  roles(options?: {
257
282
  assignable?: boolean;
258
283
  }): ResourceSource;
@@ -370,8 +395,9 @@ type TrackerTriggerInput<T extends Tracker = Tracker, W extends Where<TrackerDat
370
395
  tracker: T;
371
396
  /**
372
397
  * Which observations fire. `"new-record"`: each record's first observation (the default for X
373
- * trackers, where it means each newly collected post). `"new-observation"`: each observation
374
- * that becomes its record's current one (the default for custom trackers). `"data-changed"`: a
398
+ * and Discord trackers, where it means each newly collected post, message or reaction).
399
+ * `"new-observation"`: each observation that becomes its record's current one (the default for
400
+ * custom trackers). `"data-changed"`: a
375
401
  * new record, or a current observation whose `data` differs from the previous one.
376
402
  */
377
403
  on?: TrackerTriggerMode;
@@ -384,8 +410,9 @@ type TrackerTriggerInput<T extends Tracker = Tracker, W extends Where<TrackerDat
384
410
  where?: W;
385
411
  /**
386
412
  * The record account whose member the quest pays: `"author"` (the default), `"inReplyTo"` on
387
- * an X tracker, or a named account a custom source declares in `accounts`. Skipped when that
388
- * account is the record's author account or belongs to the author's member.
413
+ * an X tracker, `"messageAuthor"` on a Discord reactions tracker, or a named account a custom
414
+ * source declares in `accounts`. Skipped when that account is the record's author account or
415
+ * belongs to the author's member, such as a reaction to one's own message.
389
416
  */
390
417
  beneficiary?: string;
391
418
  };
@@ -408,17 +435,13 @@ type TriggerSettings<G> = G extends {
408
435
  readonly [triggerSettings]?: infer S;
409
436
  } ? unknown extends S ? never : Exclude<S, undefined> : never;
410
437
  /**
411
- * An automatic quest. With no argument it runs once its prerequisites are complete; with an
412
- * observation it runs for each matching observation; with a tracker it runs for each observation
413
- * its firing mode and filter admit, for the member Relay attributes the beneficiary account to.
438
+ * An automatic quest. With no argument it runs once its prerequisites are complete; with a tracker
439
+ * it runs for each observation its firing mode and filter admit, for the member Relay attributes
440
+ * the beneficiary account to.
414
441
  */
415
442
  declare function automatic(): {
416
443
  kind: "automatic";
417
444
  };
418
- declare function automatic(observation: z.infer<typeof observationTriggerSchema>): {
419
- kind: "automatic";
420
- observation: z.infer<typeof observationTriggerSchema>;
421
- };
422
445
  declare function automatic<T extends Tracker, const W extends Where<TrackerData<T>> | undefined = undefined>(input: TrackerTriggerInput<T, W>): TrackerTrigger<TrackerData<T>, WhereSetting<W>>;
423
446
  /**
424
447
  * What a trigger `G` supplies under key `K`: `Present` when the trigger has it, null when it cannot,
@@ -429,8 +452,6 @@ type Supplied<G, K extends string, Present, Base> = unknown extends G ? Base | n
429
452
  type ContextTracker<G> = Supplied<G, "tracker", TrackerTriggerContext<TriggerData<G>>, TrackerTriggerContext>;
430
453
  /** `ctx.content` for a trigger: the admitted post for a content trigger, null for others. */
431
454
  type ContextContent<G> = Supplied<G, "content", AdmittedContent, AdmittedContent>;
432
- /** `ctx.observation` for a trigger: the observation for an observation trigger, null for others. */
433
- type ContextObservation<G> = Supplied<G, "observation", Observation, Observation>;
434
455
  /**
435
456
  * What a `keyed()` completion key reads. TypeScript cannot carry the trigger into a completion
436
457
  * built inline, so `tracker` stays nullable here; the evaluator's `ctx.tracker` is typed.
@@ -440,7 +461,6 @@ type KeyedContext = {
440
461
  id: string;
441
462
  };
442
463
  content?: AdmittedContent | null;
443
- observation: Observation | null;
444
464
  /** The pinned tracker observation of a tracker-triggered quest; null for other triggers. */
445
465
  tracker: TrackerTriggerContext | null;
446
466
  eligibleAt: number;
@@ -549,8 +569,8 @@ declare const decision: {
549
569
  review: typeof review;
550
570
  };
551
571
  /**
552
- * What an evaluator reads. `G` is the quest's trigger: `tracker`, `content` and `observation` are
553
- * non-null for the trigger that supplies them and null otherwise. `G` defaults to `any`, which
572
+ * What an evaluator reads. `G` is the quest's trigger: `tracker` and `content` are non-null for
573
+ * the trigger that supplies them and null otherwise. `G` defaults to `any`, which
554
574
  * leaves them nullable and lets a shared evaluator, such as `evaluators.photo()`, fit every quest.
555
575
  */
556
576
  type EvaluationContext<T, I = {
@@ -563,16 +583,14 @@ type EvaluationContext<T, I = {
563
583
  input: I;
564
584
  /** The admitted post of a content quest. */
565
585
  content: ContextContent<G>;
566
- /** The observation of an observation-triggered quest. */
567
- observation: ContextObservation<G>;
568
586
  /**
569
587
  * The tracker observation that admitted this attempt, and the member and verified account it
570
588
  * was attributed to. Present for a tracker trigger, with `record.data` of the tracker's type.
571
589
  */
572
590
  tracker: ContextTracker<G>;
573
591
  /**
574
- * When the activity happened, in epoch milliseconds: the observation's or tracker record's
575
- * occurrence time, else when the attempt was admitted. Budgets and daily keys use it.
592
+ * When the activity happened, in epoch milliseconds: the tracker record's occurrence time, else
593
+ * when the attempt was admitted. Budgets and daily keys use it.
576
594
  */
577
595
  eligibleAt: number;
578
596
  /**
@@ -744,12 +762,12 @@ declare function defineQuest<T extends Record<string, Setting>, const G extends
744
762
  kind: "resource";
745
763
  default: string;
746
764
  source: {
747
- provider: "domino";
748
- resource: "point-ledger";
749
- } | {
750
765
  provider: "discord";
751
766
  resource: "channel";
752
767
  types: ("text" | "announcement")[];
768
+ } | {
769
+ provider: "domino";
770
+ resource: "point-ledger";
753
771
  } | {
754
772
  provider: "discord";
755
773
  resource: "role";
@@ -836,10 +854,6 @@ declare function defineQuest<T extends Record<string, Setting>, const G extends
836
854
  humanReview: boolean;
837
855
  trigger: {
838
856
  kind: "automatic";
839
- observation?: {
840
- source: string;
841
- type: string;
842
- } | undefined;
843
857
  content?: {
844
858
  tracker: string;
845
859
  window: {
@@ -848,11 +862,11 @@ declare function defineQuest<T extends Record<string, Setting>, const G extends
848
862
  };
849
863
  enrollment: "required" | "none";
850
864
  posts: "after-enrollment" | "since-start";
851
- historical: "staff" | "automatic" | "claim";
865
+ historical: "automatic" | "claim" | "staff";
852
866
  } | undefined;
853
867
  tracker?: {
854
868
  tracker: string;
855
- source: "custom" | "x-search";
869
+ source: string;
856
870
  beneficiary: string;
857
871
  on?: "new-record" | "new-observation" | "data-changed" | undefined;
858
872
  where?: {
@@ -899,7 +913,7 @@ declare function defineQuest<T extends Record<string, Setting>, const G extends
899
913
  minLength: number;
900
914
  maxLength: number;
901
915
  };
902
- actor?: "staff" | "member" | undefined;
916
+ actor?: "member" | "staff" | undefined;
903
917
  } | {
904
918
  kind: "manual";
905
919
  input: "url";
@@ -907,11 +921,11 @@ declare function defineQuest<T extends Record<string, Setting>, const G extends
907
921
  required: boolean;
908
922
  allowedHosts?: string[] | undefined;
909
923
  };
910
- actor?: "staff" | "member" | undefined;
924
+ actor?: "member" | "staff" | undefined;
911
925
  } | {
912
926
  kind: "manual";
913
- input: "photo" | "quiz" | "none";
914
- actor?: "staff" | "member" | undefined;
927
+ input: "none" | "quiz" | "photo";
928
+ actor?: "member" | "staff" | undefined;
915
929
  };
916
930
  requires: {
917
931
  quest: string;
@@ -952,4 +966,4 @@ declare function defineQuest<T extends Record<string, Setting>, const G extends
952
966
  * Console instances receive independent quest identities and pinned versions. */
953
967
  declare const defineQuestType: typeof defineQuest;
954
968
 
955
- export { type EvaluationContext, ImageReader, type KeyedContext, type PerformanceOutcome, Setting, Tracker, TrackerData, TrackerReader, type TrackerTrigger, TrackerTriggerContext, type TrackerTriggerInput, WalletBalance, WalletBalanceQuery, Where, XReader, automatic, budget, completed, content, customSource, decision, defineEngagementReward, defineLeaderboard, defineQuest, defineQuestType, defineReferral, defineTieredReward, defineTracker, discord, discordRole, evaluators, evidence, keyed, manual, once, perContent, pointLedgers, points, settings, staffHandover, streak, untracked, x };
969
+ export { DiscordMessageData, DiscordMessageTextData, DiscordReactionData, type EvaluationContext, ImageReader, type KeyedContext, type PerformanceOutcome, Setting, Tracker, TrackerData, TrackerReader, type TrackerTrigger, TrackerTriggerContext, type TrackerTriggerInput, WalletBalance, WalletBalanceQuery, Where, XReader, automatic, budget, completed, content, customSource, decision, defineEngagementReward, defineLeaderboard, defineQuest, defineQuestType, defineReferral, defineTieredReward, defineTracker, discord, discordRole, evaluators, evidence, keyed, manual, once, perContent, pointLedgers, points, settings, staffHandover, streak, untracked, x };
package/dist/authoring.js CHANGED
@@ -2,6 +2,10 @@ import {
2
2
  formatUnits,
3
3
  parseUnits
4
4
  } from "./chunk-V7UKZLHA.js";
5
+ import {
6
+ sourceDataSchema,
7
+ sourceRoles
8
+ } from "./chunk-FJ6O44NE.js";
5
9
  import {
6
10
  authoringKey,
7
11
  engagementDefinitionSchema,
@@ -10,7 +14,7 @@ import {
10
14
  isEvmChainId,
11
15
  leaderboardAuthoringSchema,
12
16
  referralAuthoringSchema
13
- } from "./chunk-OA2KMQVZ.js";
17
+ } from "./chunk-J52HD4AA.js";
14
18
  import {
15
19
  admittedContentSchema,
16
20
  budgetSchema,
@@ -20,6 +24,8 @@ import {
20
24
  customSourceSchema,
21
25
  decisionSchema,
22
26
  defaultTriggerMode,
27
+ discordMessagesSourceSchema,
28
+ discordReactionsSourceSchema,
23
29
  identifier,
24
30
  integrationRewardSchema,
25
31
  parseSettings,
@@ -46,9 +52,8 @@ import {
46
52
  urlOptionsSchema,
47
53
  whereSchemaIssue,
48
54
  whereSettings,
49
- xAccountRoles,
50
55
  xSearchSourceSchema
51
- } from "./chunk-CRNQP7NV.js";
56
+ } from "./chunk-J4OYDYJE.js";
52
57
 
53
58
  // src/builders.ts
54
59
  import { z } from "zod";
@@ -147,7 +152,18 @@ function isZodSchema(value) {
147
152
  function defineTracker(input) {
148
153
  return trackerDefinitionSchema.parse(input);
149
154
  }
155
+ function messages(options = {}) {
156
+ return discordMessagesSourceSchema.parse({
157
+ kind: "discord-messages",
158
+ ...options.text ? { text: true } : {}
159
+ });
160
+ }
161
+ function reactions() {
162
+ return discordReactionsSourceSchema.parse({ kind: "discord-reactions" });
163
+ }
150
164
  var discord = {
165
+ messages,
166
+ reactions,
151
167
  roles(options = {}) {
152
168
  return resourceSourceSchema.parse({
153
169
  provider: "discord",
@@ -291,44 +307,43 @@ function automatic(input) {
291
307
  if (!input) {
292
308
  return { kind: "automatic" };
293
309
  }
294
- if ("tracker" in input) {
295
- const { tracker, beneficiary = "author", on, where } = input;
296
- const { source } = tracker;
297
- if (source.kind === "x-search" && !xAccountRoles.includes(beneficiary)) {
298
- throw new Error(
299
- `X trackers pay "author" or "inReplyTo", not "${beneficiary}"`
300
- );
301
- }
302
- if (!sourceIdentities(source)) {
303
- throw new Error(
304
- 'Tracker triggers need attributable records: declare customSource(namespace, { identities: ["wallet"] }) or other identity kinds'
305
- );
306
- }
307
- if (source.kind === "custom" && beneficiary !== "author" && !source.accounts?.includes(beneficiary)) {
308
- throw new Error(
309
- `Tracker "${tracker.key}" has no "${beneficiary}" account: declare it in customSource(namespace, { accounts: ["${beneficiary}"] })`
310
- );
311
- }
312
- const policy = trackerTriggerPolicySchema.parse({
313
- tracker: tracker.key,
314
- source: source.kind,
315
- // The source's default mode is left out, so default quests keep the policy shape
316
- // earlier SDKs and servers read.
317
- ...on && on !== defaultTriggerMode(source.kind) ? { on } : {},
318
- ...where ? { where } : {},
319
- beneficiary
320
- });
321
- const issue = source.kind === "custom" && source.data ? whereSchemaIssue(source.data, policy.where) : null;
322
- if (issue) {
323
- throw new Error(issue);
324
- }
325
- const trigger = { kind: "automatic", tracker: policy };
326
- if (source.kind === "custom" && source.data) {
327
- triggerDataSchemas.set(trigger, source.data);
328
- }
329
- return trigger;
310
+ const { tracker, beneficiary = "author", on, where } = input;
311
+ if (!tracker?.source) {
312
+ throw new Error(
313
+ "automatic() takes no argument, or { tracker } with a tracker handle from defineTracker"
314
+ );
315
+ }
316
+ const { source } = tracker;
317
+ if (!sourceIdentities(source)) {
318
+ throw new Error(
319
+ 'Tracker triggers need attributable records: declare customSource(namespace, { identities: ["wallet"] }) or other identity kinds'
320
+ );
321
+ }
322
+ const roles = sourceRoles(source);
323
+ if (!roles.includes(beneficiary)) {
324
+ throw new Error(
325
+ source.kind === "custom" ? `Tracker "${tracker.key}" has no "${beneficiary}" account: declare it in customSource(namespace, { accounts: ["${beneficiary}"] })` : `Tracker "${tracker.key}" pays ${roles.map((role) => `"${role}"`).join(" or ")}, not "${beneficiary}"`
326
+ );
327
+ }
328
+ const policy = trackerTriggerPolicySchema.parse({
329
+ tracker: tracker.key,
330
+ source: source.kind,
331
+ // The source's default mode is left out, so default quests keep the policy shape
332
+ // earlier SDKs and servers read.
333
+ ...on && on !== defaultTriggerMode(source.kind) ? { on } : {},
334
+ ...where ? { where } : {},
335
+ beneficiary
336
+ });
337
+ const schema = sourceDataSchema(source);
338
+ const issue = schema ? whereSchemaIssue(schema, policy.where) : null;
339
+ if (issue) {
340
+ throw new Error(issue);
341
+ }
342
+ const trigger = { kind: "automatic", tracker: policy };
343
+ if (schema) {
344
+ triggerDataSchemas.set(trigger, schema);
330
345
  }
331
- return { kind: "automatic", observation: input };
346
+ return trigger;
332
347
  }
333
348
  var budget = (definition) => budgetSchema.parse(definition);
334
349
  var keyed = (key) => ({
@@ -406,15 +421,15 @@ function defineQuest(definition) {
406
421
  "Content triggers require perContent completion, and perContent requires a content trigger"
407
422
  );
408
423
  }
409
- const bareAutomatic = definition.trigger.kind === "automatic" && !definition.trigger.observation && !definition.trigger.content && !definition.trigger.tracker;
424
+ const bareAutomatic = definition.trigger.kind === "automatic" && !definition.trigger.content && !definition.trigger.tracker;
410
425
  if (bareAutomatic && !definition.requires?.length) {
411
426
  throw new Error(
412
- "A bare automatic() quest needs at least one requires entry, such as requires: [completed(quest)]. Give it an observation, content or tracker trigger, or a prerequisite."
427
+ "A bare automatic() quest needs at least one requires entry, such as requires: [completed(quest)]. Give it a content or tracker trigger, or a prerequisite."
413
428
  );
414
429
  }
415
430
  if (bareAutomatic && definition.completion.kind !== "once") {
416
431
  throw new Error(
417
- `A bare automatic() quest cannot use ${definition.completion.kind}() completion. Give it a tracker or observation trigger, or use once().`
432
+ `A bare automatic() quest cannot use ${definition.completion.kind}() completion. Give it a tracker trigger, or use once().`
418
433
  );
419
434
  }
420
435
  if (definition.trigger.kind === "manual" && definition.trigger.input !== "none" && !definition.evaluate) {
@@ -543,7 +558,6 @@ function defineQuest(definition) {
543
558
  member: ctx.member,
544
559
  input: ctx.input,
545
560
  content: contentTrigger ? admittedContentSchema.parse(ctx.content) : null,
546
- observation: ctx.observation ?? null,
547
561
  tracker,
548
562
  eligibleAt: ctx.eligibleAt,
549
563
  now: ctx.now,
@@ -571,7 +585,6 @@ function defineQuest(definition) {
571
585
  ...definition.completion.kind === "keyed" ? {
572
586
  completionKey: definition.completion.key({
573
587
  ...ctx,
574
- observation: ctx.observation ?? null,
575
588
  tracker: pinned
576
589
  })
577
590
  } : {}