@domino-sdk/relay 1.56.0 → 1.60.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.
- package/CHANGELOG.md +100 -0
- package/dist/{accounts-DRPENuZe.d.ts → accounts-DoabriBX.d.ts} +21 -7
- package/dist/{attempt-captures-CxxO7DeD.d.ts → attempt-captures-W2dgzGqE.d.ts} +1 -1
- package/dist/authoring.d.ts +323 -39
- package/dist/authoring.js +312 -18
- package/dist/{automatic-outcomes-DxW_v5Wc.d.ts → automatic-outcomes-Cmou89IS.d.ts} +1 -1
- package/dist/avatar.d.ts +1 -2
- package/dist/browser.d.ts +19 -11
- package/dist/browser.js +12 -10
- package/dist/{capability-error-DSd8EMQC.d.ts → capability-error-DufwG3G0.d.ts} +21 -7
- package/dist/{chunk-OTITLABX.js → chunk-2FHNY52R.js} +8 -2
- package/dist/{chunk-QNQNKIAA.js → chunk-422J3QRW.js} +12 -2
- package/dist/{chunk-INSWI2VZ.js → chunk-4OFH4BNX.js} +1 -1
- package/dist/{chunk-KBVH4XZC.js → chunk-6ZG7WNYX.js} +1 -1
- package/dist/{chunk-BHHUSBSD.js → chunk-GBSDAD3N.js} +1627 -887
- package/dist/{chunk-W5U2WXG3.js → chunk-KUPVQXUJ.js} +2 -2
- package/dist/{chunk-G6XVBYH7.js → chunk-KWFY7L7X.js} +4 -4
- package/dist/{chunk-BJYMTCWG.js → chunk-MJEJQH5A.js} +18 -6
- package/dist/{chunk-ULQU7KC4.js → chunk-N3LJ6GFK.js} +1 -5
- package/dist/{chunk-ABJ4G47X.js → chunk-N7YOS4ZU.js} +1 -1
- package/dist/{chunk-MNU6UPXY.js → chunk-OTEUP2SG.js} +1 -1
- package/dist/{chunk-NK6EER33.js → chunk-VVRQQRMQ.js} +12 -12
- package/dist/{chunk-H2MD6E7Z.js → chunk-VWMIA2TT.js} +8 -2
- package/dist/{chunk-RBPMT53S.js → chunk-XQKUJL7H.js} +25 -5
- package/dist/{chunk-CXKXPB7K.js → chunk-Y2IGFLD2.js} +36 -11
- package/dist/{chunk-VSHV7FEA.js → chunk-YNW2ZUUP.js} +56 -153
- package/dist/{chunk-CK7HO32Z.js → chunk-YOAPPIWN.js} +2 -2
- package/dist/{client-bX3oTpRu.d.ts → client-Cw1pB5sv.d.ts} +121 -117
- package/dist/{deployments-D3lxfQMB.d.ts → deployments-DI-W7fBq.d.ts} +1105 -182
- package/dist/{groups-DPE004_V.d.ts → groups-9Jm3peq3.d.ts} +14 -7
- package/dist/index.d.ts +10 -11
- package/dist/index.js +9 -9
- package/dist/{integrations-CcD5NPEA.d.ts → integrations-CmIkP1Gi.d.ts} +48 -32
- package/dist/internal.d.ts +10 -10
- package/dist/internal.js +8 -8
- package/dist/{offers-CtzMeB7O.d.ts → offers-CqXfMIxq.d.ts} +7 -2
- package/dist/{pages-BlLqB8ZQ.d.ts → pages-Bti7g5mX.d.ts} +184 -10
- package/dist/{participant-activity-iciCEs_8.d.ts → participant-activity-DHL8QYks.d.ts} +4 -0
- package/dist/portal-proxy.js +3 -3
- package/dist/react/index.d.ts +74 -74
- package/dist/react/index.js +10 -10
- package/dist/runtime/authoring.js +1 -1
- package/dist/runtime/chunks/ADUMK6CR.js +1 -0
- package/dist/runtime/chunks/EWU4OKSY.js +62 -0
- package/dist/runtime/manifest.json +5 -5
- package/dist/runtime/schema.js +1 -1
- package/dist/runtime/zod.js +1 -1
- package/dist/{schema-C4m9RhCR.d.ts → schema-CwbRkmlr.d.ts} +324 -35
- package/dist/schema.d.ts +854 -437
- package/dist/schema.js +103 -25
- package/dist/server/index.d.ts +10 -10
- package/dist/server/index.js +711 -81
- package/dist/{submission-input-wTiYGdgA.d.ts → submission-input-D9EGH_yb.d.ts} +2 -2
- package/dist/{telegram-browser-Bh3i0HiH.d.ts → telegram-browser-CTJh4Ro_.d.ts} +4 -4
- package/dist/testing.d.ts +89 -9
- package/dist/testing.js +218 -13
- package/dist/{transport-CnKA-_RL.d.ts → transport-B8Ss5lcz.d.ts} +9189 -2009
- package/dist/wallet-DZWL7lJH.d.ts +972 -0
- package/dist/{x-1czZFVUW.d.ts → x-KFJD2x8y.d.ts} +3 -3
- package/package.json +2 -2
- package/dist/profiles-BoOK03cR.d.ts +0 -299
- package/dist/runtime/chunks/IDOMZWRY.js +0 -40
- package/dist/runtime/chunks/NDB42VFF.js +0 -1
- package/dist/util.d-w9f9t3ua.d.ts +0 -5
- package/dist/wallet-Ac7OFpOr.d.ts +0 -228
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,105 @@
|
|
|
1
1
|
# @domino-sdk/relay
|
|
2
2
|
|
|
3
|
+
## 1.60.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d258795: A budget can cap what one person gives, not only what one member receives. `budget({ key, scope: "author", period, limit, cost })` counts per tracker record author: the account that caused the record, such as a reaction's reactor, whether or not a member linked it. Put it in a tracker quest's `budgets` beside a `"member"` budget to cap both sides, for example a tip paid to a message's author with `beneficiary: "messageAuthor"`: at most 20 tips a day per receiver and 10 a day per reactor. A tip over either cap is rejected with `budget-exhausted`, permanently; other reactors' tips keep paying. It works on `telegram.reactions()`, `discord.reactions()`, kudos recipients and X `inReplyTo` replies. Author budgets share keys, calendar periods and the atomic commit with the other budgets, and imported completions don't count toward them.
|
|
8
|
+
|
|
9
|
+
An author budget needs a tracker trigger. `domino check` reports `AUTHOR_BUDGET_TRACKER_REQUIRED` on another quest, `domino build` and `domino deploy` refuse it, and Relay refuses its publication.
|
|
10
|
+
|
|
11
|
+
The types SDK 1.x code reads are unchanged: `Budget` keeps `scope: "member" | "project"`, and a quest's description lists author budgets in the new optional `authorBudgets` (`AuthorBudget`, `authorBudgetSchema` from `@domino-sdk/relay/schema`), apart from `budgets`. `budget()` returns an `AuthorBudget` for `scope: "author"`. A member's quest `budgets` (`QuestBudgetView`) leave author budgets out, since they cap someone else's giving.
|
|
12
|
+
|
|
13
|
+
- d41f5da: `relay.me.get()` and `useMe()` now return the member's `clock: { now, offsetMs }`, the clock Relay judges their activity on. A test member's clock runs ahead after the staging toolbar's **Next day** or `domino test-members advance`; every other member's `offsetMs` is 0. New `memberTime(me, at?)` from `@domino-sdk/relay/browser` turns a real instant into the member's time, so an app that shows campaign phases or open quests by date follows an advanced test member. `clock` is optional, and `memberTime` returns real time when a Relay older than it omits it. On staging, the toolbar's `domino:test-state-changed` event now carries `detail: { change, actingAs }`: what changed and which test member the page is signed in as.
|
|
14
|
+
- e899f47: Member imports carry referrals. A row's optional `referral` names the member's inviter (another row's `ref`, or the sign-in identity of an existing member), when they accepted, and the referral programs they already qualified in (`qualified: [{ program, at }]`). Applying records the referral and the qualifications without paying any referral reward, milestone or bonus; they count toward the inviter's qualified friends, and the friend's later points pay the program's bonus. An inviter's row applies before the rows that name it. New refusal codes: `unknown-inviter`, `self-referral`, `inviter-already-accepted`, `referral-cycle`, `inviter-refused` and `unknown-referral-program`. The check summary adds `referrals` (`accepted`, and `qualified` by program), `management.referrals.participants()` names the import that recorded a relationship or qualification in `import`, and `management.members.get()` returns the member's accepted referral in an optional `referral` (`inviter`, `acceptedAt`, `suspended`, `import`).
|
|
15
|
+
- 8ee2000: A member import vouches for Telegram and Discord accounts too. A row's `accounts` takes `{ kind: "telegram", subject }` and `{ kind: "discord", subject }`, each a numeric user ID, at most one of each per member, from `domino import` and `management.memberImports.addRows`. They work like a vouched X account: Telegram and Discord tracker records, quest checks and Discord role checks trust them from when the import attached them, nobody else can link them, and the member's own Telegram or Discord link replaces them. They never sign in: a Telegram or Discord sign-in with one is refused with `sign-in-method-disabled`. A row naming a second account of a kind, or another one than the member's, is refused with the new `MemberImportRefusalCode.TelegramAccountSelected` (`telegram-account-selected`) or `DiscordAccountSelected` (`discord-account-selected`).
|
|
16
|
+
|
|
17
|
+
`@domino-sdk/relay/server` adds `memberImportVouchedAccountSchema`, `memberImportFullRowSchema` and `memberImportFullRowsInputSchema`, with the types `MemberImportVouchedAccount`, `MemberImportFullRow`, `MemberImportFullRowInput` and `MemberImportFullRowsInput`, for rows with every kind of vouched account; `addRows` takes `MemberImportFullRowInput[]`. `memberImportAccountSchema`, `memberImportRowSchema` and `memberImportRowsInputSchema` stay the X-and-wallet form. Member identity states carry `imported: true` for an X, Discord or Telegram account an import attached, and so does a connected `ManagedTelegramAccount`.
|
|
18
|
+
|
|
19
|
+
An imported X, Telegram or Discord account now pays tracker records from the moment it was imported. Before, a vouched X account had no link time, so its records were skipped as historical. Members imported before this release keep that unknown link time until they link their X account themselves.
|
|
20
|
+
|
|
21
|
+
- f0d5b8e: Offers can be archived and restored. `management.offers.archive` and `unarchive` (`POST /management/v1/offers/OFFER/archive|unarchive`), `domino offers archive|unarchive OFFER --reason`, Console **Settings → Resources** and the offer's card in Console **Rewards** archive one in test, and a promotion carries it to live. Each returns `{ resource, changed }`, typed by the new `offerLifecycleResultSchema`, with `resource.kind` `offer`. An archived offer leaves member offer reads and refuses redemption with `offer-paused`; management reads keep it, with the new `archivedAt` field on `Offer`, and its redemptions can still be canceled. `management.resources.list()` and `domino resources list` list offers in a new `offers` array (`managedResourceListSchema`), beside the existing kinds. A rollback now archives an offer the earlier promotion did not carry.
|
|
22
|
+
- 6b5228b: Quests can announce a completion in a connected Telegram chat or Discord channel. List `telegram.postMessage({ chat, text, replyToTriggeringMessage })` or `discord.postMessage({ channel, text, replyToTriggeringMessage })` in the new optional `announcements` of `defineQuest`, beside `rewards` (at most three; an array or a function of the settings). The text is a template with the placeholders `{beneficiary}`, `{author}`, `{points}`, `{rewards}` and `{quest}` (`announcementPlaceholders`); people are mentioned through their linked account on that platform. Relay posts after the rewards commit, as a reward delivery with the new `RewardDeliveryAction.PostMessage` action and an empty `roleId`, retried with backoff and paced per chat; a failed post never undoes the rewards, and `management.retryRewardDelivery(id)` retries one. Descriptions carry them in the new optional `announcements` field (`announcementSchema`). `discord.channels({ postable: true })` lists channels the bot can't post in as unavailable, and `TelegramChat` gains an optional `canPost`. The CLI's authoring reference documents announcements.
|
|
23
|
+
- ea1f033: Revert an applied or stopped member import: `management.memberImports.revert(id, { reason })` starts it, and `domino imports revert IMPORT --reason TEXT` starts it and waits. In the background, one row at a time, it reverses the applied rows' opening balances (taking only points members still have; `unreversedPoints` lists the rest), revokes their imported completions (reason `import-reverted`, freeing the occurrence) and removes the wallets, accounts and identities they linked unless the member signed in with one since (`keptLinks`). Members stay in the project. A reverting or reverted import reads as `applied` with `revert` set, and is reverted once; the same `actionId` answers the import again. Rows applied before imports recorded their links keep them (`linksUntracked`). Reverting needs `publish` permission and works in live from API keys and CLI sessions too. Console shows **Revert import** on applied and stopped imports.
|
|
24
|
+
`MemberImport` gains `revert`: the reason, who asked and when, rows reverted so far, then `revertedAt` and the `outcome`.
|
|
25
|
+
- 9a7ad11: Stop a member import while it applies: `management.memberImports.stop(id)` and `domino imports stop IMPORT` let the row being applied finish, apply no more rows, and end the import: it reads as `applied` with `appliedAt` null and `stoppedAt` and `stoppedBy` set, and its remaining rows stay `ready`. A stopped import can't be applied again; import the remaining rows in a new import. Stopping needs `publish` permission and works in live from API keys and CLI sessions too. Console shows **Stop import** on an applying import.
|
|
26
|
+
`MemberImport` gains `stoppedAt` and `stoppedBy`; check `stoppedAt` to tell a stopped import from a fully applied one.
|
|
27
|
+
- df3a08c: A test member's clock moves by hours and minutes, or to an instant, so time-of-day rules can be tested: block edges, or midnight in the project's time zone. `management.testMembers.advance(member, input)` takes `{ actionId }` with one of `days` (1–30, unchanged: project-calendar days that keep the time of day), `hours` (1–720), `minutes` (1–43200) or `to`, an ISO 8601 instant with an offset that must be later than the member's clock (else 422 `test-member-clock-past`). From the CLI, `domino test-members advance MEMBER` takes one of `--days`, `--hours`, `--minutes` or `--to`. The 90-day limit holds across units (422 `test-member-clock-limit`): `days` still add up to at most 90 and land no later than the 90th date, and hours, minutes and `to` never move the clock past 90 days from now. `offsetDays` still counts the days advanced with `days`; hours, minutes and `to` leave it unchanged, so read the member's date from `today`. `@domino-sdk/relay/server` exports `testMemberClockAdvanceSchema` and `TestMemberClockAdvanceInput` for every form; `testMemberAdvanceSchema` and `TestMemberAdvanceInput` stay the `days` form.
|
|
28
|
+
|
|
29
|
+
## 1.59.0
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- 1d5a195: `management.attempts.acceptAnyway({ attempt, reason })` (`POST /attempts/<id>/accept-anyway`, `review` permission) accepts a rejected attempt anyway, for any member, reversing a reviewer's or an evaluator's rejection. The acceptance pays as a reviewer's approval would, with the normal `completion.created` webhook; the rejection stays in the attempt's events beside a `staff-decision` with `decision: "accept-anyway"` and the reason, and the retry cooldown ends. Only the member's latest attempt on a quest that isn't archived qualifies (409 `attempt-superseded`, `quest-archived`), and a cap the acceptance would break refuses it instead of rejecting it again (409 `completion-cooldown`, `budget-exhausted`, `completion-revoked`, `already-completed`). `management.attempts.get` answers `supersededBy`, the member's newer attempt on the quest, or null. The CLI adds `domino attempts accept-anyway ATTEMPT --reason TEXT`.
|
|
34
|
+
- a0c77e4: Archiving or unarchiving a group, pausing or resuming a tracker, and changing the project's schedule state take an optional reason, which the audit log records: `management.groups.archive(group, { reason })` and `unarchive(group, { reason })`, `management.trackers.pause(reference, { actionId, reason })` and `resume`, and `management.schedules.setState(state, { reason })`. A reason is a trimmed string of 1–500 characters, like the other lifecycle reasons; leaving it out works as before. The CLI adds `--reason TEXT` to `domino groups archive|unarchive`, `domino trackers pause|resume` and `domino schedules pause|archive|resume`. Console asks for a reason in a dialog for each of these, and the project schedule menu no longer applies a state as soon as you pick it.
|
|
35
|
+
- 424863f: Operators can restore an entitlement they voided. `management.entitlements.restore(entitlement, { revision, reason })` (`POST /management/v1/entitlements/<id>/restore`, `review` permission) and `domino entitlements restore <id> --revision <n> --reason <text>` make a `void` entitlement `available` again at the tier an accepted completion still earns, and bring back any referral review the void settled. Restoring is refused with 409 `entitlement-status` when a completion revocation voided the entitlement or no accepted completion still earns it (the body names the `completion` to restore instead), when canceling an offer redemption voided it, or when a referral reward was voided before voids kept their reviews. Console Rewards and member detail offer **Restore reward** on a voided reward, and Audit history lists each restore with its reason.
|
|
36
|
+
- 790aa5d: Operators can restore a completion they revoked by mistake. `management.completions.restore({ completion, reason })` (`POST /management/v1/completions/<id>/restore`, `review` permission) and `domino completions restore <completion> --reason <text>` re-apply what the revocation recorded, not a fresh reward evaluation: the points it reversed are awarded again (points it could not reverse are not), its badges, group memberships, tiered rewards, Discord role grants, referral qualifications and streak milestone come back, and budgets stay spent. The result (`CompletionRestoration`) lists what came back. Restoring is refused with 409 `completion-not-revoked` when the completion isn't revoked, and with 409 `occurrence-taken` (naming the `completion` that holds it) when the revocation freed the occurrence and the member completed it again. `members.get(id).revokedCompletions` lists up to 25 revoked completions, each with its revoke's reason and result. Console member detail and attempt detail offer **Restore completion**, and the attempt history and Audit history show the restore beside the revoke.
|
|
37
|
+
- 850a252: `settlementPayoutCsv(exported)` turns the result of `management.leaderboards.settlementExport(id)` into the payout list as CSV, with the columns `member,score,rank,share,amount,unit,wallets`. `domino leaderboard-settlements export` now prints it through this helper, unchanged, and Console's prize settlement panel offers **Download payout list (CSV)** for any pool that is not points, with the same content.
|
|
38
|
+
- 7ac13ef: Solana transactions from `ctx.wallet.transactions()` now carry `signer`: whether the linked wallet signed the transaction. It is `false` for a transfer someone else sent into the wallet, and for results captured before it existed. Check it before rewarding an action. The new `solana-action` snippet completes a quest once per transaction a linked wallet signed that called your program, optionally receiving at least an amount of a token.
|
|
39
|
+
- 5b94440: Anchor instruction decoding for `ctx.wallet.transactions()`. Saving a `settings.solanaProgram()` setting now stores the program's Anchor IDL (legacy or 0.30+), read from its on-chain IDL account, in the published release's new optional `solanaIdls` (`SolanaProgramIdl`: `{ program, source, idl }`, by setting key). For a program without an on-chain IDL, an operator pastes one in Console or sends the new optional `solanaIdls: { [settingKey]: idl | null }` with `quests.updateSettings()` (`anchorIdlSchema`, `AnchorIdl`). With an IDL, each transaction gains optional `instructions`: the program's top-level and inner instructions in call order, decoded as `{ name, args, accounts }` (`WalletInstruction`). An instruction the IDL does not describe is skipped. The new `instruction(tx, name)` helper in `@domino-sdk/relay/authoring` returns the first matching instruction's args, or `null`. The testing kit's `facts.wallet.transactions` accepts `instructions`.
|
|
40
|
+
- 95cb8d8: On-chain action checks on Solana. `ctx.wallet.transactions({ program, since, afterActivation?, mint?, address? })` reads the successful, finalized transactions of the member's linked Solana wallets since `since` that invoked `program` in a top-level or inner instruction, oldest first. It returns `{ program, chain, mint, since, at, complete, transactions: [{ wallet, signature, slot, timestamp, programs, balanceChanges: [{ mint, delta }] }], observedAt }` (`WalletTransactions`, `WalletTransaction`, `WalletBalanceChange`, `walletTransactionsSchema`), with `mint` `"SOL"` for lamports (rent included, the fee the wallet paid left out) and `delta` a signed integer string, or null when the member has no linked Solana wallet, and follows `ctx.wallet.balance()`'s capture, `author-error` and `provider-unavailable` rules. With `mint`, only each wallet's associated token account for that mint is read. `since` may be at most 30 days before the evaluation (`maxWalletTransactionLookback`); each wallet's read fetches at most 1,000 transactions (`maxWalletTransactions`), and a wallet with more returns its newest ones with `complete: false` instead of throwing. `WalletReader.transactions` is optional in the type so that existing test doubles compile; Relay supplies it to every evaluation.
|
|
41
|
+
|
|
42
|
+
The program comes from the new `settings.solanaProgram({ label, default })` setting, a base58 address (`SolanaProgram`, `isSolanaProgram`) stored as a text setting with `picker: "solana-program"`. Publication, Console settings edits and unarchiving check that the account exists on Solana mainnet and is executable.
|
|
43
|
+
|
|
44
|
+
New pure helpers in `@domino-sdk/relay/authoring` read one transaction: `received(tx, mint)` and `spent(tx, mint)` return the wallet's gain or loss as an integer string, or `"0"`; `swapped(tx, { into?, from? })` checks that one mint went down and a different one went up; `invoked(tx, program)`. The testing kit answers `ctx.wallet.transactions()` from `facts.wallet.transactions`.
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
- aaa07ad: The SDK and CLI depend on Zod 4.6.5, whose schemas keep their methods on a shared prototype instead of binding about 7 KB of them to every schema instance. Importing the SDK takes far less memory: a Relay backend process that loads the server entry starts with about half the heap. Quest `settings.datetime()` values, member-import times and X post `createdAt` values (including hand-written testing fixtures) still accept minute-precision instants such as `2026-11-01T00:00Z`, which Zod 4.6 alone rejects. An X post read without a `media` field still gives an empty list.
|
|
49
|
+
|
|
50
|
+
One tracker data schema change after a rebuild: a field declared as `z.number().min(0).int()` now stores `minimum: 0`, so Relay refuses negative values at ingestion that the app's own schema already refused. Zod 4.3 stored the safe-integer minimum for that order of checks.
|
|
51
|
+
|
|
52
|
+
## 1.58.0
|
|
53
|
+
|
|
54
|
+
### Minor Changes
|
|
55
|
+
|
|
56
|
+
- 321763b: `management.discordRoles.list()` lists every Discord role the project's reward deliveries have granted in the environment, with the quests that requested it and its deliveries counted by status (`pending`, `delivered`, `failed`). It reads the whole delivery history, so a role granted only before the newest page of `management.rewardDeliveries` still appears. The response schema is `discordRoleRewardsSchema`.
|
|
57
|
+
|
|
58
|
+
### Patch Changes
|
|
59
|
+
|
|
60
|
+
- a2318dd: `stagingPathSchema` refuses paths with control characters and accepts only a path that resolves on the staging host. Browsers drop tab and newline from a URL, so a path such as `/<tab>/example.com` used to pass and open another site after a staging sign-in.
|
|
61
|
+
|
|
62
|
+
## 1.57.0
|
|
63
|
+
|
|
64
|
+
### Minor Changes
|
|
65
|
+
|
|
66
|
+
- 7012d1c: Contract state and Cosmos staking reads in quest evaluators.
|
|
67
|
+
|
|
68
|
+
`ctx.wallet.call({ call, args?, address? })` calls one `view` or `pure` EVM contract function once per linked EVM wallet, every call at one block, through dRPC on the chains `management.walletBalanceChains()` lists: state a contract keeps per address, such as `stakedOf(address)`, `getVotes(address)` or `userInfo(uint256, address)`. `{ wallet: true }` in `args` stands for each wallet's address. It returns `{ call, chain, contract, returns, total, wallets: [{ address, value }], at, observedAt }` (`WalletCall`, `walletCallSchema`), with integers as decimal strings and `total` their sum (null for `bool` and `address` returns), or null when the member has no linked EVM wallet. A revert is an `author-error` carrying the contract's reason. The call comes from the new `settings.contractCall({ label, default })` setting (`picker: "contract-call"`): the contract's CAIP-10 ID and a human-readable signature, such as `eip155:8453:0x… function stakedOf(address) view returns (uint256)` (`ContractCall`, `isContractCall`, `parseContractCall`, `parseContractFunction`). Only `view` or `pure` functions with elementary parameters that return one `uint`, `int`, `bool` or `address` are accepted; publication, Console settings edits and unarchiving also check the chain.
|
|
69
|
+
|
|
70
|
+
`ctx.wallet.delegations({ chain, validator?, address? })` reads the native staking delegations of the member's wallets linked on a Cosmos SDK chain Relay lists, at one block, in base units of the chain's staking denomination: `{ chain, denom, validator, total, wallets, validators, at, observedAt }` (`WalletDelegations`, `walletDelegationsSchema`), optionally only to one validator, or null when the member has no wallet on that chain.
|
|
71
|
+
|
|
72
|
+
Both follow `ctx.wallet.balance()`'s capture, `author-error` and `provider-unavailable` rules. `WalletReader.call` and `WalletReader.delegations` are optional in the type so that existing test doubles compile; Relay supplies them to every evaluation, and the testing kit answers them from `facts.wallet.call` and `facts.wallet.delegations`. New `contract-state` and `cosmos-staker` snippets accept members whose view call reaches a minimum, or who delegate at least a minimum, optionally to a configured validator.
|
|
73
|
+
|
|
74
|
+
- 59a01d8: On-chain action checks on EVM chains. `ctx.wallet.events({ event, account, since, afterActivation?, where?, address? })` reads the events of one contract whose indexed address argument `account` is one of the member's linked EVM wallets, from `since` to the chain's finalized block (its safe block on a chain without finality), through dRPC `eth_getLogs` on the chains `management.walletBalanceChains()` lists. It returns `{ event, chain, contract, since, at, finality, logs: [{ wallet, block, timestamp, tx, logIndex, args }], observedAt }` (`WalletEvents`, `walletEventsSchema`) with decoded arguments, or null when the member has no linked EVM wallet, and follows `ctx.wallet.balance()`'s capture, `author-error` and `provider-unavailable` rules. `where` holds equality or `{ gte }` conditions on other arguments (`WalletEventCondition`); `afterActivation` skips events before the quest's activation. `since` may be at most 30 days before the evaluation (`maxWalletEventLookback`), and a read over more than 3,000,000 blocks or 1,000 logs (`maxWalletEventLogs`) throws `author-error`. `WalletReader.events` is optional in the type so that existing test doubles compile; Relay supplies it to every evaluation.
|
|
75
|
+
|
|
76
|
+
The event comes from the new `settings.contractEvent({ label, default })` setting: a CAIP-10 contract, a space and the event's Solidity signature with argument names and `indexed` markers, such as `eip155:8453:0x… Transfer(address indexed from, address indexed to, uint256 value)` (`ContractEvent`, `isContractEvent`, `parseContractEvent`, `ContractEventParts`), stored as a text setting with `picker: "contract-event"`. An event without an indexed address argument is refused. Publication, Console settings edits and unarchiving also check that the chain reports a finalized or safe block and that the address holds a contract.
|
|
77
|
+
|
|
78
|
+
The testing kit answers `ctx.wallet.events()` from `facts.wallet.events`. A new `onchain-action` snippet rewards each new matching event since the later of the quest's activation and the wallet's link, with an optional minimum amount, keyed on `chain:tx:logIndex`.
|
|
79
|
+
|
|
80
|
+
- 956b721: NFT holding checks on EVM chains and Solana. `ctx.wallet.nfts({ collection, address? })` counts the NFTs of one collection the member's linked wallets of its family hold: on EVM, an ERC-721 contract's `balanceOf(owner)`, or one ERC-1155 token ID's `balanceOf(owner, id)`, through dRPC on the chains `management.walletBalanceChains()` lists; on Solana mainnet, the NFTs whose Metaplex metadata names the collection with `verified: true` (SPL Token and Token-2022 accounts holding exactly 1 of a 0-decimal, supply-1 mint; compressed NFTs and Metaplex Core assets are not counted). It returns `{ collection, chain, standard, total, wallets: [{ address, count }], at, observedAt }` (`WalletNfts`, `walletNftsSchema`; `standard` is `"erc721"`, `"erc1155"` or `"metaplex"`), or null when the member has no linked wallet of that family, and follows `ctx.wallet.balance()`'s capture, `author-error` and `provider-unavailable` rules. `WalletReader.nfts` is optional in the type so that existing test doubles compile; Relay supplies it to every evaluation.
|
|
81
|
+
|
|
82
|
+
The collection comes from the new `settings.nft({ label, default })` setting, a CAIP-19 asset type such as `eip155:1/erc721:0x…`, `eip155:8453/erc1155:0x…/1` or `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/nft:<collection mint>` (`NftCollection`, `isNftCollection`, `parseNftCollection`, `NftCollectionParts`), stored as a text setting with `picker: "nft"`. Publication and Console settings edits check it: an EVM chain and that the contract reports the standard through ERC-165 `supportsInterface`, so a token contract or the wrong standard is refused when it is set; a Solana mint must be a Metaplex collection NFT, so a fungible mint, a mint without Metaplex metadata, a print edition or a member NFT is refused. Unarchiving checks it too, and a platform without its dRPC key refuses every EVM collection. `ctx.wallet.balance()` pointed at an ERC-721 or ERC-1155 contract now throws `author-error` naming `ctx.wallet.nfts()` instead of reading a token count; it asks ERC-165 alongside `decimals()` on every token read.
|
|
83
|
+
|
|
84
|
+
The testing kit answers `ctx.wallet.nfts()` from `facts.wallet.nfts`. A new `nft-holder` snippet accepts members whose linked wallets hold at least one NFT from the configured collection, on EVM or Solana.
|
|
85
|
+
|
|
86
|
+
- 1770ada: A seventh starter, `loyalty`: members join a campaign, earn points from its steps, join a members' group through a quest's group membership reward, and spend points on offers, one of them limited to the group with `inGroup`. Console offers it and `domino create --template loyalty` creates it.
|
|
87
|
+
|
|
88
|
+
Starters are now an open list, so adding one no longer changes the SDK's types. `starters` lists every starter as a `Starter` with a plain string `id`, `offeredStarterSchema` checks an ID against it, and `projectCreateInputSchema` and `repositoryCreateSchema` accept any offered starter; `management.createProject` uses the first. `starterTemplates`, `StarterTemplate`, `StarterId`, `starterIdSchema`, `projectInputSchema` and `createRepositorySchema` are deprecated: they keep the first six starters and are removed in 2.0.0. To upgrade, replace `starterTemplates` with `starters` and `starterIdSchema` with `offeredStarterSchema`, and type a starter ID as `string`.
|
|
89
|
+
|
|
90
|
+
- cec850f: Create and change a tracker of every managed source without a deployment, not only X search. `management.trackers.create` and `management.trackers.update` (`POST /trackers`, `POST /trackers/:tracker/update`) take a `source`: `{ kind: "x-search", query }`, `{ kind: "discord-messages", text? }`, `{ kind: "discord-reactions" }`, `{ kind: "telegram-messages" }`, `{ kind: "telegram-reactions" }`, `{ kind: "youtube-shorts" }` or `{ kind: "tiktok-videos" }`. Each is stored as the source its builder makes, such as `telegram.reactions()`, so quests read a data tracker as they read the same tracker in code. `query` alone still creates an X search tracker; create takes exactly one of `query` or `source`. An update's `source` replaces the source's settings but never its kind, which is refused with 422 `validation-failed`. Turning Discord message text off erases the text already stored. `managedTrackerCreateSchema` validates the new input, while `trackerCreateSchema` keeps its X-only shape. `managedTrackerSource(source)` reads a published source by these names, and `managedTrackerSourceKinds` lists them.
|
|
91
|
+
|
|
92
|
+
`domino trackers create KEY --source <kind>` creates one from the CLI, with `--text on` for Discord messages; `domino trackers update TRACKER --text on|off` turns message text on or off. Console **Trackers → New tracker** offers every source.
|
|
93
|
+
|
|
94
|
+
- 94726d8: Organization automation keys (`dak_`): a credential for CI and headless coding agents that no person owns. An organization administrator creates one in Console Settings → API keys for every project or a chosen list, with chosen permissions and an optional permission to create projects. It works as `RELAY_MANAGEMENT_TOKEN`, with `domino login --token-stdin` and the Git credential helper, in the test environment only: live writes, administration and minting other credentials are refused.
|
|
95
|
+
|
|
96
|
+
The management client adds `automationKeys` (`list`, `create`, `addSecret`, `revokeSecret`, `revoke`) with `automationKeyInputSchema`, `automationKeySchema`, `issuedAutomationKeySchema` and `automationKeyPermissionSchema`. `accessSchema` gains an optional `credential` that `/access` and `domino whoami --json` fill for an automation key with its kind and scope.
|
|
97
|
+
|
|
98
|
+
- 6d9f0de: `telegram.messages()` is a tracker source of the messages members post in the project's connected Telegram groups and supergroups, one record per message with the poster's Telegram account as `author`. `data` is `TelegramMessageData`: `chatId`, `chatType`, `messageId`, `replyToMessageId` and `threadId`, never the text. Bots', service and channel messages are not recorded. In SDK 1.x it is a custom source on the reserved namespace `telegram-messages`, which Relay alone writes. The new `telegram-contribution` snippet rewards posting once per member per day.
|
|
99
|
+
- 8d11f64: `wallet.balances({ chain, token })` is a tracker source of daily balance samples that Relay writes itself. Once per project-calendar day, at a time members can't predict, Relay reads one token's balance in every wallet linked by a member who joined the project, every wallet of a run at one pinned EVM block or Cosmos height (on Solana, every read must reach the run's pinned slot). `chain` and `token` are those of `ctx.wallet.balance()`. Each record is one wallet, keyed by its CAIP-10 account on the sampled chain, which is also its `author`; each sample is a new observation whose `occurredAt` is the sample time and whose `data` is `WalletBalanceSample` (`amount` in base units, `decimals`, `block`). A provider outage retries the same block later that day and never writes a zero, so a day with no successful sample breaks a `streak({ days })`. Reward holding for days with `automatic({ tracker, where: { path: "amount", gte: { setting: "threshold" } } })` and `streak({ days })`. In SDK 1.x it is a custom source on the reserved namespace `wallet-balances`, with the chain and token in the new optional `balance` field of custom sources (`walletBalanceSourceSchema`); ingestion refuses the namespace, and a project and environment can have at most 5 such trackers (`limit-reached`).
|
|
100
|
+
|
|
101
|
+
`management.trackers.create` and Console **New tracker** take `{ kind: "wallet-balances", chain, token }` (`managedTrackerSourceSchema`), and `domino trackers create --source wallet-balances` takes `--chain` and `--token`. The new `token-hold-streak` snippet rewards holding a token for 7 days in a row.
|
|
102
|
+
|
|
3
103
|
## 1.56.0
|
|
4
104
|
|
|
5
105
|
### Minor Changes
|
|
@@ -18,7 +18,6 @@ type DiscordMessage = z.infer<typeof discordMessageSchema>;
|
|
|
18
18
|
*/
|
|
19
19
|
declare const discordMessagesSourceSchema: z.ZodObject<{
|
|
20
20
|
kind: z.ZodLiteral<"discord-messages">;
|
|
21
|
-
/** Store each message's text in `data.text`. Off unless set. */
|
|
22
21
|
text: z.ZodOptional<z.ZodBoolean>;
|
|
23
22
|
}, z.core.$strict>;
|
|
24
23
|
/**
|
|
@@ -78,6 +77,7 @@ declare const discordResourceSourceSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
78
77
|
text: "text";
|
|
79
78
|
announcement: "announcement";
|
|
80
79
|
}>>;
|
|
80
|
+
postable: z.ZodOptional<z.ZodLiteral<true>>;
|
|
81
81
|
}, z.core.$strict>, z.ZodObject<{
|
|
82
82
|
provider: z.ZodLiteral<"discord">;
|
|
83
83
|
resource: z.ZodLiteral<"role">;
|
|
@@ -137,6 +137,7 @@ declare const telegramChatSchema: z.ZodObject<{
|
|
|
137
137
|
username: z.ZodNullable<z.ZodString>;
|
|
138
138
|
status: z.ZodString;
|
|
139
139
|
issue: z.ZodNullable<z.ZodString>;
|
|
140
|
+
canPost: z.ZodOptional<z.ZodBoolean>;
|
|
140
141
|
connectedAt: z.ZodNumber;
|
|
141
142
|
}, z.core.$strip>;
|
|
142
143
|
type TelegramChat = z.infer<typeof telegramChatSchema>;
|
|
@@ -158,6 +159,7 @@ declare const telegramChatsSchema: z.ZodObject<{
|
|
|
158
159
|
username: z.ZodNullable<z.ZodString>;
|
|
159
160
|
status: z.ZodString;
|
|
160
161
|
issue: z.ZodNullable<z.ZodString>;
|
|
162
|
+
canPost: z.ZodOptional<z.ZodBoolean>;
|
|
161
163
|
connectedAt: z.ZodNumber;
|
|
162
164
|
}, z.core.$strip>>;
|
|
163
165
|
}, z.core.$strip>;
|
|
@@ -206,11 +208,7 @@ interface TelegramReader {
|
|
|
206
208
|
chat: string;
|
|
207
209
|
}): Promise<TelegramChatMember | null>;
|
|
208
210
|
}
|
|
209
|
-
|
|
210
|
-
* The namespace of the tracker source `telegram.reactions()` makes. Relay alone writes its
|
|
211
|
-
* records; ingestion into it is refused.
|
|
212
|
-
*/
|
|
213
|
-
declare const telegramReactionsNamespace = "telegram-reactions";
|
|
211
|
+
|
|
214
212
|
/**
|
|
215
213
|
* One reaction a Telegram user added to a message, as a `telegram.reactions()` record's `data`.
|
|
216
214
|
* Every field is a scalar, so a trigger's `where` can select on it.
|
|
@@ -229,6 +227,22 @@ declare const telegramReactionDataSchema: z.ZodObject<{
|
|
|
229
227
|
}, z.core.$strip>;
|
|
230
228
|
type TelegramReactionData = z.infer<typeof telegramReactionDataSchema>;
|
|
231
229
|
|
|
230
|
+
/**
|
|
231
|
+
* One message a Telegram user posted in a connected group, as a `telegram.messages()` record's
|
|
232
|
+
* `data`. It names the message and never holds its text. Every field is a scalar, so a trigger's
|
|
233
|
+
* `where` can select on it.
|
|
234
|
+
*
|
|
235
|
+
* @compat output
|
|
236
|
+
*/
|
|
237
|
+
declare const telegramMessageDataSchema: z.ZodObject<{
|
|
238
|
+
chatId: z.ZodString;
|
|
239
|
+
chatType: z.ZodString;
|
|
240
|
+
messageId: z.ZodNumber;
|
|
241
|
+
replyToMessageId: z.ZodNullable<z.ZodNumber>;
|
|
242
|
+
threadId: z.ZodNullable<z.ZodNumber>;
|
|
243
|
+
}, z.core.$strip>;
|
|
244
|
+
type TelegramMessageData = z.infer<typeof telegramMessageDataSchema>;
|
|
245
|
+
|
|
232
246
|
declare const authProviderSchema: z.ZodEnum<{
|
|
233
247
|
discord: "discord";
|
|
234
248
|
google: "google";
|
|
@@ -289,4 +303,4 @@ interface DiscordReader {
|
|
|
289
303
|
}): Promise<DiscordMessage | null>;
|
|
290
304
|
}
|
|
291
305
|
|
|
292
|
-
export { type AccountConnection as A,
|
|
306
|
+
export { type AccountConnection as A, discordReactionDataSchema as B, discordResourceSourceSchema as C, type DiscordMessageData as D, discordRewardSchema as E, telegramAccountConnectionSchema as F, telegramChatConnectionSchema as G, telegramChatIdSchema as H, telegramChatSchema as I, telegramChatsSchema as J, telegramInitDataSchema as K, telegramMemberInputSchema as L, telegramMessageDataSchema as M, telegramMiniAppSignInSchema as N, telegramReactionDataSchema as O, telegramSignInMethodsSchema as P, type TelegramAccountConnection as T, type AuthProvider as a, type TelegramSignInMethods as b, type DiscordMessageTextData as c, discordMessagesSourceSchema as d, discordReactionsSourceSchema as e, type DiscordReactionData as f, type TelegramReader as g, type DiscordReader as h, type TelegramChatMember as i, type TelegramChatMemberStatus as j, type TelegramMessageData as k, type TelegramReactionData as l, discordMemberSchema as m, discordMessageSchema as n, type DiscordMember as o, type DiscordMessage as p, type TelegramChat as q, type TelegramChatConnection as r, type TelegramChats as s, telegramChatMemberSchema as t, accountConnectionSchema as u, authProviderSchema as v, discordMemberInputSchema as w, discordMessageDataSchema as x, discordMessageInputSchema as y, discordMessageTextDataSchema as z };
|