@domino-sdk/relay 1.60.0 → 1.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/{integrations-CmIkP1Gi.d.ts → announcements-CHx3-HBw.d.ts} +4 -43
  3. package/dist/{attempt-captures-W2dgzGqE.d.ts → attempt-captures-DYnJVkfg.d.ts} +1 -1
  4. package/dist/authoring.d.ts +14 -14
  5. package/dist/authoring.js +38 -27
  6. package/dist/{automatic-outcomes-Cmou89IS.d.ts → automatic-outcomes-If88LR9f.d.ts} +1 -1
  7. package/dist/avatar.d.ts +1 -1
  8. package/dist/browser.d.ts +7 -7
  9. package/dist/browser.js +10 -10
  10. package/dist/{chunk-2FHNY52R.js → chunk-24I4R732.js} +33 -2
  11. package/dist/{chunk-MJEJQH5A.js → chunk-3Y3L2F54.js} +23 -3
  12. package/dist/{chunk-KUPVQXUJ.js → chunk-5I54XBK2.js} +2 -2
  13. package/dist/{chunk-OTEUP2SG.js → chunk-7A4J67ZL.js} +1 -1
  14. package/dist/{chunk-KWFY7L7X.js → chunk-DHXDBAJF.js} +4 -4
  15. package/dist/{chunk-N3LJ6GFK.js → chunk-DYXDZFKA.js} +5 -2
  16. package/dist/{chunk-N7YOS4ZU.js → chunk-EN3M5Z4J.js} +1 -1
  17. package/dist/{chunk-YOAPPIWN.js → chunk-L77O64I4.js} +1 -1
  18. package/dist/{chunk-422J3QRW.js → chunk-PPB7HALD.js} +1 -1
  19. package/dist/{chunk-4OFH4BNX.js → chunk-QEAS4ZGS.js} +1 -1
  20. package/dist/{chunk-XQKUJL7H.js → chunk-QNUHWK7R.js} +3 -3
  21. package/dist/{chunk-VWMIA2TT.js → chunk-RHBS5FJL.js} +1 -1
  22. package/dist/{chunk-YNW2ZUUP.js → chunk-SE4PFJPT.js} +1 -1
  23. package/dist/{chunk-VVRQQRMQ.js → chunk-SKGTNTLF.js} +8 -8
  24. package/dist/{chunk-Y2IGFLD2.js → chunk-VURRFVNP.js} +7 -7
  25. package/dist/{chunk-6ZG7WNYX.js → chunk-XBV2CK2H.js} +1 -1
  26. package/dist/{chunk-GBSDAD3N.js → chunk-ZDJLPN4L.js} +4 -0
  27. package/dist/{client-Cw1pB5sv.d.ts → client-C51w7fMb.d.ts} +5 -5
  28. package/dist/{deployments-DI-W7fBq.d.ts → deployments-kWoHFaqj.d.ts} +2 -2
  29. package/dist/{groups-9Jm3peq3.d.ts → groups-CqcA2Ycs.d.ts} +1 -1
  30. package/dist/index.d.ts +8 -8
  31. package/dist/index.js +9 -9
  32. package/dist/{analytics-URV-mxjH.d.ts → integrations-B3y36OaB.d.ts} +55 -1
  33. package/dist/internal.d.ts +11 -11
  34. package/dist/internal.js +8 -8
  35. package/dist/{offers-CqXfMIxq.d.ts → offers-BoV4ryUc.d.ts} +2 -2
  36. package/dist/{pages-Bti7g5mX.d.ts → pages-K7-KjSXw.d.ts} +2 -2
  37. package/dist/portal-proxy.js +3 -3
  38. package/dist/react/index.d.ts +15 -11
  39. package/dist/react/index.js +143 -14
  40. package/dist/runtime/authoring.js +1 -1
  41. package/dist/runtime/chunks/5QVFB4TU.js +1 -0
  42. package/dist/runtime/manifest.json +3 -3
  43. package/dist/runtime/schema.js +1 -1
  44. package/dist/{schema-CwbRkmlr.d.ts → schema-CZ6Rj0ZF.d.ts} +1 -1
  45. package/dist/schema.d.ts +14 -14
  46. package/dist/schema.js +10 -8
  47. package/dist/server/index.d.ts +11 -11
  48. package/dist/server/index.js +69 -15
  49. package/dist/{submission-input-D9EGH_yb.d.ts → submission-input-C54Q8yAD.d.ts} +2 -2
  50. package/dist/{telegram-browser-CTJh4Ro_.d.ts → telegram-browser-BUceZIGZ.d.ts} +5 -2
  51. package/dist/testing.d.ts +4 -4
  52. package/dist/testing.js +5 -5
  53. package/dist/{transport-B8Ss5lcz.d.ts → transport-BrX9pIGN.d.ts} +109 -10
  54. package/dist/{wallet-DZWL7lJH.d.ts → wallet-CIqFoxdm.d.ts} +7 -0
  55. package/dist/{x-KFJD2x8y.d.ts → x-D1PGi8Sq.d.ts} +1 -1
  56. package/package.json +1 -1
  57. package/dist/runtime/chunks/ADUMK6CR.js +0 -1
@@ -9,20 +9,20 @@ import {
9
9
  readSignInMethods,
10
10
  signInOptionsFrom,
11
11
  telegramMiniAppInitData
12
- } from "../chunk-2FHNY52R.js";
13
- import "../chunk-VVRQQRMQ.js";
12
+ } from "../chunk-24I4R732.js";
13
+ import "../chunk-SKGTNTLF.js";
14
14
  import {
15
15
  createRelayAction
16
- } from "../chunk-4OFH4BNX.js";
17
- import "../chunk-XQKUJL7H.js";
18
- import "../chunk-MJEJQH5A.js";
19
- import "../chunk-YNW2ZUUP.js";
16
+ } from "../chunk-QEAS4ZGS.js";
17
+ import "../chunk-QNUHWK7R.js";
18
+ import "../chunk-3Y3L2F54.js";
19
+ import "../chunk-SE4PFJPT.js";
20
20
  import "../chunk-KDR2VAJP.js";
21
- import "../chunk-6ZG7WNYX.js";
22
- import "../chunk-N7YOS4ZU.js";
21
+ import "../chunk-XBV2CK2H.js";
22
+ import "../chunk-EN3M5Z4J.js";
23
23
  import {
24
24
  sessionMember
25
- } from "../chunk-422J3QRW.js";
25
+ } from "../chunk-PPB7HALD.js";
26
26
  import {
27
27
  RelayError,
28
28
  RelayErrorCode,
@@ -30,7 +30,7 @@ import {
30
30
  clientError,
31
31
  isRelayError,
32
32
  isRequestError
33
- } from "../chunk-GBSDAD3N.js";
33
+ } from "../chunk-ZDJLPN4L.js";
34
34
 
35
35
  // src/react/context.ts
36
36
  import { createContext, useContext } from "react";
@@ -1055,6 +1055,40 @@ var TEST_STATE_CHANGED_EVENT = "domino:test-state-changed";
1055
1055
  function isVisible() {
1056
1056
  return typeof document === "undefined" || document.visibilityState !== "hidden";
1057
1057
  }
1058
+ var WALLET_SIGN_IN_KEY = "domino:wallet-sign-in";
1059
+ function readWalletSignIn() {
1060
+ try {
1061
+ const value = JSON.parse(
1062
+ window.sessionStorage.getItem(WALLET_SIGN_IN_KEY) ?? "null"
1063
+ );
1064
+ return typeof value?.session === "string" && typeof value.address === "string" && typeof value.chain === "string" ? value : null;
1065
+ } catch {
1066
+ return null;
1067
+ }
1068
+ }
1069
+ function writeWalletSignIn(value) {
1070
+ try {
1071
+ if (value) {
1072
+ window.sessionStorage.setItem(WALLET_SIGN_IN_KEY, JSON.stringify(value));
1073
+ } else {
1074
+ window.sessionStorage.removeItem(WALLET_SIGN_IN_KEY);
1075
+ }
1076
+ } catch {
1077
+ }
1078
+ }
1079
+ function reportingSigner(signer, signed) {
1080
+ return {
1081
+ chain: signer.chain,
1082
+ network: signer.network,
1083
+ name: signer.name,
1084
+ address: () => signer.address(),
1085
+ ...signer.chainId ? { chainId: () => signer.chainId() } : {},
1086
+ sign: (message, address) => {
1087
+ signed(address);
1088
+ return signer.sign(message, address);
1089
+ }
1090
+ };
1091
+ }
1058
1092
  var ACTIVITY_MS = 5e3;
1059
1093
  var SNAPSHOT_MS = 3e4;
1060
1094
  var FOCUS_GAP_MS = 2e3;
@@ -1089,6 +1123,9 @@ var RelayStore = class {
1089
1123
  /** The first cache of this mount: a public read's `initialData` seeds only it. */
1090
1124
  #firstCache = null;
1091
1125
  #settled = null;
1126
+ /** The wallet the current session signed in with, while the store follows its accounts. */
1127
+ #wallet = null;
1128
+ #walletSigningOut = false;
1092
1129
  constructor(client, polling = {}) {
1093
1130
  this.client = client;
1094
1131
  this.#polling = {
@@ -1167,6 +1204,7 @@ var RelayStore = class {
1167
1204
  this.#observer?.dispose();
1168
1205
  this.#observer = null;
1169
1206
  this.#stopFeed();
1207
+ this.#stopWallet(false);
1170
1208
  this.#sessionRead?.abort();
1171
1209
  this.#sessionRead = null;
1172
1210
  this.#sessionVersion++;
@@ -1226,6 +1264,32 @@ var RelayStore = class {
1226
1264
  this.#setSession({ status: "ready", data: null, error: null });
1227
1265
  this.#emit();
1228
1266
  }
1267
+ /**
1268
+ * Signs in with a wallet through the client, then follows the wallet's accounts when the signer
1269
+ * can watch them: a switch to another account, or an empty list, signs out.
1270
+ */
1271
+ async signInWithWallet(signer) {
1272
+ if (!signer.watchAccounts) {
1273
+ await this.client.auth.wallet.signIn(signer);
1274
+ return;
1275
+ }
1276
+ let address;
1277
+ const session = await this.client.auth.wallet.signIn(
1278
+ reportingSigner(signer, (signed) => {
1279
+ address = signed;
1280
+ })
1281
+ );
1282
+ if (!this.#mounted || !address || typeof session?.id !== "string") {
1283
+ return;
1284
+ }
1285
+ writeWalletSignIn({
1286
+ session: session.id,
1287
+ chain: signer.chain,
1288
+ address,
1289
+ ...signer.name ? { name: signer.name } : {}
1290
+ });
1291
+ this.#watchWallet(signer, address, session.id);
1292
+ }
1229
1293
  /**
1230
1294
  * Reads the experience again. With a feed, it is read first: the events it finds read the
1231
1295
  * experience and whatever else they changed, so a change the participant just made shows its
@@ -1319,6 +1383,63 @@ var RelayStore = class {
1319
1383
  this.#feed = null;
1320
1384
  feed?.dispose();
1321
1385
  }
1386
+ /** Signs out when the wallet `session` signed in with reports another account, or none. */
1387
+ #watchWallet(signer, address, session) {
1388
+ this.#stopWallet(false);
1389
+ const signedIn = address.toLowerCase();
1390
+ const watch = { session, stop: () => {
1391
+ } };
1392
+ this.#wallet = watch;
1393
+ watch.stop = signer.watchAccounts((accounts) => {
1394
+ if (this.#wallet === watch && accounts[0]?.toLowerCase() !== signedIn) {
1395
+ void this.#walletSwitched();
1396
+ }
1397
+ });
1398
+ }
1399
+ async #walletSwitched() {
1400
+ if (this.#walletSigningOut) {
1401
+ return;
1402
+ }
1403
+ this.#walletSigningOut = true;
1404
+ try {
1405
+ await this.signOut();
1406
+ } catch {
1407
+ } finally {
1408
+ this.#walletSigningOut = false;
1409
+ }
1410
+ }
1411
+ #stopWallet(forget) {
1412
+ const watch = this.#wallet;
1413
+ this.#wallet = null;
1414
+ watch?.stop();
1415
+ if (forget) {
1416
+ writeWalletSignIn(null);
1417
+ }
1418
+ }
1419
+ /** Follows the wallet a session restored after a reload signed in with, if it is installed. */
1420
+ async #restoreWallet(record) {
1421
+ const wallets = await discoverEvmWallets();
1422
+ const wallet = record.name ? wallets.find((candidate) => candidate.name === record.name) : wallets.length === 1 ? wallets[0] : void 0;
1423
+ if (wallet?.signer.watchAccounts && this.#mounted && !this.#wallet && this.#scope?.session?.id === record.session) {
1424
+ this.#watchWallet(wallet.signer, record.address, record.session);
1425
+ }
1426
+ }
1427
+ /** Stops following a wallet once its session ended; resumes after a reload or remount. */
1428
+ #syncWallet(session) {
1429
+ const id = session?.id ?? null;
1430
+ if (this.#wallet && this.#wallet.session !== id) {
1431
+ this.#stopWallet(true);
1432
+ }
1433
+ if (this.#wallet || !id) {
1434
+ return;
1435
+ }
1436
+ const record = readWalletSignIn();
1437
+ if (record?.session === id && record.chain === "eip155") {
1438
+ void this.#restoreWallet(record);
1439
+ } else if (record) {
1440
+ writeWalletSignIn(null);
1441
+ }
1442
+ }
1322
1443
  /** Reads again, once each, the queries the events change. */
1323
1444
  #applyEvents(events) {
1324
1445
  const keys = /* @__PURE__ */ new Map();
@@ -1457,6 +1578,9 @@ var RelayStore = class {
1457
1578
  };
1458
1579
  this.#firstCache ??= this.#scope.cache;
1459
1580
  this.#syncFeed();
1581
+ if (next.status === "ready") {
1582
+ this.#syncWallet(session);
1583
+ }
1460
1584
  }
1461
1585
  #deriveExperience() {
1462
1586
  const session = this.#session;
@@ -2444,7 +2568,8 @@ function useMe() {
2444
2568
  return useMemberQuery(relayKeys.me, (options) => relay.me.get(options));
2445
2569
  }
2446
2570
  function useSignIn() {
2447
- const relay = useRelay();
2571
+ const store = useStore();
2572
+ const relay = store.client;
2448
2573
  const [challenge, setChallengeState] = useState7(null);
2449
2574
  const latest = useRef6(null);
2450
2575
  const [busy, setBusy] = useState7(false);
@@ -2519,10 +2644,10 @@ function useSignIn() {
2519
2644
  );
2520
2645
  const withWallet = useCallback7(
2521
2646
  (signer) => run(async () => {
2522
- await relay.auth.wallet.signIn(signer);
2647
+ await store.signInWithWallet(signer);
2523
2648
  setChallenge(null);
2524
2649
  }, "Couldn't sign in with this wallet. Try again."),
2525
- [relay, run, setChallenge]
2650
+ [store, run, setChallenge]
2526
2651
  );
2527
2652
  const codeSent = challenge !== null;
2528
2653
  return useMemo7(
@@ -2540,7 +2665,11 @@ function useSignIn() {
2540
2665
  verifyCode,
2541
2666
  startOver,
2542
2667
  withProvider,
2543
- /** Signs in, or signs up, with a wallet; the wallet asks the participant to sign a message. */
2668
+ /**
2669
+ * Signs in, or signs up, with a wallet; the wallet asks the participant to sign a message. A
2670
+ * wallet that can watch its accounts, such as an EVM browser wallet, is followed: switching
2671
+ * to another account in it, or locking it, signs out.
2672
+ */
2544
2673
  withWallet,
2545
2674
  /** Leaves for Telegram Login, where the platform configured it. */
2546
2675
  withTelegram,
@@ -1 +1 @@
1
- import{$g as _,Ad as E,B as A,Bd as He,C as oe,Ce as F,D as se,E as ce,Ee as j,F as ie,Fb as Ce,Fd as q,G as ue,H as de,Hb as xe,He as at,I as le,Id as Ot,J as me,Jc as Ie,Mc as Oe,Nc as jt,Oc as Ne,Of as st,Pd as y,Pe as G,Pg as mt,Qc as Lt,Qd as Je,Rb as Me,Rc as Rt,Rd as C,Re as nt,Rf as ct,Sb as ze,Sc as Ke,Sf as it,Td as Nt,Tf as ut,Ua as K,Uf as dt,Va as ve,Vb as $e,Vc as Tt,Wa as U,Wc as Ue,X as ge,Xa as be,Xc as Bt,Y as he,Yc as Dt,Yh as ft,Ze as ot,Zg as gt,_b as Ae,_c as Ve,_g as ht,a as T,aa as pe,ba as B,bd as Pt,cd as It,dg as Zt,ea as fe,ed as Ze,eg as Qt,fa as N,fd as Qe,ga as ke,gg as Wt,ie as Kt,ja as we,jc as je,je as Ut,kc as Le,ke as Vt,le as Xe,lg as lt,mb as ye,mc as Re,me as Ye,nc as Te,oc as Be,od as Z,oe as et,pb as Se,pc as De,pd as D,qe as tt,r as Y,rc as At,s as ee,sc as Pe,sd as Q,se as rt,t as te,td as W,u as re,ub as Ee,uc as V,ud as We,v as ae,w as ne,wi as Ft,xd as Fe,xh as pt,yb as qe,yd as Ge,zd as _e}from"./chunks/ADUMK6CR.js";import{Cb as z,Ec as $,Kb as H,Pd as $t,fc as J,ic as O,jc as X,va as I,wc as R}from"./chunks/EWU4OKSY.js";function kt(e){if(!Number.isInteger(e)||e<0||e>255)throw new Error("Token decimals must be an integer from 0 to 255")}function Gt(e,r){kt(r);let t=/^(\d+)(?:\.(\d+))?$/.exec(e.trim());if(!t)throw new Error(`Use a decimal amount such as "1.5", not "${e}"`);let[,a,n=""]=t,c=n.replace(/0+$/,"");if(c.length>r)throw new Error(`"${e}" has more than ${r} decimal places, which this token cannot hold`);return BigInt(a+c.padEnd(r,"0"))}function _t(e,r){kt(r);let t=typeof e=="bigint"?e:BigInt(e),a=t<0n?"-":"",n=(t<0n?-t:t).toString().padStart(r+1,"0"),c=n.slice(0,n.length-r),i=n.slice(n.length-r).replace(/0+$/,"");return a+c+(i?"."+i:"")}function vt(e,r={}){let{trigger:t,completion:a,requires:n,performance:c,retryCooldownMs:i,completionCooldownMs:u,authorBudgets:o=[]}=e,g=t.kind==="automatic"?t.tracker:void 0,l=g?.content===!0;if(c&&!l)throw new Error("Performance requires a content quest");if(!g&&o.length)throw new Error('A budget with scope "author" counts per tracker record author: use it only on a quest with a tracker trigger');if(l){if(a.kind!=="keyed")throw new Error("Content quests complete once per content item");if(g.beneficiary!=="author"||g.on!=="new-record")throw new Error("A content quest pays each content item's author and fires on its first observation")}if(i!==void 0&&(t.kind!=="manual"||t.actor==="staff"))throw new Error("A retry cooldown applies only to quests members submit themselves");if(u!==void 0){if(t.kind!=="manual"||t.actor==="staff")throw new Error("A completion cooldown applies only to quests members submit themselves");if(a.kind==="once")throw new Error("A completion cooldown needs a quest members can complete more than once: this one completes once per member")}if(t.kind==="automatic"&&!g){if(!r.template&&n.length===0)throw new Error("Automatic quests need at least one prerequisite");if(a.kind!=="once")throw new Error("Prerequisite-only automatic quests complete once")}}var Ht=["author"],Jt=["author","messageAuthor"];function bt(e){if(!we(e))return[];switch(e.kind){case"x-search":return ge;case"discord-messages":return Ht;case"discord-reactions":return Jt;case"custom":return["author",...e.accounts??[]]}}var wt=new Map;function Xt(e){let r=e.kind==="discord-messages"&&e.text?"messages-text":e.kind,t=wt.get(r);return t||(t=A(r==="messages-text"?re:r==="discord-messages"?te:ae),wt.set(r,t)),t}function yt(e){switch(e.kind){case"x-search":return;case"discord-messages":case"discord-reactions":return Xt(e);case"custom":return e.data}}function Er(e){return y("badge",mt.parse(e))}function qr(e){return y("ledger",lt.parse(e))}function Cr(e){let{target:r,ledger:t,...a}=e,n=gt.parse({...a,qualifiedBy:e.qualifiedBy.key,balance:C(t)}),c=R($(e.metrics),_.shape.target);return{key:n.key,describe:()=>n,score(i){let u=ht.parse(i);return _.parse({target:r({metrics:c.parse(u.metrics)}),baseline:r({metrics:c.parse(u.baseline)})})}}}var er=e=>{if("timeZone"in e)throw new Error("streak() no longer takes a timeZone. Set the project timezone with calendar.timeZone in relay.json or in Console settings.");return ye.strict().parse({kind:"streak",...e})},xr=e=>ve.brand().parse({kind:"count",count:e}),Mr=(e,r={})=>U.brand().parse({kind:"calendar",period:e,...r}),zr=({days:e})=>U.brand().parse({kind:"rolling",durationMs:e*864e5}),$r=e=>({kind:"quest",quest:e});function Ar(e){let{qualification:r,inviterGroup:t,milestones:a,bonuses:n,...c}=e,i=ft.parse({...c,qualification:r.kind==="quest"?{kind:"quest",quest:r.quest.key}:r,...t?{inviterGroup:T.parse(t.key)}:{},milestones:a?.map(({key:u,...o})=>({...o,id:q({key:u,...o})})),bonuses:n?.map(({key:u,ledger:o,quests:g,...l})=>({...l,id:q({key:u,...l}),balance:C(o),quests:g?.map(M=>M.key)}))});return y("referral",i)}function jr(e={}){return{kind:"earned",...e}}function Lr(e){let{ledger:r,group:t,score:a,settle:n,...c}=e,i=n?.pool,u=pt.parse({...c,...n?{settle:{...n,prizes:n.prizes??[],...i?{pool:{...i,...i.ledger===void 0?{}:{ledger:C(i.ledger)}}}:{}}}:{},balance:C(r),...t?{group:T.parse(t.key)}:{},score:a?.kind==="earned"?{...a,quests:a.quests?.map(o=>o.key)}:a});return y("leaderboard",u)}var Rr={provider:"x",search:e=>pe.parse({kind:"x-search",...e})};function L(e,r){let{data:t,content:a,...n}=r??{};if(a!==void 0){if(t!==void 0)throw new Error(`customSource("${e}") takes data or content, not both: a content source's records carry { body, metrics }`);if(!St(a.body))throw new Error(`customSource("${e}") needs a content body schema: customSource(namespace, { content: { body: z.object({ ... }), metrics: ["likes"] } })`);let c=[...a.metrics??[]];for(let i of c)he.parse(i);return B.parse({kind:"custom",namespace:e,...n,data:A(O({body:a.body,metrics:X(Object.fromEntries(c.map(i=>[i,z().int().safe().nonnegative().optional()]))).optional()})),content:{metrics:c}})}if(!St(t))throw new Error(`customSource("${e}") needs a data schema: customSource(namespace, { data: z.object({ ... }) }) describes each record's data`);return B.parse({kind:"custom",namespace:e,...n,data:A(t)})}function St(e){return typeof e=="object"&&e!==null&&"_zod"in e}function Tr(e){return y("tracker",ke.parse(e))}function tr(e={}){return Y.parse({kind:"discord-messages",...e.text?{text:!0}:{}})}function rr(){return ee.parse({kind:"discord-reactions"})}var Br={provider:"discord",grantRole:e=>ne.parse({kind:"integration",provider:"discord",action:"grant-role",roleId:e}),postMessage(e){return Te.parse({provider:"discord",action:"post-message",...e})},messages:tr,reactions:rr,roles(e={}){return D.parse({provider:"discord",resource:"role",assignable:e.assignable??!1})},channels(e={}){return D.parse({provider:"discord",resource:"channel",types:e.types??["text","announcement"],...e.postable?{postable:!0}:{}})}},Dr={postMessage(e){return Re.parse({provider:"telegram",action:"post-message",...e})},messages(){return L(ue,{identities:["member"],data:Le})},reactions(){return L(ie,{identities:["member"],accounts:["messageAuthor"],data:je})}},Pr={shorts(){return L(de,{identities:["member"],content:{body:ct,metrics:it}})}},Ir={videos(){return L(le,{identities:["member"],content:{body:ut,metrics:dt}})}};function ar(e){let{chain:r,token:t}=e,a=t===void 0?null:t;if(a!==null&&typeof a!="string")throw new Error("wallet.balances() takes the token as a string");if(r==="solana"||r===V){if(a!==null&&!De.safeParse(a).success)throw new Error("wallet.balances() on Solana takes an SPL or Token-2022 mint address (base58)");return{chain:V,token:a}}if(typeof r=="string"&&Ie(r)){if(a!==null&&!/^0x[0-9a-fA-F]{40}$/.test(a))throw new Error("wallet.balances() on an EVM chain takes an ERC-20 contract address: 0x and 40 hex digits");return{chain:r,token:a}}if(typeof r=="string"&&/^cosmos:[-_a-zA-Z0-9]{1,32}$/.test(r)){if(a===null||!Pe.safeParse(a).success)throw new Error("wallet.balances() on a Cosmos chain takes a bank denomination such as uatom");return{chain:r,token:a}}throw new Error('wallet.balances() reads "solana", an EVM chain such as "eip155:8453" or a Cosmos network such as "cosmos:cosmoshub-4"')}var Or={balances(e){let r=ar(e),t=L(me,{identities:["wallet"],data:Oe});return B.parse({...t,balance:r})}},Nr=()=>({provider:"domino",resource:"point-ledger"});function p(e,r){return r}var Kr={pointLedger(e){let r={...e,kind:"point-ledger",default:e.default?T.parse(e.default.key):""};return p("point-ledger",Je.prefault(r.default).meta(r))},datetime(e){let r={...e,kind:"datetime",default:Q.parse(e.default)};return p("datetime",Q.default(r.default).meta(r))},resource(e){let r={...e,source:D.parse(e.source),kind:"resource",default:W.parse(e.default??"")};return p("resource",W.default(r.default).meta(r))},quiz(e){let r=Z.parse(e.default);return p("quiz",Z.default(r).meta({...e,default:r,kind:"quiz"}))},text(e){let r={...e,kind:"text",minLength:e.minLength??1,maxLength:e.maxLength??2e3,multiline:e.multiline??!1};return p("text",I().min(r.minLength).max(r.maxLength).default(r.default).meta(r))},telegramChat(e){let r={...e,kind:"text",default:e.default??"",minLength:0,maxLength:64,multiline:!1,picker:"telegram-chat"};return p("text",I().max(r.maxLength).default(r.default).meta(r))},amount(e){if(!Fe(e.default))throw new Error(`settings.amount() takes a base-unit integer string as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:100,multiline:!1,picker:"amount"};return p("text",E(r).default(r.default).meta(r))},chain(e){if(!Ge(e.default))throw new Error(`settings.chain() takes "solana" or an EVM chain ID such as "eip155:8453" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:64,multiline:!1,picker:"chain"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},nft(e){if(!Ne(e.default))throw new Error(`settings.nft() takes an NFT collection such as "eip155:1/erc721:0x\u2026" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:200,multiline:!1,picker:"nft"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},contractCall(e){if(!Ke(e.default))throw new Error(`settings.contractCall() takes a contract call such as "eip155:8453:0x\u2026 function stakedOf(address) view returns (uint256)" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:400,multiline:!1,picker:"contract-call"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},contractEvent(e){if(!Ue(e.default))throw new Error(`settings.contractEvent() takes a contract event such as "eip155:1:0x\u2026 Transfer(address indexed from, address indexed to, uint256 value)" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:1e3,multiline:!1,picker:"contract-event"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},solanaProgram(e){if(!Ve(e.default))throw new Error(`settings.solanaProgram() takes a Solana program address such as "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:32,maxLength:44,multiline:!1,picker:"solana-program"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},integer(e){return p("integer",z().int().min(e.min).max(e.max).default(e.default).meta({...e,kind:"integer"}))},boolean(e){return p("boolean",H().default(e.default).meta({...e,kind:"boolean"}))},choice(e){return p("choice",$(e.options).default(e.default).meta({...e,kind:"choice"}))},object(e){return O(e).strict()}};function qt(e,r){let t=e.balanceChanges.find(a=>a.mint===r);return t?BigInt(t.delta):0n}function Vr(e,r){let t=qt(e,r);return t>0n?t.toString():"0"}function Zr(e,r){let t=qt(e,r);return t<0n?(-t).toString():"0"}function Qr(e,r={}){let t=e.balanceChanges.filter(n=>BigInt(n.delta)>0n),a=e.balanceChanges.filter(n=>BigInt(n.delta)<0n);return t.some(n=>(r.into===void 0||n.mint===r.into)&&a.some(c=>c.mint!==n.mint&&(r.from===void 0||c.mint===r.from)))}function Wr(e,r){return e.programs.includes(r)}function Fr(e,r){return e.instructions?.find(t=>t.name===r)?.args??null}var Gr=e=>tt(e.key,e.name),_r=e=>rt(e.key,e.title),Hr=(e,r)=>Xe.parse({kind:"points",balance:C(e),amount:r}),Jr={text:(e={})=>({input:"text",constraints:Ze.parse(e)}),url:(e={})=>({input:"url",constraints:Qe.parse(e)}),photo:()=>"photo",quiz:()=>"quiz"};function Xr(e){if(e?.actor&&e.input!==void 0)throw new Error('manual() cannot combine actor "staff" with input: staff-captured evidence is not supported. Use manual({ actor: "staff" }) for a staff confirmation, or manual({ input }) for evidence the participant submits.');return typeof e?.input=="object"?{kind:"manual",...e.input}:{kind:"manual",input:e?.input??"none",...e?.actor?{actor:e.actor}:{}}}var Ct=new WeakMap,xt=new WeakMap;function Mt(e,r){let{tracker:t,beneficiary:a="author",on:n,where:c,enrollment:i,since:u,historical:o,content:g}=e;if(!t?.source)throw new Error(r==="automatic"?"automatic() takes no argument, or { tracker } with a tracker handle from defineTracker":"content() takes { tracker } with a tracker handle from defineTracker");let{source:l}=t;if(!fe(l))throw new Error('Tracker triggers need attributable records: declare customSource(namespace, { identities: ["wallet"] }) or other identity kinds');if(g&&!N(l))throw new Error(`content() needs a tracker whose source has content: x.search(), or customSource(namespace, { content: { body, metrics } }). Tracker "${t.key}" has none; use automatic({ tracker }) instead.`);if(u==="enrollment"&&i!=="required")throw new Error(`${r}() counts from enrollment only on a quest that requires it: add enrollment: "required"`);let M=bt(l);if(!M.includes(a))throw new Error(l.kind==="custom"?`Tracker "${t.key}" has no "${a}" account: declare it in customSource(namespace, { accounts: ["${a}"] })`:`Tracker "${t.key}" pays ${M.map(S=>`"${S}"`).join(" or ")}, not "${a}"`);let s=qe.parse({tracker:t.key,source:l.kind,on:g?"new-record":n??Se(l.kind),...c?{where:c}:{},beneficiary:a,...i==="required"?{enrollment:i}:{},...u&&u!=="activation"?{since:u}:{},...o&&o!==(g?"claim":"staff")?{historical:o}:{},...g?{content:g}:{}}),d=yt(l),f=d?ce(d,s.where):null;if(f)throw new Error(f);let b={kind:"automatic",tracker:s};d&&Ct.set(b,d);let w=N(l);return w&&xt.set(b,w.metrics),b}function Yr(e){return e?Mt(e,"automatic"):{kind:"automatic"}}function ea(e){if(e&&typeof e=="object"&&"source"in e&&"key"in e&&!("tracker"in e))throw new Error("content() takes { tracker }: write content({ tracker: posts }) instead of content(posts)");return Mt({...e,content:!0},"content")}function nr(e){let{key:r,cost:t,...a}=e,n={...a,id:q(e),cost:typeof t=="number"?t:{balance:C(t.ledger)}};return a.scope==="author"?ze.parse(n):Me.parse(n)}var ta=nr,or=(e=[])=>e.filter(r=>r.scope==="author"),sr=e=>({kind:"keyed",key:e}),cr=e=>{let{distinct:r,...t}=e;return{...be.parse({kind:"progress",window:{kind:"lifetime"},...t}),distinct:r}},ra=()=>({kind:"untracked"}),aa=()=>({kind:"staff-handover"}),na=()=>({kind:"automatic"});function oa(e){let{key:r,tiers:t,...a}=e,n=q(e),c=Ye.parse({id:n,...a,tiers:t.map(({key:i,...u})=>({...u,id:q({key:i,...u})}))});return y("tiered-reward",{key:c.id,tier:i=>et.parse({kind:"tier",reward:c,tier:i})})}var ir=()=>({kind:"once"});function ur(e={}){return{kind:"accept",...e}}function dr(e){return{kind:"review",...e}}var x={accept:ur,defer:e=>({kind:"defer",...e}),progress:e=>({kind:"progress",...e}),reject:e=>({kind:"reject",...e}),review:dr};function Et(e){let r=e.kind==="reject"&&e.code!==void 0?xe(e.code):null;if(r)throw new Error(r)}var sa={quiz(e,r={}){let t=ot.parse(e),a=Object.keys(t),n=z().int().min(1).max(a.length).parse(r.minimumCorrect??a.length);return async({input:c})=>{let i=Object.keys(c.answers).length===a.length&&a.every(o=>Object.hasOwn(c.answers,o)),u=a.filter(o=>c.answers[o]===t[o]).length;return i&&u>=n?x.accept():x.reject({reason:"Review your answers and try again."})}},photo(e){return async r=>{let t=e(r),a=await r.review.photo({image:r.input.photo,criteria:t.criteria});return a.kind==="unclear"?t.unclear==="human-review"?x.review({reason:a.reason}):x.reject({reason:a.reason}):a.kind==="pass"?x.accept():x.reject({reason:a.reason})}}},lr={once:ir,keyed:sr,streak:er,progress:cr};function zt(e){return function(t){let a=q(t),n=[...new Set((t.integrations??[]).map(s=>$e.parse(s.provider)))],c=t.trigger.kind==="automatic"&&t.trigger.tracker?.content===!0,i=t.trigger.kind==="automatic"&&t.trigger.tracker!==void 0,u=t.completion,o=typeof u=="function"?u(lr):u;if(c&&o!==void 0)throw new Error("A content quest completes once per content item: remove its completion");if(!c&&o===void 0)throw new Error("A quest needs a completion, such as once(), keyed(...), streak(...) or progress(...)");let g=or(t.budgets);if(vt({trigger:t.trigger,completion:o??{kind:"keyed"},requires:t.requires??[],authorBudgets:g,performance:t.performance?K.parse({metrics:t.performance.metrics,maxAgeMs:t.performance.maxAgeMs}):void 0,...t.retryCooldownMs===void 0?{}:{retryCooldownMs:t.retryCooldownMs},...t.completionCooldownMs===void 0?{}:{completionCooldownMs:t.completionCooldownMs}},{template:e}),t.retryCooldownMs!==void 0&&!F.safeParse(t.retryCooldownMs).success)throw new Error("retryCooldownMs must be whole milliseconds from 1000 (one second) to 604800000 (seven days)");if(t.completionCooldownMs!==void 0&&!F.safeParse(t.completionCooldownMs).success)throw new Error("completionCooldownMs must be whole milliseconds from 1000 (one second) to 604800000 (seven days)");if(t.performance){let s=xt.get(t.trigger)??[],d=t.performance.metrics.filter(f=>!s.includes(f));if(d.length)throw new Error(`The tracker's source does not measure ${d.join(", ")}`)}if(t.trigger.kind==="manual"&&t.trigger.input!=="none"&&!t.evaluate)throw new Error("Evidence quests require an evaluator");let l=Object.fromEntries(Object.entries(t.settings.shape).map(([s,d])=>{let f=We.safeParse(d.meta());if(!f.success)throw new Error(`Setting "${s}" is not a quest setting: build it with a settings builder, such as settings.integer({ label, default, min, max })`);return[s,f.data]}));for(let s of Ee(t.trigger.kind==="automatic"?t.trigger.tracker?.where:void 0))if(!_e(l[s]))throw new Error(`The tracker filter compares with setting "${s}", which is not an integer or amount setting`);function M(s){let d=t.settings.parse(s),f=He(l,d),b=at.parse(typeof t.rewards=="function"?t.rewards({settings:d}):t.rewards),w=J(Be).max(3,"A quest posts at most three announcements").parse((typeof t.announcements=="function"?t.announcements({settings:d}):t.announcements)??[]),S=t.trigger.kind==="automatic"&&t.trigger.tracker!==void 0;for(let m of w){let v=Ae(m.text),P="segments"in v&&v.segments.some(k=>k.kind==="placeholder"&&k.name==="author");if(!S&&P)throw new Error("An announcement names {author} only on a quest with an automatic tracker trigger");if(!S&&m.replyToTriggeringMessage)throw new Error("An announcement replies to the triggering message only on a quest with an automatic tracker trigger")}let h=[...b.flatMap(m=>m.kind==="integration"?[m.provider]:[]),...w.flatMap(m=>m.provider==="discord"?["discord"]:[]),...Object.values(l).flatMap(m=>m.kind==="resource"&&m.source.provider!=="domino"?[m.source.provider]:[])];for(let m of h)if(!n.includes(m))throw new Error(`Declare the ${m} integration on this quest`);return nt.parse({quest:a,evaluatorProtocol:G,title:typeof t.title=="function"?t.title({settings:d}):t.title,presentation:t.presentation?.({settings:d})??{},fields:l,values:f,rewards:b,...w.length?{announcements:w}:{},humanReview:t.review?.({settings:d})?.enabled??!0,trigger:t.trigger,...t.performance?{performance:K.parse({metrics:t.performance.metrics,maxAgeMs:t.performance.maxAgeMs})}:{},integrations:n,completion:o?o.kind==="progress"?{kind:o.kind,goal:o.goal,window:o.window,repeat:o.repeat}:o.kind==="streak"?o:{kind:o.kind}:{kind:"keyed"},visibility:t.visibility??"visible",profile:t.profile??{visible:!1},budgets:(t.budgets??[]).filter(m=>m.scope!=="author"),...g.length?{authorBudgets:g}:{},requires:t.requires??[],...t.campaign?{campaign:t.campaign}:{},...t.availability?{availability:t.availability}:{},...t.retryCooldownMs===void 0?{}:{retryCooldownMs:t.retryCooldownMs},...t.completionCooldownMs===void 0?{}:{completionCooldownMs:t.completionCooldownMs}})}return y("quest",{protocol:G,key:a,describe:M,async evaluate(s){let d=t.settings.parse(s.settings),f=i?Ce.parse(s.tracker):null,b=Ct.get(t.trigger),w=f&&b?oe(b,f.record.data):null;if(w)return j.parse({kind:"reject",reason:`The record's data does not match the data schema this quest was built with: ${w.path} ${w.reason}`});let S=f;if(s.performance){if(!t.performance)throw new Error("Quest has no performance evaluator");let v=st.parse(s.performance),P=R($(t.performance.metrics),z().int().safe().nonnegative()).parse(v.metrics),k=await t.performance.evaluate({settings:d,member:s.member,tracker:S,metrics:P,observedAt:v.observedAt});if(!k)throw new Error("Performance evaluator returned no decision");if(k.rewards!==void 0)throw new Error("A performance evaluator cannot select rewards. It gates the rewards content evaluation selected: return accept, review or reject with a reason only.");return Et(k),j.parse(k.kind==="accept"?{kind:"accept",rewards:v.rewards}:k.kind==="review"&&s.humanReview?{kind:"review",reason:k.reason,rewards:v.rewards}:{kind:"reject",reason:k.reason,...k.kind==="review"?{requestedReview:!0}:k.code===void 0?{}:{code:k.code}})}let h=t.evaluate?await t.evaluate({settings:d,member:s.member,input:s.input,tracker:S,eligibleAt:s.eligibleAt,calendar:s.calendar,now:s.now,review:s.review,trackers:se(s.trackers),wallet:s.wallet,images:s.images,...s.telegram?{telegram:s.telegram}:{},...Object.fromEntries(n.map(v=>[v,s[v]]))}):x.accept();if(!h)throw new Error("Evaluator returned no decision");if(Et(h),h.kind==="review"&&!s.humanReview)return j.parse({kind:"reject",reason:h.reason,requestedReview:!0});(h.kind==="accept"||h.kind==="review")&&h.completionKey!==void 0&&o?.kind!=="keyed"&&s.diagnose?.({code:"completion-key-ignored",message:mr(o,h.completionKey)});let m={...s,settings:d,tracker:f};return j.parse(h.kind==="accept"||h.kind==="review"?{...h,rewards:h.rewards??s.rewards,...o?.kind==="keyed"||o?.kind==="progress"?{completionKey:o.kind==="progress"?o.distinct(m):h.completionKey??o.key(m)}:{}}:h)}})}}function mr(e,r){let t=`ignores completionKey ${JSON.stringify(r)}`;switch(e?.kind){case void 0:return`A content quest completes once per content item, under a key Relay sets, so it ${t}`;case"once":return`once() completes the quest once per member and ${t}: use keyed(...) to complete it once per key`;case"streak":return`streak(...) keys its own completions and ${t}`;case"progress":return`progress(...) keys each contribution with its distinct(...) and ${t}: derive the key in distinct(...)`}}var ca=zt(!1),ia=zt(!0);export{Wt as CapabilityError,Yr as automatic,na as automaticFulfillment,Gr as badge,Ut as balanceAtLeast,ta as budget,Mr as calendar,Qt as capabilityErrorCodes,Kt as completed,ea as content,Pe as cosmosDenomSchema,At as cosmosNetworkSchema,xr as count,L as customSource,x as decision,Er as defineBadge,Ot as defineCampaign,Zt as defineDashboard,Cr as defineEngagementReward,Nt as defineGroup,Lr as defineLeaderboard,qr as defineLedger,Ft as defineOffer,ca as defineQuest,ia as defineQuestType,Ar as defineReferral,oa as defineTieredReward,Tr as defineTracker,Br as discord,jr as earned,sa as evaluators,Jr as evidence,_t as formatUnits,_r as groupMembership,Vt as inGroup,Fr as instruction,Wr as invoked,Ke as isContractCall,Ue as isContractEvent,Ie as isEvmChainId,Ne as isNftCollection,Ve as isSolanaProgram,sr as keyed,Xr as manual,Bt as maxWalletEventLogs,Dt as maxWalletEventLookback,It as maxWalletTransactionLookback,Pt as maxWalletTransactions,ir as once,Rt as parseContractCall,Tt as parseContractEvent,Lt as parseContractFunction,jt as parseNftCollection,Gt as parseUnits,Nr as pointLedgers,Hr as points,cr as progress,$r as questCompleted,Vr as received,zr as rolling,Kr as settings,Zr as spent,aa as staffHandover,er as streak,Qr as swapped,Dr as telegram,Ir as tiktok,A as trackerDataSchema,Ce as trackerTriggerContextSchema,ra as untracked,Or as wallet,Rr as x,Pr as youtube,$t as z};
1
+ import{$b as je,$c as Ze,Ad as He,B as j,Bd as E,C as se,Cd as Je,D as ce,De as G,E as ie,F as ue,Fb as xe,Fe as L,G as de,Gd as q,H as le,Hb as Me,Hh as gt,I as me,Ie as nt,Ig as dt,J as ge,Jd as Nt,Jg as lt,Kc as Oe,Kg as H,Nc as Ne,Oc as Lt,Pc as Ke,Pf as ct,Qd as y,Qe as _,Rb as ze,Rc as Rt,Rd as Xe,Sb as $e,Sc as Tt,Sd as C,Se as ot,Tc as Ue,Ua as U,Ud as Kt,Uh as $,Va as be,Vb as Ae,Wa as V,Wc as Bt,Wf as it,X as he,Xa as ye,Xc as Ve,Y as pe,Yc as Dt,Zc as Pt,_e as st,a as B,aa as fe,ba as D,cd as It,dd as Ot,ea as ke,fa as K,fd as Qe,ga as we,gd as We,gh as mt,gi as Qt,hi as ht,ii as pt,ja as ve,je as Ut,ji as ft,kc as Le,ke as Vt,ki as kt,lc as Re,le as Zt,mb as Se,me as Ye,nc as Te,ne as et,oc as Be,pb as Ee,pc as De,pd as Q,pe as tt,qc as Pe,qd as P,r as ee,re as rt,s as te,sc as jt,t as re,tc as Ie,td as W,te as at,u as ae,ub as qe,ud as F,v as ne,vc as Z,vd as Fe,vi as Wt,w as oe,wi as Ft,yb as Ce,yd as Ge,yg as ut,yi as Gt,zd as _e}from"./chunks/5QVFB4TU.js";import{Cb as z,Ec as A,Kb as J,Pd as At,fc as X,ic as N,jc as Y,va as O,wc as T}from"./chunks/EWU4OKSY.js";function wt(e){if(!Number.isInteger(e)||e<0||e>255)throw new Error("Token decimals must be an integer from 0 to 255")}function _t(e,r){wt(r);let t=/^(\d+)(?:\.(\d+))?$/.exec(e.trim());if(!t)throw new Error(`Use a decimal amount such as "1.5", not "${e}"`);let[,a,n=""]=t,c=n.replace(/0+$/,"");if(c.length>r)throw new Error(`"${e}" has more than ${r} decimal places, which this token cannot hold`);return BigInt(a+c.padEnd(r,"0"))}function Ht(e,r){wt(r);let t=typeof e=="bigint"?e:BigInt(e),a=t<0n?"-":"",n=(t<0n?-t:t).toString().padStart(r+1,"0"),c=n.slice(0,n.length-r),i=n.slice(n.length-r).replace(/0+$/,"");return a+c+(i?"."+i:"")}function bt(e,r={}){let{trigger:t,completion:a,requires:n,performance:c,retryCooldownMs:i,completionCooldownMs:u,authorBudgets:o=[]}=e,g=t.kind==="automatic"?t.tracker:void 0,l=g?.content===!0;if(c&&!l)throw new Error("Performance requires a content quest");if(!g&&o.length)throw new Error('A budget with scope "author" counts per tracker record author: use it only on a quest with a tracker trigger');if(l){if(a.kind!=="keyed")throw new Error("Content quests complete once per content item");if(g.beneficiary!=="author"||g.on!=="new-record")throw new Error("A content quest pays each content item's author and fires on its first observation")}if(i!==void 0&&(t.kind!=="manual"||t.actor==="staff"))throw new Error("A retry cooldown applies only to quests members submit themselves");if(u!==void 0){if(t.kind!=="manual"||t.actor==="staff")throw new Error("A completion cooldown applies only to quests members submit themselves");if(a.kind==="once")throw new Error("A completion cooldown needs a quest members can complete more than once: this one completes once per member")}if(t.kind==="automatic"&&!g){if(!r.template&&n.length===0)throw new Error("Automatic quests need at least one prerequisite");if(a.kind!=="once")throw new Error("Prerequisite-only automatic quests complete once")}}var Jt=["author"],Xt=["author","messageAuthor"];function yt(e){if(!ve(e))return[];switch(e.kind){case"x-search":return he;case"discord-messages":return Jt;case"discord-reactions":return Xt;case"custom":return["author",...e.accounts??[]]}}var vt=new Map;function Yt(e){let r=e.kind==="discord-messages"&&e.text?"messages-text":e.kind,t=vt.get(r);return t||(t=j(r==="messages-text"?ae:r==="discord-messages"?re:ne),vt.set(r,t)),t}function St(e){switch(e.kind){case"x-search":return;case"discord-messages":case"discord-reactions":return Yt(e);case"custom":return e.data}}function qr(e){return y("badge",$("Badge",ut,e))}function Cr(e){return y("ledger",$("Point ledger",it,e))}function xr(e){let{target:r,ledger:t,...a}=e,n=dt.parse({...a,qualifiedBy:e.qualifiedBy.key,balance:C(t)}),c=T(A(e.metrics),H.shape.target);return{key:n.key,describe:()=>n,score(i){let u=lt.parse(i);return H.parse({target:r({metrics:c.parse(u.metrics)}),baseline:r({metrics:c.parse(u.baseline)})})}}}var tr=e=>{if("timeZone"in e)throw new Error("streak() no longer takes a timeZone. Set the project timezone with calendar.timeZone in relay.json or in Console settings.");return Se.strict().parse({kind:"streak",...e})},Mr=e=>be.brand().parse({kind:"count",count:e}),zr=(e,r={})=>V.brand().parse({kind:"calendar",period:e,...r}),$r=({days:e})=>V.brand().parse({kind:"rolling",durationMs:e*864e5}),Ar=e=>({kind:"quest",quest:e});function jr(e){let{qualification:r,inviterGroup:t,milestones:a,bonuses:n,...c}=e,i=$("Referral",gt,{...c,qualification:r.kind==="quest"?{kind:"quest",quest:r.quest.key}:r,...t?{inviterGroup:B.parse(t.key)}:{},milestones:a?.map(({key:u,...o})=>({...o,id:q({key:u,...o})})),bonuses:n?.map(({key:u,ledger:o,quests:g,...l})=>({...l,id:q({key:u,...l}),balance:C(o),quests:g?.map(M=>M.key)}))});return y("referral",i)}function Lr(e={}){return{kind:"earned",...e}}function Rr(e){let{ledger:r,group:t,score:a,settle:n,...c}=e,i=n?.pool,u=$("Leaderboard",mt,{...c,...n?{settle:{...n,prizes:n.prizes??[],...i?{pool:{...i,...i.ledger===void 0?{}:{ledger:C(i.ledger)}}}:{}}}:{},balance:C(r),...t?{group:B.parse(t.key)}:{},score:a?.kind==="earned"?{...a,quests:a.quests?.map(o=>o.key)}:a});return y("leaderboard",u)}var Tr={provider:"x",search:e=>fe.parse({kind:"x-search",...e})};function R(e,r){let{data:t,content:a,...n}=r??{};if(a!==void 0){if(t!==void 0)throw new Error(`customSource("${e}") takes data or content, not both: a content source's records carry { body, metrics }`);if(!Et(a.body))throw new Error(`customSource("${e}") needs a content body schema: customSource(namespace, { content: { body: z.object({ ... }), metrics: ["likes"] } })`);let c=[...a.metrics??[]];for(let i of c)pe.parse(i);return D.parse({kind:"custom",namespace:e,...n,data:j(N({body:a.body,metrics:Y(Object.fromEntries(c.map(i=>[i,z().int().safe().nonnegative().optional()]))).optional()})),content:{metrics:c}})}if(!Et(t))throw new Error(`customSource("${e}") needs a data schema: customSource(namespace, { data: z.object({ ... }) }) describes each record's data`);return D.parse({kind:"custom",namespace:e,...n,data:j(t)})}function Et(e){return typeof e=="object"&&e!==null&&"_zod"in e}function Br(e){return y("tracker",$("Tracker",we,e))}function rr(e={}){return ee.parse({kind:"discord-messages",...e.text?{text:!0}:{}})}function ar(){return te.parse({kind:"discord-reactions"})}var Dr={provider:"discord",grantRole:e=>oe.parse({kind:"integration",provider:"discord",action:"grant-role",roleId:e}),postMessage(e){return Be.parse({provider:"discord",action:"post-message",...e})},messages:rr,reactions:ar,roles(e={}){return P.parse({provider:"discord",resource:"role",assignable:e.assignable??!1})},channels(e={}){return P.parse({provider:"discord",resource:"channel",types:e.types??["text","announcement"],...e.postable?{postable:!0}:{}})}},Pr={postMessage(e){return Te.parse({provider:"telegram",action:"post-message",...e})},messages(){return R(de,{identities:["member"],data:Re})},reactions(){return R(ue,{identities:["member"],accounts:["messageAuthor"],data:Le})}},Ir={shorts(){return R(le,{identities:["member"],content:{body:ht,metrics:pt}})}},Or={videos(){return R(me,{identities:["member"],content:{body:ft,metrics:kt}})}};function nr(e){let{chain:r,token:t}=e,a=t===void 0?null:t;if(a!==null&&typeof a!="string")throw new Error("wallet.balances() takes the token as a string");if(r==="solana"||r===Z){if(a!==null&&!Pe.safeParse(a).success)throw new Error("wallet.balances() on Solana takes an SPL or Token-2022 mint address (base58)");return{chain:Z,token:a}}if(typeof r=="string"&&Oe(r)){if(a!==null&&!/^0x[0-9a-fA-F]{40}$/.test(a))throw new Error("wallet.balances() on an EVM chain takes an ERC-20 contract address: 0x and 40 hex digits");return{chain:r,token:a}}if(typeof r=="string"&&/^cosmos:[-_a-zA-Z0-9]{1,32}$/.test(r)){if(a===null||!Ie.safeParse(a).success)throw new Error("wallet.balances() on a Cosmos chain takes a bank denomination such as uatom");return{chain:r,token:a}}throw new Error('wallet.balances() reads "solana", an EVM chain such as "eip155:8453" or a Cosmos network such as "cosmos:cosmoshub-4"')}var Nr={balances(e){let r=nr(e),t=R(ge,{identities:["wallet"],data:Ne});return D.parse({...t,balance:r})}},Kr=()=>({provider:"domino",resource:"point-ledger"});function p(e,r){return r}var Ur={pointLedger(e){let r={...e,kind:"point-ledger",default:e.default?B.parse(e.default.key):""};return p("point-ledger",Xe.prefault(r.default).meta(r))},datetime(e){let r={...e,kind:"datetime",default:W.parse(e.default)};return p("datetime",W.default(r.default).meta(r))},resource(e){let r={...e,source:P.parse(e.source),kind:"resource",default:F.parse(e.default??"")};return p("resource",F.default(r.default).meta(r))},quiz(e){let r=Q.parse(e.default);return p("quiz",Q.default(r).meta({...e,default:r,kind:"quiz"}))},text(e){let r={...e,kind:"text",minLength:e.minLength??1,maxLength:e.maxLength??2e3,multiline:e.multiline??!1};return p("text",O().min(r.minLength).max(r.maxLength).default(r.default).meta(r))},telegramChat(e){let r={...e,kind:"text",default:e.default??"",minLength:0,maxLength:64,multiline:!1,picker:"telegram-chat"};return p("text",O().max(r.maxLength).default(r.default).meta(r))},amount(e){if(!Ge(e.default))throw new Error(`settings.amount() takes a base-unit integer string as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:100,multiline:!1,picker:"amount"};return p("text",E(r).default(r.default).meta(r))},chain(e){if(!_e(e.default))throw new Error(`settings.chain() takes "solana" or an EVM chain ID such as "eip155:8453" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:64,multiline:!1,picker:"chain"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},nft(e){if(!Ke(e.default))throw new Error(`settings.nft() takes an NFT collection such as "eip155:1/erc721:0x\u2026" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:200,multiline:!1,picker:"nft"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},contractCall(e){if(!Ue(e.default))throw new Error(`settings.contractCall() takes a contract call such as "eip155:8453:0x\u2026 function stakedOf(address) view returns (uint256)" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:400,multiline:!1,picker:"contract-call"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},contractEvent(e){if(!Ve(e.default))throw new Error(`settings.contractEvent() takes a contract event such as "eip155:1:0x\u2026 Transfer(address indexed from, address indexed to, uint256 value)" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:1,maxLength:1e3,multiline:!1,picker:"contract-event"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},solanaProgram(e){if(!Ze(e.default))throw new Error(`settings.solanaProgram() takes a Solana program address such as "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4" as its default, not "${e.default}"`);let r={...e,kind:"text",minLength:32,maxLength:44,multiline:!1,picker:"solana-program"};return p("text",E(r).transform(t=>t).default(r.default).meta(r))},integer(e){return p("integer",z().int().min(e.min).max(e.max).default(e.default).meta({...e,kind:"integer"}))},boolean(e){return p("boolean",J().default(e.default).meta({...e,kind:"boolean"}))},choice(e){return p("choice",A(e.options).default(e.default).meta({...e,kind:"choice"}))},object(e){return N(e).strict()}};function Ct(e,r){let t=e.balanceChanges.find(a=>a.mint===r);return t?BigInt(t.delta):0n}function Zr(e,r){let t=Ct(e,r);return t>0n?t.toString():"0"}function Qr(e,r){let t=Ct(e,r);return t<0n?(-t).toString():"0"}function Wr(e,r={}){let t=e.balanceChanges.filter(n=>BigInt(n.delta)>0n),a=e.balanceChanges.filter(n=>BigInt(n.delta)<0n);return t.some(n=>(r.into===void 0||n.mint===r.into)&&a.some(c=>c.mint!==n.mint&&(r.from===void 0||c.mint===r.from)))}function Fr(e,r){return e.programs.includes(r)}function Gr(e,r){return e.instructions?.find(t=>t.name===r)?.args??null}var _r=e=>rt(e.key,e.name),Hr=e=>at(e.key,e.title),Jr=(e,r)=>Ye.parse({kind:"points",balance:C(e),amount:r}),Xr={text:(e={})=>({input:"text",constraints:Qe.parse(e)}),url:(e={})=>({input:"url",constraints:We.parse(e)}),photo:()=>"photo",quiz:()=>"quiz"};function Yr(e){if(e?.actor&&e.input!==void 0)throw new Error('manual() cannot combine actor "staff" with input: staff-captured evidence is not supported. Use manual({ actor: "staff" }) for a staff confirmation, or manual({ input }) for evidence the participant submits.');return typeof e?.input=="object"?{kind:"manual",...e.input}:{kind:"manual",input:e?.input??"none",...e?.actor?{actor:e.actor}:{}}}var xt=new WeakMap,Mt=new WeakMap;function zt(e,r){let{tracker:t,beneficiary:a="author",on:n,where:c,enrollment:i,since:u,historical:o,content:g}=e;if(!t?.source)throw new Error(r==="automatic"?"automatic() takes no argument, or { tracker } with a tracker handle from defineTracker":"content() takes { tracker } with a tracker handle from defineTracker");let{source:l}=t;if(!ke(l))throw new Error('Tracker triggers need attributable records: declare customSource(namespace, { identities: ["wallet"] }) or other identity kinds');if(g&&!K(l))throw new Error(`content() needs a tracker whose source has content: x.search(), or customSource(namespace, { content: { body, metrics } }). Tracker "${t.key}" has none; use automatic({ tracker }) instead.`);if(u==="enrollment"&&i!=="required")throw new Error(`${r}() counts from enrollment only on a quest that requires it: add enrollment: "required"`);let M=yt(l);if(!M.includes(a))throw new Error(l.kind==="custom"?`Tracker "${t.key}" has no "${a}" account: declare it in customSource(namespace, { accounts: ["${a}"] })`:`Tracker "${t.key}" pays ${M.map(S=>`"${S}"`).join(" or ")}, not "${a}"`);let s=Ce.parse({tracker:t.key,source:l.kind,on:g?"new-record":n??Ee(l.kind),...c?{where:c}:{},beneficiary:a,...i==="required"?{enrollment:i}:{},...u&&u!=="activation"?{since:u}:{},...o&&o!==(g?"claim":"staff")?{historical:o}:{},...g?{content:g}:{}}),d=St(l),f=d?ie(d,s.where):null;if(f)throw new Error(f);let b={kind:"automatic",tracker:s};d&&xt.set(b,d);let w=K(l);return w&&Mt.set(b,w.metrics),b}function ea(e){return e?zt(e,"automatic"):{kind:"automatic"}}function ta(e){if(e&&typeof e=="object"&&"source"in e&&"key"in e&&!("tracker"in e))throw new Error("content() takes { tracker }: write content({ tracker: posts }) instead of content(posts)");return zt({...e,content:!0},"content")}function or(e){let{key:r,cost:t,...a}=e,n={...a,id:q(e),cost:typeof t=="number"?t:{balance:C(t.ledger)}};return a.scope==="author"?$e.parse(n):ze.parse(n)}var ra=or,sr=(e=[])=>e.filter(r=>r.scope==="author"),cr=e=>({kind:"keyed",key:e}),ir=e=>{let{distinct:r,...t}=e;return{...ye.parse({kind:"progress",window:{kind:"lifetime"},...t}),distinct:r}},aa=()=>({kind:"untracked"}),na=()=>({kind:"staff-handover"}),oa=()=>({kind:"automatic"});function sa(e){let{key:r,tiers:t,...a}=e,n=q(e),c=et.parse({id:n,...a,tiers:t.map(({key:i,...u})=>({...u,id:q({key:i,...u})}))});return y("tiered-reward",{key:c.id,tier:i=>tt.parse({kind:"tier",reward:c,tier:i})})}var ur=()=>({kind:"once"});function dr(e={}){return{kind:"accept",...e}}function lr(e){return{kind:"review",...e}}var x={accept:dr,defer:e=>({kind:"defer",...e}),progress:e=>({kind:"progress",...e}),reject:e=>({kind:"reject",...e}),review:lr};function qt(e){let r=e.kind==="reject"&&e.code!==void 0?Me(e.code):null;if(r)throw new Error(r)}var ca={quiz(e,r={}){let t=st.parse(e),a=Object.keys(t),n=z().int().min(1).max(a.length).parse(r.minimumCorrect??a.length);return async({input:c})=>{let i=Object.keys(c.answers).length===a.length&&a.every(o=>Object.hasOwn(c.answers,o)),u=a.filter(o=>c.answers[o]===t[o]).length;return i&&u>=n?x.accept():x.reject({reason:"Review your answers and try again."})}},photo(e){return async r=>{let t=e(r),a=await r.review.photo({image:r.input.photo,criteria:t.criteria});return a.kind==="unclear"?t.unclear==="human-review"?x.review({reason:a.reason}):x.reject({reason:a.reason}):a.kind==="pass"?x.accept():x.reject({reason:a.reason})}}},mr={once:ur,keyed:cr,streak:tr,progress:ir};function $t(e){return function(t){let a=q(t),n=[...new Set((t.integrations??[]).map(s=>Ae.parse(s.provider)))],c=t.trigger.kind==="automatic"&&t.trigger.tracker?.content===!0,i=t.trigger.kind==="automatic"&&t.trigger.tracker!==void 0,u=t.completion,o=typeof u=="function"?u(mr):u;if(c&&o!==void 0)throw new Error("A content quest completes once per content item: remove its completion");if(!c&&o===void 0)throw new Error("A quest needs a completion, such as once(), keyed(...), streak(...) or progress(...)");let g=sr(t.budgets);if(bt({trigger:t.trigger,completion:o??{kind:"keyed"},requires:t.requires??[],authorBudgets:g,performance:t.performance?U.parse({metrics:t.performance.metrics,maxAgeMs:t.performance.maxAgeMs}):void 0,...t.retryCooldownMs===void 0?{}:{retryCooldownMs:t.retryCooldownMs},...t.completionCooldownMs===void 0?{}:{completionCooldownMs:t.completionCooldownMs}},{template:e}),t.retryCooldownMs!==void 0&&!G.safeParse(t.retryCooldownMs).success)throw new Error("retryCooldownMs must be whole milliseconds from 1000 (one second) to 604800000 (seven days)");if(t.completionCooldownMs!==void 0&&!G.safeParse(t.completionCooldownMs).success)throw new Error("completionCooldownMs must be whole milliseconds from 1000 (one second) to 604800000 (seven days)");if(t.performance){let s=Mt.get(t.trigger)??[],d=t.performance.metrics.filter(f=>!s.includes(f));if(d.length)throw new Error(`The tracker's source does not measure ${d.join(", ")}`)}if(t.trigger.kind==="manual"&&t.trigger.input!=="none"&&!t.evaluate)throw new Error("Evidence quests require an evaluator");let l=Object.fromEntries(Object.entries(t.settings.shape).map(([s,d])=>{let f=Fe.safeParse(d.meta());if(!f.success)throw new Error(`Setting "${s}" is not a quest setting: build it with a settings builder, such as settings.integer({ label, default, min, max })`);return[s,f.data]}));for(let s of qe(t.trigger.kind==="automatic"?t.trigger.tracker?.where:void 0))if(!He(l[s]))throw new Error(`The tracker filter compares with setting "${s}", which is not an integer or amount setting`);function M(s){let d=t.settings.parse(s),f=Je(l,d),b=nt.parse(typeof t.rewards=="function"?t.rewards({settings:d}):t.rewards),w=X(De).max(3,"A quest posts at most three announcements").parse((typeof t.announcements=="function"?t.announcements({settings:d}):t.announcements)??[]),S=t.trigger.kind==="automatic"&&t.trigger.tracker!==void 0;for(let m of w){let v=je(m.text),I="segments"in v&&v.segments.some(k=>k.kind==="placeholder"&&k.name==="author");if(!S&&I)throw new Error("An announcement names {author} only on a quest with an automatic tracker trigger");if(!S&&m.replyToTriggeringMessage)throw new Error("An announcement replies to the triggering message only on a quest with an automatic tracker trigger")}let h=[...b.flatMap(m=>m.kind==="integration"?[m.provider]:[]),...w.flatMap(m=>m.provider==="discord"?["discord"]:[]),...Object.values(l).flatMap(m=>m.kind==="resource"&&m.source.provider!=="domino"?[m.source.provider]:[])];for(let m of h)if(!n.includes(m))throw new Error(`Declare the ${m} integration on this quest`);return ot.parse({quest:a,evaluatorProtocol:_,title:typeof t.title=="function"?t.title({settings:d}):t.title,presentation:t.presentation?.({settings:d})??{},fields:l,values:f,rewards:b,...w.length?{announcements:w}:{},humanReview:t.review?.({settings:d})?.enabled??!0,trigger:t.trigger,...t.performance?{performance:U.parse({metrics:t.performance.metrics,maxAgeMs:t.performance.maxAgeMs})}:{},integrations:n,completion:o?o.kind==="progress"?{kind:o.kind,goal:o.goal,window:o.window,repeat:o.repeat}:o.kind==="streak"?o:{kind:o.kind}:{kind:"keyed"},visibility:t.visibility??"visible",profile:t.profile??{visible:!1},budgets:(t.budgets??[]).filter(m=>m.scope!=="author"),...g.length?{authorBudgets:g}:{},requires:t.requires??[],...t.campaign?{campaign:t.campaign}:{},...t.availability?{availability:t.availability}:{},...t.retryCooldownMs===void 0?{}:{retryCooldownMs:t.retryCooldownMs},...t.completionCooldownMs===void 0?{}:{completionCooldownMs:t.completionCooldownMs}})}return y("quest",{protocol:_,key:a,describe:M,async evaluate(s){let d=t.settings.parse(s.settings),f=i?xe.parse(s.tracker):null,b=xt.get(t.trigger),w=f&&b?se(b,f.record.data):null;if(w)return L.parse({kind:"reject",reason:`The record's data does not match the data schema this quest was built with: ${w.path} ${w.reason}`});let S=f;if(s.performance){if(!t.performance)throw new Error("Quest has no performance evaluator");let v=ct.parse(s.performance),I=T(A(t.performance.metrics),z().int().safe().nonnegative()).parse(v.metrics),k=await t.performance.evaluate({settings:d,member:s.member,tracker:S,metrics:I,observedAt:v.observedAt});if(!k)throw new Error("Performance evaluator returned no decision");if(k.rewards!==void 0)throw new Error("A performance evaluator cannot select rewards. It gates the rewards content evaluation selected: return accept, review or reject with a reason only.");return qt(k),L.parse(k.kind==="accept"?{kind:"accept",rewards:v.rewards}:k.kind==="review"&&s.humanReview?{kind:"review",reason:k.reason,rewards:v.rewards}:{kind:"reject",reason:k.reason,...k.kind==="review"?{requestedReview:!0}:k.code===void 0?{}:{code:k.code}})}let h=t.evaluate?await t.evaluate({settings:d,member:s.member,input:s.input,tracker:S,eligibleAt:s.eligibleAt,calendar:s.calendar,now:s.now,review:s.review,trackers:ce(s.trackers),wallet:s.wallet,images:s.images,...s.telegram?{telegram:s.telegram}:{},...Object.fromEntries(n.map(v=>[v,s[v]]))}):x.accept();if(!h)throw new Error("Evaluator returned no decision");if(qt(h),h.kind==="review"&&!s.humanReview)return L.parse({kind:"reject",reason:h.reason,requestedReview:!0});(h.kind==="accept"||h.kind==="review")&&h.completionKey!==void 0&&o?.kind!=="keyed"&&s.diagnose?.({code:"completion-key-ignored",message:gr(o,h.completionKey)});let m={...s,settings:d,tracker:f};return L.parse(h.kind==="accept"||h.kind==="review"?{...h,rewards:h.rewards??s.rewards,...o?.kind==="keyed"||o?.kind==="progress"?{completionKey:o.kind==="progress"?o.distinct(m):h.completionKey??o.key(m)}:{}}:h)}})}}function gr(e,r){let t=`ignores completionKey ${JSON.stringify(r)}`;switch(e?.kind){case void 0:return`A content quest completes once per content item, under a key Relay sets, so it ${t}`;case"once":return`once() completes the quest once per member and ${t}: use keyed(...) to complete it once per key`;case"streak":return`streak(...) keys its own completions and ${t}`;case"progress":return`progress(...) keys each contribution with its distinct(...) and ${t}: derive the key in distinct(...)`}}var ia=$t(!1),ua=$t(!0);export{Gt as CapabilityError,ea as automatic,oa as automaticFulfillment,_r as badge,Vt as balanceAtLeast,ra as budget,zr as calendar,Ft as capabilityErrorCodes,Ut as completed,ta as content,Ie as cosmosDenomSchema,jt as cosmosNetworkSchema,Mr as count,R as customSource,x as decision,qr as defineBadge,Nt as defineCampaign,Wt as defineDashboard,xr as defineEngagementReward,Kt as defineGroup,Rr as defineLeaderboard,Cr as defineLedger,Qt as defineOffer,ia as defineQuest,ua as defineQuestType,jr as defineReferral,sa as defineTieredReward,Br as defineTracker,Dr as discord,Lr as earned,ca as evaluators,Xr as evidence,Ht as formatUnits,Hr as groupMembership,Zt as inGroup,Gr as instruction,Fr as invoked,Ue as isContractCall,Ve as isContractEvent,Oe as isEvmChainId,Ke as isNftCollection,Ze as isSolanaProgram,cr as keyed,Yr as manual,Dt as maxWalletEventLogs,Pt as maxWalletEventLookback,Ot as maxWalletTransactionLookback,It as maxWalletTransactions,ur as once,Tt as parseContractCall,Bt as parseContractEvent,Rt as parseContractFunction,Lt as parseNftCollection,_t as parseUnits,Kr as pointLedgers,Jr as points,ir as progress,Ar as questCompleted,Zr as received,$r as rolling,Ur as settings,Qr as spent,na as staffHandover,tr as streak,Wr as swapped,Pr as telegram,Or as tiktok,j as trackerDataSchema,xe as trackerTriggerContextSchema,aa as untracked,Nr as wallet,Tr as x,Ir as youtube,At as z};