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
@@ -3,13 +3,14 @@ import * as z from 'zod/mini'
3
3
 
4
4
  import * as Db from '../../db/Db.js'
5
5
  import * as Organizations from '../../db/tables/organizations.js'
6
- import * as Projects from '../../db/tables/projects.js'
7
6
  import * as ZoneDelegations from '../../db/tables/zoneDelegations.js'
8
7
  import * as OpenApi from '../../internal/OpenApi.js'
9
8
  import * as Response from '../../internal/Response.js'
10
9
  import * as Schema from '../../internal/Schema.js'
11
10
  import * as ZoneDelegation from '../../internal/ZoneDelegation.js'
11
+ import * as ZoneDelegationApproval from '../../internal/ZoneDelegationApproval.js'
12
12
  import * as ZoneDelegationBackfill from '../../internal/ZoneDelegationBackfill.js'
13
+ import * as ZoneKeyRewrite from '../../internal/ZoneKeyRewrite.js'
13
14
  import type * as App from '../App.js'
14
15
 
15
16
  /** Request and response schemas for organization Zone delegations and their members. */
@@ -60,14 +61,12 @@ export namespace schema {
60
61
  chainId: Schema.ChainId,
61
62
  environment: ZoneDelegation.schema.Environment,
62
63
  orgId: OrgId,
63
- projects: ZoneDelegation.schema.Projects,
64
64
  tokens: z.optional(ZoneDelegation.schema.AddressList),
65
65
  tokensAll: TokensAll,
66
66
  })
67
67
  export const Patch = z
68
68
  .strictObject({
69
69
  accountsAll: z.optional(AccountsAll),
70
- projects: z.optional(ZoneDelegation.schema.Projects),
71
70
  tokensAll: z.optional(TokensAll),
72
71
  })
73
72
  .check(z.refine((patch) => Object.keys(patch).length > 0, 'At least one field is required.'))
@@ -83,7 +82,6 @@ export namespace schema {
83
82
  environment: ZoneDelegation.schema.Environment,
84
83
  id: Params.shape.id,
85
84
  orgId: OwnerId,
86
- projects: ZoneDelegation.schema.Projects,
87
85
  revokedAt: z
88
86
  .optional(z.string())
89
87
  .check(
@@ -107,7 +105,6 @@ export namespace schema {
107
105
  chainId: Schema.ChainId,
108
106
  environment: ZoneDelegation.schema.Environment,
109
107
  orgId: OwnerId,
110
- projects: ZoneDelegation.schema.Projects,
111
108
  tokensAll: z.literal(true),
112
109
  }),
113
110
  )
@@ -145,6 +142,73 @@ export namespace schema {
145
142
  .number()
146
143
  .check(z.describe('Slots already holding a delegation, left untouched.'), z.meta({ examples: [0] })), // prettier-ignore
147
144
  })
145
+ const RewriteKey = z.object({
146
+ environment: ZoneDelegation.schema.Environment,
147
+ id: z.string().check(z.describe('Key id.'), z.meta({ examples: ['key_1a2b3c4d5e6f7g8h9j0k1m2n'] })), // prettier-ignore
148
+ name: z.optional(z.string()).check(z.describe('Key name, when set.'), z.meta({ examples: ['Integration'] })), // prettier-ignore
149
+ orgId: OwnerId,
150
+ projectId: z.optional(z.string()).check(z.describe('Attributed project id, when any.'), z.meta({ examples: ['prj_1a2b3c4d5e6f7g8h9j0k1m2n'] })), // prettier-ignore
151
+ })
152
+ export const RewritePlan = z.object({
153
+ changes: z
154
+ .array(
155
+ z.extend(RewriteKey, {
156
+ complete: z.boolean().check(z.describe('Whether the record already holds `zone:read` and every tag; only its delegations are ensured.'), z.meta({ examples: [false] })), // prettier-ignore
157
+ revoked: z.array(Schema.ChainId).check(z.describe('Zones whose delegation an admin revoked; the key is left unwritten while any remain.'), z.meta({ examples: [[]] })), // prettier-ignore
158
+ scopes: z.array(z.string()).check(z.describe('Scopes after the rewrite.'), z.meta({ examples: [['data:read', 'zone:421700001:read', 'zone:read']] })), // prettier-ignore
159
+ undelegated: z.array(Schema.ChainId).check(z.describe('Zones the per-Zone scopes grant without an active delegation for the organization; applying ensures one unless the slot was revoked.'), z.meta({ examples: [[421700002]] })), // prettier-ignore
160
+ zoneTags: z.array(Schema.ChainId).check(z.describe('Zone chain ids the key reads after the rewrite.'), z.meta({ examples: [[421700001, 421700002]] })), // prettier-ignore
161
+ }),
162
+ )
163
+ .check(z.describe('Keys holding per-Zone read scopes, with the scopes and tags they will carry.'), z.meta({ examples: [[{ complete: false, environment: 'production', id: 'key_1a2b3c4d5e6f7g8h9j0k1m2n', orgId: 'org_1a2b3c4d5e6f7g8h9j0k1m2n', revoked: [], scopes: ['data:read', 'zone:421700001:read', 'zone:read'], undelegated: [], zoneTags: [421700001] }]] })), // prettier-ignore
164
+ expiring: z
165
+ .array(RewriteKey)
166
+ .check(z.describe('Keys expiring within a minute; they lapse on their own and are left unchanged.'), z.meta({ examples: [[]] })), // prettier-ignore
167
+ invalid: z
168
+ .array(RewriteKey)
169
+ .check(z.describe('Keys whose rewritten record the schema refuses; left unchanged for a manual fix.'), z.meta({ examples: [[]] })), // prettier-ignore
170
+ keys: z
171
+ .number()
172
+ .check(z.describe('Live, unfenced key records read.'), z.meta({ examples: [338] })),
173
+ mixed: z
174
+ .array(RewriteKey)
175
+ .check(z.describe('Keys whose per-Zone write Zones differ from their read Zones; one tag list cannot express both, so re-mint them by hand.'), z.meta({ examples: [[]] })), // prettier-ignore
176
+ narrow: z
177
+ .array(Delegation)
178
+ .check(z.describe('Active delegations for a planned Zone that list members; apply refuses until they cover the whole Zone.'), z.meta({ examples: [[]] })), // prettier-ignore
179
+ orgless: z
180
+ .array(RewriteKey)
181
+ .check(z.describe('Self-owned keys left unchanged; assign them an organization with `PUT /api-keys/{id}/organization` first.'), z.meta({ examples: [[]] })), // prettier-ignore
182
+ revoked: z
183
+ .array(Delegation)
184
+ .check(z.describe('Zone slots an admin revoked that a planned key still reads through its scope; those keys stay unwritten until an admin delegates the Zone again.'), z.meta({ examples: [[]] })), // prettier-ignore
185
+ tagless: z
186
+ .array(RewriteKey)
187
+ .check(z.describe('Keys holding `zone:read` without tags; they read no Zone and are listed, not changed.'), z.meta({ examples: [[]] })), // prettier-ignore
188
+ unconfigured: z
189
+ .array(Schema.ChainId)
190
+ .check(z.describe('Zone chain ids named by per-Zone scopes that this deployment does not serve; no tag, delegations revoked on apply.'), z.meta({ examples: [[421700005]] })), // prettier-ignore
191
+ unreadableRecords: z
192
+ .number()
193
+ .check(z.describe('Key records the store could not read; left unchanged.'), z.meta({ examples: [0] })), // prettier-ignore
194
+ wildcard: z
195
+ .array(RewriteKey)
196
+ .check(
197
+ z.describe('Wildcard keys, listed for an explicit decision and left unchanged.'),
198
+ z.meta({ examples: [[]] }),
199
+ ),
200
+ })
201
+ export const RewriteApplied = z.extend(RewritePlan, {
202
+ createdDelegations: z
203
+ .number()
204
+ .check(z.describe('Whole-Zone delegations this run created.'), z.meta({ examples: [3] })),
205
+ revokedDelegations: z
206
+ .number()
207
+ .check(z.describe('Active delegations for unconfigured Zones this run revoked.'), z.meta({ examples: [0] })), // prettier-ignore
208
+ rewritten: z
209
+ .number()
210
+ .check(z.describe('Records this run rewrote.'), z.meta({ examples: [12] })),
211
+ })
148
212
  export const ListResponse = z.object({
149
213
  data: z.array(Delegation).check(z.describe('Delegations, newest first.')),
150
214
  })
@@ -174,7 +238,7 @@ export namespace schema {
174
238
  })
175
239
  }
176
240
 
177
- /** Admin CRUD for organization-level Zone read delegations and their members; the gate only logs their decisions. */
241
+ /** Admin CRUD for organization-level Zone read delegations and their members, which decide Zone read admission. */
178
242
  export function zoneDelegations() {
179
243
  return new Hono<App.Environment>()
180
244
  .get(
@@ -208,31 +272,18 @@ export function zoneDelegations() {
208
272
  operationId: 'createZoneDelegation',
209
273
  responses: OpenApi.responses({
210
274
  errors: {
211
- 404: 'Organization or project not found.',
212
- 409: 'An active delegation already covers this Zone.',
275
+ 403: 'Delegations are created through the two-approver request workflow.',
276
+ 404: 'Organization not found.',
213
277
  },
214
- success: { description: 'The created delegation.', schema: schema.Response },
278
+ success: { description: 'Never returned; kept for the typed client.', schema: schema.Response }, // prettier-ignore
215
279
  }),
216
280
  summary: 'Create Zone delegation',
217
281
  tags: ['Zone Delegations'],
218
282
  }),
219
283
  async (c) => {
220
- const input = c.req.valid('json')
221
- const db = Db.get(c.get('db'))
222
- if (!(await validOwner(db, input))) return notFound(c)
223
- try {
224
- const data = await ZoneDelegations.create(db, input)
225
- return c.json(Response.validated(schema.Response, { data }), 200)
226
- } catch (cause) {
227
- if (cause instanceof ZoneDelegations.ConflictError)
228
- return Response.error(c, {
229
- code: 'zone_delegation_exists',
230
- message:
231
- 'An active delegation already covers this organization, environment, and Zone; update or revoke it instead.',
232
- status: 409,
233
- })
234
- throw cause
235
- }
284
+ if (!(await Organizations.get(Db.get(c.get('db')), c.req.valid('json').orgId))) return notFound(c) // prettier-ignore
285
+ // Granting an organization a Zone widens access, so it only lands through an approved request.
286
+ return approvalRequired(c)
236
287
  },
237
288
  )
238
289
  .get(
@@ -271,6 +322,54 @@ export function zoneDelegations() {
271
322
  return c.json(Response.validated(schema.BackfillApplied, applied), 200)
272
323
  },
273
324
  )
325
+ .get(
326
+ '/rewrite-keys',
327
+ OpenApi.describeRoute({
328
+ operationId: 'planZoneKeyRewrite',
329
+ responses: OpenApi.responses({
330
+ success: {
331
+ description:
332
+ 'Keys whose per-Zone read scopes would gain `zone:read` plus tags beside them.',
333
+ schema: schema.RewritePlan,
334
+ },
335
+ }),
336
+ summary: 'Plan Zone key rewrite',
337
+ tags: ['Zone Delegations'],
338
+ }),
339
+ async (c) => {
340
+ const plan = await ZoneKeyRewrite.plan({ db: Db.get(c.get('db')), store: c.get('kv').store, zones: hostedZones(c) }) // prettier-ignore
341
+ return c.json(Response.validated(schema.RewritePlan, plan), 200)
342
+ },
343
+ )
344
+ .post(
345
+ '/rewrite-keys',
346
+ OpenApi.describeRoute({
347
+ operationId: 'applyZoneKeyRewrite',
348
+ responses: OpenApi.responses({
349
+ errors: { 400: 'An active delegation for a planned Zone lists members; nothing was written.' }, // prettier-ignore
350
+ success: {
351
+ description:
352
+ 'The plan after ensuring delegations and writing its keys; reruns change nothing.',
353
+ schema: schema.RewriteApplied,
354
+ },
355
+ }),
356
+ summary: 'Apply Zone key rewrite',
357
+ tags: ['Zone Delegations'],
358
+ }),
359
+ async (c) => {
360
+ const options = { db: Db.get(c.get('db')), store: c.get('kv').store, zones: hostedZones(c) }
361
+ try {
362
+ return c.json(Response.validated(schema.RewriteApplied, await ZoneKeyRewrite.apply(options)), 200) // prettier-ignore
363
+ } catch (error) {
364
+ if (!(error instanceof ZoneKeyRewrite.NarrowDelegationsError)) throw error
365
+ return Response.error(c, {
366
+ code: 'zone_delegations_narrow',
367
+ message: `${error.message} Delegations: ${error.rows.map(({ id }) => id).join(', ')}.`,
368
+ status: 400,
369
+ })
370
+ }
371
+ },
372
+ )
274
373
  .get(
275
374
  '/:id',
276
375
  OpenApi.validate('param', schema.Params, { code: 'param_invalid', message: 'Invalid id' }),
@@ -308,13 +407,8 @@ export function zoneDelegations() {
308
407
  const existing = await ZoneDelegations.get(db, c.req.valid('param').id)
309
408
  if (!existing) return notFound(c)
310
409
  if (existing.revokedAt !== undefined) return revoked(c)
311
- // Only new projects are checked, so a deleted project never blocks unrelated changes.
312
- if (
313
- patch.projects &&
314
- !(await validOwner(db, { orgId: existing.orgId, projects: patch.projects }))
315
- )
316
- // prettier-ignore
317
- return notFound(c)
410
+ // Narrowing is a single-admin edit; widening is revoke plus a new delegation through the request workflow.
411
+ if (widens(patch)) return approvalRequired(c)
318
412
  const data = await ZoneDelegations.update(db, existing.id, patch)
319
413
  if (!data) return notFound(c)
320
414
  return c.json(Response.validated(schema.Response, { data }), 200)
@@ -388,7 +482,9 @@ function memberRoutes(kind: ZoneDelegations.Kind) {
388
482
  tags: ['Zone Delegations'],
389
483
  }),
390
484
  async (c) => {
391
- const result = await ZoneDelegations.Members.add(Db.get(c.get('db')), { ...c.req.valid('json'), id: c.req.valid('param').id, kind }) // prettier-ignore
485
+ // A member added under a listed selection widens coverage; under `all` it stays inert.
486
+ const result = await ZoneDelegations.Members.addInert(Db.get(c.get('db')), { ...c.req.valid('json'), id: c.req.valid('param').id, kind }) // prettier-ignore
487
+ if (result.status === 'widens') return approvalRequired(c)
392
488
  if (result.status !== 'ok') return refused(c, result.status)
393
489
  return c.json(Response.validated(schema.MembersResponse, { all: result.all, data: result.data, nextCursor: null }), 200) // prettier-ignore
394
490
  },
@@ -414,19 +510,23 @@ function memberRoutes(kind: ZoneDelegations.Kind) {
414
510
  )
415
511
  }
416
512
 
417
- /** Whether the organization exists and every listed project belongs to it, in two concurrent statements. */
418
- async function validOwner(
419
- db: Db.Db,
420
- input: Pick<ZoneDelegations.Record, 'orgId' | 'projects'>,
421
- ): Promise<boolean> {
422
- const [organization, projects] = await Promise.all([
423
- Organizations.get(db, input.orgId),
424
- input.projects === 'all' ? [] : Projects.listByIds(db, input.projects),
425
- ])
426
- if (!organization) return false
427
- if (input.projects === 'all') return true
428
- const owned = new Set(projects.flatMap((project) => (project.orgId === input.orgId ? [project.id] : []))) // prettier-ignore
429
- return input.projects.every((id) => owned.has(id))
513
+ /** Chain ids of the Zones this admin deployment serves. */
514
+ function hostedZones(c: Context<App.Environment>): ReadonlySet<number> {
515
+ return new Set(c.get('zones').map((zone) => zone.id))
516
+ }
517
+
518
+ /** Whether a patch could grant more than the delegation covers: a member flag set on. Decided without reading the row, so a concurrent narrowing cannot be undone. */
519
+ function widens(patch: ZoneDelegations.update.Patch): boolean {
520
+ return patch.accountsAll === true || patch.tokensAll === true
521
+ }
522
+
523
+ /** The 403 every direct write that widens Zone access reports. */
524
+ function approvalRequired(c: Context<App.Environment>) {
525
+ return Response.error(c, {
526
+ code: 'zone_delegation_approval_required',
527
+ message: new ZoneDelegationApproval.RequiredError().message,
528
+ status: 403,
529
+ })
430
530
  }
431
531
 
432
532
  /** The 404 or 409 a member write reports for a missing or revoked delegation. */
@@ -1,3 +1,3 @@
1
1
  export * as App from './App.js'
2
2
  export * as Mcp from './Mcp.js'
3
- export * as ZoneKeyApproval from '../internal/ZoneKeyApproval.js'
3
+ export * as ZoneDelegationApproval from '../internal/ZoneDelegationApproval.js'
@@ -186,7 +186,7 @@ export function readScopes(form: FormData, options: readScopes.Options = {}) {
186
186
  const value = form.get(key)
187
187
  return typeof value === 'string' ? value.trim() : ''
188
188
  }
189
- const pendingZoneScopes = (['read', 'write'] as const).map((access) => {
189
+ const pendingZoneScopes = (['write'] as const).map((access) => {
190
190
  const chainId = field(`zoneChainId_${access}`)
191
191
  return {
192
192
  chainId,
@@ -242,8 +242,9 @@ export function ScopeFields(options: ScopeFields.Props) {
242
242
  return zoneAccess ? (
243
243
  <ZoneScopeRow
244
244
  access={zoneAccess}
245
- defaultScopes={options.defaultScopes.filter(
246
- (scope) => scope.startsWith('zone:') && scope.endsWith(`:${zoneAccess}`),
245
+ // Only concrete per-Zone scopes belong to the template row; the generic `zone:write` is a plain checkbox.
246
+ defaultScopes={options.defaultScopes.filter((scope) =>
247
+ new RegExp(`^zone:\\d+:${zoneAccess}$`).test(scope),
247
248
  )}
248
249
  description={entry.description}
249
250
  key={entry.scope}
@@ -6,14 +6,14 @@ import { client } from './client.js'
6
6
  /** The bootstrap contract the SPA reads from `GET config.json` once loaded. */
7
7
  export type Config = {
8
8
  auth: {
9
+ /** Whether the signed-in identity belongs to the delegation approver group; `null` when unknown. */
10
+ delegationApprover: boolean | null
9
11
  /** The signed-in admin identity, or `null` when logged out (shell is public). */
10
12
  identity: { email: string } | null
11
13
  /** Where the deployer's sign-in page lives; shown when logged out. */
12
14
  loginUrl?: string
13
15
  /** Where to send the user to sign out (e.g. Cloudflare Access logout). */
14
16
  logoutUrl?: string
15
- /** Whether the signed-in identity belongs to the Zone key approver group; `null` when unknown. */
16
- zoneKeyApprover: boolean | null
17
17
  }
18
18
  rewards: {
19
19
  /** Tempo chain served by the reward runner, or `null` when unavailable. */
@@ -45,7 +45,7 @@ export async function getConfig(): Promise<Config> {
45
45
  const response = await client['config.json'].$get()
46
46
  if (!response.ok)
47
47
  return {
48
- auth: { identity: null, zoneKeyApprover: false },
48
+ auth: { delegationApprover: false, identity: null },
49
49
  rewards: { chainId: null, operatorAddress: null },
50
50
  }
51
51
  return response.json() as Promise<Config>
@@ -24,7 +24,7 @@ export const persistOptions: Omit<PersistQueryClientOptions, 'queryClient'> = {
24
24
  query.queryKey[0] !== 'organizations' &&
25
25
  query.queryKey[0] !== 'audit-logs' &&
26
26
  query.queryKey[0] !== 'sentinel' &&
27
- query.queryKey[0] !== 'zone-key-requests' &&
27
+ query.queryKey[0] !== 'zone-delegation-requests' &&
28
28
  query.queryKey[0] !== 'routes-access-requests' &&
29
29
  defaultShouldDehydrateQuery(query),
30
30
  },
@@ -2,10 +2,10 @@ import * as ReactQuery from '@tanstack/react-query'
2
2
 
3
3
  import * as AccessRequests from './routes-access-requests.js'
4
4
  import * as Sentinel from './sentinel.js'
5
- import * as ZoneKeyRequests from './zone-key-requests.js'
5
+ import * as DelegationRequests from './zone-delegation-requests.js'
6
6
 
7
7
  /** Path of a page that holds a review queue. */
8
- export type Queue = '/routes/access-requests' | '/sentinel' | '/zone-key-requests'
8
+ export type Queue = '/routes/access-requests' | '/sentinel' | '/zone-delegation-requests'
9
9
 
10
10
  /** Items waiting in one review queue; `more` marks a full first page with further pages. */
11
11
  export type Waiting =
@@ -15,12 +15,12 @@ export type Waiting =
15
15
 
16
16
  /** Waiting items in each review queue, keyed by queue path. */
17
17
  export function useWaiting(): Record<Queue, Waiting> {
18
- const zone = ReactQuery.useQuery(ZoneKeyRequests.list.options())
19
18
  const sentinel = Sentinel.list.useQuery()
19
+ const delegations = ReactQuery.useQuery(DelegationRequests.list.options())
20
20
  const access = ReactQuery.useInfiniteQuery(AccessRequests.list.options('pending'))
21
21
  const accessPage = access.data?.pages[0]
22
- const zonePending = zone.data?.data.filter(
23
- (request) => ZoneKeyRequests.status(request) === 'pending',
22
+ const delegationsPending = delegations.data?.data.filter(
23
+ (request) => DelegationRequests.status(request) === 'pending',
24
24
  )
25
25
  return {
26
26
  '/routes/access-requests': accessPage
@@ -30,14 +30,14 @@ export function useWaiting(): Record<Queue, Waiting> {
30
30
  ? { count: sentinel.data.data.length, more: false, status: 'success' }
31
31
  : { status: sentinel.isError ? 'error' : 'pending' },
32
32
  // Newest-first pages mix statuses, so only an all-pending full page implies more waiting.
33
- '/zone-key-requests':
34
- zone.data && zonePending
33
+ '/zone-delegation-requests':
34
+ delegations.data && delegationsPending
35
35
  ? {
36
- count: zonePending.length,
37
- more: Boolean(zone.data.nextCursor) && zonePending.length === zone.data.data.length,
36
+ count: delegationsPending.length,
37
+ more: Boolean(delegations.data.nextCursor) && delegationsPending.length === delegations.data.data.length, // prettier-ignore
38
38
  status: 'success',
39
39
  }
40
- : { status: zone.isError ? 'error' : 'pending' },
40
+ : { status: delegations.isError ? 'error' : 'pending' },
41
41
  }
42
42
  }
43
43
 
@@ -69,11 +69,10 @@ const subsidy = {
69
69
  } as const
70
70
 
71
71
  describe('keyAccess', () => {
72
- it('separates keys that can be granted from ones that cannot or need nothing', () => {
72
+ it('separates keys that can be granted from ones that need nothing', () => {
73
73
  expect(Setup.keyAccess({ scopes: ['data:read'] })).toBe('grantable')
74
74
  expect(Setup.keyAccess({ scopes: ['data:read', 'routes:write'] })).toBe('granted')
75
75
  expect(Setup.keyAccess({ scopes: ['*'] })).toBe('granted')
76
- expect(Setup.keyAccess({ scopes: ['zone:7:read'] })).toBe('locked')
77
76
  })
78
77
  })
79
78
 
@@ -2,7 +2,6 @@ import type * as Organizations from './organizations.js'
2
2
  import * as ApiKeys from './api-keys.js'
3
3
  import * as Policy from '../../../../internal/routes/Policy.js'
4
4
  import * as Policies from './route-policies.js'
5
- import * as ZoneKeyRequests from './zone-key-requests.js'
6
5
 
7
6
  /** Scope that lets an API key create route transfers and deposit addresses. */
8
7
  export const writeScope = 'routes:write'
@@ -47,11 +46,10 @@ export type Input = {
47
46
  }
48
47
  }
49
48
 
50
- /** Whether a key can receive the write scope here. */
51
- export function keyAccess(key: Pick<Key, 'scopes'>): 'granted' | 'grantable' | 'locked' {
49
+ /** Whether a key already holds the write scope or can receive it here. */
50
+ export function keyAccess(key: Pick<Key, 'scopes'>): 'granted' | 'grantable' {
52
51
  if (key.scopes.includes(writeScope) || key.scopes.includes('*')) return 'granted'
53
- // Zone read keys change only through a reviewed reissue.
54
- return ZoneKeyRequests.required(key.scopes) ? 'locked' : 'grantable'
52
+ return 'grantable'
55
53
  }
56
54
 
57
55
  /** Active keys of one environment. */
@@ -4,19 +4,16 @@ import * as Scopes from './scopes.js'
4
4
 
5
5
  describe('fromZoneChainId', () => {
6
6
  it('builds canonical Zone scopes', () => {
7
- const read = Scopes.fromZoneChainId(' 000421700001 ')
8
7
  const write = Scopes.fromZoneChainId(' 000421700001 ', 'write')
9
8
 
10
- expect(read).toBe('zone:421700001:read')
11
9
  expect(write).toBe('zone:421700001:write')
12
- expectTypeOf(read).toEqualTypeOf<`zone:${string}:read` | undefined>()
13
10
  expectTypeOf(write).toEqualTypeOf<`zone:${string}:write` | undefined>()
14
11
  })
15
12
 
16
13
  it('rejects non-positive and malformed chain ids', () => {
17
- expect(['', '0', '-1', '1.5', 'mainnet'].map((value) => Scopes.fromZoneChainId(value))).toEqual(
18
- [undefined, undefined, undefined, undefined, undefined],
19
- )
14
+ expect(
15
+ ['', '0', '-1', '1.5', 'mainnet'].map((value) => Scopes.fromZoneChainId(value, 'write')),
16
+ ).toEqual([undefined, undefined, undefined, undefined, undefined])
20
17
  })
21
18
  })
22
19
 
@@ -6,9 +6,8 @@ import { client } from './client.js'
6
6
  /** A single issuable API-key scope from the catalog endpoint. */
7
7
  export type Scope = InferResponseType<(typeof client)['scopes']['$get'], 200>['data'][number]
8
8
 
9
- /** Dynamic Zone scope templates returned by the scope catalog. */
9
+ /** Dynamic Zone scope templates returned by the scope catalog; reads use `zone:read` plus tags instead. */
10
10
  export const zoneTemplates = {
11
- read: 'zone:<chainId>:read',
12
11
  write: 'zone:<chainId>:write',
13
12
  } as const
14
13
 
@@ -17,21 +16,15 @@ export type ZoneAccess = keyof typeof zoneTemplates
17
16
 
18
17
  /** Returns the access level represented by a dynamic Zone scope template. */
19
18
  export function accessFromTemplate(value: string): ZoneAccess | undefined {
20
- if (value === zoneTemplates.read) return 'read'
21
19
  if (value === zoneTemplates.write) return 'write'
22
20
  return undefined
23
21
  }
24
22
 
25
23
  /** Builds a canonical Zone scope from a positive integer chain id. */
26
- export function fromZoneChainId(value: string): `zone:${string}:read` | undefined
27
24
  export function fromZoneChainId<const access extends ZoneAccess>(
28
25
  value: string,
29
26
  access: access,
30
- ): `zone:${string}:${access}` | undefined
31
- export function fromZoneChainId(
32
- value: string,
33
- access: ZoneAccess = 'read',
34
- ): `zone:${string}:${ZoneAccess}` | undefined {
27
+ ): `zone:${string}:${access}` | undefined {
35
28
  const chainId = value.trim()
36
29
  if (!/^\d+$/.test(chainId)) return undefined
37
30
  const normalized = BigInt(chainId)
@@ -1,24 +1,24 @@
1
1
  import * as ReactQuery from '@tanstack/react-query'
2
2
  import type { InferRequestType, InferResponseType } from 'hono/client'
3
3
 
4
- import * as ZoneKeyApproval from '../../../../internal/ZoneKeyApproval.js'
4
+ import * as ZoneDelegationApproval from '../../../../internal/ZoneDelegationApproval.js'
5
5
  import { client } from './client.js'
6
6
  import * as Response from './response.js'
7
7
 
8
- /** A Zone key request row from the list endpoint. */
8
+ /** A Zone delegation request row from the list endpoint. */
9
9
  export type Request = InferResponseType<
10
- (typeof client)['zone-key-requests']['$get'],
10
+ (typeof client)['zone-delegation-requests']['$get'],
11
11
  200
12
12
  >['data'][number]
13
13
 
14
- /** A Zone key request with its recorded approvals. */
15
- export type Detail = InferResponseType<(typeof client)['zone-key-requests'][':id']['$get'], 200>
16
-
17
- /** Approvals required before the requester can issue the key. */
18
- export const quorum = ZoneKeyApproval.quorum
14
+ /** A Zone delegation request with its recorded approvals. */
15
+ export type Detail = InferResponseType<
16
+ (typeof client)['zone-delegation-requests'][':id']['$get'],
17
+ 200
18
+ >
19
19
 
20
- /** Returns whether scopes need the approval workflow (Zone read or wildcard). */
21
- export const required = ZoneKeyApproval.required
20
+ /** Approvals required before the requester can apply the delegation. */
21
+ export const quorum = ZoneDelegationApproval.quorum
22
22
 
23
23
  /** Returns the request status, reporting lapsed pending requests as `expired`. */
24
24
  export function status(request: Request) {
@@ -34,16 +34,16 @@ export function validApprovals(detail: Detail) {
34
34
  )
35
35
  }
36
36
 
37
- const baseKey = ['zone-key-requests'] as const
37
+ const baseKey = ['zone-delegation-requests'] as const
38
38
 
39
- /** Lists one page of Zone key requests, newest first. */
39
+ /** Lists one page of delegation requests, newest first. */
40
40
  export namespace list {
41
41
  export const key = [...baseKey, 'list'] as const
42
42
  export async function fn(cursor?: string) {
43
- const response = await client['zone-key-requests'].$get({ query: cursor ? { cursor } : {} })
43
+ const response = await client['zone-delegation-requests'].$get({ query: cursor ? { cursor } : {} }) // prettier-ignore
44
44
  if (!response.ok)
45
45
  throw new Error(
46
- await Response.errorMessage(response, { fallback: 'Failed to load Zone key requests.' }),
46
+ await Response.errorMessage(response, { fallback: 'Failed to load delegation requests.' }),
47
47
  )
48
48
  return response.json()
49
49
  }
@@ -56,10 +56,10 @@ export namespace list {
56
56
  }
57
57
  }
58
58
 
59
- /** Reads one Zone key request with its approvals. */
59
+ /** Reads one delegation request with its approvals. */
60
60
  export namespace get {
61
61
  export async function fn(id: string) {
62
- const response = await client['zone-key-requests'][':id'].$get({ param: { id } })
62
+ const response = await client['zone-delegation-requests'][':id'].$get({ param: { id } })
63
63
  if (!response.ok)
64
64
  throw new Error(
65
65
  await Response.errorMessage(response, { fallback: 'Failed to load the request.' }),
@@ -76,11 +76,11 @@ export namespace get {
76
76
  }
77
77
  }
78
78
 
79
- /** Submits immutable key settings for review. */
79
+ /** Submits immutable delegation settings for review. */
80
80
  export namespace create {
81
- export type Input = InferRequestType<(typeof client)['zone-key-requests']['$post']>['json']
81
+ export type Input = InferRequestType<(typeof client)['zone-delegation-requests']['$post']>['json'] // prettier-ignore
82
82
  export async function fn(json: Input) {
83
- const response = await client['zone-key-requests'].$post({ json })
83
+ const response = await client['zone-delegation-requests'].$post({ json })
84
84
  if (!response.ok)
85
85
  throw new Error(
86
86
  await Response.errorMessage(response, { fallback: 'Failed to submit the request.' }),
@@ -99,7 +99,7 @@ export namespace create {
99
99
  /** Records the current member's approval. */
100
100
  export namespace approve {
101
101
  export async function fn(id: string) {
102
- const response = await client['zone-key-requests'][':id'].approve.$post({ param: { id } })
102
+ const response = await client['zone-delegation-requests'][':id'].approve.$post({ param: { id } }) // prettier-ignore
103
103
  if (!response.ok)
104
104
  throw new Error(
105
105
  await Response.errorMessage(response, { fallback: 'Failed to approve the request.' }),
@@ -115,13 +115,13 @@ export namespace approve {
115
115
  }
116
116
  }
117
117
 
118
- /** Issues the approved key once, returning its plaintext token. */
119
- export namespace issue {
118
+ /** Applies the approved request once, creating the delegation. */
119
+ export namespace apply {
120
120
  export async function fn(id: string) {
121
- const response = await client['zone-key-requests'][':id'].issue.$post({ param: { id } })
121
+ const response = await client['zone-delegation-requests'][':id'].apply.$post({ param: { id } }) // prettier-ignore
122
122
  if (!response.ok)
123
123
  throw new Error(
124
- await Response.errorMessage(response, { fallback: 'Failed to issue the key.' }),
124
+ await Response.errorMessage(response, { fallback: 'Failed to apply the delegation.' }),
125
125
  )
126
126
  return response.json()
127
127
  }
@@ -129,12 +129,8 @@ export namespace issue {
129
129
  const queryClient = ReactQuery.useQueryClient()
130
130
  return ReactQuery.useMutation({
131
131
  mutationFn: fn,
132
- // Issuance may consume the request even when the response fails.
133
- onSettled: () =>
134
- Promise.all([
135
- queryClient.invalidateQueries({ queryKey: baseKey }),
136
- queryClient.invalidateQueries({ queryKey: ['api-keys'] }),
137
- ]),
132
+ // Applying consumes the request even when the response fails.
133
+ onSettled: () => queryClient.invalidateQueries({ queryKey: baseKey }),
138
134
  })
139
135
  }
140
136
  }
@@ -142,7 +138,7 @@ export namespace issue {
142
138
  /** Cancels a pending request. */
143
139
  export namespace cancel {
144
140
  export async function fn(id: string) {
145
- const response = await client['zone-key-requests'][':id'].$delete({ param: { id } })
141
+ const response = await client['zone-delegation-requests'][':id'].$delete({ param: { id } })
146
142
  if (!response.ok)
147
143
  throw new Error(
148
144
  await Response.errorMessage(response, { fallback: 'Failed to cancel the request.' }),