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
@@ -6,7 +6,6 @@ const token = `0x${'cd'.repeat(20)}`
6
6
  const delegation = {
7
7
  accounts: 'all',
8
8
  id: 'zd_read',
9
- projects: 'all',
10
9
  tokens: 'all',
11
10
  } satisfies ZoneDelegation.Delegation
12
11
 
@@ -16,7 +15,6 @@ describe('decide', () => {
16
15
  ZoneDelegation.decide({
17
16
  accounts: [],
18
17
  delegation: undefined,
19
- grant: 'scope',
20
18
  tokens: [],
21
19
  }),
22
20
  ).toMatchInlineSnapshot(`
@@ -28,7 +26,6 @@ describe('decide', () => {
28
26
  ZoneDelegation.decide({
29
27
  accounts: [],
30
28
  delegation: undefined,
31
- grant: 'scope',
32
29
  tokens: [],
33
30
  }),
34
31
  ).toMatchInlineSnapshot(`
@@ -43,7 +40,6 @@ describe('decide', () => {
43
40
  ZoneDelegation.decide({
44
41
  accounts: [],
45
42
  delegation,
46
- grant: 'scope',
47
43
  tokens: [],
48
44
  }),
49
45
  ).toMatchInlineSnapshot(`
@@ -56,33 +52,17 @@ describe('decide', () => {
56
52
  ZoneDelegation.decide({
57
53
  accounts: [account],
58
54
  delegation,
59
- grant: 'wildcard',
60
55
  tokens: [token],
61
56
  }).decision,
62
57
  ).toBe('allow')
63
58
  })
64
59
 
65
- test('narrows by project, with organization-wide keys needing all projects', () => {
66
- const narrowed = { ...delegation, projects: ['prj_a'] }
67
- const decide = (projectId: string | undefined) =>
68
- ZoneDelegation.decide({ accounts: [], delegation: narrowed, grant: 'scope', projectId, tokens: [] }) // prettier-ignore
69
- .decision
70
- expect([decide('prj_a'), decide('prj_b'), decide(undefined)]).toMatchInlineSnapshot(`
71
- [
72
- "allow",
73
- "deny",
74
- "deny",
75
- ]
76
- `)
77
- })
78
-
79
60
  test('narrows by account, with zone-wide requests needing all accounts', () => {
80
61
  const narrowed = { ...delegation, accounts: [account] }
81
62
  const decide = (accounts: readonly string[]) =>
82
63
  ZoneDelegation.decide({
83
64
  accounts,
84
65
  delegation: narrowed,
85
- grant: 'scope',
86
66
  tokens: [],
87
67
  }).decision
88
68
  expect([decide([account]), decide([account, `0x${'ef'.repeat(20)}`]), decide([])])
@@ -101,7 +81,6 @@ describe('decide', () => {
101
81
  ZoneDelegation.decide({
102
82
  accounts: [],
103
83
  delegation: narrowed,
104
- grant: 'scope',
105
84
  tokens,
106
85
  }).decision
107
86
  expect([decide([token]), decide([`0x${'ef'.repeat(20)}`]), decide([])]).toMatchInlineSnapshot(`
@@ -113,21 +92,11 @@ describe('decide', () => {
113
92
  `)
114
93
  })
115
94
 
116
- test('denies a key whose own scopes refuse, naming the delegation it would have used', () => {
117
- expect(ZoneDelegation.decide({ accounts: [], delegation, tokens: [] })).toMatchInlineSnapshot(`
118
- {
119
- "decision": "deny",
120
- "id": "zd_read",
121
- }
122
- `)
123
- })
124
-
125
95
  test('reports the delegation id even when its narrowing denies', () => {
126
96
  expect(
127
97
  ZoneDelegation.decide({
128
98
  accounts: [],
129
99
  delegation: { ...delegation, accounts: [account] },
130
- grant: 'scope',
131
100
  tokens: [],
132
101
  }),
133
102
  ).toMatchInlineSnapshot(`
@@ -144,8 +113,6 @@ describe('schema', () => {
144
113
  expect(ZoneDelegation.schema.AddressList.parse([`0x${'AB'.repeat(20)}`])).toEqual([account])
145
114
  expect(ZoneDelegation.schema.AddressList.safeParse([]).success).toBe(false)
146
115
  expect(ZoneDelegation.schema.AddressList.safeParse(['0xnope']).success).toBe(false)
147
- expect(ZoneDelegation.schema.Projects.parse('all')).toBe('all')
148
- expect(ZoneDelegation.schema.Projects.safeParse(['key_1']).success).toBe(false)
149
116
  })
150
117
  })
151
118
 
@@ -159,8 +126,7 @@ describe('fromKeys', () => {
159
126
  { ...base, environment: 'sandbox', id: 'key_3', scopes: ['zone:421700002:read'] },
160
127
  { ...base, id: 'key_4', name: 'Integration', orgId: 'org_b', scopes: ['*', 'zone:421700003:read'] }, // prettier-ignore
161
128
  { ...base, id: 'key_5', scopes: ['data:read'] },
162
- { ...base, id: 'key_6', orgId: 'org_c', projectId: 'prj_a', scopes: ['zone:421700002:read'] }, // prettier-ignore
163
- { ...base, id: 'key_7', orgId: 'org_c', projectId: 'prj_b', scopes: ['zone:421700002:read'] }, // prettier-ignore
129
+ { ...base, id: 'key_6', orgId: 'org_c', scopes: ['zone:421700002:read'] },
164
130
  ]),
165
131
  ).toMatchInlineSnapshot(`
166
132
  {
@@ -170,7 +136,6 @@ describe('fromKeys', () => {
170
136
  "chainId": 421700002,
171
137
  "environment": "production",
172
138
  "orgId": "org_a",
173
- "projects": "all",
174
139
  "tokensAll": true,
175
140
  },
176
141
  {
@@ -178,7 +143,6 @@ describe('fromKeys', () => {
178
143
  "chainId": 421700002,
179
144
  "environment": "sandbox",
180
145
  "orgId": "org_a",
181
- "projects": "all",
182
146
  "tokensAll": true,
183
147
  },
184
148
  {
@@ -186,10 +150,6 @@ describe('fromKeys', () => {
186
150
  "chainId": 421700002,
187
151
  "environment": "production",
188
152
  "orgId": "org_c",
189
- "projects": [
190
- "prj_a",
191
- "prj_b",
192
- ],
193
153
  "tokensAll": true,
194
154
  },
195
155
  ],
@@ -3,7 +3,6 @@ import * as z from 'zod/mini'
3
3
  import type * as ApiKey from '../ApiKey.js'
4
4
  import * as Scope from '../Scope.js'
5
5
  import * as Schema from './Schema.js'
6
- import type * as ZoneAccess from './ZoneAccess.js'
7
6
 
8
7
  /** Resources a delegation covers: every resource, or an explicit lowercase list. */
9
8
  export type Selection = 'all' | readonly string[]
@@ -14,8 +13,6 @@ export type Delegation = {
14
13
  accounts: Selection
15
14
  /** Delegation id (`zd_…`). */
16
15
  id: string
17
- /** Project ids the delegation covers, or `all`. */
18
- projects: Selection
19
16
  /** Requested tokens the delegation lists, or `all`. */
20
17
  tokens: Selection
21
18
  }
@@ -25,7 +22,7 @@ export type Decision = 'allow' | 'deny'
25
22
 
26
23
  /** Delegation decision for one request. */
27
24
  export type Result = {
28
- /** Whether delegations alone would admit the request. */
25
+ /** Whether the organization's delegation covers the request. */
29
26
  decision: Decision
30
27
  /** Active delegation for the Zone, when one exists; absent when the organization holds none. */
31
28
  id?: string | undefined
@@ -39,18 +36,6 @@ export namespace schema {
39
36
  z.describe('API-key environment the delegation applies to.'),
40
37
  z.meta({ examples: ['production'] }),
41
38
  )
42
- export const Projects = z
43
- .union([
44
- z.literal('all'),
45
- z.pipe(
46
- z.array(z.string().check(z.regex(/^prj_[A-Za-z0-9_-]+$/))).check(z.maxLength(1_000)),
47
- z.transform((ids) => [...new Set(ids)]),
48
- ),
49
- ])
50
- .check(
51
- z.describe('Project ids the delegation covers, or `all`.'),
52
- z.meta({ examples: ['all'] }),
53
- )
54
39
  export const AddressList = z
55
40
  .pipe(
56
41
  z.array(Schema.Address).check(z.minLength(1), z.maxLength(1_000)),
@@ -63,16 +48,13 @@ export namespace schema {
63
48
  }
64
49
 
65
50
  /**
66
- * Decides whether an organization's delegation admits one Zone read from a key
67
- * whose own scopes allow it. The key's project must be covered, and every
51
+ * Decides whether an organization's delegation covers one Zone read: every
68
52
  * requested account and token must be covered (a request naming none needs
69
- * `all`).
53
+ * `all`). The key's own scope and tags are checked by the gate before this runs.
70
54
  */
71
55
  export function decide(options: decide.Options): Result {
72
- const { accounts, delegation, grant, projectId, tokens } = options
56
+ const { accounts, delegation, tokens } = options
73
57
  if (!delegation) return { decision: 'deny' }
74
- // The key's own Zone scope stays its allowlist: a delegation grants nothing to a key without one.
75
- if (grant === undefined) return { decision: 'deny', id: delegation.id }
76
58
  // A request naming nothing from a list sees everything (raw RPC, unfiltered lists,
77
59
  // balances across every token), so only an `all` selection covers it.
78
60
  const covers = (selection: Selection, values: readonly string[]) => {
@@ -80,12 +62,7 @@ export function decide(options: decide.Options): Result {
80
62
  const members = new Set(selection)
81
63
  return values.length > 0 && values.every((value) => members.has(value))
82
64
  }
83
- // A key without a project is organization-wide, so only an `all` delegation covers it.
84
- const projectCovered =
85
- delegation.projects === 'all' ||
86
- (projectId !== undefined && delegation.projects.includes(projectId))
87
- const allowed =
88
- projectCovered && covers(delegation.accounts, accounts) && covers(delegation.tokens, tokens)
65
+ const allowed = covers(delegation.accounts, accounts) && covers(delegation.tokens, tokens)
89
66
  return { decision: allowed ? 'allow' : 'deny', id: delegation.id }
90
67
  }
91
68
 
@@ -96,10 +73,6 @@ export declare namespace decide {
96
73
  accounts: readonly string[]
97
74
  /** The organization's active delegation for the Zone, when one exists. */
98
75
  delegation?: Delegation | undefined
99
- /** Grant the key's own scopes produced for this request; absent when they refuse it. */
100
- grant?: ZoneAccess.Grant | undefined
101
- /** Project attributed to the API key, when any. */
102
- projectId?: string | undefined
103
76
  /** Lowercase token contracts the request is about; empty when not token-scoped. */
104
77
  tokens: readonly string[]
105
78
  }
@@ -107,10 +80,9 @@ export declare namespace decide {
107
80
 
108
81
  /**
109
82
  * Derives the whole-zone delegations that preserve each key's current Zone
110
- * read scopes, one per organization, environment, and Zone, covering the
111
- * projects of the source keys. Write scopes need no delegation. Wildcard keys
112
- * are returned separately and derive nothing: a delegation for them is a
113
- * decision, not a backfill.
83
+ * read scopes, one per organization, environment, and Zone. Write scopes need
84
+ * no delegation. Wildcard keys are returned separately and derive nothing: a
85
+ * delegation for them is a decision, not a backfill.
114
86
  */
115
87
  export function fromKeys(keys: readonly fromKeys.Key[]): fromKeys.Result {
116
88
  const delegations = new Map<string, fromKeys.Input>()
@@ -124,19 +96,11 @@ export function fromKeys(keys: readonly fromKeys.Key[]): fromKeys.Result {
124
96
  for (const scope of key.scopes) {
125
97
  const chainId = Scope.zoneReadChainId(scope)
126
98
  if (chainId === undefined) continue
127
- const id = `${key.orgId}:${key.environment}:${chainId}`
128
- const existing = delegations.get(id)
129
- // Projects widen to the union of the source keys; an organization-wide key means every project.
130
- const projects: Selection =
131
- existing?.projects === 'all' || key.projectId === undefined
132
- ? 'all'
133
- : [...new Set([...(existing?.projects ?? []), key.projectId])]
134
- delegations.set(id, {
99
+ delegations.set(`${key.orgId}:${key.environment}:${chainId}`, {
135
100
  accountsAll: true,
136
101
  chainId,
137
102
  environment: key.environment,
138
103
  orgId: key.orgId,
139
- projects,
140
104
  tokensAll: true,
141
105
  })
142
106
  }
@@ -146,7 +110,7 @@ export function fromKeys(keys: readonly fromKeys.Key[]): fromKeys.Result {
146
110
 
147
111
  export declare namespace fromKeys {
148
112
  /** Key fields the derivation reads. */
149
- type Key = Pick<ApiKey.ApiKey, 'environment' | 'id' | 'orgId' | 'projectId' | 'scopes'> & {
113
+ type Key = Pick<ApiKey.ApiKey, 'environment' | 'id' | 'orgId' | 'scopes'> & {
150
114
  /** Human-readable key name, when set. */
151
115
  name?: string | undefined
152
116
  }
@@ -161,8 +125,6 @@ export declare namespace fromKeys {
161
125
  environment: ApiKey.ApiKey['environment']
162
126
  /** Receiving organization id. */
163
127
  orgId: string
164
- /** Projects of the source keys, or `all` when any key is organization-wide. */
165
- projects: Selection
166
128
  /** Every token is covered. */
167
129
  tokensAll: true
168
130
  }
@@ -0,0 +1,22 @@
1
+ import * as ZoneDelegationApproval from './ZoneDelegationApproval.js'
2
+
3
+ describe('active', () => {
4
+ test('rejects absent, expired, malformed, or incomplete session identities', () => {
5
+ const member = {
6
+ email: 'staff@tempo.xyz',
7
+ eligible: false,
8
+ expiresAt: new Date(Date.now() + 60_000).toISOString(),
9
+ id: 'employee_staff',
10
+ }
11
+ expect(ZoneDelegationApproval.active(member)).toBe(true)
12
+ for (const value of [
13
+ null,
14
+ undefined,
15
+ { ...member, expiresAt: new Date().toISOString() },
16
+ { ...member, expiresAt: 'invalid' },
17
+ { ...member, id: '' },
18
+ { ...member, email: '' },
19
+ ])
20
+ expect(ZoneDelegationApproval.active(value)).toBe(false)
21
+ })
22
+ })
@@ -1,16 +1,9 @@
1
- import * as Scope from '../Scope.js'
2
-
3
- /** Number of independent approvals required for Zone read credentials. */
1
+ /** Number of independent approvals required to create a Zone delegation. */
4
2
  export const quorum = 2
5
3
 
6
4
  /** Maximum lifetime of an approval, matching the request lifetime and bounded by its authenticated session. */
7
5
  export const approvalLifetime = 24 * 60 * 60 * 1_000
8
6
 
9
- /** Returns whether scopes grant access subject to Zone read approval. */
10
- export function required(scopes: readonly string[]): boolean {
11
- return scopes.some((scope) => scope === '*' || Scope.parseZone(scope)?.verb === 'read')
12
- }
13
-
14
7
  /** An authenticated identity supplied by the host's verified identity integration. */
15
8
  export type Member = {
16
9
  /** Verified employee email, used for attribution only. */
@@ -41,11 +34,11 @@ export type Status = {
41
34
  /** Looks up current account and group status, throwing when fresh results are unavailable. */
42
35
  export type Lookup = (ids: readonly string[]) => Promise<readonly Status[]>
43
36
 
44
- /** Expected rejection of a Zone key request or an unapproved issuance path. */
37
+ /** Expected rejection of a delegation request, or of a direct write that widens Zone access. */
45
38
  export class RequiredError extends Error {
46
- override name = 'ZoneKeyApproval.RequiredError'
39
+ override name = 'ZoneDelegationApproval.RequiredError'
47
40
  constructor(
48
- message = 'Zone read keys require two independent group approvals through the admin key-request workflow.',
41
+ message = 'Zone delegations require two independent group approvals through the admin delegation-request workflow.',
49
42
  ) {
50
43
  super(message)
51
44
  }
@@ -0,0 +1,231 @@
1
+ import type * as ApiKey from '../ApiKey.js'
2
+ import * as ApiKeys from '../ApiKeys.js'
3
+ import type * as Db from '../db/Db.js'
4
+ import * as ApiKeyAdmissions from '../db/tables/apiKeyAdmissions.js'
5
+ import * as Organizations from '../db/tables/organizations.js'
6
+ import * as ZoneDelegations from '../db/tables/zoneDelegations.js'
7
+ import type * as Store from './Store.js'
8
+
9
+ /** The additive rewrite adding `zone:read` plus tags beside stored per-Zone read scopes, and what it leaves out. */
10
+ export type Plan = {
11
+ /** Keys holding per-Zone read scopes, with the scopes and tags they end up holding; `complete` ones are only checked. */
12
+ changes: readonly Change[]
13
+ /** Keys expiring within a minute; KV refuses their TTL and they lapse on their own, so they are left unchanged. */
14
+ expiring: readonly Key[]
15
+ /** Keys whose rewritten record the schema refuses (say, past the tag limit); left unchanged for a manual fix. */
16
+ invalid: readonly Key[]
17
+ /** Live, unfenced key records read from the store. */
18
+ keys: number
19
+ /** Keys whose per-Zone write Zones differ from their read Zones; one tag list cannot express both, so they are re-minted by hand. */
20
+ mixed: readonly Key[]
21
+ /** Active delegations listing members for a planned Zone; apply refuses until they are whole-Zone. */
22
+ narrow: readonly ZoneDelegations.Record[]
23
+ /** Zone slots an admin revoked that a planned key still reads through its scope; the key stays unwritten until an admin delegates it again. */
24
+ revoked: readonly ZoneDelegations.Record[]
25
+ /** Keys owned by themselves (no organization row); left unchanged until `PUT /api-keys/{id}/organization` assigns one. */
26
+ orgless: readonly Key[]
27
+ /** Keys holding `zone:read` without tags or per-Zone scopes; they read no Zone and are listed, not changed. */
28
+ tagless: readonly Key[]
29
+ /** Zone chain ids named by per-Zone scopes that this deployment does not serve; no tag, delegations revoked. */
30
+ unconfigured: readonly number[]
31
+ /** Records the store could not read (expired, or scopes outside the catalog); left unchanged. */
32
+ unreadableRecords: number
33
+ /** Wildcard keys, listed for an explicit decision and left unchanged. */
34
+ wildcard: readonly Key[]
35
+ }
36
+
37
+ /** A key named in a plan. */
38
+ export type Key = {
39
+ /** Key environment. */
40
+ environment: ApiKey.ApiKey['environment']
41
+ /** Key id. */
42
+ id: string
43
+ /** Human-readable key name, when set. */
44
+ name?: string | undefined
45
+ /** Owning organization id, or the key id for legacy keys minted without one. */
46
+ orgId: string
47
+ /** Attributed project id, when any. */
48
+ projectId?: string | undefined
49
+ }
50
+
51
+ /** One key the rewrite changes or checks. */
52
+ export type Change = Key & {
53
+ /** Whether the record already holds `zone:read` and every tag; only its delegations are ensured, nothing is written. */
54
+ complete: boolean
55
+ /** Zones the per-Zone scopes grant whose delegation an admin revoked; the key is left unwritten while any remain. */
56
+ revoked: readonly number[]
57
+ /** Scopes the key holds after the rewrite. */
58
+ scopes: readonly string[]
59
+ /** Zones the per-Zone scopes grant that lack any delegation for the organization; applying ensures one for each. */
60
+ undelegated: readonly number[]
61
+ /** Zone chain ids the key reads after the rewrite. */
62
+ zoneTags: readonly number[]
63
+ }
64
+
65
+ /** A plan after its changes were written. */
66
+ export type Applied = Plan & {
67
+ /** Whole-Zone delegations this run created so rewritten keys keep their reads. */
68
+ createdDelegations: number
69
+ /** Active delegations for unconfigured Zones this run revoked. */
70
+ revokedDelegations: number
71
+ /** Records this run rewrote. */
72
+ rewritten: number
73
+ }
74
+
75
+ /**
76
+ * Derives the rewrite from the live key store without writing: every key
77
+ * holding a per-Zone read scope, the tags it would carry, and which of those
78
+ * Zones its organization is not yet delegated.
79
+ */
80
+ export async function plan(options: Options): Promise<Plan> {
81
+ const { db, store, zones } = options
82
+ return summarize(db, await ApiKeys.planZoneReadRewrite(store, { zones }))
83
+ }
84
+
85
+ /**
86
+ * Rewrites every planned key so it keeps the reads it has today: ensures a
87
+ * whole-Zone delegation for each tagged Zone without one, then writes each
88
+ * record under its admission lock. Self-owned keys, and keys reading a Zone
89
+ * whose delegation an admin revoked, are skipped and reported. Throws
90
+ * {@link NarrowDelegationsError} before writing anything when an active
91
+ * delegation for a planned Zone lists members.
92
+ */
93
+ export async function apply(options: Options): Promise<Applied> {
94
+ const { db, store, zones } = options
95
+ const planned = await ApiKeys.planZoneReadRewrite(store, { zones })
96
+ const summary = await summarize(db, planned)
97
+ if (summary.narrow.length) throw new NarrowDelegationsError(summary.narrow)
98
+ // A key reading a Zone an admin revoked keeps its scope untouched, so the gap stays in the plan.
99
+ const rewritable = summary.changes.filter(({ revoked }) => revoked.length === 0)
100
+ // Keys of one organization, environment, and Zone share a slot; one whole-Zone row covers them all.
101
+ const slots = new Map<string, ZoneDelegations.Scope>()
102
+ for (const change of rewritable)
103
+ for (const chainId of change.undelegated)
104
+ slots.set(`${change.orgId}:${change.environment}:${chainId}`, { chainId, environment: change.environment, orgId: change.orgId }) // prettier-ignore
105
+ let createdDelegations = 0
106
+ for (const slot of slots.values()) {
107
+ // Delegations grant reads only, so a whole-Zone row restores exactly what the scopes granted.
108
+ const result = await ZoneDelegations.ensure(db, { ...slot, accountsAll: true, tokensAll: true })
109
+ if (result.created) createdDelegations += 1
110
+ }
111
+ // Delegations for the unconfigured Zones an owner's own keys name grant nothing; they go with the tags.
112
+ let revokedDelegations = 0
113
+ const unconfiguredBy = new Map<string, Set<number>>()
114
+ for (const { record, unconfigured } of planned.changes) {
115
+ const owner = `${record.orgId}:${record.environment}`
116
+ unconfiguredBy.set(owner, new Set([...(unconfiguredBy.get(owner) ?? []), ...unconfigured]))
117
+ }
118
+ for (const [owner, chainIds] of unconfiguredBy) {
119
+ if (chainIds.size === 0) continue
120
+ const [orgId, environment] = owner.split(':') as [string, ZoneDelegations.Record['environment']]
121
+ for (const row of await ZoneDelegations.listActive(db, { environment, orgId }))
122
+ if (chainIds.has(row.chainId) && (await ZoneDelegations.revoke(db, row.id))) revokedDelegations += 1 // prettier-ignore
123
+ }
124
+ // Each record is written under the key's admission lock, re-read and re-planned there, so an owner edit committed meanwhile is never overwritten.
125
+ let rewritten = 0
126
+ const ids = new Set(rewritable.map(({ id }) => id))
127
+ for (const change of planned.changes.filter(({ record }) => ids.has(record.id)))
128
+ rewritten += await db.transaction(async (tx) => {
129
+ await ApiKeyAdmissions.lock(tx, change.record.id)
130
+ return ApiKeys.applyZoneReadRewrite(store, [change], { zones })
131
+ })
132
+ // The response describes the store as the run left it, not the snapshot it started from.
133
+ const final = await ApiKeys.planZoneReadRewrite(store, { zones })
134
+ return { ...(await summarize(db, final)), createdDelegations, revokedDelegations, rewritten }
135
+ }
136
+
137
+ /** Classifies planned changes by organization row and delegation coverage. */
138
+ async function summarize(db: Db.Db, planned: ApiKeys.planZoneReadRewrite.Result): Promise<Plan> {
139
+ const organizations = new Set(
140
+ (
141
+ await Organizations.listByIds(db, [
142
+ ...new Set(planned.changes.map(({ record }) => record.orgId)),
143
+ ])
144
+ ).map(({ id }) => id),
145
+ )
146
+ // Self-owned keys cannot hold a delegation, so they are reported rather than rewritten.
147
+ const owned = planned.changes.filter(({ record }) => organizations.has(record.orgId))
148
+ // One listing per organization and environment, revoked rows included, shared by every key it owns.
149
+ const rows = new Map<string, readonly ZoneDelegations.Record[]>()
150
+ for (const { record } of owned) {
151
+ const owner = `${record.orgId}:${record.environment}`
152
+ if (!rows.has(owner)) rows.set(owner, await ZoneDelegations.list(db, { environment: record.environment, orgId: record.orgId })) // prettier-ignore
153
+ }
154
+ const narrow = new Map<string, ZoneDelegations.Record>()
155
+ const revokedSlots = new Map<string, ZoneDelegations.Record>()
156
+ const changes = owned.map(({ chainIds, complete, record, rewritten, writeChainIds }) => {
157
+ const listed = rows.get(`${record.orgId}:${record.environment}`) ?? []
158
+ const active = listed.filter((row) => row.revokedAt === undefined)
159
+ // Only Zones the per-Zone scopes grant are repaired; tags added by hand never earn a delegation.
160
+ // Any active row covers (projects are not part of the model); one listing members would narrow a
161
+ // whole-Zone reader, so it blocks the apply instead. Broadcasts never check members, so write
162
+ // Zones only need a row to exist.
163
+ for (const row of active)
164
+ if (chainIds.includes(row.chainId) && !(row.accountsAll && row.tokensAll)) narrow.set(row.id, row) // prettier-ignore
165
+ const undelegated = [...new Set([...chainIds, ...writeChainIds])]
166
+ .sort((a, b) => a - b)
167
+ .filter((chainId) => !active.some((row) => row.chainId === chainId))
168
+ // A slot an admin revoked is a decision the rewrite must not undo; the key is reported instead.
169
+ const revoked = undelegated.filter((chainId) => {
170
+ const row = listed.find((candidate) => candidate.chainId === chainId)
171
+ if (row) revokedSlots.set(row.id, row)
172
+ return row !== undefined
173
+ })
174
+ return {
175
+ ...key(rewritten),
176
+ complete,
177
+ revoked,
178
+ scopes: rewritten.scopes,
179
+ undelegated,
180
+ zoneTags: rewritten.zoneTags ?? [],
181
+ }
182
+ })
183
+ return {
184
+ changes,
185
+ expiring: planned.expiring.map(key),
186
+ invalid: planned.invalid.map(key),
187
+ keys: planned.keys,
188
+ mixed: planned.mixed.map(key),
189
+ narrow: [...narrow.values()],
190
+ revoked: [...revokedSlots.values()],
191
+ orgless: planned.changes
192
+ .map(({ record }) => record)
193
+ .filter((record) => !organizations.has(record.orgId))
194
+ .map(key),
195
+ tagless: planned.tagless.map(key),
196
+ unconfigured: [...new Set(planned.changes.flatMap(({ unconfigured }) => unconfigured))].sort((a, b) => a - b), // prettier-ignore
197
+ unreadableRecords: planned.unreadableRecords,
198
+ wildcard: planned.wildcard.map(key),
199
+ }
200
+ }
201
+
202
+ /** Stores the rewrite reads and writes, and the Zones this deployment serves. */
203
+ export type Options = {
204
+ /** Authoritative Postgres database holding organizations and delegations. */
205
+ db: Db.Db
206
+ /** KV state store holding API-key records and fences. */
207
+ store: Store.State
208
+ /** Chain ids of the hosted Zones; per-Zone scopes naming any other Zone earn no tag. */
209
+ zones: ReadonlySet<number>
210
+ }
211
+
212
+ function key(record: ApiKeys.Record): Key {
213
+ return {
214
+ environment: record.environment,
215
+ id: record.id,
216
+ ...(record.name === undefined ? {} : { name: record.name }),
217
+ orgId: record.orgId,
218
+ ...(record.projectId === undefined ? {} : { projectId: record.projectId }),
219
+ }
220
+ }
221
+
222
+ /** Thrown by {@link apply} when an active delegation for a planned Zone lists members; nothing was written. */
223
+ export class NarrowDelegationsError extends Error {
224
+ override readonly name = 'ZoneKeyRewrite.NarrowDelegationsError'
225
+ /** The delegations to widen to whole-Zone coverage (or revoke) before applying. */
226
+ readonly rows: readonly ZoneDelegations.Record[]
227
+ constructor(rows: readonly ZoneDelegations.Record[]) {
228
+ super(`${rows.length} active Zone delegation(s) list members; revoke them or request whole-Zone ones before rewriting keys.`) // prettier-ignore
229
+ this.rows = rows
230
+ }
231
+ }
@@ -811,6 +811,8 @@ export type RunEvidence = {
811
811
  deferredRecipients?: number | undefined
812
812
  /** Stable registration high-water mark consumed by the run. */
813
813
  eligibilityCheckpoint?: string | undefined
814
+ /** When the run was delivered, in Unix seconds. */
815
+ deliveredAt?: number | undefined
814
816
  /** Exact eligibility snapshot identity used by resumable calculation. */
815
817
  eligibilityVersion?: Hex | undefined
816
818
  /** Exact effective exclusion set identity used by resumable calculation. */
@@ -79,12 +79,10 @@ export namespace schema {
79
79
  z.describe('Recipients skipped by the batch.'),
80
80
  z.meta({ examples: [0] }),
81
81
  ),
82
- timestamp: z.iso
83
- .datetime()
84
- .check(
85
- z.describe('Indexed block timestamp.'),
86
- z.meta({ examples: ['2026-10-13T16:01:22.000Z'] }),
87
- ),
82
+ timestamp: Schema.dateTime().check(
83
+ z.describe('Indexed block timestamp.'),
84
+ z.meta({ examples: ['2026-10-13T16:01:22.000Z'] }),
85
+ ),
88
86
  transactionHash: Schema.Hash.check(
89
87
  z.describe('Distribution transaction hash.'),
90
88
  z.meta({ examples: [`0x${'11'.repeat(32)}`] }),
@@ -164,12 +162,10 @@ export namespace schema {
164
162
  z.describe('Chain block number.'),
165
163
  z.meta({ examples: [123456] }),
166
164
  ),
167
- timestamp: z.iso
168
- .datetime()
169
- .check(
170
- z.describe('Chain block timestamp.'),
171
- z.meta({ examples: ['2026-10-13T16:01:22.000Z'] }),
172
- ),
165
+ timestamp: Schema.dateTime().check(
166
+ z.describe('Chain block timestamp.'),
167
+ z.meta({ examples: ['2026-10-13T16:01:22.000Z'] }),
168
+ ),
173
169
  })
174
170
  .check(
175
171
  z.describe('Chain block supporting the displayed evidence.'),