tapimo 0.7.0 → 0.7.2

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 (689) hide show
  1. package/dist/ApiKeys.d.ts +24 -7
  2. package/dist/ApiKeys.d.ts.map +1 -1
  3. package/dist/ApiKeys.js +17 -5
  4. package/dist/ApiKeys.js.map +1 -1
  5. package/dist/App.d.ts +12104 -7861
  6. package/dist/App.d.ts.map +1 -1
  7. package/dist/App.js +191 -128
  8. package/dist/App.js.map +1 -1
  9. package/dist/Assets.d.ts +10 -0
  10. package/dist/Assets.d.ts.map +1 -1
  11. package/dist/Assets.js +17 -4
  12. package/dist/Assets.js.map +1 -1
  13. package/dist/Scope.d.ts +19 -8
  14. package/dist/Scope.d.ts.map +1 -1
  15. package/dist/Scope.js +25 -9
  16. package/dist/Scope.js.map +1 -1
  17. package/dist/Webhooks.d.ts +1 -1
  18. package/dist/admin/App.d.ts +601 -20
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +12 -2
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +94 -11
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +141 -32
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/earn-vaults.d.ts +1069 -0
  27. package/dist/admin/apps/earn-vaults.d.ts.map +1 -0
  28. package/dist/admin/apps/earn-vaults.js +409 -0
  29. package/dist/admin/apps/earn-vaults.js.map +1 -0
  30. package/dist/admin/apps/verified-tokens.d.ts +166 -166
  31. package/dist/admin/ui.generated.d.ts +1 -1
  32. package/dist/admin/ui.generated.d.ts.map +1 -1
  33. package/dist/admin/ui.generated.js +151 -95
  34. package/dist/admin/ui.generated.js.map +1 -1
  35. package/dist/analytics/Analytics.d.ts +2 -0
  36. package/dist/analytics/Analytics.d.ts.map +1 -1
  37. package/dist/analytics/Analytics.js +18 -2
  38. package/dist/analytics/Analytics.js.map +1 -1
  39. package/dist/analytics/tables/requestEvents.d.ts +22 -1
  40. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  41. package/dist/analytics/tables/requestEvents.js +59 -39
  42. package/dist/analytics/tables/requestEvents.js.map +1 -1
  43. package/dist/apps/Zones.d.ts +8335 -0
  44. package/dist/apps/Zones.d.ts.map +1 -0
  45. package/dist/apps/Zones.js +38 -0
  46. package/dist/apps/Zones.js.map +1 -0
  47. package/dist/apps/data/App.d.ts +14377 -10165
  48. package/dist/apps/data/App.d.ts.map +1 -1
  49. package/dist/apps/data/App.js +91 -19
  50. package/dist/apps/data/App.js.map +1 -1
  51. package/dist/apps/data/FxOracle.d.ts +1 -1
  52. package/dist/apps/data/FxOracle.d.ts.map +1 -1
  53. package/dist/apps/data/index.d.ts +0 -1
  54. package/dist/apps/data/index.d.ts.map +1 -1
  55. package/dist/apps/data/index.js +0 -1
  56. package/dist/apps/data/index.js.map +1 -1
  57. package/dist/apps/data/routes/activities.d.ts +32 -32
  58. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  59. package/dist/apps/data/routes/activities.js +130 -65
  60. package/dist/apps/data/routes/activities.js.map +1 -1
  61. package/dist/apps/data/routes/addresses.d.ts +312 -312
  62. package/dist/apps/data/routes/balances.d.ts +18 -18
  63. package/dist/apps/data/routes/balances.js +5 -5
  64. package/dist/apps/data/routes/balances.js.map +1 -1
  65. package/dist/apps/data/routes/coingecko.d.ts +176 -176
  66. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  67. package/dist/apps/data/routes/coingecko.js +62 -35
  68. package/dist/apps/data/routes/coingecko.js.map +1 -1
  69. package/dist/apps/data/routes/earn.d.ts +2144 -0
  70. package/dist/apps/data/routes/earn.d.ts.map +1 -0
  71. package/dist/apps/data/routes/earn.js +947 -0
  72. package/dist/apps/data/routes/earn.js.map +1 -0
  73. package/dist/apps/data/routes/exchanges.d.ts +1231 -324
  74. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  75. package/dist/apps/data/routes/exchanges.js +656 -193
  76. package/dist/apps/data/routes/exchanges.js.map +1 -1
  77. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  78. package/dist/apps/data/routes/fee-amm.js +59 -8
  79. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  80. package/dist/apps/data/routes/funding.d.ts +4092 -387
  81. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  82. package/dist/apps/data/routes/funding.js +1403 -256
  83. package/dist/apps/data/routes/funding.js.map +1 -1
  84. package/dist/apps/data/routes/indexer.d.ts +5 -5
  85. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  86. package/dist/apps/data/routes/indexer.js +19 -2
  87. package/dist/apps/data/routes/indexer.js.map +1 -1
  88. package/dist/apps/data/routes/receipts.d.ts +265 -265
  89. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  90. package/dist/apps/data/routes/receipts.js +11 -11
  91. package/dist/apps/data/routes/receipts.js.map +1 -1
  92. package/dist/apps/data/routes/rpc.d.ts +5 -5
  93. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  94. package/dist/apps/data/routes/rpc.js +211 -22
  95. package/dist/apps/data/routes/rpc.js.map +1 -1
  96. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  97. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  98. package/dist/apps/data/routes/tokenlist.js +49 -9
  99. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  100. package/dist/apps/data/routes/tokens.d.ts +116 -88
  101. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  102. package/dist/apps/data/routes/tokens.js +198 -91
  103. package/dist/apps/data/routes/tokens.js.map +1 -1
  104. package/dist/apps/data/routes/transactions.d.ts +55 -55
  105. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  106. package/dist/apps/data/routes/transactions.js +78 -39
  107. package/dist/apps/data/routes/transactions.js.map +1 -1
  108. package/dist/apps/data/routes/transfers.d.ts +78 -29
  109. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  110. package/dist/apps/data/routes/transfers.js +165 -67
  111. package/dist/apps/data/routes/transfers.js.map +1 -1
  112. package/dist/apps/data/routes/valuation.d.ts +10 -10
  113. package/dist/apps/data/routes/valuation.js +2 -2
  114. package/dist/apps/data/routes/valuation.js.map +1 -1
  115. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  116. package/dist/apps/data/routes/verified-tokens.js +34 -9
  117. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  118. package/dist/apps/data/routes/webhooks.d.ts +5 -3
  119. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  120. package/dist/apps/data/routes/webhooks.js +175 -65
  121. package/dist/apps/data/routes/webhooks.js.map +1 -1
  122. package/dist/apps/data/routes/zones.d.ts +281 -0
  123. package/dist/apps/data/routes/zones.d.ts.map +1 -0
  124. package/dist/apps/data/routes/zones.js +252 -0
  125. package/dist/apps/data/routes/zones.js.map +1 -0
  126. package/dist/apps/docs/reference.js +6 -5
  127. package/dist/apps/docs/reference.js.map +1 -1
  128. package/dist/apps/index.d.ts +2 -1
  129. package/dist/apps/index.d.ts.map +1 -1
  130. package/dist/apps/index.js +2 -1
  131. package/dist/apps/index.js.map +1 -1
  132. package/dist/apps/management/App.d.ts +670 -670
  133. package/dist/apps/management/Billing.d.ts +8 -0
  134. package/dist/apps/management/Billing.d.ts.map +1 -1
  135. package/dist/apps/management/Billing.js +12 -0
  136. package/dist/apps/management/Billing.js.map +1 -1
  137. package/dist/apps/management/Error.d.ts +12 -0
  138. package/dist/apps/management/Error.d.ts.map +1 -0
  139. package/dist/apps/management/Error.js +10 -0
  140. package/dist/apps/management/Error.js.map +1 -0
  141. package/dist/apps/management/routes/api-keys.d.ts +5 -5
  142. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  143. package/dist/apps/management/routes/api-keys.js +2 -8
  144. package/dist/apps/management/routes/api-keys.js.map +1 -1
  145. package/dist/apps/management/routes/billing.d.ts +119 -119
  146. package/dist/apps/management/routes/faucet.d.ts +35 -35
  147. package/dist/apps/management/routes/invitations.d.ts +62 -62
  148. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  149. package/dist/apps/management/routes/invitations.js +4 -10
  150. package/dist/apps/management/routes/invitations.js.map +1 -1
  151. package/dist/apps/management/routes/invite-links.d.ts +30 -30
  152. package/dist/apps/management/routes/me.d.ts +6 -6
  153. package/dist/apps/management/routes/members.d.ts +78 -78
  154. package/dist/apps/management/routes/orgs.d.ts +48 -48
  155. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  156. package/dist/apps/management/routes/orgs.js +2 -8
  157. package/dist/apps/management/routes/orgs.js.map +1 -1
  158. package/dist/apps/management/routes/projects.d.ts +9 -9
  159. package/dist/apps/management/routes/scopes.js +2 -2
  160. package/dist/apps/management/routes/scopes.js.map +1 -1
  161. package/dist/apps/management/routes/usage.d.ts +80 -80
  162. package/dist/apps/management/routes/verified-token-requests.d.ts +36 -36
  163. package/dist/apps/management/routes/webhooks.d.ts +50 -50
  164. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  165. package/dist/apps/management/routes/webhooks.js +15 -3
  166. package/dist/apps/management/routes/webhooks.js.map +1 -1
  167. package/dist/apps/mpp/App.d.ts +55 -56
  168. package/dist/apps/mpp/App.d.ts.map +1 -1
  169. package/dist/apps/mpp/App.js +192 -27
  170. package/dist/apps/mpp/App.js.map +1 -1
  171. package/dist/apps/mpp/Mpp.d.ts +0 -20
  172. package/dist/apps/mpp/Mpp.d.ts.map +1 -1
  173. package/dist/apps/mpp/Mpp.js +0 -24
  174. package/dist/apps/mpp/Mpp.js.map +1 -1
  175. package/dist/apps/mpp/internal/Adapter.d.ts +40 -0
  176. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -0
  177. package/dist/apps/mpp/internal/Adapter.js +66 -0
  178. package/dist/apps/mpp/internal/Adapter.js.map +1 -0
  179. package/dist/apps/mpp/internal/Error.d.ts +4 -0
  180. package/dist/apps/mpp/internal/Error.d.ts.map +1 -0
  181. package/dist/apps/mpp/internal/Error.js +41 -0
  182. package/dist/apps/mpp/internal/Error.js.map +1 -0
  183. package/dist/apps/mpp/internal/Idempotency.d.ts +33 -0
  184. package/dist/apps/mpp/internal/Idempotency.d.ts.map +1 -0
  185. package/dist/apps/mpp/internal/Idempotency.js +28 -0
  186. package/dist/apps/mpp/internal/Idempotency.js.map +1 -0
  187. package/dist/apps/mpp/internal/Policy.d.ts +46 -0
  188. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -0
  189. package/dist/apps/mpp/internal/Policy.js +57 -0
  190. package/dist/apps/mpp/internal/Policy.js.map +1 -0
  191. package/dist/apps/mpp/internal/ScreenManager.d.ts +27 -0
  192. package/dist/apps/mpp/internal/ScreenManager.d.ts.map +1 -0
  193. package/dist/apps/mpp/internal/ScreenManager.js +18 -0
  194. package/dist/apps/mpp/internal/ScreenManager.js.map +1 -0
  195. package/dist/apps/mpp/internal/Screening.d.ts +35 -0
  196. package/dist/apps/mpp/internal/Screening.d.ts.map +1 -0
  197. package/dist/apps/mpp/internal/Screening.js +20 -0
  198. package/dist/apps/mpp/internal/Screening.js.map +1 -0
  199. package/dist/apps/mpp/internal/Sponsorship.d.ts +36 -0
  200. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -0
  201. package/dist/apps/mpp/internal/Sponsorship.js +103 -0
  202. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -0
  203. package/dist/apps/mpp/internal/Utils.d.ts +7 -0
  204. package/dist/apps/mpp/internal/Utils.d.ts.map +1 -0
  205. package/dist/apps/mpp/internal/Utils.js +24 -0
  206. package/dist/apps/mpp/internal/Utils.js.map +1 -0
  207. package/dist/apps/relay/App.js +184 -24
  208. package/dist/apps/relay/App.js.map +1 -1
  209. package/dist/apps/relay/Sponsorships.d.ts +4 -0
  210. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  211. package/dist/apps/relay/Sponsorships.js +16 -7
  212. package/dist/apps/relay/Sponsorships.js.map +1 -1
  213. package/dist/db/Db.d.ts +20 -0
  214. package/dist/db/Db.d.ts.map +1 -1
  215. package/dist/db/Db.js +342 -0
  216. package/dist/db/Db.js.map +1 -1
  217. package/dist/db/Schema.d.ts +921 -1
  218. package/dist/db/Schema.d.ts.map +1 -1
  219. package/dist/db/Schema.js +269 -1
  220. package/dist/db/Schema.js.map +1 -1
  221. package/dist/db/tables/earnVaults.d.ts +68 -0
  222. package/dist/db/tables/earnVaults.d.ts.map +1 -0
  223. package/dist/db/tables/earnVaults.js +72 -0
  224. package/dist/db/tables/earnVaults.js.map +1 -0
  225. package/dist/db/tables/fundingCatalog.d.ts +56 -0
  226. package/dist/db/tables/fundingCatalog.d.ts.map +1 -0
  227. package/dist/db/tables/fundingCatalog.js +85 -0
  228. package/dist/db/tables/fundingCatalog.js.map +1 -0
  229. package/dist/db/tables/fundingDepositAddresses.d.ts +159 -0
  230. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -0
  231. package/dist/db/tables/fundingDepositAddresses.js +206 -0
  232. package/dist/db/tables/fundingDepositAddresses.js.map +1 -0
  233. package/dist/db/tables/fundingDeposits.d.ts +115 -0
  234. package/dist/db/tables/fundingDeposits.d.ts.map +1 -0
  235. package/dist/db/tables/fundingDeposits.js +100 -0
  236. package/dist/db/tables/fundingDeposits.js.map +1 -0
  237. package/dist/db/tables/fundingIdempotency.d.ts +91 -0
  238. package/dist/db/tables/fundingIdempotency.d.ts.map +1 -0
  239. package/dist/db/tables/fundingIdempotency.js +103 -0
  240. package/dist/db/tables/fundingIdempotency.js.map +1 -0
  241. package/dist/db/tables/fundingTransferEvents.d.ts +12 -0
  242. package/dist/db/tables/fundingTransferEvents.d.ts.map +1 -0
  243. package/dist/db/tables/fundingTransferEvents.js +18 -0
  244. package/dist/db/tables/fundingTransferEvents.js.map +1 -0
  245. package/dist/db/tables/fundingTransferTransactions.d.ts +15 -0
  246. package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -0
  247. package/dist/db/tables/fundingTransferTransactions.js +27 -0
  248. package/dist/db/tables/fundingTransferTransactions.js.map +1 -0
  249. package/dist/db/tables/fundingTransfers.d.ts +82 -0
  250. package/dist/db/tables/fundingTransfers.d.ts.map +1 -0
  251. package/dist/db/tables/fundingTransfers.js +89 -0
  252. package/dist/db/tables/fundingTransfers.js.map +1 -0
  253. package/dist/db/tables/organizations.d.ts +8 -0
  254. package/dist/db/tables/organizations.d.ts.map +1 -1
  255. package/dist/db/tables/organizations.js +35 -0
  256. package/dist/db/tables/organizations.js.map +1 -1
  257. package/dist/db/tables/projects.d.ts +8 -0
  258. package/dist/db/tables/projects.d.ts.map +1 -1
  259. package/dist/db/tables/projects.js +16 -0
  260. package/dist/db/tables/projects.js.map +1 -1
  261. package/dist/db/tables/requestUsage.d.ts +13 -0
  262. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  263. package/dist/db/tables/requestUsage.js +16 -0
  264. package/dist/db/tables/requestUsage.js.map +1 -1
  265. package/dist/db/tables/sponsoredTransactions.d.ts +4 -2
  266. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  267. package/dist/db/tables/sponsoredTransactions.js +14 -4
  268. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  269. package/dist/db/tables/users.d.ts +8 -0
  270. package/dist/db/tables/users.d.ts.map +1 -1
  271. package/dist/db/tables/users.js +16 -0
  272. package/dist/db/tables/users.js.map +1 -1
  273. package/dist/db/tables/verifiedTokens.d.ts +14 -7
  274. package/dist/db/tables/verifiedTokens.d.ts.map +1 -1
  275. package/dist/db/tables/verifiedTokens.js +9 -7
  276. package/dist/db/tables/verifiedTokens.js.map +1 -1
  277. package/dist/db/tables/webhookSubscriptions.d.ts +31 -1
  278. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  279. package/dist/db/tables/webhookSubscriptions.js +24 -3
  280. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  281. package/dist/handlers/relay.js +108 -108
  282. package/dist/handlers/relay.js.map +1 -1
  283. package/dist/internal/Auth.d.ts +26 -0
  284. package/dist/internal/Auth.d.ts.map +1 -1
  285. package/dist/internal/Auth.js +35 -2
  286. package/dist/internal/Auth.js.map +1 -1
  287. package/dist/internal/Cache.d.ts.map +1 -1
  288. package/dist/internal/Cache.js +16 -10
  289. package/dist/internal/Cache.js.map +1 -1
  290. package/dist/internal/Cursor.js +1 -1
  291. package/dist/internal/Cursor.js.map +1 -1
  292. package/dist/internal/EarnRates.d.ts +89 -0
  293. package/dist/internal/EarnRates.d.ts.map +1 -0
  294. package/dist/internal/EarnRates.js +266 -0
  295. package/dist/internal/EarnRates.js.map +1 -0
  296. package/dist/internal/EarnVaults.d.ts +171 -0
  297. package/dist/internal/EarnVaults.d.ts.map +1 -0
  298. package/dist/internal/EarnVaults.js +547 -0
  299. package/dist/internal/EarnVaults.js.map +1 -0
  300. package/dist/internal/EdgeCache.d.ts +9 -2
  301. package/dist/internal/EdgeCache.d.ts.map +1 -1
  302. package/dist/internal/EdgeCache.js +36 -9
  303. package/dist/internal/EdgeCache.js.map +1 -1
  304. package/dist/internal/Id.d.ts +11 -0
  305. package/dist/internal/Id.d.ts.map +1 -1
  306. package/dist/internal/Id.js +13 -0
  307. package/dist/internal/Id.js.map +1 -1
  308. package/dist/internal/Idempotency.d.ts +83 -0
  309. package/dist/internal/Idempotency.d.ts.map +1 -0
  310. package/dist/internal/Idempotency.js +113 -0
  311. package/dist/internal/Idempotency.js.map +1 -0
  312. package/dist/internal/Log.d.ts +64 -9
  313. package/dist/internal/Log.d.ts.map +1 -1
  314. package/dist/internal/Log.js +29 -7
  315. package/dist/internal/Log.js.map +1 -1
  316. package/dist/internal/MetricSink.d.ts.map +1 -1
  317. package/dist/internal/MetricSink.js +47 -1
  318. package/dist/internal/MetricSink.js.map +1 -1
  319. package/dist/internal/OpenApi.d.ts +1 -1
  320. package/dist/internal/OpenApi.d.ts.map +1 -1
  321. package/dist/internal/OpenApi.js +3 -0
  322. package/dist/internal/OpenApi.js.map +1 -1
  323. package/dist/internal/Provider.d.ts +14 -0
  324. package/dist/internal/Provider.d.ts.map +1 -0
  325. package/dist/internal/Provider.js +5 -0
  326. package/dist/internal/Provider.js.map +1 -0
  327. package/dist/internal/Schema.d.ts +8 -3
  328. package/dist/internal/Schema.d.ts.map +1 -1
  329. package/dist/internal/Schema.js +24 -13
  330. package/dist/internal/Schema.js.map +1 -1
  331. package/dist/internal/Store.d.ts +6 -0
  332. package/dist/internal/Store.d.ts.map +1 -1
  333. package/dist/internal/Store.js +35 -0
  334. package/dist/internal/Store.js.map +1 -1
  335. package/dist/internal/Tidx.d.ts +43 -24
  336. package/dist/internal/Tidx.d.ts.map +1 -1
  337. package/dist/internal/Tidx.js +79 -11
  338. package/dist/internal/Tidx.js.map +1 -1
  339. package/dist/internal/Viem.d.ts +82 -65
  340. package/dist/internal/Viem.d.ts.map +1 -1
  341. package/dist/internal/Viem.js +83 -12
  342. package/dist/internal/Viem.js.map +1 -1
  343. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  344. package/dist/internal/WebhookDestination.js +34 -28
  345. package/dist/internal/WebhookDestination.js.map +1 -1
  346. package/dist/internal/Webhooks.d.ts +9 -0
  347. package/dist/internal/Webhooks.d.ts.map +1 -1
  348. package/dist/internal/Webhooks.js +15 -10
  349. package/dist/internal/Webhooks.js.map +1 -1
  350. package/dist/internal/exchange/Provider.d.ts +219 -0
  351. package/dist/internal/exchange/Provider.d.ts.map +1 -0
  352. package/dist/internal/exchange/Provider.js +117 -0
  353. package/dist/internal/exchange/Provider.js.map +1 -0
  354. package/dist/internal/exchange/index.d.ts +2 -0
  355. package/dist/internal/exchange/index.d.ts.map +1 -0
  356. package/dist/internal/exchange/index.js +2 -0
  357. package/dist/internal/exchange/index.js.map +1 -0
  358. package/dist/internal/exchange/providers/uniswap.d.ts +57 -0
  359. package/dist/internal/exchange/providers/uniswap.d.ts.map +1 -0
  360. package/dist/internal/exchange/providers/uniswap.js +553 -0
  361. package/dist/internal/exchange/providers/uniswap.js.map +1 -0
  362. package/dist/internal/funding/Action.d.ts +55 -0
  363. package/dist/internal/funding/Action.d.ts.map +1 -0
  364. package/dist/internal/funding/Action.js +74 -0
  365. package/dist/internal/funding/Action.js.map +1 -0
  366. package/dist/internal/funding/Catalog.d.ts +107 -0
  367. package/dist/internal/funding/Catalog.d.ts.map +1 -0
  368. package/dist/internal/funding/Catalog.js +270 -0
  369. package/dist/internal/funding/Catalog.js.map +1 -0
  370. package/dist/internal/funding/Chain.d.ts +76 -0
  371. package/dist/internal/funding/Chain.d.ts.map +1 -0
  372. package/dist/internal/funding/Chain.js +38 -0
  373. package/dist/internal/funding/Chain.js.map +1 -0
  374. package/dist/internal/funding/Deposit.d.ts +366 -0
  375. package/dist/internal/funding/Deposit.d.ts.map +1 -0
  376. package/dist/internal/funding/Deposit.js +286 -0
  377. package/dist/internal/funding/Deposit.js.map +1 -0
  378. package/dist/internal/funding/DepositAddress.d.ts +345 -0
  379. package/dist/internal/funding/DepositAddress.d.ts.map +1 -0
  380. package/dist/internal/funding/DepositAddress.js +189 -0
  381. package/dist/internal/funding/DepositAddress.js.map +1 -0
  382. package/dist/internal/funding/Evidence.d.ts +52 -0
  383. package/dist/internal/funding/Evidence.d.ts.map +1 -0
  384. package/dist/internal/funding/Evidence.js +314 -0
  385. package/dist/internal/funding/Evidence.js.map +1 -0
  386. package/dist/internal/funding/Provider.d.ts +1186 -0
  387. package/dist/internal/funding/Provider.d.ts.map +1 -0
  388. package/dist/internal/funding/Provider.js +1081 -0
  389. package/dist/internal/funding/Provider.js.map +1 -0
  390. package/dist/internal/funding/Reconciliation.d.ts +113 -0
  391. package/dist/internal/funding/Reconciliation.d.ts.map +1 -0
  392. package/dist/internal/funding/Reconciliation.js +676 -0
  393. package/dist/internal/funding/Reconciliation.js.map +1 -0
  394. package/dist/internal/funding/Route.d.ts +21 -0
  395. package/dist/internal/funding/Route.d.ts.map +1 -0
  396. package/dist/internal/funding/Route.js +5 -0
  397. package/dist/internal/funding/Route.js.map +1 -0
  398. package/dist/internal/funding/Subsidy.d.ts +113 -0
  399. package/dist/internal/funding/Subsidy.d.ts.map +1 -0
  400. package/dist/internal/funding/Subsidy.js +138 -0
  401. package/dist/internal/funding/Subsidy.js.map +1 -0
  402. package/dist/internal/funding/Token.d.ts +41 -0
  403. package/dist/internal/funding/Token.d.ts.map +1 -0
  404. package/dist/internal/funding/Token.js +22 -0
  405. package/dist/internal/funding/Token.js.map +1 -0
  406. package/dist/internal/funding/Transfer.d.ts +643 -0
  407. package/dist/internal/funding/Transfer.d.ts.map +1 -0
  408. package/dist/internal/funding/Transfer.js +332 -0
  409. package/dist/internal/funding/Transfer.js.map +1 -0
  410. package/dist/internal/funding/index.d.ts +13 -0
  411. package/dist/internal/funding/index.d.ts.map +1 -0
  412. package/dist/internal/funding/index.js +13 -0
  413. package/dist/internal/funding/index.js.map +1 -0
  414. package/dist/internal/funding/providers/across.d.ts +21 -0
  415. package/dist/internal/funding/providers/across.d.ts.map +1 -0
  416. package/dist/internal/funding/providers/across.js +117 -0
  417. package/dist/internal/funding/providers/across.js.map +1 -0
  418. package/dist/internal/funding/providers/relay.d.ts +46 -0
  419. package/dist/internal/funding/providers/relay.d.ts.map +1 -0
  420. package/dist/internal/funding/providers/relay.js +464 -0
  421. package/dist/internal/funding/providers/relay.js.map +1 -0
  422. package/dist/internal/funding/providers/rhino.d.ts +15 -0
  423. package/dist/internal/funding/providers/rhino.d.ts.map +1 -0
  424. package/dist/internal/funding/providers/rhino.js +116 -0
  425. package/dist/internal/funding/providers/rhino.js.map +1 -0
  426. package/dist/internal/funding/providers/squid.d.ts +19 -0
  427. package/dist/internal/funding/providers/squid.d.ts.map +1 -0
  428. package/dist/internal/funding/providers/squid.js +120 -0
  429. package/dist/internal/funding/providers/squid.js.map +1 -0
  430. package/dist/internal/funding/providers/symbiosis.d.ts +20 -0
  431. package/dist/internal/funding/providers/symbiosis.d.ts.map +1 -0
  432. package/dist/internal/funding/providers/symbiosis.js +176 -0
  433. package/dist/internal/funding/providers/symbiosis.js.map +1 -0
  434. package/dist/internal/index.d.ts +5 -1
  435. package/dist/internal/index.d.ts.map +1 -1
  436. package/dist/internal/index.js +5 -1
  437. package/dist/internal/index.js.map +1 -1
  438. package/dist/internal/webhookDestinations/url.js +61 -57
  439. package/dist/internal/webhookDestinations/url.js.map +1 -1
  440. package/dist/providers/index.d.ts +43 -0
  441. package/dist/providers/index.d.ts.map +1 -0
  442. package/dist/providers/index.js +19 -0
  443. package/dist/providers/index.js.map +1 -0
  444. package/package.json +9 -4
  445. package/src/ApiKeys.test.ts +11 -7
  446. package/src/ApiKeys.ts +37 -9
  447. package/src/App.test.ts +85 -10
  448. package/src/App.ts +224 -137
  449. package/src/Assets.ts +29 -4
  450. package/src/Client.test-d.ts +650 -30
  451. package/src/Scope.test.ts +19 -0
  452. package/src/Scope.ts +28 -11
  453. package/src/Webhooks.test.ts +25 -0
  454. package/src/Webhooks.ts +1 -1
  455. package/src/admin/App.test.ts +9 -2
  456. package/src/admin/App.ts +32 -9
  457. package/src/admin/apps/api-keys.test.ts +167 -23
  458. package/src/admin/apps/api-keys.ts +166 -28
  459. package/src/admin/apps/earn-vaults.test.ts +338 -0
  460. package/src/admin/apps/earn-vaults.ts +572 -0
  461. package/src/admin/apps/scopes.test.ts +16 -1
  462. package/src/admin/ui/plugin.ts +2 -2
  463. package/src/admin/ui/src/components/EarnVaultForm.tsx +137 -0
  464. package/src/admin/ui/src/components/MobileProfile.tsx +2 -2
  465. package/src/admin/ui/src/components/Page.tsx +1 -1
  466. package/src/admin/ui/src/components/ThemeToggle.tsx +1 -1
  467. package/src/admin/ui/src/lib/api-keys.ts +37 -7
  468. package/src/admin/ui/src/lib/client.ts +1 -1
  469. package/src/admin/ui/src/lib/config.ts +1 -1
  470. package/src/admin/ui/src/lib/early-access.ts +8 -9
  471. package/src/admin/ui/src/lib/earn-vaults.ts +207 -0
  472. package/src/admin/ui/src/lib/format.ts +13 -0
  473. package/src/admin/ui/src/lib/organizations.test.ts +14 -4
  474. package/src/admin/ui/src/lib/organizations.ts +7 -1
  475. package/src/admin/ui/src/lib/response.ts +22 -0
  476. package/src/admin/ui/src/lib/scopes.test.ts +19 -11
  477. package/src/admin/ui/src/lib/scopes.ts +28 -7
  478. package/src/admin/ui/src/lib/verified-tokens.ts +10 -9
  479. package/src/admin/ui/src/routeTree.gen.ts +70 -7
  480. package/src/admin/ui/src/router.tsx +2 -2
  481. package/src/admin/ui/src/routes/__root.tsx +9 -8
  482. package/src/admin/ui/src/routes/api-keys.tsx +475 -64
  483. package/src/admin/ui/src/routes/early-access.tsx +5 -12
  484. package/src/admin/ui/src/routes/earn.vaults.tsx +348 -0
  485. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +154 -0
  486. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +190 -0
  487. package/src/admin/ui/src/routes/organizations.tsx +4 -7
  488. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +56 -54
  489. package/src/admin/ui/src/routes/verified-tokens.tsx +4 -4
  490. package/src/admin/ui/vite.config.ts +4 -1
  491. package/src/admin/ui.generated.ts +189 -95
  492. package/src/analytics/Analytics.test.ts +69 -10
  493. package/src/analytics/Analytics.ts +20 -1
  494. package/src/analytics/tables/requestEvents.ts +79 -37
  495. package/src/apps/Zones.test.ts +33 -0
  496. package/src/apps/Zones.ts +40 -0
  497. package/src/apps/composition.test.ts +84 -1
  498. package/src/apps/data/App.test.ts +38 -9
  499. package/src/apps/data/App.ts +96 -33
  500. package/src/apps/data/FxOracle.ts +1 -1
  501. package/src/apps/data/index.ts +0 -1
  502. package/src/apps/data/routes/activities.test.ts +82 -6
  503. package/src/apps/data/routes/activities.ts +131 -71
  504. package/src/apps/data/routes/balances.test.ts +50 -37
  505. package/src/apps/data/routes/balances.ts +5 -5
  506. package/src/apps/data/routes/blocks.test.ts +2 -0
  507. package/src/apps/data/routes/coingecko.test.ts +22 -0
  508. package/src/apps/data/routes/coingecko.ts +84 -48
  509. package/src/apps/data/routes/earn.test.ts +1108 -0
  510. package/src/apps/data/routes/earn.ts +1391 -0
  511. package/src/apps/data/routes/exchanges.test.ts +82 -33
  512. package/src/apps/data/routes/exchanges.ts +842 -227
  513. package/src/apps/data/routes/fee-amm.test.ts +4 -6
  514. package/src/apps/data/routes/fee-amm.ts +69 -12
  515. package/src/apps/data/routes/funding.test.ts +2712 -221
  516. package/src/apps/data/routes/funding.ts +1604 -387
  517. package/src/apps/data/routes/indexer.test.ts +43 -34
  518. package/src/apps/data/routes/indexer.ts +19 -2
  519. package/src/apps/data/routes/receipts.test.ts +5 -3
  520. package/src/apps/data/routes/receipts.ts +13 -11
  521. package/src/apps/data/routes/rpc.test.ts +446 -28
  522. package/src/apps/data/routes/rpc.ts +243 -25
  523. package/src/apps/data/routes/tokenlist.test.ts +15 -0
  524. package/src/apps/data/routes/tokenlist.ts +88 -22
  525. package/src/apps/data/routes/tokens.ts +262 -86
  526. package/src/apps/data/routes/transactions.test.ts +2 -0
  527. package/src/apps/data/routes/transactions.ts +77 -42
  528. package/src/apps/data/routes/transfers.test.ts +166 -4
  529. package/src/apps/data/routes/transfers.ts +216 -78
  530. package/src/apps/data/routes/valuation.test.ts +62 -9
  531. package/src/apps/data/routes/valuation.ts +2 -2
  532. package/src/apps/data/routes/verified-tokens.test.ts +51 -0
  533. package/src/apps/data/routes/verified-tokens.ts +52 -15
  534. package/src/apps/data/routes/webhooks.test.ts +432 -33
  535. package/src/apps/data/routes/webhooks.ts +189 -79
  536. package/src/apps/data/routes/zones.test.ts +473 -0
  537. package/src/apps/data/routes/zones.ts +338 -0
  538. package/src/apps/docs/reference.ts +8 -6
  539. package/src/apps/index.ts +2 -1
  540. package/src/apps/management/Billing.test.ts +29 -0
  541. package/src/apps/management/Billing.ts +23 -0
  542. package/src/apps/management/Error.ts +12 -0
  543. package/src/apps/management/routes/api-keys.test.ts +5 -3
  544. package/src/apps/management/routes/api-keys.ts +2 -9
  545. package/src/apps/management/routes/invitations.ts +4 -11
  546. package/src/apps/management/routes/orgs.ts +2 -9
  547. package/src/apps/management/routes/scopes.test.ts +7 -2
  548. package/src/apps/management/routes/scopes.ts +2 -2
  549. package/src/apps/management/routes/webhooks.test.ts +6 -1
  550. package/src/apps/management/routes/webhooks.ts +15 -3
  551. package/src/apps/mpp/App.ts +276 -29
  552. package/src/apps/mpp/Mpp.test.ts +631 -26
  553. package/src/apps/mpp/Mpp.ts +0 -42
  554. package/src/apps/mpp/internal/Adapter.ts +108 -3
  555. package/src/apps/mpp/internal/Error.test.ts +33 -0
  556. package/src/apps/mpp/internal/Error.ts +44 -6
  557. package/src/apps/mpp/internal/Idempotency.test.ts +213 -0
  558. package/src/apps/mpp/internal/Idempotency.ts +59 -5
  559. package/src/apps/mpp/internal/Policy.test.ts +122 -0
  560. package/src/apps/mpp/internal/Policy.ts +98 -0
  561. package/src/apps/mpp/internal/ScreenManager.test.ts +68 -0
  562. package/src/apps/mpp/internal/ScreenManager.ts +41 -0
  563. package/src/apps/mpp/internal/Screening.ts +40 -3
  564. package/src/apps/mpp/internal/Sponsorship.ts +144 -0
  565. package/src/apps/mpp/internal/Utils.ts +30 -0
  566. package/src/apps/relay/App.test.ts +495 -64
  567. package/src/apps/relay/App.ts +234 -24
  568. package/src/apps/relay/Sponsorships.test.ts +51 -0
  569. package/src/apps/relay/Sponsorships.ts +19 -7
  570. package/src/db/Db.ts +439 -0
  571. package/src/db/Schema.ts +325 -2
  572. package/src/db/tables/earnVaults.test.ts +185 -0
  573. package/src/db/tables/earnVaults.ts +151 -0
  574. package/src/db/tables/fundingCatalog.test.ts +108 -0
  575. package/src/db/tables/fundingCatalog.ts +157 -0
  576. package/src/db/tables/fundingDepositAddresses.test.ts +580 -0
  577. package/src/db/tables/fundingDepositAddresses.ts +376 -0
  578. package/src/db/tables/fundingDeposits.test.ts +261 -0
  579. package/src/db/tables/fundingDeposits.ts +229 -0
  580. package/src/db/tables/fundingIdempotency.test.ts +182 -0
  581. package/src/db/tables/fundingIdempotency.ts +180 -0
  582. package/src/db/tables/fundingTransferEvents.ts +28 -0
  583. package/src/db/tables/fundingTransferTransactions.test.ts +69 -0
  584. package/src/db/tables/fundingTransferTransactions.ts +37 -0
  585. package/src/db/tables/fundingTransfers.test.ts +89 -0
  586. package/src/db/tables/fundingTransfers.ts +153 -0
  587. package/src/db/tables/organizations.test.ts +88 -0
  588. package/src/db/tables/organizations.ts +42 -1
  589. package/src/db/tables/projects.ts +16 -0
  590. package/src/db/tables/requestUsage.ts +23 -0
  591. package/src/db/tables/sponsoredTransactions.test.ts +52 -2
  592. package/src/db/tables/sponsoredTransactions.ts +18 -6
  593. package/src/db/tables/users.ts +16 -0
  594. package/src/db/tables/verifiedTokens.ts +19 -14
  595. package/src/db/tables/webhookSubscriptions.ts +58 -3
  596. package/src/handlers/relay.test.ts +2 -0
  597. package/src/handlers/relay.ts +95 -99
  598. package/src/internal/Auth.test.ts +48 -0
  599. package/src/internal/Auth.ts +61 -2
  600. package/src/internal/Cache.ts +13 -9
  601. package/src/internal/Cursor.test.ts +2 -2
  602. package/src/internal/Cursor.ts +1 -1
  603. package/src/internal/EarnRates.test.ts +125 -0
  604. package/src/internal/EarnRates.ts +409 -0
  605. package/src/internal/EarnVaults.test.ts +195 -0
  606. package/src/internal/EarnVaults.ts +876 -0
  607. package/src/internal/EdgeCache.test.ts +37 -5
  608. package/src/internal/EdgeCache.ts +39 -7
  609. package/src/internal/Id.ts +14 -0
  610. package/src/internal/Idempotency.test.ts +109 -0
  611. package/src/internal/Idempotency.ts +237 -0
  612. package/src/internal/Log.test-d.ts +41 -8
  613. package/src/internal/Log.test.ts +189 -8
  614. package/src/internal/Log.ts +124 -17
  615. package/src/internal/MetricSink.test.ts +244 -4
  616. package/src/internal/MetricSink.ts +51 -1
  617. package/src/internal/OpenApi.ts +3 -0
  618. package/src/internal/Provider.test.ts +17 -0
  619. package/src/internal/Provider.ts +17 -0
  620. package/src/internal/Schema.test.ts +13 -0
  621. package/src/internal/Schema.ts +41 -24
  622. package/src/internal/Store.test.ts +25 -0
  623. package/src/internal/Store.ts +46 -0
  624. package/src/internal/Tidx.local.test.ts +78 -3
  625. package/src/internal/Tidx.test.ts +212 -18
  626. package/src/internal/Tidx.ts +112 -32
  627. package/src/internal/VerifiedTokens.test.ts +15 -0
  628. package/src/internal/Viem.test.ts +170 -17
  629. package/src/internal/Viem.ts +111 -28
  630. package/src/internal/WebhookDestination.ts +25 -23
  631. package/src/internal/Webhooks.test.ts +59 -0
  632. package/src/internal/Webhooks.ts +34 -10
  633. package/src/internal/exchange/Provider.test.ts +216 -0
  634. package/src/internal/exchange/Provider.ts +326 -0
  635. package/src/internal/exchange/index.test.ts +6 -0
  636. package/src/internal/exchange/index.ts +1 -0
  637. package/src/internal/exchange/providers/uniswap.test.ts +122 -0
  638. package/src/internal/exchange/providers/uniswap.ts +682 -0
  639. package/src/internal/funding/Action.test.ts +138 -0
  640. package/src/internal/funding/Action.ts +117 -0
  641. package/src/internal/funding/Catalog.test.ts +311 -0
  642. package/src/internal/funding/Catalog.ts +347 -0
  643. package/src/internal/funding/Chain.test.ts +79 -0
  644. package/src/internal/funding/Chain.ts +120 -0
  645. package/src/internal/funding/Deposit.test.ts +26 -0
  646. package/src/internal/funding/Deposit.ts +453 -0
  647. package/src/internal/funding/DepositAddress.test.ts +18 -0
  648. package/src/internal/funding/DepositAddress.ts +312 -0
  649. package/src/internal/funding/Evidence.test.ts +297 -0
  650. package/src/internal/funding/Evidence.ts +430 -0
  651. package/src/internal/funding/Provider.test.ts +1328 -0
  652. package/src/internal/funding/Provider.ts +1796 -0
  653. package/src/internal/funding/Reconciliation.local.test.ts +504 -0
  654. package/src/internal/funding/Reconciliation.test.ts +2020 -0
  655. package/src/internal/funding/Reconciliation.ts +930 -0
  656. package/src/internal/funding/Route.test.ts +66 -0
  657. package/src/internal/funding/Route.ts +29 -0
  658. package/src/internal/funding/Subsidy.local.test.ts +152 -0
  659. package/src/internal/funding/Subsidy.test.ts +75 -0
  660. package/src/internal/funding/Subsidy.ts +260 -0
  661. package/src/internal/funding/Token.test.ts +47 -0
  662. package/src/internal/funding/Token.ts +59 -0
  663. package/src/internal/funding/Transfer.test.ts +369 -0
  664. package/src/internal/funding/Transfer.ts +522 -0
  665. package/src/internal/funding/index.test.ts +20 -0
  666. package/src/internal/funding/index.ts +12 -0
  667. package/src/internal/funding/providers/across.ts +149 -0
  668. package/src/{apps/data/FundingQuoteProviders.test.ts → internal/funding/providers/index.test.ts} +178 -157
  669. package/src/internal/funding/providers/relay.test.ts +474 -0
  670. package/src/internal/funding/providers/relay.ts +559 -0
  671. package/src/internal/funding/providers/rhino.ts +139 -0
  672. package/src/internal/funding/providers/squid.ts +151 -0
  673. package/src/internal/funding/providers/symbiosis.ts +221 -0
  674. package/src/internal/index.test.ts +5 -1
  675. package/src/internal/index.ts +5 -1
  676. package/src/internal/webhookDestinations/url.ts +49 -45
  677. package/src/providers/index.test.ts +14 -0
  678. package/src/providers/index.ts +54 -0
  679. package/dist/apps/data/FundingQuoteProviders.d.ts +0 -174
  680. package/dist/apps/data/FundingQuoteProviders.d.ts.map +0 -1
  681. package/dist/apps/data/FundingQuoteProviders.js +0 -775
  682. package/dist/apps/data/FundingQuoteProviders.js.map +0 -1
  683. package/dist/internal/FundingQuotes.d.ts +0 -864
  684. package/dist/internal/FundingQuotes.d.ts.map +0 -1
  685. package/dist/internal/FundingQuotes.js +0 -672
  686. package/dist/internal/FundingQuotes.js.map +0 -1
  687. package/src/apps/data/FundingQuoteProviders.ts +0 -1043
  688. package/src/internal/FundingQuotes.test.ts +0 -456
  689. package/src/internal/FundingQuotes.ts +0 -944
package/src/Scope.test.ts CHANGED
@@ -1,5 +1,23 @@
1
1
  import * as Scope from './Scope.js'
2
2
 
3
+ describe('schema.Zone', () => {
4
+ test('accepts concrete read and write scopes', () => {
5
+ expect(
6
+ ['zone:421700005:read', 'zone:421700005:write'].map((scope) =>
7
+ Scope.schema.Zone.safeParse(scope),
8
+ ),
9
+ ).toMatchObject([{ success: true }, { success: true }])
10
+ })
11
+
12
+ test('rejects templates and unsupported access levels', () => {
13
+ expect(
14
+ ['zone:<chainId>:read', 'zone:421700005:admin'].map((scope) =>
15
+ Scope.schema.Zone.safeParse(scope),
16
+ ),
17
+ ).toMatchObject([{ success: false }, { success: false }])
18
+ })
19
+ })
20
+
3
21
  describe('extend', () => {
4
22
  test('appends host scopes to the built-in catalog', () => {
5
23
  expect(
@@ -13,6 +31,7 @@ describe('extend', () => {
13
31
  ).toEqual([
14
32
  ...Scope.catalog,
15
33
  Scope.zoneEntry,
34
+ Scope.zoneWriteEntry,
16
35
  {
17
36
  description: 'Read project accounts.',
18
37
  scope: 'accounts:read',
package/src/Scope.ts CHANGED
@@ -33,6 +33,16 @@ export const catalog = [
33
33
  scope: 'data:read',
34
34
  selfServe: true,
35
35
  },
36
+ {
37
+ description: 'Read organization funding transfers, deposit addresses, and deposits.',
38
+ scope: 'funding:read',
39
+ selfServe: false,
40
+ },
41
+ {
42
+ description: 'Create funding transfers and register their source transactions.',
43
+ scope: 'funding:write',
44
+ selfServe: false,
45
+ },
36
46
  {
37
47
  description: 'Run ad-hoc queries against the raw indexer passthrough.',
38
48
  scope: 'indexer:query',
@@ -50,7 +60,7 @@ export const catalog = [
50
60
  selfServe: true,
51
61
  },
52
62
  {
53
- description: 'Validate and broadcast MPP payment credentials through the Tempo relay.',
63
+ description: 'Validate and broadcast MPP credentials through Tempo.',
54
64
  scope: 'mpp:write',
55
65
  selfServe: true,
56
66
  },
@@ -76,28 +86,35 @@ export const catalog = [
76
86
  },
77
87
  ] as const satisfies readonly Entry[]
78
88
 
79
- /**
80
- * Templated `/v1/scopes` entry for per-zone read scopes. Concrete grants use
81
- * `zone:<chainId>:read` and are never self-serve.
82
- */
89
+ /** Templated `/v1/scopes` entry for per-zone read scopes. */
83
90
  export const zoneEntry = {
84
91
  description: 'Read RPC and indexed data for one zone chain id.',
85
92
  scope: 'zone:<chainId>:read',
86
93
  selfServe: false,
87
94
  } as const satisfies Entry
88
95
 
96
+ /** Templated `/v1/scopes` entry for per-zone transaction broadcast scopes. */
97
+ export const zoneWriteEntry = {
98
+ description: 'Broadcast signed transactions to one zone chain id.',
99
+ scope: 'zone:<chainId>:write',
100
+ selfServe: false,
101
+ } as const satisfies Entry
102
+
89
103
  /** Zod schemas owned by the scope vocabulary. */
90
104
  export namespace schema {
91
- /** A concrete per-zone read scope (`zone:421700001:read`). */
105
+ /** A concrete per-zone read or write scope. */
92
106
  export const Zone = z
93
- .templateLiteral(['zone:', z.int(), ':read'])
107
+ .union([
108
+ z.templateLiteral(['zone:', z.int(), ':read']),
109
+ z.templateLiteral(['zone:', z.int(), ':write']),
110
+ ])
94
111
  .check(
95
- z.regex(/^zone:[1-9]\d*:read$/),
96
- z.describe('Per-zone read scope (`zone:<chainId>:read`).'),
112
+ z.regex(/^zone:[1-9]\d*:(read|write)$/),
113
+ z.describe('Per-zone read or write scope (`zone:<chainId>:read|write`).'),
97
114
  )
98
115
  }
99
116
 
100
- /** Per-zone read scope, granting access to one zone chain id. */
117
+ /** Per-zone read or write scope, granting access to one zone chain id. */
101
118
  export type Zone = z.output<typeof schema.Zone>
102
119
 
103
120
  /** Issuable API-key scope identifier, including host-defined scopes. */
@@ -123,7 +140,7 @@ export const selfServe: readonly Id[] = catalog
123
140
  */
124
141
  export function extend(entries: readonly Entry[] = []): Catalog {
125
142
  const identifiers = new Set<string>()
126
- const result = [...catalog, zoneEntry, ...entries]
143
+ const result = [...catalog, zoneEntry, zoneWriteEntry, ...entries]
127
144
  for (const entry of result) {
128
145
  if (!entry.scope.trim()) throw new Error('Scope identifier must not be empty.')
129
146
  if (identifiers.has(entry.scope)) throw new Error(`Duplicate scope \`${entry.scope}\`.`)
@@ -47,4 +47,29 @@ describe('createPoller', () => {
47
47
  ]
48
48
  `)
49
49
  })
50
+
51
+ test('clamps a creation checkpoint to genesis', async () => {
52
+ const db = TestApp.database()
53
+ const subscription = await Webhooks.createSubscription(
54
+ db,
55
+ {
56
+ chainId: 42431,
57
+ destination: { type: 'url', url: 'https://hooks.example.com/x' },
58
+ eventType: 'block:created',
59
+ owner: { orgId: 'org_test', type: 'api_key' },
60
+ },
61
+ { startBlockNumber: 1 },
62
+ )
63
+ const poller = Webhooks.createPoller({
64
+ db,
65
+ defaultChainId: 42431,
66
+ })
67
+
68
+ await poller.tick({
69
+ eventTypes: ['block:created'],
70
+ headBlockNumber: 1,
71
+ })
72
+
73
+ expect(decodeCursor(await Webhooks.getCursor(db, subscription.id))).toEqual([0, 2_147_483_647])
74
+ })
50
75
  })
package/src/Webhooks.ts CHANGED
@@ -126,7 +126,7 @@ export declare namespace createPoller {
126
126
 
127
127
  /** Knobs shared by every {@link Poller.tick}; each is overridable per tick. */
128
128
  type Defaults = {
129
- /** Max matching rows scanned per subscription per tick (default 100). */
129
+ /** Max matching rows scanned per subscription per tick (default 200). */
130
130
  batchSize?: number | undefined
131
131
  /** Reorg-safety window: only emit blocks this far behind head (default 2). */
132
132
  confirmations?: number | undefined
@@ -1,4 +1,5 @@
1
1
  import { Hono } from 'hono'
2
+ import * as Organizations from '../db/tables/organizations.js'
2
3
  import * as TestAdmin from '../../test/Admin.js'
3
4
 
4
5
  // Route behavior (mint/list/revoke, the scope catalog) is covered in
@@ -18,6 +19,11 @@ describe('create', () => {
18
19
  method: 'POST',
19
20
  }),
20
21
  new Request('http://admin/api-keys/key_x', { method: 'DELETE' }),
22
+ new Request('http://admin/earn/verified-vaults', {
23
+ body: JSON.stringify({}),
24
+ headers: { 'content-type': 'application/json' },
25
+ method: 'PUT',
26
+ }),
21
27
  new Request('http://admin/organizations'),
22
28
  new Request('http://admin/organizations/org_x'),
23
29
  new Request('http://admin/organizations/org_x/billing-sources/stripe', { method: 'PUT' }),
@@ -61,9 +67,10 @@ describe('create', () => {
61
67
  })
62
68
 
63
69
  test('verified identity is recorded as createdBy on minted keys', async () => {
64
- const { app } = TestAdmin.setup({ identify: () => ({ email: 'ops@tempo.xyz' }) })
70
+ const { app, db } = TestAdmin.setup({ identify: () => ({ email: 'ops@tempo.xyz' }) })
71
+ await Organizations.create(db, { id: 'org', name: 'Operations' })
65
72
  const response = await app.request('http://admin/api-keys', {
66
- body: JSON.stringify({ orgId: 'org', scopes: ['data:read'] }),
73
+ body: JSON.stringify({ name: 'Operations', orgId: 'org', scopes: ['data:read'] }),
67
74
  headers: { 'content-type': 'application/json' },
68
75
  method: 'POST',
69
76
  })
package/src/admin/App.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type Context, Hono, type Next } from 'hono'
2
2
  import { HTTPException } from 'hono/http-exception'
3
3
  import { requestId, type RequestIdVariables } from 'hono/request-id'
4
+ import type { Chain } from 'viem'
4
5
 
5
6
  import * as ApiKey from '../ApiKey.js'
6
7
  import type * as Assets from '../Assets.js'
@@ -9,9 +10,12 @@ import * as Db from '../db/Db.js'
9
10
  import * as AdminAuditLogs from '../db/tables/adminAuditLogs.js'
10
11
  import type * as Store from '../internal/Store.js'
11
12
  import * as Response from '../internal/Response.js'
13
+ import * as Viem from '../internal/Viem.js'
14
+ import * as Zones from '../apps/Zones.js'
12
15
 
13
16
  import { apiKeys } from './apps/api-keys.js'
14
17
  import { earlyAccess } from './apps/early-access.js'
18
+ import { earnVaults } from './apps/earn-vaults.js'
15
19
  import { organizations } from './apps/organizations.js'
16
20
  import { scopes } from './apps/scopes.js'
17
21
  import { verifiedTokens } from './apps/verified-tokens.js'
@@ -30,12 +34,18 @@ export type Environment = {
30
34
  analytics: Analytics.Source
31
35
  /** Static-asset writer (e.g. the R2 icon bucket), when configured. */
32
36
  assets: create.Assets | undefined
37
+ /** Path where the admin app is mounted. */
38
+ basePath: string
33
39
  /** Authoritative Postgres store, or a per-request factory. Resolve at the leaf with `Db.get`. */
34
40
  db: Db.Source
35
- /** KV state store backing API-key records (mint/list/revoke). */
36
- kv: { store: Store.State }
41
+ /** Gets a Tempo RPC client for a chain id. */
42
+ getClient: Viem.GetClient
37
43
  /** The admin identity, or `null` when unauthenticated (gated routes reject). */
38
44
  identity: Identity | null
45
+ /** KV state store backing API-key records (mint/list/revoke). */
46
+ kv: { store: Store.State }
47
+ /** Zone chains available to admin routes. */
48
+ zones: readonly Chain[]
39
49
  }
40
50
  }
41
51
 
@@ -45,6 +55,10 @@ export type App = ReturnType<typeof create>
45
55
  /** Creates the admin portal Hono app. */
46
56
  export function create(options: create.Options) {
47
57
  const { identify } = options
58
+
59
+ const zones = options.zones === true ? Zones.chains : (options.zones ?? [])
60
+ const getClient = Viem.createGetClient({ rpc: options.rpc, zones })
61
+
48
62
  // `false` (disabled) collapses to `undefined` so only a real config surfaces
49
63
  // `loginUrl`/`logoutUrl` in `/config.json`.
50
64
  const ui = options.ui || undefined
@@ -62,8 +76,11 @@ export function create(options: create.Options) {
62
76
  c.header('Cache-Control', 'no-store')
63
77
  c.set('analytics', options.analytics)
64
78
  c.set('assets', options.assets)
79
+ c.set('basePath', c.req.routePath.replace(/\*$/, '').replace(/\/$/, ''))
65
80
  c.set('db', options.db)
81
+ c.set('getClient', getClient)
66
82
  c.set('kv', options.kv)
83
+ c.set('zones', zones)
67
84
  c.set('identity', await identify(c.req.raw))
68
85
  return next()
69
86
  })
@@ -83,13 +100,12 @@ export function create(options: create.Options) {
83
100
  // Renders the public SPA shell: stamps its hydration-safe base and auth
84
101
  // placeholders with request values. `<` is escaped to keep the config script.
85
102
  const serveShell = (c: Context<Environment>) => {
86
- const mount = c.req.routePath.replace(/\*$/, '').replace(/\/$/, '')
87
103
  const config = JSON.stringify(authConfig(c.get('identity'))).replaceAll('<', '\\u003c')
88
104
  return c.html(
89
105
  Ui.shell
90
106
  .replace(
91
107
  '<base data-tempo-base="true" href="/"/>',
92
- `<base data-tempo-base="true" href="${mount}/"/>`,
108
+ `<base data-tempo-base="true" href="${c.get('basePath')}/"/>`,
93
109
  )
94
110
  .replace('window.__TEMPO_API_CONFIG__=undefined', `window.__TEMPO_API_CONFIG__=${config}`),
95
111
  )
@@ -120,6 +136,8 @@ export function create(options: create.Options) {
120
136
  '/api-keys/*',
121
137
  '/early-access',
122
138
  '/early-access/*',
139
+ '/earn/verified-vaults',
140
+ '/earn/verified-vaults/*',
123
141
  '/organizations',
124
142
  '/organizations/*',
125
143
  '/scopes',
@@ -156,6 +174,7 @@ export function create(options: create.Options) {
156
174
  .get('/config.json', (c) => c.json(authConfig(c.get('identity')), 200))
157
175
  .route('/api-keys', apiKeys())
158
176
  .route('/early-access', earlyAccess())
177
+ .route('/earn/verified-vaults', earnVaults())
159
178
  .route('/organizations', organizations())
160
179
  .route('/scopes', scopes())
161
180
  .route('/verified-tokens', verifiedTokens())
@@ -222,22 +241,26 @@ export declare namespace create {
222
241
  * (`() => Db.postgres(...)`) on Workers.
223
242
  */
224
243
  db: Db.Source
225
- /**
226
- * KV state store backing API-key records (shared with the main API's
227
- * `kv` option), provisioned against by the `/api-keys` routes.
228
- */
229
- kv: { store: Store.State }
230
244
  /**
231
245
  * Extracts the verified admin identity from a request, or `null` to deny.
232
246
  * Must only return an identity for an already-authenticated request (a
233
247
  * verified Access JWT, or a header set by a trusted proxy).
234
248
  */
235
249
  identify: (request: Request) => Identity | null | Promise<Identity | null>
250
+ /**
251
+ * KV state store backing API-key records (shared with the main API's
252
+ * `kv` option), provisioned against by the `/api-keys` routes.
253
+ */
254
+ kv: { store: Store.State }
255
+ /** Tempo RPC options used by onchain verification. */
256
+ rpc?: Viem.getClient.Rpc | undefined
236
257
  /**
237
258
  * Admin UI options, or `false` to disable the bundled UI (JSON API only).
238
259
  * `loginUrl`/`logoutUrl` are surfaced in `GET /config.json`.
239
260
  */
240
261
  ui?: Ui | false | undefined
262
+ /** Zone chains available to admin routes. Pass true to use the hosted Zone list. */
263
+ zones?: true | readonly Chain[] | undefined
241
264
  }
242
265
 
243
266
  /** Admin UI options surfaced to the SPA via `GET /config.json`. */
@@ -1,16 +1,19 @@
1
1
  import * as ApiKey from '../../ApiKey.js'
2
2
  import * as core_ApiKeys from '../../ApiKeys.js'
3
+ import * as Organizations from '../../db/tables/organizations.js'
4
+ import * as Projects from '../../db/tables/projects.js'
5
+ import * as Users from '../../db/tables/users.js'
3
6
 
4
7
  import * as TestAdmin from '../../../test/Admin.js'
5
8
  import * as TestApp from '../../../test/App.js'
6
9
  import * as ApiKeys from './api-keys.js'
7
10
 
8
11
  /** Minimal valid mint payload. */
9
- const validBody = { orgId: 'org_test', scopes: ['data:read'] } as const
12
+ const validBody = { name: 'CI', orgId: 'org_test', scopes: ['data:read'] } as const
10
13
 
11
14
  describe('POST /api-keys', () => {
12
15
  test('mints a key, returns the token once, persists a hashed record', async () => {
13
- const { client, store } = TestAdmin.setup()
16
+ const { client, store } = await setup()
14
17
  const response = await client['api-keys'].$post({ json: { ...validBody, name: 'CI' } })
15
18
  const body = await TestApp.json(response, ApiKeys.schema.createApiKey.Response)
16
19
 
@@ -44,7 +47,7 @@ describe('POST /api-keys', () => {
44
47
  })
45
48
 
46
49
  test('defaults to the production environment', async () => {
47
- const { client, store } = TestAdmin.setup()
50
+ const { client, store } = await setup()
48
51
  const response = await client['api-keys'].$post({ json: validBody })
49
52
  const body = await TestApp.json(response, ApiKeys.schema.createApiKey.Response)
50
53
 
@@ -53,8 +56,17 @@ describe('POST /api-keys', () => {
53
56
  expect((await core_ApiKeys.list(store))[0]?.environment).toBe('production')
54
57
  })
55
58
 
59
+ test('requires a human-readable name', async () => {
60
+ const { client } = await setup()
61
+ const response = await client['api-keys'].$post({
62
+ json: { orgId: 'org_test', scopes: ['data:read'] } as never,
63
+ })
64
+
65
+ expect(response.status).toBe(400)
66
+ })
67
+
56
68
  test('persists a sandbox environment when provided', async () => {
57
- const { client, store } = TestAdmin.setup()
69
+ const { client, store } = await setup()
58
70
  const response = await client['api-keys'].$post({
59
71
  json: { ...validBody, environment: 'sandbox' },
60
72
  })
@@ -68,21 +80,21 @@ describe('POST /api-keys', () => {
68
80
  expect(resolved?.environment).toBe('sandbox')
69
81
  })
70
82
 
71
- test('mints a key with a concrete Zone read scope', async () => {
72
- const { client, store } = TestAdmin.setup()
73
- const scope = 'zone:421700001:read' as const
83
+ test('mints a key with concrete Zone read and write scopes', async () => {
84
+ const { client, store } = await setup()
85
+ const scopes = ['zone:421700001:read', 'zone:421700001:write'] as const
74
86
  const response = await client['api-keys'].$post({
75
- json: { ...validBody, scopes: [scope] },
87
+ json: { ...validBody, scopes },
76
88
  })
77
89
  const body = await TestApp.json(response, ApiKeys.schema.createApiKey.Response)
78
90
 
79
91
  expect(response.status).toBe(200)
80
- expect(body.scopes).toEqual([scope])
81
- expect((await core_ApiKeys.resolve(store, body.token))?.scopes).toEqual([scope])
92
+ expect(body.scopes).toEqual(scopes)
93
+ expect((await core_ApiKeys.resolve(store, body.token))?.scopes).toEqual(scopes)
82
94
  })
83
95
 
84
96
  test('records the expiry when provided', async () => {
85
- const { client, store } = TestAdmin.setup()
97
+ const { client, store } = await setup()
86
98
  const expiresAt = '2100-01-01T00:00:00.000Z'
87
99
  const response = await client['api-keys'].$post({ json: { ...validBody, expiresAt } })
88
100
  const body = await TestApp.json(response, ApiKeys.schema.createApiKey.Response)
@@ -93,7 +105,7 @@ describe('POST /api-keys', () => {
93
105
  })
94
106
 
95
107
  test('rejects an unknown scope with 400', async () => {
96
- const { client } = TestAdmin.setup()
108
+ const { client } = await setup()
97
109
  const response = await client['api-keys'].$post({
98
110
  // Cast past the typed client to exercise runtime validation.
99
111
  json: { ...validBody, scopes: ['nope:read'] } as never,
@@ -105,8 +117,13 @@ describe('POST /api-keys', () => {
105
117
  })
106
118
 
107
119
  test('rejects non-concrete or non-canonical Zone scopes with 400', async () => {
108
- for (const scope of ['zone:<chainId>:read', 'zone:0:read', 'zone:000421700001:read']) {
109
- const { client } = TestAdmin.setup()
120
+ for (const scope of [
121
+ 'zone:<chainId>:read',
122
+ 'zone:0:read',
123
+ 'zone:0:write',
124
+ 'zone:000421700001:read',
125
+ ]) {
126
+ const { client } = await setup()
110
127
  const response = await client['api-keys'].$post({
111
128
  // Cast past the typed client to exercise runtime validation.
112
129
  json: { ...validBody, scopes: [scope] } as never,
@@ -119,7 +136,7 @@ describe('POST /api-keys', () => {
119
136
  })
120
137
 
121
138
  test('ignores a client-supplied createdBy (audit trail is server-set)', async () => {
122
- const { client } = TestAdmin.setup()
139
+ const { client } = await setup()
123
140
  const response = await client['api-keys'].$post({
124
141
  // Cast past the typed client: the body schema omits createdBy, so an
125
142
  // unknown key is stripped and the server records the verified identity.
@@ -130,8 +147,68 @@ describe('POST /api-keys', () => {
130
147
  expect(response.status).toBe(200)
131
148
  expect(body.createdBy).toBe(TestAdmin.identity.email)
132
149
  })
150
+
151
+ test('allows a one-off key without organization attribution', async () => {
152
+ const { client, store } = TestAdmin.setup()
153
+ const response = await client['api-keys'].$post({
154
+ json: { name: 'Trial', scopes: ['data:read'] },
155
+ })
156
+ const body = await TestApp.json(response, ApiKeys.schema.createApiKey.Response)
157
+
158
+ expect(response.status).toBe(200)
159
+ expect(body.orgId).toBe(body.id)
160
+ expect((await core_ApiKeys.resolve(store, body.token))?.orgId).toBe(body.id)
161
+ })
162
+
163
+ test('rejects an unknown organization', async () => {
164
+ const { client } = TestAdmin.setup()
165
+ const response = await client['api-keys'].$post({ json: validBody })
166
+
167
+ expect(response.status).toBe(404)
168
+ })
169
+
170
+ test('infers organization attribution from a project', async () => {
171
+ const { client, db, store } = TestAdmin.setup()
172
+ const organization = await Organizations.create(db, { name: 'Project owner' })
173
+ const project = await Projects.create(db, { name: 'Project', orgId: organization.id })
174
+ const response = await client['api-keys'].$post({
175
+ json: { name: 'Project key', projectId: project.id, scopes: ['data:read'] },
176
+ })
177
+ const body = await TestApp.json(response, ApiKeys.schema.createApiKey.Response)
178
+
179
+ expect(response.status).toBe(200)
180
+ expect(body.orgId).toBe(organization.id)
181
+ expect(body.projectId).toBe(project.id)
182
+ expect((await core_ApiKeys.resolve(store, body.token))?.orgId).toBe(organization.id)
183
+ })
184
+
185
+ test('rejects an unknown project', async () => {
186
+ const { client } = await setup()
187
+ const response = await client['api-keys'].$post({
188
+ json: { ...validBody, projectId: 'prj_missing' },
189
+ })
190
+
191
+ expect(response.status).toBe(404)
192
+ })
193
+
194
+ test('rejects a project owned by another organization', async () => {
195
+ const { client, db } = await setup()
196
+ const other = await Organizations.create(db, { name: 'Other' })
197
+ const project = await Projects.create(db, { name: 'Other project', orgId: other.id })
198
+ const response = await client['api-keys'].$post({
199
+ json: { ...validBody, projectId: project.id },
200
+ })
201
+
202
+ expect(response.status).toBe(404)
203
+ })
133
204
  })
134
205
 
206
+ async function setup() {
207
+ const context = TestAdmin.setup()
208
+ await Organizations.create(context.db, { id: validBody.orgId, name: 'Test' })
209
+ return context
210
+ }
211
+
135
212
  describe('GET /api-keys', () => {
136
213
  test('lists records as metadata only (never the token)', async () => {
137
214
  const { client, store } = TestAdmin.setup()
@@ -142,6 +219,11 @@ describe('GET /api-keys', () => {
142
219
 
143
220
  expect(response.status).toBe(200)
144
221
  expect(body.data).toHaveLength(1)
222
+ expect(body.data[0]).toMatchObject({
223
+ createdByLabel: null,
224
+ organizationName: null,
225
+ projectName: null,
226
+ })
145
227
  // No record (and no serialized response) may carry the plaintext token.
146
228
  expect(body.data[0]).not.toHaveProperty('token')
147
229
  expect(JSON.stringify(body)).not.toContain(token)
@@ -157,6 +239,30 @@ describe('GET /api-keys', () => {
157
239
 
158
240
  expect(body.data.map((record) => record.orgId)).toEqual(['org_a'])
159
241
  })
242
+
243
+ test('resolves organization, project, and creator display labels', async () => {
244
+ const { client, db, store } = TestAdmin.setup()
245
+ const user = await Users.upsertByAddress(db, { address: `0x${'aa'.repeat(20)}` })
246
+ await Users.setEmail(db, user.id, 'alex@tempo.xyz')
247
+ const organization = await Organizations.create(db, { name: 'Tempo' })
248
+ const project = await Projects.create(db, { name: 'Explorer', orgId: organization.id })
249
+ await core_ApiKeys.mint(store, {
250
+ createdBy: user.id,
251
+ name: 'Explorer testnet',
252
+ orgId: organization.id,
253
+ projectId: project.id,
254
+ scopes: ['data:read'],
255
+ })
256
+
257
+ const response = await client['api-keys'].$get({ query: {} })
258
+ const body = await TestApp.json(response, ApiKeys.schema.listApiKeys.Response)
259
+
260
+ expect(body.data[0]).toMatchObject({
261
+ createdByLabel: 'alex@tempo.xyz',
262
+ organizationName: 'Tempo',
263
+ projectName: 'Explorer',
264
+ })
265
+ })
160
266
  })
161
267
 
162
268
  describe('DELETE /api-keys/:id', () => {
@@ -184,22 +290,60 @@ describe('DELETE /api-keys/:id', () => {
184
290
  })
185
291
 
186
292
  describe('PATCH /api-keys/:id', () => {
187
- test('re-attributes a key to an org and project', async () => {
188
- const { client, store } = TestAdmin.setup()
189
- const { record, token } = await core_ApiKeys.mint(store, validBody)
293
+ test('renames and associates a one-off key without changing its token', async () => {
294
+ const { client, db, store } = TestAdmin.setup()
295
+ const organization = await Organizations.create(db, { name: 'Tempo' })
296
+ const { record, token } = await core_ApiKeys.mint(store, {
297
+ name: 'Trial',
298
+ scopes: ['data:read'],
299
+ })
190
300
 
191
301
  const response = await client['api-keys'][':id'].$patch({
192
- json: { orgId: 'org_real', projectId: 'prj_real' },
302
+ json: { name: 'Explorer', orgId: organization.id, projectId: 'prj_real' },
193
303
  param: { id: record.id },
194
304
  })
195
305
  expect(response.status).toBe(200)
196
306
  const body = await TestApp.json(response, core_ApiKeys.schema.Record)
197
- expect(body.orgId).toBe('org_real')
307
+ expect(body.name).toBe('Explorer')
308
+ expect(body.orgId).toBe(organization.id)
198
309
  expect(body.projectId).toBe('prj_real')
199
310
 
200
- // The original token keeps resolving, now carrying the attribution.
201
- const resolved = await core_ApiKeys.resolve(store, token)
202
- expect(resolved?.projectId).toBe('prj_real')
311
+ expect((await core_ApiKeys.resolve(store, token))?.orgId).toBe(organization.id)
312
+ expect(await core_ApiKeys.listByOrg(store, record.id)).toEqual([])
313
+ expect((await core_ApiKeys.listByOrg(store, organization.id)).map(({ id }) => id)).toEqual([
314
+ record.id,
315
+ ])
316
+ })
317
+
318
+ test('rejects an unknown organization without changing the key', async () => {
319
+ const { client, store } = TestAdmin.setup()
320
+ const { record } = await core_ApiKeys.mint(store, { scopes: ['data:read'] })
321
+ const response = await client['api-keys'][':id'].$patch({
322
+ json: { orgId: 'org_missing' },
323
+ param: { id: record.id },
324
+ })
325
+
326
+ expect(response.status).toBe(404)
327
+ expect((await core_ApiKeys.get(store, record.id))?.orgId).toBe(record.id)
328
+ })
329
+
330
+ test('rejects changing an assigned organization', async () => {
331
+ const { client, db, store } = TestAdmin.setup()
332
+ const organization = await Organizations.create(db, { name: 'Tempo' })
333
+ const other = await Organizations.create(db, { name: 'Other' })
334
+ const { record, token } = await core_ApiKeys.mint(store, {
335
+ orgId: organization.id,
336
+ scopes: ['data:read'],
337
+ })
338
+ const response = await client['api-keys'][':id'].$patch({
339
+ json: { orgId: other.id },
340
+ param: { id: record.id },
341
+ })
342
+ const body = (await response.json()) as { error?: { code?: string } }
343
+
344
+ expect(response.status).toBe(409)
345
+ expect(body.error?.code).toBe('organization_already_assigned')
346
+ expect((await core_ApiKeys.resolve(store, token))?.orgId).toBe(organization.id)
203
347
  })
204
348
 
205
349
  test('unknown id → 404', async () => {