tapimo 0.19.0 → 0.20.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 (494) hide show
  1. package/README.md +13 -5
  2. package/dist/ApiKey.d.ts +2 -2
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +2 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +85 -11
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +218 -56
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +12543 -13912
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +4 -5
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +12 -20
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +20 -36
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/admin/App.d.ts +871 -828
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +14 -26
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +93 -186
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +3 -5
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/audit-logs.d.ts +18 -18
  27. package/dist/admin/apps/audit-logs.js +1 -1
  28. package/dist/admin/apps/audit-logs.js.map +1 -1
  29. package/dist/admin/apps/earn-vaults.d.ts +27 -27
  30. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  31. package/dist/admin/apps/earn-vaults.js +11 -5
  32. package/dist/admin/apps/earn-vaults.js.map +1 -1
  33. package/dist/admin/apps/organizations.d.ts +17 -17
  34. package/dist/admin/apps/prop-amms.d.ts +4 -4
  35. package/dist/admin/apps/routes-support.js +1 -38
  36. package/dist/admin/apps/routes-support.js.map +1 -1
  37. package/dist/admin/apps/routes.d.ts +153 -153
  38. package/dist/admin/apps/sentinel.d.ts +4 -4
  39. package/dist/admin/apps/verified-tokens.d.ts +24 -24
  40. package/dist/admin/apps/zone-delegation-requests.d.ts +332 -0
  41. package/dist/admin/apps/zone-delegation-requests.d.ts.map +1 -0
  42. package/dist/admin/apps/zone-delegation-requests.js +200 -0
  43. package/dist/admin/apps/zone-delegation-requests.js.map +1 -0
  44. package/dist/admin/apps/zone-delegations.d.ts +512 -52
  45. package/dist/admin/apps/zone-delegations.d.ts.map +1 -1
  46. package/dist/admin/apps/zone-delegations.js +134 -44
  47. package/dist/admin/apps/zone-delegations.js.map +1 -1
  48. package/dist/admin/index.d.ts +1 -1
  49. package/dist/admin/index.d.ts.map +1 -1
  50. package/dist/admin/index.js +1 -1
  51. package/dist/admin/index.js.map +1 -1
  52. package/dist/admin/ui.generated.d.ts +1 -1
  53. package/dist/admin/ui.generated.d.ts.map +1 -1
  54. package/dist/admin/ui.generated.js +341 -397
  55. package/dist/admin/ui.generated.js.map +1 -1
  56. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  57. package/dist/analytics/tables/requestEvents.js +4 -2
  58. package/dist/analytics/tables/requestEvents.js.map +1 -1
  59. package/dist/apps/data/App.d.ts +11932 -13214
  60. package/dist/apps/data/App.d.ts.map +1 -1
  61. package/dist/apps/data/App.js +32 -13
  62. package/dist/apps/data/App.js.map +1 -1
  63. package/dist/apps/data/ZoneSelection.d.ts +1 -1
  64. package/dist/apps/data/ZoneSelection.d.ts.map +1 -1
  65. package/dist/apps/data/ZoneSelection.js +2 -2
  66. package/dist/apps/data/ZoneSelection.js.map +1 -1
  67. package/dist/apps/data/routes/activities.d.ts +60 -27
  68. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  69. package/dist/apps/data/routes/activities.js +91 -16
  70. package/dist/apps/data/routes/activities.js.map +1 -1
  71. package/dist/apps/data/routes/addresses.d.ts +893 -875
  72. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  73. package/dist/apps/data/routes/balances.d.ts +36 -36
  74. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  75. package/dist/apps/data/routes/balances.js +3 -1
  76. package/dist/apps/data/routes/balances.js.map +1 -1
  77. package/dist/apps/data/routes/blocks.d.ts +40 -40
  78. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  79. package/dist/apps/data/routes/blocks.js +3 -7
  80. package/dist/apps/data/routes/blocks.js.map +1 -1
  81. package/dist/apps/data/routes/coingecko.d.ts +236 -236
  82. package/dist/apps/data/routes/earn-transactions.d.ts +14 -14
  83. package/dist/apps/data/routes/earn.d.ts +261 -1445
  84. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  85. package/dist/apps/data/routes/earn.js +64 -490
  86. package/dist/apps/data/routes/earn.js.map +1 -1
  87. package/dist/apps/data/routes/exchanges.d.ts +144 -144
  88. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  89. package/dist/apps/data/routes/exchanges.js +5 -15
  90. package/dist/apps/data/routes/exchanges.js.map +1 -1
  91. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  92. package/dist/apps/data/routes/fee-amm.js +3 -9
  93. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  94. package/dist/apps/data/routes/indexer.d.ts +13 -13
  95. package/dist/apps/data/routes/receipts.d.ts +53 -53
  96. package/dist/apps/data/routes/receipts.js +1 -1
  97. package/dist/apps/data/routes/receipts.js.map +1 -1
  98. package/dist/apps/data/routes/rpc.d.ts +52 -0
  99. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  100. package/dist/apps/data/routes/rpc.js +19 -18
  101. package/dist/apps/data/routes/rpc.js.map +1 -1
  102. package/dist/apps/data/routes/tokenlist.d.ts +14 -14
  103. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  104. package/dist/apps/data/routes/tokenlist.js +1 -3
  105. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  106. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  107. package/dist/apps/data/routes/tokens.js +7 -5
  108. package/dist/apps/data/routes/tokens.js.map +1 -1
  109. package/dist/apps/data/routes/transactions.d.ts +281 -281
  110. package/dist/apps/data/routes/transactions.js +3 -3
  111. package/dist/apps/data/routes/transactions.js.map +1 -1
  112. package/dist/apps/data/routes/transfers.d.ts +12 -12
  113. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  114. package/dist/apps/data/routes/transfers.js +1 -3
  115. package/dist/apps/data/routes/transfers.js.map +1 -1
  116. package/dist/apps/data/routes/valuation.d.ts +30 -30
  117. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  118. package/dist/apps/data/routes/valuation.js +1 -3
  119. package/dist/apps/data/routes/valuation.js.map +1 -1
  120. package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
  121. package/dist/apps/data/routes/webhooks.d.ts +102 -102
  122. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  123. package/dist/apps/data/routes/webhooks.js +9 -23
  124. package/dist/apps/data/routes/webhooks.js.map +1 -1
  125. package/dist/apps/data/routes/zone-deposits.d.ts +16 -16
  126. package/dist/apps/data/routes/zone-withdrawals.d.ts +31 -31
  127. package/dist/apps/data/routes/zones.d.ts +28 -28
  128. package/dist/apps/management/App.d.ts +18 -102
  129. package/dist/apps/management/App.d.ts.map +1 -1
  130. package/dist/apps/management/App.js +1 -1
  131. package/dist/apps/management/App.js.map +1 -1
  132. package/dist/apps/management/routes/api-keys.d.ts +253 -339
  133. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  134. package/dist/apps/management/routes/api-keys.js +25 -11
  135. package/dist/apps/management/routes/api-keys.js.map +1 -1
  136. package/dist/apps/management/routes/billing.d.ts +92 -92
  137. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  138. package/dist/apps/management/routes/billing.js +5 -13
  139. package/dist/apps/management/routes/billing.js.map +1 -1
  140. package/dist/apps/management/routes/cli.d.ts.map +1 -1
  141. package/dist/apps/management/routes/cli.js +3 -9
  142. package/dist/apps/management/routes/cli.js.map +1 -1
  143. package/dist/apps/management/routes/faucet.d.ts +16 -16
  144. package/dist/apps/management/routes/fee-payer-usage.d.ts +38 -38
  145. package/dist/apps/management/routes/fee-payer-usage.d.ts.map +1 -1
  146. package/dist/apps/management/routes/fee-payer-usage.js +2 -4
  147. package/dist/apps/management/routes/fee-payer-usage.js.map +1 -1
  148. package/dist/apps/management/routes/invitations.d.ts +52 -52
  149. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  150. package/dist/apps/management/routes/invitations.js +4 -12
  151. package/dist/apps/management/routes/invitations.js.map +1 -1
  152. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  153. package/dist/apps/management/routes/invite-links.js +6 -14
  154. package/dist/apps/management/routes/invite-links.js.map +1 -1
  155. package/dist/apps/management/routes/me.d.ts +6 -6
  156. package/dist/apps/management/routes/me.d.ts.map +1 -1
  157. package/dist/apps/management/routes/me.js +3 -7
  158. package/dist/apps/management/routes/me.js.map +1 -1
  159. package/dist/apps/management/routes/members.d.ts +84 -84
  160. package/dist/apps/management/routes/members.d.ts.map +1 -1
  161. package/dist/apps/management/routes/members.js +2 -4
  162. package/dist/apps/management/routes/members.js.map +1 -1
  163. package/dist/apps/management/routes/orgs.d.ts +44 -44
  164. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  165. package/dist/apps/management/routes/orgs.js +2 -6
  166. package/dist/apps/management/routes/orgs.js.map +1 -1
  167. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  168. package/dist/apps/management/routes/projects.js +2 -6
  169. package/dist/apps/management/routes/projects.js.map +1 -1
  170. package/dist/apps/management/routes/route-usage.d.ts +34 -34
  171. package/dist/apps/management/routes/route-usage.d.ts.map +1 -1
  172. package/dist/apps/management/routes/route-usage.js +2 -4
  173. package/dist/apps/management/routes/route-usage.js.map +1 -1
  174. package/dist/apps/management/routes/routes-access-requests.d.ts +120 -91
  175. package/dist/apps/management/routes/routes-access-requests.d.ts.map +1 -1
  176. package/dist/apps/management/routes/routes-access-requests.js +49 -9
  177. package/dist/apps/management/routes/routes-access-requests.js.map +1 -1
  178. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  179. package/dist/apps/management/routes/usage.js +8 -16
  180. package/dist/apps/management/routes/usage.js.map +1 -1
  181. package/dist/apps/management/routes/verified-token-requests.d.ts +39 -39
  182. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
  183. package/dist/apps/management/routes/verified-token-requests.js +3 -7
  184. package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
  185. package/dist/apps/management/routes/webhooks.d.ts +2089 -2089
  186. package/dist/apps/management/routes/zone-delegations.d.ts +14 -17
  187. package/dist/apps/management/routes/zone-delegations.d.ts.map +1 -1
  188. package/dist/apps/management/routes/zone-delegations.js +1 -6
  189. package/dist/apps/management/routes/zone-delegations.js.map +1 -1
  190. package/dist/apps/mpp/App.d.ts +44 -44
  191. package/dist/apps/mpp/App.js +3 -3
  192. package/dist/apps/mpp/App.js.map +1 -1
  193. package/dist/apps/mpp/internal/Adapter.js +1 -1
  194. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  195. package/dist/apps/mpp/internal/Error.d.ts.map +1 -1
  196. package/dist/apps/mpp/internal/Error.js +1 -0
  197. package/dist/apps/mpp/internal/Error.js.map +1 -1
  198. package/dist/apps/mpp/internal/Policy.d.ts +5 -1
  199. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  200. package/dist/apps/mpp/internal/Policy.js +35 -13
  201. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  202. package/dist/apps/relay/App.d.ts +2 -2
  203. package/dist/apps/relay/App.d.ts.map +1 -1
  204. package/dist/apps/relay/App.js +25 -16
  205. package/dist/apps/relay/App.js.map +1 -1
  206. package/dist/apps/routes/App.d.ts +311 -311
  207. package/dist/apps/routes/routes/deposit-addresses.d.ts +1099 -1099
  208. package/dist/apps/routes/routes/list.d.ts +74 -74
  209. package/dist/apps/routes/routes/transfers.d.ts +94 -94
  210. package/dist/cli/ApiKeys.d.ts +19 -26
  211. package/dist/cli/ApiKeys.d.ts.map +1 -1
  212. package/dist/db/Db.d.ts +3 -3
  213. package/dist/db/Db.d.ts.map +1 -1
  214. package/dist/db/Db.js +27 -0
  215. package/dist/db/Db.js.map +1 -1
  216. package/dist/db/Schema.d.ts +28 -62
  217. package/dist/db/Schema.d.ts.map +1 -1
  218. package/dist/db/Schema.js +18 -18
  219. package/dist/db/Schema.js.map +1 -1
  220. package/dist/db/tables/rewardRuns.d.ts +21 -0
  221. package/dist/db/tables/rewardRuns.d.ts.map +1 -1
  222. package/dist/db/tables/rewardRuns.js +19 -0
  223. package/dist/db/tables/rewardRuns.js.map +1 -1
  224. package/dist/db/tables/routesAccessRequests.d.ts +13 -0
  225. package/dist/db/tables/routesAccessRequests.d.ts.map +1 -1
  226. package/dist/db/tables/routesAccessRequests.js +12 -0
  227. package/dist/db/tables/routesAccessRequests.js.map +1 -1
  228. package/dist/db/tables/zoneDelegationRequests.d.ts +165 -0
  229. package/dist/db/tables/zoneDelegationRequests.d.ts.map +1 -0
  230. package/dist/db/tables/{zoneKeyRequests.js → zoneDelegationRequests.js} +43 -42
  231. package/dist/db/tables/zoneDelegationRequests.js.map +1 -0
  232. package/dist/db/tables/zoneDelegations.d.ts +11 -5
  233. package/dist/db/tables/zoneDelegations.d.ts.map +1 -1
  234. package/dist/db/tables/zoneDelegations.js +21 -3
  235. package/dist/db/tables/zoneDelegations.js.map +1 -1
  236. package/dist/handlers/internal/accounts.d.ts +7 -0
  237. package/dist/handlers/internal/accounts.d.ts.map +1 -0
  238. package/dist/handlers/internal/{multisig.js → accounts.js} +10 -10
  239. package/dist/handlers/internal/{multisig.js.map → accounts.js.map} +1 -1
  240. package/dist/handlers/internal/sponsorship.js +17 -17
  241. package/dist/handlers/internal/sponsorship.js.map +1 -1
  242. package/dist/handlers/relay.d.ts +6 -6
  243. package/dist/handlers/relay.d.ts.map +1 -1
  244. package/dist/handlers/relay.js +15 -15
  245. package/dist/handlers/relay.js.map +1 -1
  246. package/dist/internal/Auth.d.ts.map +1 -1
  247. package/dist/internal/Auth.js +4 -8
  248. package/dist/internal/Auth.js.map +1 -1
  249. package/dist/internal/EarnRates.d.ts.map +1 -1
  250. package/dist/internal/EarnRates.js +1 -3
  251. package/dist/internal/EarnRates.js.map +1 -1
  252. package/dist/internal/EarnVaults.js +2 -2
  253. package/dist/internal/Log.d.ts +2 -4
  254. package/dist/internal/Log.d.ts.map +1 -1
  255. package/dist/internal/Log.js +0 -3
  256. package/dist/internal/Log.js.map +1 -1
  257. package/dist/internal/Response.d.ts +1 -1
  258. package/dist/internal/Response.d.ts.map +1 -1
  259. package/dist/internal/Response.js +0 -3
  260. package/dist/internal/Response.js.map +1 -1
  261. package/dist/internal/Schema.d.ts +11 -0
  262. package/dist/internal/Schema.d.ts.map +1 -1
  263. package/dist/internal/Schema.js +24 -1
  264. package/dist/internal/Schema.js.map +1 -1
  265. package/dist/internal/ZoneAccess.d.ts +70 -35
  266. package/dist/internal/ZoneAccess.d.ts.map +1 -1
  267. package/dist/internal/ZoneAccess.js +312 -131
  268. package/dist/internal/ZoneAccess.js.map +1 -1
  269. package/dist/internal/ZoneDelegation.d.ts +7 -19
  270. package/dist/internal/ZoneDelegation.d.ts.map +1 -1
  271. package/dist/internal/ZoneDelegation.js +8 -29
  272. package/dist/internal/ZoneDelegation.js.map +1 -1
  273. package/dist/internal/{ZoneKeyApproval.d.ts → ZoneDelegationApproval.d.ts} +3 -5
  274. package/dist/internal/ZoneDelegationApproval.d.ts.map +1 -0
  275. package/dist/internal/ZoneDelegationApproval.js +16 -0
  276. package/dist/internal/ZoneDelegationApproval.js.map +1 -0
  277. package/dist/internal/ZoneKeyRewrite.d.ts +98 -0
  278. package/dist/internal/ZoneKeyRewrite.d.ts.map +1 -0
  279. package/dist/internal/ZoneKeyRewrite.js +151 -0
  280. package/dist/internal/ZoneKeyRewrite.js.map +1 -0
  281. package/dist/internal/rewards/Campaigns.d.ts +2 -0
  282. package/dist/internal/rewards/Campaigns.d.ts.map +1 -1
  283. package/dist/internal/rewards/Campaigns.js.map +1 -1
  284. package/dist/internal/rewards/Distributions.d.ts.map +1 -1
  285. package/dist/internal/rewards/Distributions.js +2 -6
  286. package/dist/internal/rewards/Distributions.js.map +1 -1
  287. package/dist/internal/rewards/Monitor.d.ts +4 -1
  288. package/dist/internal/rewards/Monitor.d.ts.map +1 -1
  289. package/dist/internal/rewards/Monitor.js +19 -2
  290. package/dist/internal/rewards/Monitor.js.map +1 -1
  291. package/dist/internal/rewards/Runner.d.ts.map +1 -1
  292. package/dist/internal/rewards/Runner.js +9 -1
  293. package/dist/internal/rewards/Runner.js.map +1 -1
  294. package/dist/internal/routes/Action.d.ts.map +1 -1
  295. package/dist/internal/routes/Action.js +2 -3
  296. package/dist/internal/routes/Action.js.map +1 -1
  297. package/dist/internal/routes/Deposit.d.ts.map +1 -1
  298. package/dist/internal/routes/Deposit.js +2 -6
  299. package/dist/internal/routes/Deposit.js.map +1 -1
  300. package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
  301. package/dist/internal/routes/DepositAddress.js +4 -10
  302. package/dist/internal/routes/DepositAddress.js.map +1 -1
  303. package/dist/internal/routes/Policy.d.ts.map +1 -1
  304. package/dist/internal/routes/Policy.js +2 -1
  305. package/dist/internal/routes/Policy.js.map +1 -1
  306. package/dist/internal/routes/Provider.js +8 -8
  307. package/dist/internal/routes/Provider.js.map +1 -1
  308. package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
  309. package/dist/internal/routes/Reconciliation.js +3 -2
  310. package/dist/internal/routes/Reconciliation.js.map +1 -1
  311. package/dist/internal/routes/Transfer.d.ts.map +1 -1
  312. package/dist/internal/routes/Transfer.js +4 -12
  313. package/dist/internal/routes/Transfer.js.map +1 -1
  314. package/dist/internal/routes/UniversalDepositAddress.d.ts.map +1 -1
  315. package/dist/internal/routes/UniversalDepositAddress.js +3 -6
  316. package/dist/internal/routes/UniversalDepositAddress.js.map +1 -1
  317. package/dist/internal/routes/providers/SquidOrder.d.ts.map +1 -1
  318. package/dist/internal/routes/providers/SquidOrder.js +3 -2
  319. package/dist/internal/routes/providers/SquidOrder.js.map +1 -1
  320. package/dist/internal/routes/providers/relay.d.ts.map +1 -1
  321. package/dist/internal/routes/providers/relay.js +4 -3
  322. package/dist/internal/routes/providers/relay.js.map +1 -1
  323. package/package.json +20 -5
  324. package/src/ApiKey.ts +2 -2
  325. package/src/ApiKeys.test.ts +284 -51
  326. package/src/ApiKeys.ts +297 -64
  327. package/src/App.ts +4 -5
  328. package/src/Client.test-d.ts +33 -126
  329. package/src/Scope.test.ts +26 -45
  330. package/src/Scope.ts +24 -37
  331. package/src/admin/App.test.ts +51 -4
  332. package/src/admin/App.ts +25 -33
  333. package/src/admin/Mcp.test.ts +2 -1
  334. package/src/admin/apps/api-keys.test.ts +90 -20
  335. package/src/admin/apps/api-keys.ts +5 -8
  336. package/src/admin/apps/audit-logs.ts +1 -1
  337. package/src/admin/apps/earn-vaults.test.ts +19 -19
  338. package/src/admin/apps/earn-vaults.ts +11 -5
  339. package/src/admin/apps/routes-support.test.ts +254 -3
  340. package/src/admin/apps/routes-support.ts +1 -44
  341. package/src/admin/apps/scopes.test.ts +3 -3
  342. package/src/admin/apps/zone-delegation-requests.test.ts +246 -0
  343. package/src/admin/apps/zone-delegation-requests.ts +240 -0
  344. package/src/admin/apps/zone-delegations.test.ts +218 -58
  345. package/src/admin/apps/zone-delegations.ts +146 -46
  346. package/src/admin/index.ts +1 -1
  347. package/src/admin/ui/src/components/ApiKeyForm.tsx +4 -3
  348. package/src/admin/ui/src/lib/config.ts +3 -3
  349. package/src/admin/ui/src/lib/query-client.ts +1 -1
  350. package/src/admin/ui/src/lib/review-queues.ts +10 -10
  351. package/src/admin/ui/src/lib/routes-setup.test.ts +1 -2
  352. package/src/admin/ui/src/lib/routes-setup.ts +3 -5
  353. package/src/admin/ui/src/lib/scopes.test.ts +3 -6
  354. package/src/admin/ui/src/lib/scopes.ts +2 -9
  355. package/src/admin/ui/src/lib/{zone-key-requests.ts → zone-delegation-requests.ts} +27 -31
  356. package/src/admin/ui/src/routeTree.gen.ts +17 -17
  357. package/src/admin/ui/src/routes/__root.tsx +1 -1
  358. package/src/admin/ui/src/routes/api-keys.tsx +2 -15
  359. package/src/admin/ui/src/routes/audit-logs.tsx +2 -2
  360. package/src/admin/ui/src/routes/index.tsx +11 -11
  361. package/src/admin/ui/src/routes/organizations.tsx +3 -1
  362. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +3 -1
  363. package/src/admin/ui/src/routes/organizations_.$orgId_.setup.tsx +1 -3
  364. package/src/admin/ui/src/routes/{zone-key-requests.tsx → zone-delegation-requests.tsx} +228 -172
  365. package/src/admin/ui/vite.config.ts +14 -1
  366. package/src/admin/ui.generated.ts +412 -583
  367. package/src/analytics/tables/requestEvents.test.ts +13 -3
  368. package/src/analytics/tables/requestEvents.ts +4 -3
  369. package/src/apps/data/App.test.ts +72 -35
  370. package/src/apps/data/App.ts +29 -13
  371. package/src/apps/data/ZoneSelection.test.ts +53 -70
  372. package/src/apps/data/ZoneSelection.ts +2 -2
  373. package/src/apps/data/routes/activities.test.ts +140 -6
  374. package/src/apps/data/routes/activities.ts +124 -18
  375. package/src/apps/data/routes/balances.ts +5 -1
  376. package/src/apps/data/routes/blocks.ts +9 -13
  377. package/src/apps/data/routes/earn-transactions.local.test.ts +6 -1
  378. package/src/apps/data/routes/earn-transactions.test.ts +7 -3
  379. package/src/apps/data/routes/earn.bench.ts +0 -14
  380. package/src/apps/data/routes/earn.discovery.test.ts +4 -39
  381. package/src/apps/data/routes/earn.local.test.ts +27 -34
  382. package/src/apps/data/routes/earn.test.ts +172 -490
  383. package/src/apps/data/routes/earn.ts +103 -652
  384. package/src/apps/data/routes/exchanges.ts +20 -30
  385. package/src/apps/data/routes/fee-amm.ts +12 -18
  386. package/src/apps/data/routes/indexer.test.ts +14 -12
  387. package/src/apps/data/routes/receipts.ts +1 -1
  388. package/src/apps/data/routes/rpc.test.ts +23 -18
  389. package/src/apps/data/routes/rpc.ts +21 -21
  390. package/src/apps/data/routes/rpc.zone.test.ts +60 -6
  391. package/src/apps/data/routes/tokenlist.ts +4 -6
  392. package/src/apps/data/routes/tokens.test.ts +20 -0
  393. package/src/apps/data/routes/tokens.ts +10 -5
  394. package/src/apps/data/routes/transactions.ts +3 -3
  395. package/src/apps/data/routes/transfers.ts +4 -6
  396. package/src/apps/data/routes/valuation.test.ts +2 -4
  397. package/src/apps/data/routes/valuation.ts +4 -6
  398. package/src/apps/data/routes/webhooks.test.ts +1 -5
  399. package/src/apps/data/routes/webhooks.ts +30 -44
  400. package/src/apps/data/routes/zones.test.ts +35 -19
  401. package/src/apps/management/App.ts +3 -1
  402. package/src/apps/management/routes/api-keys.test.ts +112 -22
  403. package/src/apps/management/routes/api-keys.ts +30 -15
  404. package/src/apps/management/routes/billing.ts +17 -25
  405. package/src/apps/management/routes/cli.ts +12 -18
  406. package/src/apps/management/routes/fee-payer-usage.ts +5 -4
  407. package/src/apps/management/routes/invitations.ts +16 -21
  408. package/src/apps/management/routes/invite-links.ts +18 -26
  409. package/src/apps/management/routes/me.ts +9 -13
  410. package/src/apps/management/routes/members.ts +5 -7
  411. package/src/apps/management/routes/orgs.ts +8 -12
  412. package/src/apps/management/routes/projects.ts +8 -12
  413. package/src/apps/management/routes/route-usage.ts +5 -4
  414. package/src/apps/management/routes/routes-access-requests.test.ts +64 -2
  415. package/src/apps/management/routes/routes-access-requests.ts +99 -15
  416. package/src/apps/management/routes/scopes.test.ts +3 -3
  417. package/src/apps/management/routes/usage.ts +20 -28
  418. package/src/apps/management/routes/verified-token-requests.ts +9 -13
  419. package/src/apps/management/routes/zone-delegations.test.ts +3 -5
  420. package/src/apps/management/routes/zone-delegations.ts +4 -9
  421. package/src/apps/mpp/App.ts +3 -3
  422. package/src/apps/mpp/Mpp.zone.test.ts +49 -18
  423. package/src/apps/mpp/internal/Adapter.ts +1 -1
  424. package/src/apps/mpp/internal/Error.test.ts +3 -0
  425. package/src/apps/mpp/internal/Error.ts +1 -0
  426. package/src/apps/mpp/internal/Policy.test.ts +9 -8
  427. package/src/apps/mpp/internal/Policy.ts +37 -14
  428. package/src/apps/relay/App.sandbox.test.ts +15 -14
  429. package/src/apps/relay/App.test.ts +120 -61
  430. package/src/apps/relay/App.ts +28 -18
  431. package/src/apps/relay/App.zone-billing.test.ts +9 -4
  432. package/src/apps/routes/App.test.ts +21 -22
  433. package/src/db/Db.ts +34 -3
  434. package/src/db/Schema.ts +26 -26
  435. package/src/db/tables/rewardRuns.ts +39 -0
  436. package/src/db/tables/routesAccessRequests.test.ts +65 -0
  437. package/src/db/tables/routesAccessRequests.ts +25 -0
  438. package/src/db/tables/{zoneKeyRequests.test.ts → zoneDelegationRequests.test.ts} +36 -77
  439. package/src/db/tables/{zoneKeyRequests.ts → zoneDelegationRequests.ts} +69 -52
  440. package/src/db/tables/zoneDelegations.test.ts +5 -6
  441. package/src/db/tables/zoneDelegations.ts +25 -8
  442. package/src/handlers/internal/{multisig.store.test.ts → accounts.store.test.ts} +16 -16
  443. package/src/handlers/internal/{multisig.test.ts → accounts.test.ts} +85 -82
  444. package/src/handlers/internal/{multisig.ts → accounts.ts} +9 -9
  445. package/src/handlers/internal/sponsorship.ts +20 -20
  446. package/src/handlers/relay.test.ts +48 -46
  447. package/src/handlers/relay.ts +26 -26
  448. package/src/internal/Auth.test.ts +6 -2
  449. package/src/internal/Auth.ts +4 -10
  450. package/src/internal/EarnRates.ts +4 -6
  451. package/src/internal/EarnVaults.ts +2 -2
  452. package/src/internal/Log.test-d.ts +1 -0
  453. package/src/internal/Log.test.ts +4 -6
  454. package/src/internal/Log.ts +2 -6
  455. package/src/internal/Response.ts +0 -3
  456. package/src/internal/Schema.test.ts +42 -0
  457. package/src/internal/Schema.ts +36 -1
  458. package/src/internal/ZoneAccess.test.ts +515 -312
  459. package/src/internal/ZoneAccess.ts +410 -158
  460. package/src/internal/ZoneDelegation.test.ts +1 -41
  461. package/src/internal/ZoneDelegation.ts +10 -48
  462. package/src/internal/ZoneDelegationApproval.test.ts +22 -0
  463. package/src/internal/{ZoneKeyApproval.ts → ZoneDelegationApproval.ts} +4 -11
  464. package/src/internal/ZoneKeyRewrite.ts +231 -0
  465. package/src/internal/rewards/Campaigns.ts +2 -0
  466. package/src/internal/rewards/Distributions.ts +8 -12
  467. package/src/internal/rewards/Monitor.test.ts +64 -0
  468. package/src/internal/rewards/Monitor.ts +27 -4
  469. package/src/internal/rewards/Runner.ts +9 -1
  470. package/src/internal/routes/Action.ts +5 -6
  471. package/src/internal/routes/Deposit.ts +8 -12
  472. package/src/internal/routes/DepositAddress.ts +13 -19
  473. package/src/internal/routes/Policy.ts +2 -1
  474. package/src/internal/routes/Provider.ts +8 -8
  475. package/src/internal/routes/Reconciliation.ts +3 -2
  476. package/src/internal/routes/Transfer.ts +16 -24
  477. package/src/internal/routes/UniversalDepositAddress.ts +9 -12
  478. package/src/internal/routes/providers/SquidOrder.ts +3 -2
  479. package/src/internal/routes/providers/relay.ts +4 -3
  480. package/dist/admin/apps/zone-key-requests.d.ts +0 -406
  481. package/dist/admin/apps/zone-key-requests.d.ts.map +0 -1
  482. package/dist/admin/apps/zone-key-requests.js +0 -183
  483. package/dist/admin/apps/zone-key-requests.js.map +0 -1
  484. package/dist/db/tables/zoneKeyRequests.d.ts +0 -289
  485. package/dist/db/tables/zoneKeyRequests.d.ts.map +0 -1
  486. package/dist/db/tables/zoneKeyRequests.js.map +0 -1
  487. package/dist/handlers/internal/multisig.d.ts +0 -7
  488. package/dist/handlers/internal/multisig.d.ts.map +0 -1
  489. package/dist/internal/ZoneKeyApproval.d.ts.map +0 -1
  490. package/dist/internal/ZoneKeyApproval.js +0 -21
  491. package/dist/internal/ZoneKeyApproval.js.map +0 -1
  492. package/src/admin/apps/zone-key-requests.test.ts +0 -272
  493. package/src/admin/apps/zone-key-requests.ts +0 -231
  494. package/src/internal/ZoneKeyApproval.test.ts +0 -46
@@ -5,14 +5,19 @@ import * as ApiKeys from '../../../ApiKeys.js'
5
5
  import * as Db from '../../../db/Db.js'
6
6
  import * as RoutesAccessRequests from '../../../db/tables/routesAccessRequests.js'
7
7
  import * as Auth from '../../../internal/Auth.js'
8
+ import * as ExecutionContext from '../../../internal/ExecutionContext.js'
8
9
  import * as OpenApi from '../../../internal/OpenApi.js'
9
10
  import * as Response from '../../../internal/Response.js'
11
+ import * as RoutesCatalog from '../../../internal/routes/Catalog.js'
10
12
  import * as Schema from '../../../internal/Schema.js'
11
13
  import type { Environment } from '../App.js'
12
14
 
13
15
  /** Most keys or routes one request may name. */
14
16
  const maxItems = 50
15
17
 
18
+ /** Quiet period after an organization's request during which later requests skip the reviewer notice. */
19
+ const noticeCooldownMs = 10 * 60_000
20
+
16
21
  /** OpenAPI schemas owned by Routes access requests. */
17
22
  export namespace schema {
18
23
  const id = (description: string, example: string) =>
@@ -44,12 +49,10 @@ export namespace schema {
44
49
  export const RoutesAccessRequest = OpenApi.component(
45
50
  Schema.describe(
46
51
  z.object({
47
- createdAt: z.iso
48
- .datetime()
49
- .check(
50
- z.describe('When the request was created (ISO 8601).'),
51
- z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
52
- ),
52
+ createdAt: Schema.dateTime().check(
53
+ z.describe('When the request was created (ISO 8601).'),
54
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
55
+ ),
53
56
  environment,
54
57
  expectedVolume: z
55
58
  .nullable(z.string())
@@ -100,7 +103,7 @@ export namespace schema {
100
103
  z.meta({ examples: ['Approved for Base USDC only.', null] }),
101
104
  ),
102
105
  reviewedAt: z
103
- .nullable(z.iso.datetime())
106
+ .nullable(Schema.dateTime())
104
107
  .check(
105
108
  z.describe('When the request was reviewed (ISO 8601), or null while pending.'),
106
109
  z.meta({ examples: ['2026-01-02T00:00:00.000Z', null] }),
@@ -129,12 +132,10 @@ export namespace schema {
129
132
  z.describe('Whether 1:1 subsidized delivery was requested.'),
130
133
  z.meta({ examples: [true] }),
131
134
  ),
132
- updatedAt: z.iso
133
- .datetime()
134
- .check(
135
- z.describe('When the request was last changed (ISO 8601).'),
136
- z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
137
- ),
135
+ updatedAt: Schema.dateTime().check(
136
+ z.describe('When the request was last changed (ISO 8601).'),
137
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
138
+ ),
138
139
  }),
139
140
  "A project's request for Routes transfer access.",
140
141
  ),
@@ -286,7 +287,7 @@ const path =
286
287
  '/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/projects/:projectId{prj_[A-Za-z0-9_-]+}/routes-access-requests'
287
288
 
288
289
  /** Mounts project Routes access request operations. */
289
- export function routesAccessRequests() {
290
+ export function routesAccessRequests(options: routesAccessRequests.Options = {}) {
290
291
  return new Hono<Environment>()
291
292
  .post(
292
293
  path,
@@ -341,7 +342,8 @@ export function routesAccessRequests() {
341
342
  message: `Choose live ${body.environment} keys from this project (${unknown.join(', ')})`,
342
343
  status: 400,
343
344
  })
344
- const record = await RoutesAccessRequests.create(Db.get(c.get('db')), {
345
+ const db = Db.get(c.get('db'))
346
+ const record = await RoutesAccessRequests.create(db, {
345
347
  environment: body.environment,
346
348
  ...(body.expectedVolume ? { expectedVolume: body.expectedVolume } : {}),
347
349
  keyIds: [...new Set(body.keyIds)],
@@ -358,6 +360,7 @@ export function routesAccessRequests() {
358
360
  message: 'This project already has a pending Routes access request',
359
361
  status: 409,
360
362
  })
363
+ dispatchNotice(c, { db, notify: options.notify, record })
361
364
  return c.json(
362
365
  Response.validated(schema.RoutesAccessRequest, RoutesAccessRequests.toRequest(record)),
363
366
  200,
@@ -458,6 +461,87 @@ export function routesAccessRequests() {
458
461
  )
459
462
  }
460
463
 
464
+ export declare namespace routesAccessRequests {
465
+ /** Options for the Routes access request operations. */
466
+ type Options = {
467
+ /** Called in the background for each new request, so reviewers hear about it; failures never affect the response. */
468
+ notify?: ((notice: Notice) => Promise<void>) | undefined
469
+ }
470
+
471
+ /** A new Routes access request, summarized for reviewers. */
472
+ type Notice = {
473
+ /** Environment the requested keys belong to. */
474
+ environment: RoutesAccessRequests.Record['environment']
475
+ /** Requester's expected monthly volume, as typed. */
476
+ expectedVolume?: string | undefined
477
+ /** Number of keys the request names. */
478
+ keyCount: number
479
+ /** Requester's note to reviewers. */
480
+ note?: string | undefined
481
+ /** Organization name. */
482
+ organization: string
483
+ /** Project name. */
484
+ project: string
485
+ /** Requester's verified email, when the session has one. */
486
+ requester?: string | undefined
487
+ /** Requested routes as `USDC on Base → OUSD on Tempo`; empty leaves the choice to Tempo. */
488
+ routes: readonly string[]
489
+ /** Whether the requester asked for 1:1 subsidized delivery. */
490
+ subsidy: boolean
491
+ }
492
+ }
493
+
494
+ /** Hands a new request to the notifier after the response, labelling routes from the catalog. */
495
+ function dispatchNotice(c: Context<Environment>, options: dispatchNotice.Options) {
496
+ const { db, notify, record } = options
497
+ if (!notify) return
498
+ const principal = Auth.getPrincipal(c)
499
+ const organization = Auth.org(c).name
500
+ const project = Auth.project(c).name
501
+ const task = (async () => {
502
+ // A cancel-and-recreate loop would otherwise ping the reviewer every time; the queue still lists every request.
503
+ const since = new Date(Date.parse(record.createdAt) - noticeCooldownMs).toISOString()
504
+ const recent = await RoutesAccessRequests.hasRecent(db, {
505
+ excludeId: record.id,
506
+ orgId: record.orgId,
507
+ since,
508
+ }).catch(() => false)
509
+ if (recent) return
510
+ // Labels are best effort: a failed catalog read falls back to raw ids instead of dropping the notice.
511
+ const catalog = await RoutesCatalog.read(db).catch(() => undefined)
512
+ const label = (chainId: string, tokenId: string) =>
513
+ `${catalog?.tokensById.get(tokenId)?.symbol ?? tokenId} on ${(catalog && RoutesCatalog.getChain(catalog, chainId)?.name) ?? chainId}`
514
+ await notify({
515
+ environment: record.environment,
516
+ ...(record.expectedVolume ? { expectedVolume: record.expectedVolume } : {}),
517
+ keyCount: record.keyIds.length,
518
+ ...(record.note ? { note: record.note } : {}),
519
+ organization,
520
+ project,
521
+ ...(principal?.type === 'session' && principal.email ? { requester: principal.email } : {}),
522
+ routes: record.routes.map(
523
+ (route) =>
524
+ `${label(route.sourceChainId, route.sourceTokenId)} → ${label(route.destinationChainId, route.destinationTokenId)}`,
525
+ ),
526
+ subsidy: record.subsidy,
527
+ })
528
+ })().catch((error) => console.error('routes access request notice failed', error))
529
+ const waitUntil = ExecutionContext.waitUntil(c)
530
+ // Without an execution context (Node, tests) the floating promise settles on its own.
531
+ if (waitUntil) waitUntil(task)
532
+ }
533
+
534
+ declare namespace dispatchNotice {
535
+ type Options = {
536
+ /** Database the request was written to; labels routes from its catalog. */
537
+ db: Db.Db
538
+ /** Reviewer notifier, when configured. */
539
+ notify: routesAccessRequests.Options['notify']
540
+ /** The request just created. */
541
+ record: RoutesAccessRequests.Record
542
+ }
543
+ }
544
+
461
545
  function keysNotEnabled(c: Context<Environment>) {
462
546
  return Response.error(c, {
463
547
  code: 'api_keys_not_enabled',
@@ -85,7 +85,7 @@ describe('scopes', () => {
85
85
  `"private, max-age=300, stale-while-revalidate=3600"`,
86
86
  )
87
87
  expect(body.data).toEqual(
88
- [...Scope.catalog, Scope.zoneEntry, Scope.zoneWriteEntry].map((entry) => ({ ...entry })),
88
+ [...Scope.catalog, Scope.zoneWriteEntry].map((entry) => ({ ...entry })),
89
89
  )
90
90
  expect(body.data.map((entry) => entry.scope)).toMatchInlineSnapshot(`
91
91
  [
@@ -103,7 +103,7 @@ describe('scopes', () => {
103
103
  "webhooks:read",
104
104
  "webhooks:write",
105
105
  "zone:read",
106
- "zone:<chainId>:read",
106
+ "zone:write",
107
107
  "zone:<chainId>:write",
108
108
  ]
109
109
  `)
@@ -120,6 +120,6 @@ describe('scopes', () => {
120
120
  const body = await TestApp.json(response, Scopes.schema.getScopes.Response)
121
121
 
122
122
  expect(response.status).toBe(200)
123
- expect(body.data).toEqual([...Scope.catalog, Scope.zoneEntry, Scope.zoneWriteEntry, custom])
123
+ expect(body.data).toEqual([...Scope.catalog, Scope.zoneWriteEntry, custom])
124
124
  })
125
125
  })
@@ -64,7 +64,7 @@ export namespace schema {
64
64
  .optional(z.enum(['production', 'sandbox']))
65
65
  .check(z.describe('Only include requests made with this API-key environment.'), z.meta({ examples: ['sandbox'] })), // prettier-ignore
66
66
  from: z
67
- .optional(z.iso.datetime({ offset: true }))
67
+ .optional(Schema.dateTime({ offset: true }))
68
68
  .check(
69
69
  z.describe('Only include requests at or after this ISO 8601 timestamp.'),
70
70
  z.meta({ examples: ['2026-01-01T00:00:00Z'] }),
@@ -80,7 +80,7 @@ export namespace schema {
80
80
  z.meta({ examples: ['prj_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
81
81
  ),
82
82
  to: z
83
- .optional(z.iso.datetime({ offset: true }))
83
+ .optional(Schema.dateTime({ offset: true }))
84
84
  .check(
85
85
  z.describe('Only include requests at or before this ISO 8601 timestamp.'),
86
86
  z.meta({ examples: ['2026-01-31T23:59:59Z'] }),
@@ -125,12 +125,10 @@ export namespace schema {
125
125
  requests: z
126
126
  .number()
127
127
  .check(z.int(), z.describe('Total requests.'), z.meta({ examples: [40] })),
128
- time: z.iso
129
- .datetime()
130
- .check(
131
- z.describe('Bucket start timestamp (ISO 8601).'),
132
- z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
133
- ),
128
+ time: Schema.dateTime().check(
129
+ z.describe('Bucket start timestamp (ISO 8601).'),
130
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
131
+ ),
134
132
  })
135
133
  .check(z.describe('One usage series point.')),
136
134
  'RequestUsageSeriesPoint',
@@ -179,12 +177,10 @@ export namespace schema {
179
177
  byKey: z.array(KeyBreakdown).check(z.describe('Usage grouped by API key.'), z.meta({ examples: [[]] })), // prettier-ignore
180
178
  byRoute: z.array(RouteBreakdown).check(z.describe('Usage grouped by route.'), z.meta({ examples: [[]] })), // prettier-ignore
181
179
  byStatus: z.array(StatusBreakdown).check(z.describe('Usage grouped by status code.'), z.meta({ examples: [[]] })), // prettier-ignore
182
- from: z.iso
183
- .datetime()
184
- .check(
185
- z.describe('Inclusive lower timestamp bound used for the read (ISO 8601).'),
186
- z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
187
- ),
180
+ from: Schema.dateTime().check(
181
+ z.describe('Inclusive lower timestamp bound used for the read (ISO 8601).'),
182
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
183
+ ),
188
184
  interval: z
189
185
  .enum(['day', 'hour'])
190
186
  .check(
@@ -192,12 +188,10 @@ export namespace schema {
192
188
  z.meta({ examples: ['day'] }),
193
189
  ),
194
190
  series: z.array(SeriesPoint).check(z.describe('Usage grouped into time buckets.'), z.meta({ examples: [[]] })), // prettier-ignore
195
- to: z.iso
196
- .datetime()
197
- .check(
198
- z.describe('Inclusive upper timestamp bound used for the read (ISO 8601).'),
199
- z.meta({ examples: ['2026-01-31T23:59:59.000Z'] }),
200
- ),
191
+ to: Schema.dateTime().check(
192
+ z.describe('Inclusive upper timestamp bound used for the read (ISO 8601).'),
193
+ z.meta({ examples: ['2026-01-31T23:59:59.000Z'] }),
194
+ ),
201
195
  totals: Totals,
202
196
  }),
203
197
  'Request usage.',
@@ -238,12 +232,10 @@ export namespace schema {
238
232
  z.describe('Committed fees for the bucket.'),
239
233
  z.meta({ examples: [{ amount: '12.34', currency: 'usd' }] }),
240
234
  ),
241
- timestamp: z.iso
242
- .datetime()
243
- .check(
244
- z.describe('Bucket start (ISO 8601), aligned to UTC calendar boundaries.'),
245
- z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
246
- ),
235
+ timestamp: Schema.dateTime().check(
236
+ z.describe('Bucket start (ISO 8601), aligned to UTC calendar boundaries.'),
237
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
238
+ ),
247
239
  }),
248
240
  'One time bucket of sponsorship usage.',
249
241
  ),
@@ -272,7 +264,7 @@ export namespace schema {
272
264
  z.meta({ examples: ['production'] }),
273
265
  ),
274
266
  from: z
275
- .optional(z.iso.datetime({ offset: true }))
267
+ .optional(Schema.dateTime({ offset: true }))
276
268
  .check(
277
269
  z.describe('Window start (ISO 8601), inclusive. Defaults to 30 days before `to`.'),
278
270
  z.meta({ examples: ['2026-01-01T00:00:00Z'] }),
@@ -290,7 +282,7 @@ export namespace schema {
290
282
  z.meta({ examples: ['prj_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
291
283
  ),
292
284
  to: z
293
- .optional(z.iso.datetime({ offset: true }))
285
+ .optional(Schema.dateTime({ offset: true }))
294
286
  .check(
295
287
  z.describe('Window end (ISO 8601), exclusive. Defaults to now.'),
296
288
  z.meta({ examples: ['2026-01-31T00:00:00Z'] }),
@@ -34,12 +34,10 @@ export namespace schema {
34
34
  Schema.describe(
35
35
  z.extend(tokenSchema.Input, {
36
36
  chainId,
37
- createdAt: z.iso
38
- .datetime()
39
- .check(
40
- z.describe('When the request was created (ISO 8601).'),
41
- z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
42
- ),
37
+ createdAt: Schema.dateTime().check(
38
+ z.describe('When the request was created (ISO 8601).'),
39
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
40
+ ),
43
41
  id: z
44
42
  .string()
45
43
  .check(
@@ -79,7 +77,7 @@ export namespace schema {
79
77
  z.meta({ examples: ['Logo URL is unreachable.', null] }),
80
78
  ),
81
79
  reviewedAt: z
82
- .nullable(z.iso.datetime())
80
+ .nullable(Schema.dateTime())
83
81
  .check(
84
82
  z.describe('When the request was reviewed (ISO 8601), or null while pending.'),
85
83
  z.meta({ examples: ['2026-01-02T00:00:00.000Z', null] }),
@@ -87,12 +85,10 @@ export namespace schema {
87
85
  status: z
88
86
  .enum(['approved', 'denied', 'pending'])
89
87
  .check(z.describe('Review status of the request.'), z.meta({ examples: ['pending'] })),
90
- updatedAt: z.iso
91
- .datetime()
92
- .check(
93
- z.describe('When the request was last changed (ISO 8601).'),
94
- z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
95
- ),
88
+ updatedAt: Schema.dateTime().check(
89
+ z.describe('When the request was last changed (ISO 8601).'),
90
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
91
+ ),
96
92
  }),
97
93
  "An organization's request to add a token to the curated verified list.",
98
94
  ),
@@ -41,11 +41,11 @@ test('publishes the list operation', async () => {
41
41
  })
42
42
 
43
43
  test('lists active delegations per environment for sessions and management keys', async () => {
44
- const { app, cookie, db, kv, org, path, project } = await setup()
45
- const base = { accountsAll: true, orgId: org.id, projects: 'all', tokensAll: true } as const
44
+ const { app, cookie, db, kv, org, path } = await setup()
45
+ const base = { accountsAll: true, orgId: org.id, tokensAll: true } as const
46
46
  const revoked = await ZoneDelegations.create(db, { ...base, chainId: 1_424_310_003, environment: 'production' }) // prettier-ignore
47
47
  await ZoneDelegations.revoke(db, revoked.id)
48
- await ZoneDelegations.create(db, { ...base, accountsAll: false, chainId: 421_700_002, environment: 'production', projects: [project.id] }) // prettier-ignore
48
+ await ZoneDelegations.create(db, { ...base, accountsAll: false, chainId: 421_700_002, environment: 'production' }) // prettier-ignore
49
49
  await ZoneDelegations.create(db, { ...base, chainId: 421_700_001, environment: 'production' })
50
50
  await ZoneDelegations.create(db, { ...base, chainId: 421_700_001, environment: 'sandbox' })
51
51
 
@@ -60,7 +60,6 @@ test('lists active delegations per environment for sessions and management keys'
60
60
  createdAt: expect.any(String),
61
61
  environment: 'production',
62
62
  name: 'zone-mainnet-internal',
63
- projects: 'all',
64
63
  tokensAll: true,
65
64
  },
66
65
  {
@@ -69,7 +68,6 @@ test('lists active delegations per environment for sessions and management keys'
69
68
  createdAt: expect.any(String),
70
69
  environment: 'production',
71
70
  name: 'zone-deel',
72
- projects: [project.id],
73
71
  tokensAll: true,
74
72
  },
75
73
  ])
@@ -42,12 +42,10 @@ export namespace schema {
42
42
  z.meta({ examples: [true] }),
43
43
  ),
44
44
  chainId: z.int().check(z.describe('Zone chain id.'), z.meta({ examples: [421700001] })),
45
- createdAt: z.iso
46
- .datetime()
47
- .check(
48
- z.describe('When the delegation was created (ISO 8601).'),
49
- z.meta({ examples: ['2026-10-19T00:00:00.000Z'] }),
50
- ),
45
+ createdAt: Schema.dateTime().check(
46
+ z.describe('When the delegation was created (ISO 8601).'),
47
+ z.meta({ examples: ['2026-10-19T00:00:00.000Z'] }),
48
+ ),
51
49
  environment: ZoneDelegation.schema.Environment,
52
50
  name: z
53
51
  .optional(z.string())
@@ -55,7 +53,6 @@ export namespace schema {
55
53
  z.describe('Zone name when the Zone is hosted by Tempo.'),
56
54
  z.meta({ examples: ['zone-mainnet-internal'] }),
57
55
  ),
58
- projects: ZoneDelegation.schema.Projects,
59
56
  tokensAll: z
60
57
  .boolean()
61
58
  .check(
@@ -83,7 +80,6 @@ export namespace schema {
83
80
  createdAt: '2026-10-19T00:00:00.000Z',
84
81
  environment: 'production',
85
82
  name: 'zone-mainnet-internal',
86
- projects: 'all',
87
83
  tokensAll: true,
88
84
  },
89
85
  ],
@@ -170,7 +166,6 @@ export function zoneDelegations() {
170
166
  createdAt: record.createdAt,
171
167
  environment: record.environment,
172
168
  ...(name === undefined ? {} : { name }),
173
- projects: record.projects,
174
169
  tokensAll: record.tokensAll,
175
170
  }
176
171
  }),
@@ -45,7 +45,7 @@ export function mpp(options: mpp.Options) {
45
45
  // Record the Zone decision here; the adapter re-checks without recording.
46
46
  const response = await Timing.time(c, 'mpp_verify', async () => {
47
47
  try {
48
- Policy.assertChainAccess(c, {
48
+ await Policy.assertChainAccess(c, {
49
49
  chainId,
50
50
  supportedChainIds: c.get('supportedChainIds'),
51
51
  zones: c.get('zones'),
@@ -168,7 +168,7 @@ async function authorizeBroadcast(
168
168
  const chainId = Policy.chainId(input) ?? c.get('chainId')
169
169
  const principal = Auth.getPrincipal(c) ?? undefined
170
170
  try {
171
- Policy.assertChainAccess(c, {
171
+ await Policy.assertChainAccess(c, {
172
172
  chainId,
173
173
  supportedChainIds: c.get('supportedChainIds'),
174
174
  zones: c.get('zones'),
@@ -316,7 +316,7 @@ async function broadcast(c: Context<App.Environment>, options: broadcast.Options
316
316
  async function reconcile(c: Context<App.Environment>, options: reconcile.Options) {
317
317
  const { options: options_mpp, submission } = options
318
318
  try {
319
- Policy.assertChainAccess(c, {
319
+ await Policy.assertChainAccess(c, {
320
320
  chainId: submission.chainId,
321
321
  supportedChainIds: c.get('supportedChainIds'),
322
322
  zones: c.get('zones'),
@@ -70,7 +70,7 @@ describe('MPP Zone authorization', () => {
70
70
  expect(await response.json()).toEqual({
71
71
  error: {
72
72
  code: 'policy_denied',
73
- message: `Broadcasting to zone ${zone.id} requires \`zone:${zone.id}:write\`.`,
73
+ message: `Broadcasting to zone ${zone.id} requires \`zone:write\` with a tag for Zone ${zone.id}, issued to an organization delegated that Zone.`,
74
74
  },
75
75
  success: false,
76
76
  })
@@ -84,11 +84,14 @@ describe('MPP Zone authorization', () => {
84
84
  )
85
85
 
86
86
  test.each(['validate', 'broadcast'] as const)(
87
- '%s confines wildcard sandbox keys to testnet without requiring sponsorship',
87
+ '%s confines tagged sandbox keys to testnet without requiring sponsorship',
88
88
  async (operation) => {
89
89
  const resolutions: number[] = []
90
+ const db = TestApp.database()
91
+ await TestApp.delegateZone(db, { chainIds: [zone.id], environment: 'sandbox', orgId: key.orgId }) // prettier-ignore
90
92
  const app = TestApp.create({
91
- auth: { keys: [{ ...key, environment: 'sandbox', scopes: ['*'] }] },
93
+ auth: { keys: [{ ...key, environment: 'sandbox', scopes: ['mpp:write', 'zone:write'], zoneTags: [zone.id] }] }, // prettier-ignore
94
+ db,
92
95
  rpc: ({ chainId }) => {
93
96
  resolutions.push(chainId)
94
97
  return { url: runtime.zone.internalRpcUrl }
@@ -120,8 +123,11 @@ describe('MPP Zone authorization', () => {
120
123
 
121
124
  test('requires active billing before mainnet Zone fee-payer access', async () => {
122
125
  const resolutions: number[] = []
126
+ const db = TestApp.database()
127
+ await TestApp.delegateZone(db, { chainIds: [zone.id], orgId: key.orgId })
123
128
  const app = TestApp.create({
124
- auth: { keys: [{ ...key, scopes: ['mpp:write', `zone:${zone.id}:write`] }] },
129
+ auth: { keys: [{ ...key, scopes: ['mpp:write', 'zone:write'], zoneTags: [zone.id] }] },
130
+ db,
125
131
  mpp: { feePayer: Tempo.accounts[2], state: Store.memory() },
126
132
  rpc: ({ chainId }) => {
127
133
  resolutions.push(chainId)
@@ -143,28 +149,53 @@ describe('MPP Zone authorization', () => {
143
149
 
144
150
  test('requires write scope to validate or broadcast Zone credentials', async () => {
145
151
  const input = await credential()
146
- const app = TestApp.create({
147
- auth: { keys: [{ ...key, scopes: ['mpp:write', `zone:${zone.id}:read`] }] },
148
- zones: [zone],
149
- })
150
- for (const operation of ['validate', 'broadcast'] as const)
151
- expect(await (await post(app, operation, input)).json()).toEqual({
152
- error: {
153
- code: 'policy_denied',
154
- message: `Broadcasting to zone ${zone.id} requires \`zone:${zone.id}:write\`.`,
155
- },
156
- success: false,
157
- })
152
+ // A read scope never broadcasts, nor does a generic write scope without a tag for the Zone or
153
+ // without a delegation, nor the wildcard however it is tagged.
154
+ const db = TestApp.database()
155
+ await TestApp.delegateZone(db, { chainIds: [zone.id], orgId: key.orgId })
156
+ for (const reader of [
157
+ { scopes: ['mpp:write', 'zone:read'], zoneTags: [zone.id] },
158
+ { scopes: ['mpp:write', 'zone:write'] },
159
+ { scopes: ['mpp:write', 'zone:write'], zoneTags: [zone.id + 1] },
160
+ { orgId: 'org_undelegated', scopes: ['mpp:write', 'zone:write'], zoneTags: [zone.id] },
161
+ { scopes: ['*'] },
162
+ { scopes: ['*'], zoneTags: [zone.id] },
163
+ ]) {
164
+ const app = TestApp.create({ auth: { keys: [{ ...key, ...reader }] }, db, zones: [zone] })
165
+ for (const operation of ['validate', 'broadcast'] as const)
166
+ expect(await (await post(app, operation, input)).json()).toEqual({
167
+ error: {
168
+ code: 'policy_denied',
169
+ message: `Broadcasting to zone ${zone.id} requires \`zone:write\` with a tag for Zone ${zone.id}, issued to an organization delegated that Zone.`,
170
+ },
171
+ success: false,
172
+ })
173
+ }
158
174
  })
159
175
 
160
176
  test.each([
161
177
  { environment: 'production', scopes: ['mpp:write', `zone:${zone.id}:write`], sourceId: 4217 },
162
- { environment: 'production', scopes: ['*'], sourceId: 4217 },
178
+ // The wildcard grants no Zone on its own; it may sit beside the explicit write grant.
179
+ { environment: 'production', scopes: ['*', `zone:${zone.id}:write`], sourceId: 4217 },
163
180
  { environment: 'sandbox', scopes: ['mpp:write', `zone:${zone.id}:write`], sourceId: 42431 },
181
+ { environment: 'production', scopes: ['mpp:write', 'zone:write'], sourceId: 4217, zoneTags: [zone.id] }, // prettier-ignore
182
+ { environment: 'sandbox', scopes: ['mpp:write', 'zone:write'], sourceId: 42431, zoneTags: [zone.id] }, // prettier-ignore
164
183
  ] as const)('allows authorized $environment Zone credentials with $scopes', async (options) => {
165
184
  const input = await credential()
185
+ const db = TestApp.database()
186
+ await TestApp.delegateZone(db, { chainIds: [zone.id], environment: options.environment, orgId: key.orgId }) // prettier-ignore
166
187
  const app = TestApp.create({
167
- auth: { keys: [{ ...key, environment: options.environment, scopes: [...options.scopes] }] },
188
+ db,
189
+ auth: {
190
+ keys: [
191
+ {
192
+ ...key,
193
+ environment: options.environment,
194
+ scopes: [...options.scopes],
195
+ ...('zoneTags' in options ? { zoneTags: [...options.zoneTags] } : {}),
196
+ },
197
+ ],
198
+ },
168
199
  zones: [{ ...zone, sourceId: options.sourceId }],
169
200
  })
170
201
  for (const operation of ['validate', 'broadcast'] as const)
@@ -200,7 +200,7 @@ function isCanonical(serialized: Hex.Hex) {
200
200
  if (!/^0x7[68]/.test(serialized)) return true
201
201
  try {
202
202
  const envelope = TxEnvelopeTempo.deserialize(serialized as TxEnvelopeTempo.Serialized)
203
- // Fee-payer handoffs encode a sender address or, for multisig senders, the `0x00` marker; parsing recovers `from` either way.
203
+ // Fee-payer handoffs encode a sender address or, for configurable account senders, the `0x00` marker; parsing recovers `from` either way.
204
204
  const slot = (Rlp.toHex(Hex.slice(serialized, 1)) as readonly Hex.Hex[])[11]
205
205
  const serialized_parsed = serialized.startsWith(TxEnvelopeTempo.feePayerMagic)
206
206
  ? TxEnvelopeTempo.serialize(envelope, {
@@ -4,6 +4,7 @@ import * as Mpp from '../Mpp.js'
4
4
  import * as Confirmation from './Confirmation.js'
5
5
  import * as MppError from './Error.js'
6
6
  import * as Idempotency from './Idempotency.js'
7
+ import * as Policy from './Policy.js'
7
8
  import * as ScreenManager from './ScreenManager.js'
8
9
 
9
10
  describe('map', () => {
@@ -26,6 +27,8 @@ describe('map', () => {
26
27
  Mpp.relayErrorCode.alreadyUsed,
27
28
  ],
28
29
  [new Idempotency.LeaseLostError(), Mpp.relayErrorCode.temporarilyUnavailable],
30
+ [new Policy.AccessUnavailableError(), Mpp.relayErrorCode.temporarilyUnavailable],
31
+ [new Policy.PolicyDeniedError(), Mpp.relayErrorCode.policyDenied],
29
32
  [new Confirmation.UnconfirmedError({ status: 502 }), Mpp.relayErrorCode.temporarilyUnavailable],
30
33
  [new ScreenManager.RejectedError(), Mpp.relayErrorCode.screenRejected],
31
34
  [new Error('Transaction simulation failed.'), Mpp.relayErrorCode.simulationFailed],
@@ -12,6 +12,7 @@ export function map(cause: unknown): Mpp.RelayError {
12
12
  const message = cause instanceof Error ? cause.message : undefined
13
13
 
14
14
  switch (true) {
15
+ case cause instanceof Policy.AccessUnavailableError:
15
16
  case cause instanceof Idempotency.LeaseLostError:
16
17
  // The transaction may still land; an idempotent retry reconciles it.
17
18
  case cause instanceof Confirmation.UnconfirmedError:
@@ -87,32 +87,33 @@ describe('assertFeeMarketAdmission', () => {
87
87
  })
88
88
 
89
89
  describe('assertChainAccess', () => {
90
- test('rejects chains outside the deployment allowlist', () => {
91
- expect(() =>
90
+ test('rejects chains outside the deployment allowlist', async () => {
91
+ await expect(
92
92
  Policy.assertChainAccess(new Context(new Request('http://tempo-api.test/')), {
93
93
  chainId: 1,
94
94
  supportedChainIds: new Set([4217]),
95
95
  zones,
96
96
  }),
97
- ).toThrowErrorMatchingInlineSnapshot(
97
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
98
98
  `[Mpp.Policy.UnsupportedChainError: Unsupported chain id 1.]`,
99
99
  )
100
100
  })
101
101
 
102
- test('requires a Zone write scope; read scopes never admit', () => {
102
+ test('requires a Zone write scope; read grants never admit', async () => {
103
103
  const chainId = Zones.zoneModeratoInternal.id
104
104
  const c = new Context(new Request('http://tempo-api.test/'))
105
105
  c.set(
106
106
  'principal' as never,
107
107
  {
108
108
  ...principal,
109
- apiKey: { ...principal.apiKey, scopes: ['mpp:write', `zone:${chainId}:read`] },
109
+ apiKey: { ...principal.apiKey, scopes: ['mpp:write', 'zone:read'] },
110
+ zoneTags: [chainId],
110
111
  } as never,
111
112
  )
112
- expect(() =>
113
+ await expect(
113
114
  Policy.assertChainAccess(c, { chainId, supportedChainIds: new Set([chainId]), zones }),
114
- ).toThrowErrorMatchingInlineSnapshot(
115
- `[Mpp.Policy.PolicyDeniedError: Broadcasting to zone 1424310003 requires \`zone:1424310003:write\`.]`,
115
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
116
+ `[Mpp.Policy.PolicyDeniedError: Broadcasting to zone 1424310003 requires \`zone:write\` with a tag for Zone 1424310003, issued to an organization delegated that Zone.]`,
116
117
  )
117
118
  expect(c.get('zoneAccess' as never)).toMatchObject({ chainId, verb: 'write' })
118
119
  })