tapimo 0.11.0 → 0.13.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 (443) hide show
  1. package/dist/App.d.ts +6396 -4575
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +39 -4
  4. package/dist/App.js.map +1 -1
  5. package/dist/Assets.d.ts +15 -0
  6. package/dist/Assets.d.ts.map +1 -1
  7. package/dist/Assets.js +7 -0
  8. package/dist/Assets.js.map +1 -1
  9. package/dist/Scope.d.ts +2 -0
  10. package/dist/Scope.d.ts.map +1 -1
  11. package/dist/Scope.js +17 -0
  12. package/dist/Scope.js.map +1 -1
  13. package/dist/admin/App.d.ts +176 -78
  14. package/dist/admin/App.d.ts.map +1 -1
  15. package/dist/admin/apps/api-keys.d.ts +84 -4
  16. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  17. package/dist/admin/apps/api-keys.js +54 -0
  18. package/dist/admin/apps/api-keys.js.map +1 -1
  19. package/dist/admin/apps/earn-vaults.d.ts +123 -9
  20. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  21. package/dist/admin/apps/earn-vaults.js +60 -7
  22. package/dist/admin/apps/earn-vaults.js.map +1 -1
  23. package/dist/admin/apps/organizations.d.ts.map +1 -1
  24. package/dist/admin/apps/organizations.js +4 -2
  25. package/dist/admin/apps/organizations.js.map +1 -1
  26. package/dist/admin/apps/verified-tokens.d.ts +90 -90
  27. package/dist/admin/ui.generated.d.ts +1 -1
  28. package/dist/admin/ui.generated.js +71 -71
  29. package/dist/admin/ui.generated.js.map +1 -1
  30. package/dist/apps/Zones.d.ts +16 -16
  31. package/dist/apps/Zones.js +4 -4
  32. package/dist/apps/data/App.d.ts +1699 -749
  33. package/dist/apps/data/App.d.ts.map +1 -1
  34. package/dist/apps/data/App.js +58 -9
  35. package/dist/apps/data/App.js.map +1 -1
  36. package/dist/apps/data/ZoneSelection.d.ts +62 -0
  37. package/dist/apps/data/ZoneSelection.d.ts.map +1 -0
  38. package/dist/apps/data/ZoneSelection.js +44 -0
  39. package/dist/apps/data/ZoneSelection.js.map +1 -0
  40. package/dist/apps/data/routes/activities.d.ts +2417 -50
  41. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  42. package/dist/apps/data/routes/activities.js +1896 -1293
  43. package/dist/apps/data/routes/activities.js.map +1 -1
  44. package/dist/apps/data/routes/addresses.d.ts +471 -340
  45. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  46. package/dist/apps/data/routes/balances.d.ts +12 -12
  47. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  48. package/dist/apps/data/routes/balances.js +44 -17
  49. package/dist/apps/data/routes/balances.js.map +1 -1
  50. package/dist/apps/data/routes/blocks.d.ts +42 -42
  51. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  52. package/dist/apps/data/routes/blocks.js +22 -12
  53. package/dist/apps/data/routes/blocks.js.map +1 -1
  54. package/dist/apps/data/routes/coingecko.d.ts +179 -179
  55. package/dist/apps/data/routes/earn.d.ts +144 -19
  56. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  57. package/dist/apps/data/routes/earn.js +160 -28
  58. package/dist/apps/data/routes/earn.js.map +1 -1
  59. package/dist/apps/data/routes/exchanges.d.ts +719 -13
  60. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  61. package/dist/apps/data/routes/exchanges.js +16 -13
  62. package/dist/apps/data/routes/exchanges.js.map +1 -1
  63. package/dist/apps/data/routes/fee-amm.d.ts +2 -2
  64. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  65. package/dist/apps/data/routes/fee-amm.js +9 -11
  66. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  67. package/dist/apps/data/routes/indexer.d.ts +34 -34
  68. package/dist/apps/data/routes/receipts.d.ts +363 -263
  69. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  70. package/dist/apps/data/routes/receipts.js +29 -11
  71. package/dist/apps/data/routes/receipts.js.map +1 -1
  72. package/dist/apps/data/routes/rpc.js +24 -10
  73. package/dist/apps/data/routes/rpc.js.map +1 -1
  74. package/dist/apps/data/routes/tokenlist.d.ts +13 -13
  75. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  76. package/dist/apps/data/routes/tokenlist.js +16 -15
  77. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  78. package/dist/apps/data/routes/tokens.d.ts +112 -98
  79. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  80. package/dist/apps/data/routes/tokens.js +85 -35
  81. package/dist/apps/data/routes/tokens.js.map +1 -1
  82. package/dist/apps/data/routes/transactions.d.ts +7 -2
  83. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  84. package/dist/apps/data/routes/transactions.js +38 -18
  85. package/dist/apps/data/routes/transactions.js.map +1 -1
  86. package/dist/apps/data/routes/transfers.d.ts +1 -1
  87. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  88. package/dist/apps/data/routes/transfers.js +25 -21
  89. package/dist/apps/data/routes/transfers.js.map +1 -1
  90. package/dist/apps/data/routes/valuation.d.ts +1 -1
  91. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  92. package/dist/apps/data/routes/valuation.js +12 -7
  93. package/dist/apps/data/routes/valuation.js.map +1 -1
  94. package/dist/apps/data/routes/verified-tokens.d.ts +3 -3
  95. package/dist/apps/data/routes/webhooks.d.ts +15 -15
  96. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  97. package/dist/apps/data/routes/webhooks.js +2 -2
  98. package/dist/apps/data/routes/webhooks.js.map +1 -1
  99. package/dist/apps/data/routes/zones.d.ts +32 -32
  100. package/dist/apps/data/routes/zones.js +1 -1
  101. package/dist/apps/funding/App.d.ts +38 -27
  102. package/dist/apps/funding/App.d.ts.map +1 -1
  103. package/dist/apps/funding/routes/chains.d.ts.map +1 -1
  104. package/dist/apps/funding/routes/chains.js +5 -4
  105. package/dist/apps/funding/routes/chains.js.map +1 -1
  106. package/dist/apps/funding/routes/deposit-addresses.d.ts +16 -16
  107. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  108. package/dist/apps/funding/routes/deposit-addresses.js +24 -19
  109. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  110. package/dist/apps/funding/routes/providers.d.ts +13 -13
  111. package/dist/apps/funding/routes/providers.d.ts.map +1 -1
  112. package/dist/apps/funding/routes/providers.js +3 -2
  113. package/dist/apps/funding/routes/providers.js.map +1 -1
  114. package/dist/apps/funding/routes/quotes.d.ts.map +1 -1
  115. package/dist/apps/funding/routes/quotes.js +2 -2
  116. package/dist/apps/funding/routes/quotes.js.map +1 -1
  117. package/dist/apps/funding/routes/transfers.d.ts +60 -48
  118. package/dist/apps/funding/routes/transfers.d.ts.map +1 -1
  119. package/dist/apps/funding/routes/transfers.js +27 -19
  120. package/dist/apps/funding/routes/transfers.js.map +1 -1
  121. package/dist/apps/management/App.d.ts +4558 -3700
  122. package/dist/apps/management/App.d.ts.map +1 -1
  123. package/dist/apps/management/Billing.d.ts.map +1 -1
  124. package/dist/apps/management/Billing.js +19 -6
  125. package/dist/apps/management/Billing.js.map +1 -1
  126. package/dist/apps/management/routes/api-keys.d.ts +786 -175
  127. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  128. package/dist/apps/management/routes/api-keys.js +312 -34
  129. package/dist/apps/management/routes/api-keys.js.map +1 -1
  130. package/dist/apps/management/routes/billing.d.ts +103 -30
  131. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  132. package/dist/apps/management/routes/billing.js +91 -32
  133. package/dist/apps/management/routes/billing.js.map +1 -1
  134. package/dist/apps/management/routes/faucet.d.ts +35 -35
  135. package/dist/apps/management/routes/faucet.d.ts.map +1 -1
  136. package/dist/apps/management/routes/faucet.js +23 -12
  137. package/dist/apps/management/routes/faucet.js.map +1 -1
  138. package/dist/apps/management/routes/invitations.d.ts +46 -13
  139. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  140. package/dist/apps/management/routes/invitations.js +79 -29
  141. package/dist/apps/management/routes/invitations.js.map +1 -1
  142. package/dist/apps/management/routes/invite-links.d.ts +120 -75
  143. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  144. package/dist/apps/management/routes/invite-links.js +100 -41
  145. package/dist/apps/management/routes/invite-links.js.map +1 -1
  146. package/dist/apps/management/routes/me.d.ts +5 -5
  147. package/dist/apps/management/routes/me.d.ts.map +1 -1
  148. package/dist/apps/management/routes/me.js +14 -10
  149. package/dist/apps/management/routes/me.js.map +1 -1
  150. package/dist/apps/management/routes/members.d.ts +99 -78
  151. package/dist/apps/management/routes/members.d.ts.map +1 -1
  152. package/dist/apps/management/routes/members.js +37 -18
  153. package/dist/apps/management/routes/members.js.map +1 -1
  154. package/dist/apps/management/routes/orgs.d.ts +48 -8
  155. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  156. package/dist/apps/management/routes/orgs.js +48 -19
  157. package/dist/apps/management/routes/orgs.js.map +1 -1
  158. package/dist/apps/management/routes/projects.d.ts +108 -46
  159. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  160. package/dist/apps/management/routes/projects.js +72 -21
  161. package/dist/apps/management/routes/projects.js.map +1 -1
  162. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  163. package/dist/apps/management/routes/scopes.js +8 -5
  164. package/dist/apps/management/routes/scopes.js.map +1 -1
  165. package/dist/apps/management/routes/usage.d.ts +82 -82
  166. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  167. package/dist/apps/management/routes/usage.js +41 -31
  168. package/dist/apps/management/routes/usage.js.map +1 -1
  169. package/dist/apps/management/routes/verified-token-requests.d.ts +35 -7
  170. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
  171. package/dist/apps/management/routes/verified-token-requests.js +36 -17
  172. package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
  173. package/dist/apps/management/routes/webhooks.d.ts +200 -183
  174. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  175. package/dist/apps/management/routes/webhooks.js +80 -35
  176. package/dist/apps/management/routes/webhooks.js.map +1 -1
  177. package/dist/apps/mpp/internal/Adapter.d.ts +1 -1
  178. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  179. package/dist/apps/mpp/internal/Adapter.js +12 -0
  180. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  181. package/dist/db/Db.d.ts +2 -0
  182. package/dist/db/Db.d.ts.map +1 -1
  183. package/dist/db/Db.js +52 -1
  184. package/dist/db/Db.js.map +1 -1
  185. package/dist/db/Schema.d.ts +26 -3
  186. package/dist/db/Schema.d.ts.map +1 -1
  187. package/dist/db/Schema.js +24 -5
  188. package/dist/db/Schema.js.map +1 -1
  189. package/dist/db/tables/earnVaults.d.ts +5 -1
  190. package/dist/db/tables/earnVaults.d.ts.map +1 -1
  191. package/dist/db/tables/earnVaults.js +5 -0
  192. package/dist/db/tables/earnVaults.js.map +1 -1
  193. package/dist/db/tables/fundingCatalog.d.ts +4 -2
  194. package/dist/db/tables/fundingCatalog.d.ts.map +1 -1
  195. package/dist/db/tables/fundingCatalog.js +5 -1
  196. package/dist/db/tables/fundingCatalog.js.map +1 -1
  197. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -1
  198. package/dist/db/tables/webhookDeliveries.js +10 -0
  199. package/dist/db/tables/webhookDeliveries.js.map +1 -1
  200. package/dist/db/tables/webhookQueueCompletions.d.ts +15 -0
  201. package/dist/db/tables/webhookQueueCompletions.d.ts.map +1 -0
  202. package/dist/db/tables/webhookQueueCompletions.js +32 -0
  203. package/dist/db/tables/webhookQueueCompletions.js.map +1 -0
  204. package/dist/db/tables/webhookQueueEvents.d.ts +14 -20
  205. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
  206. package/dist/db/tables/webhookQueueEvents.js +68 -47
  207. package/dist/db/tables/webhookQueueEvents.js.map +1 -1
  208. package/dist/db/tables/webhookSubscriptions.d.ts +16 -5
  209. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  210. package/dist/db/tables/webhookSubscriptions.js +29 -5
  211. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  212. package/dist/handlers/internal/utils.d.ts.map +1 -1
  213. package/dist/handlers/internal/utils.js +9 -0
  214. package/dist/handlers/internal/utils.js.map +1 -1
  215. package/dist/internal/Auth.d.ts +11 -2
  216. package/dist/internal/Auth.d.ts.map +1 -1
  217. package/dist/internal/Auth.js +19 -6
  218. package/dist/internal/Auth.js.map +1 -1
  219. package/dist/internal/Cache.d.ts.map +1 -1
  220. package/dist/internal/Cache.js +11 -7
  221. package/dist/internal/Cache.js.map +1 -1
  222. package/dist/internal/EarnVaults.d.ts +43 -4
  223. package/dist/internal/EarnVaults.d.ts.map +1 -1
  224. package/dist/internal/EarnVaults.js +167 -0
  225. package/dist/internal/EarnVaults.js.map +1 -1
  226. package/dist/internal/Fetch.d.ts +23 -0
  227. package/dist/internal/Fetch.d.ts.map +1 -0
  228. package/dist/internal/Fetch.js +26 -0
  229. package/dist/internal/Fetch.js.map +1 -0
  230. package/dist/internal/Log.d.ts +3 -1
  231. package/dist/internal/Log.d.ts.map +1 -1
  232. package/dist/internal/Log.js +16 -3
  233. package/dist/internal/Log.js.map +1 -1
  234. package/dist/internal/OpenApi.d.ts +30 -24
  235. package/dist/internal/OpenApi.d.ts.map +1 -1
  236. package/dist/internal/OpenApi.js +140 -41
  237. package/dist/internal/OpenApi.js.map +1 -1
  238. package/dist/internal/Response.d.ts +14 -9
  239. package/dist/internal/Response.d.ts.map +1 -1
  240. package/dist/internal/Response.js +16 -5
  241. package/dist/internal/Response.js.map +1 -1
  242. package/dist/internal/Schema.d.ts +11 -10
  243. package/dist/internal/Schema.d.ts.map +1 -1
  244. package/dist/internal/Schema.js +14 -9
  245. package/dist/internal/Schema.js.map +1 -1
  246. package/dist/internal/Store.d.ts +28 -6
  247. package/dist/internal/Store.d.ts.map +1 -1
  248. package/dist/internal/Store.js +121 -25
  249. package/dist/internal/Store.js.map +1 -1
  250. package/dist/internal/Tidx.d.ts +2 -0
  251. package/dist/internal/Tidx.d.ts.map +1 -1
  252. package/dist/internal/Tidx.js +23 -6
  253. package/dist/internal/Tidx.js.map +1 -1
  254. package/dist/internal/Timeout.d.ts +36 -0
  255. package/dist/internal/Timeout.d.ts.map +1 -0
  256. package/dist/internal/Timeout.js +37 -0
  257. package/dist/internal/Timeout.js.map +1 -0
  258. package/dist/internal/Timing.d.ts +9 -0
  259. package/dist/internal/Timing.d.ts.map +1 -1
  260. package/dist/internal/Timing.js +7 -0
  261. package/dist/internal/Timing.js.map +1 -1
  262. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  263. package/dist/internal/WebhookDestination.js +3 -0
  264. package/dist/internal/WebhookDestination.js.map +1 -1
  265. package/dist/internal/Webhooks.d.ts +29 -12
  266. package/dist/internal/Webhooks.d.ts.map +1 -1
  267. package/dist/internal/Webhooks.js +37 -20
  268. package/dist/internal/Webhooks.js.map +1 -1
  269. package/dist/internal/funding/Action.d.ts +9 -0
  270. package/dist/internal/funding/Action.d.ts.map +1 -1
  271. package/dist/internal/funding/Action.js +16 -8
  272. package/dist/internal/funding/Action.js.map +1 -1
  273. package/dist/internal/funding/Catalog.d.ts +9 -2
  274. package/dist/internal/funding/Catalog.d.ts.map +1 -1
  275. package/dist/internal/funding/Catalog.js +19 -8
  276. package/dist/internal/funding/Catalog.js.map +1 -1
  277. package/dist/internal/funding/Deposit.d.ts +2 -2
  278. package/dist/internal/funding/Deposit.d.ts.map +1 -1
  279. package/dist/internal/funding/Deposit.js +9 -8
  280. package/dist/internal/funding/Deposit.js.map +1 -1
  281. package/dist/internal/funding/DepositAddress.d.ts +4 -4
  282. package/dist/internal/funding/DepositAddress.d.ts.map +1 -1
  283. package/dist/internal/funding/DepositAddress.js +9 -8
  284. package/dist/internal/funding/DepositAddress.js.map +1 -1
  285. package/dist/internal/funding/Provider.d.ts +68 -13
  286. package/dist/internal/funding/Provider.d.ts.map +1 -1
  287. package/dist/internal/funding/Provider.js +42 -20
  288. package/dist/internal/funding/Provider.js.map +1 -1
  289. package/dist/internal/funding/Transfer.d.ts +13 -12
  290. package/dist/internal/funding/Transfer.d.ts.map +1 -1
  291. package/dist/internal/funding/Transfer.js +23 -21
  292. package/dist/internal/funding/Transfer.js.map +1 -1
  293. package/dist/internal/funding/providers/stargate.d.ts +38 -0
  294. package/dist/internal/funding/providers/stargate.d.ts.map +1 -0
  295. package/dist/internal/funding/providers/stargate.js +277 -0
  296. package/dist/internal/funding/providers/stargate.js.map +1 -0
  297. package/dist/internal/index.d.ts +1 -0
  298. package/dist/internal/index.d.ts.map +1 -1
  299. package/dist/internal/index.js +1 -0
  300. package/dist/internal/index.js.map +1 -1
  301. package/dist/providers/index.d.ts +7 -0
  302. package/dist/providers/index.d.ts.map +1 -1
  303. package/dist/providers/index.js +3 -0
  304. package/dist/providers/index.js.map +1 -1
  305. package/package.json +3 -3
  306. package/src/App.test.ts +148 -0
  307. package/src/App.ts +45 -4
  308. package/src/Assets.test.ts +18 -0
  309. package/src/Assets.ts +22 -0
  310. package/src/Client.test-d.ts +311 -16
  311. package/src/Scope.test.ts +20 -0
  312. package/src/Scope.ts +16 -0
  313. package/src/admin/apps/api-keys.test.ts +75 -0
  314. package/src/admin/apps/api-keys.ts +64 -0
  315. package/src/admin/apps/earn-vaults.test.ts +143 -0
  316. package/src/admin/apps/earn-vaults.ts +84 -7
  317. package/src/admin/apps/organizations.ts +6 -2
  318. package/src/admin/ui/src/lib/api-keys.ts +19 -0
  319. package/src/admin/ui/src/routes/api-keys.tsx +125 -2
  320. package/src/admin/ui.generated.ts +71 -71
  321. package/src/apps/Zones.test.ts +4 -4
  322. package/src/apps/Zones.ts +4 -4
  323. package/src/apps/composition.test.ts +1 -1
  324. package/src/apps/data/App.test.ts +72 -0
  325. package/src/apps/data/App.ts +58 -10
  326. package/src/apps/data/ZoneSelection.test.ts +196 -0
  327. package/src/apps/data/ZoneSelection.ts +108 -0
  328. package/src/apps/data/routes/activities.test.ts +1843 -2
  329. package/src/apps/data/routes/activities.ts +2211 -1388
  330. package/src/apps/data/routes/balances.ts +134 -98
  331. package/src/apps/data/routes/blocks.test.ts +533 -0
  332. package/src/apps/data/routes/blocks.ts +36 -17
  333. package/src/apps/data/routes/earn.test.ts +187 -25
  334. package/src/apps/data/routes/earn.ts +228 -32
  335. package/src/apps/data/routes/earn.zone-access.test.ts +46 -0
  336. package/src/apps/data/routes/exchanges.test.ts +31 -1
  337. package/src/apps/data/routes/exchanges.ts +19 -15
  338. package/src/apps/data/routes/fee-amm.ts +18 -11
  339. package/src/apps/data/routes/receipts.ts +48 -17
  340. package/src/apps/data/routes/rpc.test.ts +75 -0
  341. package/src/apps/data/routes/rpc.ts +23 -9
  342. package/src/apps/data/routes/tokenlist.ts +21 -18
  343. package/src/apps/data/routes/tokens.test.ts +607 -0
  344. package/src/apps/data/routes/tokens.ts +312 -231
  345. package/src/apps/data/routes/transactions.ts +69 -30
  346. package/src/apps/data/routes/transfers.test.ts +424 -3
  347. package/src/apps/data/routes/transfers.ts +57 -36
  348. package/src/apps/data/routes/valuation.ts +94 -78
  349. package/src/apps/data/routes/webhooks.ts +6 -2
  350. package/src/apps/data/routes/zones.test.ts +21 -15
  351. package/src/apps/data/routes/zones.ts +1 -1
  352. package/src/apps/funding/routes/chains.test.ts +211 -7
  353. package/src/apps/funding/routes/chains.ts +19 -12
  354. package/src/apps/funding/routes/deposit-addresses.test.ts +416 -0
  355. package/src/apps/funding/routes/deposit-addresses.ts +101 -84
  356. package/src/apps/funding/routes/providers.ts +9 -5
  357. package/src/apps/funding/routes/quotes.test.ts +42 -0
  358. package/src/apps/funding/routes/quotes.ts +8 -5
  359. package/src/apps/funding/routes/transfers.test.ts +430 -40
  360. package/src/apps/funding/routes/transfers.ts +76 -59
  361. package/src/apps/management/Billing.test.ts +26 -0
  362. package/src/apps/management/Billing.ts +24 -7
  363. package/src/apps/management/routes/api-keys.test.ts +398 -0
  364. package/src/apps/management/routes/api-keys.ts +481 -145
  365. package/src/apps/management/routes/billing.test.ts +209 -0
  366. package/src/apps/management/routes/billing.ts +254 -177
  367. package/src/apps/management/routes/faucet.test.ts +39 -0
  368. package/src/apps/management/routes/faucet.ts +75 -41
  369. package/src/apps/management/routes/invitations.test.ts +216 -0
  370. package/src/apps/management/routes/invitations.ts +186 -109
  371. package/src/apps/management/routes/invite-links.test.ts +263 -1
  372. package/src/apps/management/routes/invite-links.ts +295 -214
  373. package/src/apps/management/routes/me.test.ts +49 -0
  374. package/src/apps/management/routes/me.ts +42 -32
  375. package/src/apps/management/routes/members.test.ts +124 -1
  376. package/src/apps/management/routes/members.ts +81 -51
  377. package/src/apps/management/routes/orgs.test.ts +176 -0
  378. package/src/apps/management/routes/orgs.ts +101 -59
  379. package/src/apps/management/routes/projects.test.ts +183 -0
  380. package/src/apps/management/routes/projects.ts +124 -60
  381. package/src/apps/management/routes/scopes.test.ts +44 -0
  382. package/src/apps/management/routes/scopes.ts +37 -28
  383. package/src/apps/management/routes/usage.test.ts +92 -0
  384. package/src/apps/management/routes/usage.ts +186 -151
  385. package/src/apps/management/routes/verified-token-requests.test.ts +114 -0
  386. package/src/apps/management/routes/verified-token-requests.ts +166 -133
  387. package/src/apps/management/routes/webhooks.test.ts +234 -0
  388. package/src/apps/management/routes/webhooks.ts +191 -78
  389. package/src/apps/mpp/internal/Adapter.ts +13 -1
  390. package/src/db/Db.test.ts +41 -0
  391. package/src/db/Db.ts +75 -1
  392. package/src/db/Schema.ts +33 -5
  393. package/src/db/tables/earnVaults.test.ts +22 -0
  394. package/src/db/tables/earnVaults.ts +11 -1
  395. package/src/db/tables/fundingCatalog.test.ts +16 -2
  396. package/src/db/tables/fundingCatalog.ts +9 -3
  397. package/src/db/tables/webhookDeliveries.ts +13 -0
  398. package/src/db/tables/webhookQueueCompletions.ts +55 -0
  399. package/src/db/tables/webhookQueueEvents.ts +95 -61
  400. package/src/db/tables/webhookSubscriptions.ts +45 -6
  401. package/src/handlers/internal/utils.test.ts +53 -0
  402. package/src/handlers/internal/utils.ts +15 -0
  403. package/src/internal/Auth.ts +35 -9
  404. package/src/internal/Cache.ts +14 -7
  405. package/src/internal/EarnVaults.capabilities.test.ts +33 -0
  406. package/src/internal/EarnVaults.test.ts +79 -0
  407. package/src/internal/EarnVaults.ts +277 -0
  408. package/src/internal/Fetch.test.ts +46 -0
  409. package/src/internal/Fetch.ts +56 -0
  410. package/src/internal/Log.test.ts +21 -0
  411. package/src/internal/Log.ts +20 -5
  412. package/src/internal/OpenApi.ts +177 -51
  413. package/src/internal/Response.test.ts +95 -0
  414. package/src/internal/Response.ts +41 -3
  415. package/src/internal/Schema.test.ts +18 -0
  416. package/src/internal/Schema.ts +19 -9
  417. package/src/internal/Store.test.ts +364 -0
  418. package/src/internal/Store.ts +153 -27
  419. package/src/internal/Tidx.test.ts +21 -1
  420. package/src/internal/Tidx.ts +23 -6
  421. package/src/internal/Timeout.test.ts +35 -0
  422. package/src/internal/Timeout.ts +73 -0
  423. package/src/internal/Timing.ts +16 -0
  424. package/src/internal/WebhookDestination.ts +3 -0
  425. package/src/internal/Webhooks.test.ts +122 -8
  426. package/src/internal/Webhooks.ts +59 -29
  427. package/src/internal/funding/Action.test.ts +41 -1
  428. package/src/internal/funding/Action.ts +69 -41
  429. package/src/internal/funding/Catalog.test.ts +34 -0
  430. package/src/internal/funding/Catalog.ts +28 -11
  431. package/src/internal/funding/Deposit.ts +71 -64
  432. package/src/internal/funding/DepositAddress.ts +50 -43
  433. package/src/internal/funding/Provider.test.ts +73 -0
  434. package/src/internal/funding/Provider.ts +246 -170
  435. package/src/internal/funding/Transfer.ts +133 -110
  436. package/src/internal/funding/providers/index.test.ts +22 -0
  437. package/src/internal/funding/providers/relay.test.ts +2 -2
  438. package/src/internal/funding/providers/stargate.test.ts +163 -0
  439. package/src/internal/funding/providers/stargate.ts +409 -0
  440. package/src/internal/index.test.ts +1 -0
  441. package/src/internal/index.ts +1 -0
  442. package/src/providers/index.test.ts +1 -0
  443. package/src/providers/index.ts +9 -0
@@ -5,11 +5,11 @@ describe('chains', () => {
5
5
  expect(Zones.chains).toMatchObject([
6
6
  {
7
7
  contracts: {
8
- messenger: { address: '0x2fB7Aba18510622cd88F5f45B3AC0E7Dd70606a5' },
9
- portal: { address: '0x5765e8B9003054e479df44D12D3dEeaADEfa8b7c' },
10
- verifier: { address: '0xfa16b9C6A356a096F0e7ceF0135C393A81d4a355' },
8
+ messenger: { address: '0x5A4d000000000000000000000000000000000000' },
9
+ portal: { address: '0x5Ad0000000000000000000000000000000000003' },
10
+ verifier: { address: '0x5a56000000000000000000000000000000000000' },
11
11
  },
12
- id: 1_424_310_001,
12
+ id: 1_424_310_003,
13
13
  name: 'zone-moderato-internal',
14
14
  rpcUrls: {
15
15
  default: { http: ['https://zone-internal-rpc.testnet.tempo.xyz'] },
package/src/apps/Zones.ts CHANGED
@@ -6,11 +6,11 @@ export const zoneModeratoInternal = defineChain({
6
6
  ...tempoTestnet,
7
7
  contracts: {
8
8
  ...tempoTestnet.contracts,
9
- messenger: { address: '0x2fB7Aba18510622cd88F5f45B3AC0E7Dd70606a5' },
10
- portal: { address: '0x5765e8B9003054e479df44D12D3dEeaADEfa8b7c' },
11
- verifier: { address: '0xfa16b9C6A356a096F0e7ceF0135C393A81d4a355' },
9
+ messenger: { address: '0x5A4d000000000000000000000000000000000000' },
10
+ portal: { address: '0x5Ad0000000000000000000000000000000000003' },
11
+ verifier: { address: '0x5a56000000000000000000000000000000000000' },
12
12
  },
13
- id: 1_424_310_001,
13
+ id: 1_424_310_003,
14
14
  name: 'zone-moderato-internal',
15
15
  rpcUrls: {
16
16
  default: { http: ['https://zone-internal-rpc.testnet.tempo.xyz'] },
@@ -197,7 +197,7 @@ describe('data()', () => {
197
197
  42431,
198
198
  421700001,
199
199
  421700006,
200
- 1424310001,
200
+ 1424310003,
201
201
  ],
202
202
  }
203
203
  `)
@@ -149,14 +149,54 @@ describe('MPP session management', () => {
149
149
  PaymentRequest.serialize({ _mppx_scope: 'GET /v1/scopes' }),
150
150
  )
151
151
  })
152
+
153
+ test('applies POST auth overrides to QUERY aliases', async () => {
154
+ const app = TestApp.create({
155
+ auth: {
156
+ overrides: {
157
+ 'POST /v1/exchange/quotes': { mpp: false, public: false },
158
+ },
159
+ },
160
+ })
161
+
162
+ const post = await app.request('/v1/exchange/quotes', { method: 'POST' })
163
+ const query = await app.request('/v1/exchange/quotes', { method: 'QUERY' })
164
+
165
+ expect([post.status, query.status]).toEqual([401, 401])
166
+ })
167
+
168
+ test('prefers an explicit QUERY auth override', async () => {
169
+ const app = TestApp.create({
170
+ auth: {
171
+ overrides: {
172
+ 'POST /v1/exchange/quotes': { mpp: false, public: false },
173
+ 'QUERY /v1/exchange/quotes': false,
174
+ },
175
+ },
176
+ })
177
+
178
+ const post = await app.request('/v1/exchange/quotes', { method: 'POST' })
179
+ const query = await app.request('/v1/exchange/quotes', { method: 'QUERY' })
180
+
181
+ expect([post.status, query.status]).toEqual([401, 400])
182
+ })
152
183
  })
153
184
 
154
185
  describe('zone chain gate', () => {
186
+ const legacyModerato = 1_424_310_001
187
+ const moderato = 1_424_310_003
155
188
  /** A consumer-supplied zone chain id (the API never derives these). */
156
189
  const zone = 421_700_001
157
190
  /** A second zone, isolating per-zone grants. */
158
191
  const zoneB = 4_217_000_002
159
192
 
193
+ const legacyModeratoReader = {
194
+ id: 'key_legacy_moderato',
195
+ orgId: 'org_test',
196
+ scopes: ['data:read', 'indexer:query', `zone:${legacyModerato}:read`],
197
+ token: 'secret_legacy_moderato',
198
+ } satisfies TestApp.kvStore.Key
199
+
160
200
  function zoneOptions(chainId: number) {
161
201
  return TestApp.zone({
162
202
  chainId,
@@ -261,6 +301,38 @@ describe('zone chain gate', () => {
261
301
  expect(response.status).toBe(200)
262
302
  })
263
303
 
304
+ test('the legacy Moderato id and read scope route to current upstreams', async () => {
305
+ const fetch = vi
306
+ .spyOn(globalThis, 'fetch')
307
+ .mockResolvedValueOnce(Response.json({ id: 1, jsonrpc: '2.0', result: '0x54e89ac3' }))
308
+ .mockResolvedValueOnce(Response.json({ columns: [], ok: true, row_count: 0, rows: [] }))
309
+ try {
310
+ const app = TestApp.create({
311
+ auth: { keys: [legacyModeratoReader] },
312
+ rpc: { url: (chainId) => `https://${chainId}.rpc.test` },
313
+ tidx: { baseUrl: (chainId) => `https://${chainId}.tidx.test` },
314
+ zones: true,
315
+ })
316
+ const rpc = await app.request(`/rpc/${legacyModerato}`, {
317
+ body: JSON.stringify({ id: 1, jsonrpc: '2.0', method: 'eth_chainId' }),
318
+ headers: as(legacyModeratoReader).headers,
319
+ method: 'POST',
320
+ })
321
+ const tidx = await app.request(
322
+ `/v1/indexer/query?chainId=${legacyModerato}&sql=select%201`,
323
+ as(legacyModeratoReader),
324
+ )
325
+ const tidxUpstream = new URL((fetch.mock.calls[1]![0] as Request).url)
326
+
327
+ expect([rpc.status, tidx.status]).toEqual([200, 200])
328
+ expect((fetch.mock.calls[0]![0] as Request).url).toBe(`https://${moderato}.rpc.test/`)
329
+ expect(tidxUpstream.origin).toBe(`https://${moderato}.tidx.test`)
330
+ expect(tidxUpstream.searchParams.get('chainId')).toBe(String(moderato))
331
+ } finally {
332
+ fetch.mockRestore()
333
+ }
334
+ })
335
+
264
336
  test('a Zone write scope reads Zone data', async () => {
265
337
  const response = await zoneApp().request(`/v1/tokenlist?chainId=${zone}`, as(zoneWriter))
266
338
  expect(response.status).toBe(200)
@@ -3,7 +3,7 @@ import { matchedRoutes } from 'hono/route'
3
3
  import { ZoneRpcAuthentication } from 'ox/tempo'
4
4
  import * as z from 'zod/mini'
5
5
 
6
- import type * as Assets from '../../Assets.js'
6
+ import * as Assets from '../../Assets.js'
7
7
  import type * as App from '../../App.js'
8
8
  import * as Auth from '../../internal/Auth.js'
9
9
  import * as EdgeCache from '../../internal/EdgeCache.js'
@@ -17,6 +17,7 @@ import * as Scope from '../../Scope.js'
17
17
  import * as Metadata from '../metadata.js'
18
18
 
19
19
  import type * as FxOracle from './FxOracle.js'
20
+ import * as ZoneSelection from './ZoneSelection.js'
20
21
 
21
22
  import { transactions as transactionActivities } from './routes/activities.js'
22
23
  import { addresses } from './routes/addresses.js'
@@ -58,9 +59,17 @@ export function data(options: data.Options = {}) {
58
59
  const dataRouteHandlers = new Set<unknown>()
59
60
 
60
61
  const getTidx = Tidx.createGetClient({ tidx })
62
+ const addresses_routes = addresses({ fx: options.fx })
61
63
  const earn_routes = earn({ fx: options.fx })
62
64
  const indexer_routes = indexer()
65
+ const transactionActivities_routes = transactionActivities({ fx: options.fx })
63
66
  const indexerRouteHandlers = new Set(indexer_routes.routes.map((route) => route.handler))
67
+ const inferredZoneRouteHandlers = new Set([
68
+ ...addresses_routes.routes
69
+ .filter((route) => route.path === '/v1/addresses/:address/activities')
70
+ .map((route) => route.handler),
71
+ ...transactionActivities_routes.routes.map((route) => route.handler),
72
+ ])
64
73
  const rpcOnlyRouteHandlers = new Set(
65
74
  earn_routes.routes
66
75
  .filter((route) => route.path === '/v1/earn/vaults/:vaultId/positions/:address')
@@ -106,6 +115,7 @@ export function data(options: data.Options = {}) {
106
115
  c,
107
116
  defaultChainId,
108
117
  handlers: dataRouteHandlers,
118
+ inferredZoneHandlers: inferredZoneRouteHandlers,
109
119
  indexerHandlers: indexerRouteHandlers,
110
120
  rpcOnlyHandlers: rpcOnlyRouteHandlers,
111
121
  })
@@ -135,6 +145,30 @@ export function data(options: data.Options = {}) {
135
145
  c.set('supportedChainIds', narrowedChainIds)
136
146
  if (!narrowedChainIds.has(selection.chainId))
137
147
  return Response.unsupportedChainId(c, selection.chainId, narrowedChainIds)
148
+ if (selection.inferredZones) {
149
+ if (principal?.type !== 'api_key')
150
+ return Response.error(c, {
151
+ code: 'api_key_forbidden',
152
+ message: '`include=zones` requires an API key with readable Zone scopes.',
153
+ status: 403,
154
+ })
155
+ const zoneChainIds = ZoneSelection.readableChainIds({
156
+ parentChainId: selection.chainId,
157
+ principal,
158
+ rpc: rpc_config,
159
+ tidx: tidx_config,
160
+ zones,
161
+ })
162
+ if (zoneChainIds.length === 0)
163
+ return Response.error(c, {
164
+ code: 'api_key_forbidden',
165
+ message: 'The API key has no readable configured Zones.',
166
+ status: 403,
167
+ })
168
+ c.set('supportedChainIds', new Set([selection.chainId, ...zoneChainIds]))
169
+ c.set('zoneChainIds', zoneChainIds)
170
+ return next()
171
+ }
138
172
  c.set('chainId', selection.chainId)
139
173
  return next()
140
174
  })
@@ -147,10 +181,12 @@ export function data(options: data.Options = {}) {
147
181
  c,
148
182
  defaultChainId: c.get('chainId'),
149
183
  handlers: dataRouteHandlers,
184
+ inferredZoneHandlers: inferredZoneRouteHandlers,
150
185
  indexerHandlers: indexerRouteHandlers,
151
186
  rpcOnlyHandlers: rpcOnlyRouteHandlers,
152
187
  })
153
188
  if (!selection.matched) return next()
189
+ if (selection.inferredZones) return next()
154
190
  const chainId = c.get('chainId')
155
191
  if (!zones.has(chainId)) return next()
156
192
 
@@ -165,8 +201,8 @@ export function data(options: data.Options = {}) {
165
201
  return Response.error(c, {
166
202
  code: 'api_key_forbidden',
167
203
  message: selection.rpc
168
- ? `Chain id ${chainId} is a zone. Use an API key granting \`zone:${chainId}:read\` or \`zone:${chainId}:write\`, or pass a Zone token via \`X-Authorization-Token\`.`
169
- : `Chain id ${chainId} is a zone. Use an API key granting \`zone:${chainId}:read\` or \`zone:${chainId}:write\`.`,
204
+ ? `Chain ID ${chainId} is a Zone. Use an API key granting \`zone:${chainId}:read\` or \`zone:${chainId}:write\`, or pass a Zone token via \`X-Authorization-Token\`.`
205
+ : `Chain ID ${chainId} is a Zone. Use an API key granting \`zone:${chainId}:read\` or \`zone:${chainId}:write\`.`,
170
206
  status: 403,
171
207
  })
172
208
 
@@ -187,10 +223,12 @@ export function data(options: data.Options = {}) {
187
223
  c,
188
224
  defaultChainId: c.get('chainId'),
189
225
  handlers: dataRouteHandlers,
226
+ inferredZoneHandlers: inferredZoneRouteHandlers,
190
227
  indexerHandlers: indexerRouteHandlers,
191
228
  rpcOnlyHandlers: rpcOnlyRouteHandlers,
192
229
  })
193
- if (!selection.matched || !Viem.isMainnet(c.get('chainId'))) return next()
230
+ if (!selection.matched || selection.inferredZones || !Viem.isMainnet(c.get('chainId')))
231
+ return next()
194
232
 
195
233
  return Response.error(c, {
196
234
  code: 'api_key_forbidden',
@@ -211,7 +249,7 @@ export function data(options: data.Options = {}) {
211
249
  'Content-Type': asset.contentType,
212
250
  })
213
251
  })
214
- .route('/', addresses({ fx: options.fx }))
252
+ .route('/', addresses_routes)
215
253
  .route('/', blocks())
216
254
  .route('/', earn_routes)
217
255
  .route('/', exchanges({ fx: options.fx }))
@@ -221,7 +259,7 @@ export function data(options: data.Options = {}) {
221
259
  .route('/', tokenlist())
222
260
  .route('/', tokens())
223
261
  .route('/', transactions())
224
- .route('/', transactionActivities({ fx: options.fx }))
262
+ .route('/', transactionActivities_routes)
225
263
  .route('/', transfers({ fx: options.fx }))
226
264
  .route('/', verifiedTokens())
227
265
  .route(
@@ -240,14 +278,16 @@ export function data(options: data.Options = {}) {
240
278
  c,
241
279
  defaultChainId: c.get('chainId'),
242
280
  handlers: dataRouteHandlers,
281
+ inferredZoneHandlers: inferredZoneRouteHandlers,
243
282
  indexerHandlers: indexerRouteHandlers,
244
283
  rpcOnlyHandlers: rpcOnlyRouteHandlers,
245
284
  })
246
- if (selection.matched && !selection.conflict && !selection.invalid)
285
+ if (selection.matched && !selection.conflict && !selection.inferredZones && !selection.invalid)
247
286
  c.set('chainId', selection.chainId)
248
287
  return (
249
288
  selection.matched &&
250
289
  !selection.conflict &&
290
+ !selection.inferredZones &&
251
291
  !selection.invalid &&
252
292
  !c.get('zones').has(selection.chainId)
253
293
  )
@@ -302,6 +342,7 @@ function resolveChainSelector(options: {
302
342
  c: Context<App.Environment>
303
343
  defaultChainId: Viem.ChainId
304
344
  handlers: ReadonlySet<unknown>
345
+ inferredZoneHandlers: ReadonlySet<unknown>
305
346
  indexerHandlers: ReadonlySet<unknown>
306
347
  rpcOnlyHandlers: ReadonlySet<unknown>
307
348
  }) {
@@ -310,9 +351,11 @@ function resolveChainSelector(options: {
310
351
  let rpc = false
311
352
  let rpcOnly = false
312
353
  let indexer = false
354
+ let inferredZonesAllowed = false
313
355
  for (const route of matchedRoutes(options.c)) {
314
356
  if (!options.handlers.has(route.handler)) continue
315
357
  matched = true
358
+ if (options.inferredZoneHandlers.has(route.handler)) inferredZonesAllowed = true
316
359
  if (options.indexerHandlers.has(route.handler)) indexer = true
317
360
  if (options.rpcOnlyHandlers.has(route.handler)) rpcOnly = true
318
361
  const selector = pathChainSelector(route.path, options.c.req.path)
@@ -326,6 +369,7 @@ function resolveChainSelector(options: {
326
369
  return {
327
370
  chainId: options.defaultChainId,
328
371
  conflict: false,
372
+ inferredZones: false,
329
373
  indexer: false,
330
374
  invalid: false,
331
375
  matched: false,
@@ -334,6 +378,10 @@ function resolveChainSelector(options: {
334
378
  }
335
379
 
336
380
  const search = new URL(options.c.req.url).searchParams
381
+ const include = inferredZonesAllowed
382
+ ? search.getAll('include').flatMap((value) => value.split(',').map((part) => part.trim()))
383
+ : []
384
+ const inferredZones = include.includes('zones')
337
385
  const raw = [
338
386
  ...(path === undefined ? [] : [path]),
339
387
  ...(rpc ? [] : search.getAll('chainId')),
@@ -344,6 +392,7 @@ function resolveChainSelector(options: {
344
392
  return {
345
393
  chainId: chainIds[0] ?? options.defaultChainId,
346
394
  conflict: chainIds.length > 1,
395
+ inferredZones,
347
396
  indexer,
348
397
  invalid: parsed.some((result) => !result.success),
349
398
  matched: true,
@@ -473,7 +522,6 @@ function createGetAsset(options: createGetAsset.Options): App.GetAsset {
473
522
  const { assets, basePath, origin } = options
474
523
  if (!assets) return () => undefined
475
524
  const getAsset: App.GetAsset = async (chainId, path) => {
476
- const pathname = Path.join(basePath, 'assets', String(chainId), path)
477
525
  // `path` may be absolute (`Path.join` returns a leading slash); strip it so
478
526
  // the key is `:chainId/:path`, not `:chainId//:path`.
479
527
  const key = `${chainId}/${path.replace(/^\/+/, '')}`
@@ -483,7 +531,7 @@ function createGetAsset(options: createGetAsset.Options): App.GetAsset {
483
531
  response: new globalThis.Response(asset.body, {
484
532
  headers: { 'Content-Type': asset.contentType },
485
533
  }),
486
- uri: new URL(pathname, origin).toString(),
534
+ uri: Assets.url({ basePath, chainId, origin, path }),
487
535
  }
488
536
  }
489
537
  const list = assets.list
@@ -492,7 +540,7 @@ function createGetAsset(options: createGetAsset.Options): App.GetAsset {
492
540
  const prefix = `${chainId}/${path.replace(/^\/+/, '')}`
493
541
  return (await list(prefix)).map((key) => ({
494
542
  key,
495
- uri: new URL(Path.join(basePath, 'assets', key), origin).toString(),
543
+ uri: Assets.url({ basePath, chainId, origin, path: key.slice(String(chainId).length + 1) }),
496
544
  }))
497
545
  }
498
546
  return getAsset
@@ -0,0 +1,196 @@
1
+ import * as ApiKey from '../../ApiKey.js'
2
+ import * as App from '../../App.js'
3
+ import * as Db from '../../db/Db.js'
4
+ import type * as Auth from '../../internal/Auth.js'
5
+ import * as Viem from '../../internal/Viem.js'
6
+ import * as Zones from '../Zones.js'
7
+
8
+ import * as Data from './App.js'
9
+ import * as ZoneSelection from './ZoneSelection.js'
10
+ import * as Activities from './routes/activities.js'
11
+
12
+ describe('transaction activity Zone query', () => {
13
+ test('accepts the Zones include with an optional parent chain', () => {
14
+ expect(
15
+ Activities.schema.getTransactionActivities.Query.parse({ include: 'zones' }).include,
16
+ ).toStrictEqual(['zones'])
17
+ expect(
18
+ Activities.schema.getTransactionActivities.Query.parse({
19
+ chainId: '4217',
20
+ include: 'zones',
21
+ }),
22
+ ).toMatchObject({ chainId: 4217, include: ['zones'] })
23
+ expect(
24
+ Activities.schema.getTransactionActivities.Query.safeParse({ includeZones: 'true' }).success,
25
+ ).toBe(false)
26
+ })
27
+
28
+ test('opts in only activity routes and accepts a parent chain', async () => {
29
+ const app = App.create({
30
+ auth: false,
31
+ db: Db.postgres({ connectionString: 'postgresql://unused@127.0.0.1:1/unused' }),
32
+ zones: [Zones.zoneModeratoInternal],
33
+ }).route('/', Data.data({ webhook: false }))
34
+ const address = '0x0000000000000000000000000000000000000001'
35
+ const hash = `0x${'00'.repeat(32)}`
36
+ const addressScoped = await app.request(
37
+ `/v1/addresses/${address}/activities?include=zones&chainId=${Viem.chainId.testnet}`,
38
+ )
39
+ const forbidden = await app.request(`/v1/transactions/${hash}/activities?include=zones`)
40
+ const scoped = await app.request(
41
+ `/v1/transactions/${hash}/activities?include=zones&chainId=${Viem.chainId.testnet}`,
42
+ )
43
+ const unsupported = await app.request('/v1/tokenlist?include=zones')
44
+
45
+ expect(forbidden.status).toBe(403)
46
+ expect(forbidden.headers.get('cache-control')).toBe('no-store')
47
+ expect(await addressScoped.json()).toMatchObject({ error: { code: 'api_key_forbidden' } })
48
+ expect(await scoped.json()).toMatchObject({ error: { code: 'api_key_forbidden' } })
49
+ expect(await unsupported.json()).toMatchObject({ error: { code: 'query_invalid' } })
50
+ })
51
+ })
52
+
53
+ describe('readableChainIds', () => {
54
+ test('intersects the parent chain, scopes, and configured routable Zones', () => {
55
+ const principal = apiKeyPrincipal({
56
+ scopes: [
57
+ 'data:read',
58
+ `zone:${Zones.zoneMainnetInternal.id}:read`,
59
+ `zone:${Zones.zoneModeratoInternal.id}:write`,
60
+ ],
61
+ })
62
+
63
+ expect(
64
+ ZoneSelection.readableChainIds({
65
+ parentChainId: Viem.chainId.testnet,
66
+ principal,
67
+ zones: new Map(Zones.chains.map((zone) => [zone.id, zone])),
68
+ }),
69
+ ).toStrictEqual([Zones.zoneModeratoInternal.id])
70
+ expect(
71
+ ZoneSelection.readableChainIds({
72
+ parentChainId: Viem.chainId.mainnet,
73
+ principal,
74
+ zones: new Map(Zones.chains.map((zone) => [zone.id, zone])),
75
+ }),
76
+ ).toStrictEqual([Zones.zoneMainnetInternal.id])
77
+ })
78
+
79
+ test('lets wildcard keys read every configured routable Zone of the parent chain', () => {
80
+ expect(
81
+ ZoneSelection.readableChainIds({
82
+ parentChainId: Viem.chainId.testnet,
83
+ principal: apiKeyPrincipal({ scopes: ['*'] }),
84
+ zones: new Map(Zones.chains.map((zone) => [zone.id, zone])),
85
+ }),
86
+ ).toStrictEqual([Zones.zoneModeratoInternal.id])
87
+ })
88
+
89
+ test('filters sandbox keys by each Zone parent chain', () => {
90
+ const principal = apiKeyPrincipal({
91
+ environment: 'sandbox',
92
+ scopes: [
93
+ 'data:read',
94
+ `zone:${Zones.zoneMainnetInternal.id}:read`,
95
+ `zone:${Zones.zoneModeratoInternal.id}:read`,
96
+ ],
97
+ })
98
+
99
+ expect(
100
+ ZoneSelection.readableChainIds({
101
+ parentChainId: Viem.chainId.testnet,
102
+ principal,
103
+ zones: new Map(Zones.chains.map((zone) => [zone.id, zone])),
104
+ }),
105
+ ).toStrictEqual([Zones.zoneModeratoInternal.id])
106
+ expect(
107
+ ZoneSelection.readableChainIds({
108
+ parentChainId: Viem.chainId.mainnet,
109
+ principal,
110
+ zones: new Map(Zones.chains.map((zone) => [zone.id, zone])),
111
+ }),
112
+ ).toStrictEqual([])
113
+ })
114
+
115
+ test('requires data read access and both upstreams', () => {
116
+ const zone = {
117
+ ...Zones.zoneModeratoInternal,
118
+ id: 1_424_310_099,
119
+ rpcUrls: { default: { http: ['https://zone.rpc.test'] } },
120
+ }
121
+ const zones = new Map([[zone.id, zone]])
122
+
123
+ expect(
124
+ ZoneSelection.readableChainIds({
125
+ parentChainId: zone.sourceId,
126
+ principal: apiKeyPrincipal({ scopes: [`zone:${zone.id}:read`] }),
127
+ zones,
128
+ }),
129
+ ).toStrictEqual([])
130
+ expect(
131
+ ZoneSelection.readableChainIds({
132
+ parentChainId: zone.sourceId,
133
+ principal: apiKeyPrincipal({ scopes: ['data:read', `zone:${zone.id}:read`] }),
134
+ zones,
135
+ }),
136
+ ).toStrictEqual([])
137
+ })
138
+ })
139
+
140
+ describe('uniqueMatch', () => {
141
+ test('selects one match after every chain completes', () => {
142
+ expect(
143
+ ZoneSelection.uniqueMatch([
144
+ { chainId: 1, value: null },
145
+ { chainId: 2, value: 'receipt' },
146
+ ]),
147
+ ).toStrictEqual({ chainId: 2, kind: 'selected', value: 'receipt' })
148
+ })
149
+
150
+ test('distinguishes no match from ambiguous matches', () => {
151
+ expect(ZoneSelection.uniqueMatch([{ chainId: 1, value: null }])).toStrictEqual({
152
+ kind: 'not_found',
153
+ })
154
+ expect(
155
+ ZoneSelection.uniqueMatch([
156
+ { chainId: 1, value: 'first' },
157
+ { chainId: 2, value: 'second' },
158
+ ]),
159
+ ).toStrictEqual({ kind: 'ambiguous' })
160
+ })
161
+
162
+ test('fails the selection when any chain lookup fails', () => {
163
+ const cause = new Error('unavailable')
164
+ expect(
165
+ ZoneSelection.uniqueMatch([
166
+ { chainId: 1, value: 'receipt' },
167
+ { cause, chainId: 2 },
168
+ ]),
169
+ ).toStrictEqual({ failures: [{ cause, chainId: 2 }], kind: 'failed' })
170
+ })
171
+ })
172
+
173
+ function apiKeyPrincipal(
174
+ options: apiKeyPrincipal.Options,
175
+ ): Extract<Auth.Principal, { type: 'api_key' }> {
176
+ const apiKey = ApiKey.schema.ApiKey.parse({
177
+ environment: options.environment,
178
+ id: 'key_test',
179
+ orgId: 'org_test',
180
+ scopes: options.scopes,
181
+ })
182
+ return {
183
+ apiKey,
184
+ environment: apiKey.environment,
185
+ id: apiKey.id,
186
+ orgId: apiKey.orgId,
187
+ type: 'api_key',
188
+ }
189
+ }
190
+
191
+ declare namespace apiKeyPrincipal {
192
+ type Options = {
193
+ environment?: 'production' | 'sandbox' | undefined
194
+ scopes: readonly string[]
195
+ }
196
+ }
@@ -0,0 +1,108 @@
1
+ import type { Chain } from 'viem'
2
+
3
+ import type * as Auth from '../../internal/Auth.js'
4
+ import * as Tidx from '../../internal/Tidx.js'
5
+ import * as Viem from '../../internal/Viem.js'
6
+ import * as Scope from '../../Scope.js'
7
+
8
+ /** Returns configured and routable Zones that an API key may read. */
9
+ export function readableChainIds(options: readableChainIds.Options): readonly number[] {
10
+ const { parentChainId, principal, zones } = options
11
+ const scopes = principal.apiKey.scopes
12
+ if (!scopes.includes(Scope.wildcard) && !scopes.includes('data:read')) return []
13
+
14
+ const chainIds = [...zones.values()].flatMap((zone) => {
15
+ if (zone.sourceId !== parentChainId) return []
16
+ const allowed =
17
+ scopes.includes(Scope.wildcard) ||
18
+ scopes.includes(`zone:${zone.id}:read`) ||
19
+ scopes.includes(`zone:${zone.id}:write`)
20
+ if (!allowed) return []
21
+ if (
22
+ principal.environment === 'sandbox' &&
23
+ (zone.sourceId === undefined || Viem.isMainnet(zone.sourceId))
24
+ )
25
+ return []
26
+
27
+ const context = { chainId: zone.id, principal, zone }
28
+ if (Viem.resolveRpc(options.rpc, context).url === undefined) return []
29
+ if (Tidx.resolve(options.tidx, context).baseUrl === undefined) return []
30
+ return [zone.id]
31
+ })
32
+ return chainIds.sort((a, b) => a - b)
33
+ }
34
+
35
+ export declare namespace readableChainIds {
36
+ /** Inputs for resolving the readable inferred-Zone set. */
37
+ type Options = {
38
+ /** Parent Tempo chain whose Zones may be selected. */
39
+ parentChainId: Viem.ChainId
40
+ /** Authenticated API-key principal selecting Zones. */
41
+ principal: Extract<Auth.Principal, { type: 'api_key' }>
42
+ /** RPC configuration used to exclude unroutable Zones. */
43
+ rpc?: Viem.getClient.Rpc | undefined
44
+ /** TIDX configuration used to exclude unroutable Zones. */
45
+ tidx?: Tidx.getClient.Tidx | undefined
46
+ /** Hosted Zone metadata keyed by chain id. */
47
+ zones: ReadonlyMap<number, Chain>
48
+ }
49
+ }
50
+
51
+ /** Resolves chain receipt probes without treating partial upstream results as complete. */
52
+ export function uniqueMatch<const value>(
53
+ probes: readonly uniqueMatch.Probe<value>[],
54
+ ): uniqueMatch.Result<value> {
55
+ const failures = probes.flatMap((probe) => ('cause' in probe ? [probe] : []))
56
+ if (failures.length > 0) return { failures, kind: 'failed' }
57
+
58
+ const matches = probes.flatMap((probe) =>
59
+ 'value' in probe && probe.value !== null
60
+ ? [{ chainId: probe.chainId, value: probe.value }]
61
+ : [],
62
+ )
63
+ if (matches.length === 0) return { kind: 'not_found' }
64
+ if (matches.length > 1) return { kind: 'ambiguous' }
65
+ return { ...matches[0]!, kind: 'selected' }
66
+ }
67
+
68
+ export declare namespace uniqueMatch {
69
+ /** One completed chain lookup. */
70
+ type Probe<value> =
71
+ | {
72
+ /** Chain that completed the lookup. */
73
+ chainId: number
74
+ /** Matching value, or null when the chain did not contain the resource. */
75
+ value: value | null
76
+ }
77
+ | {
78
+ /** Upstream failure from this chain. */
79
+ cause: unknown
80
+ /** Chain that failed the lookup. */
81
+ chainId: number
82
+ }
83
+
84
+ /** Unique-match decision across every requested chain. */
85
+ type Result<value> =
86
+ | {
87
+ /** Chain containing the unique match. */
88
+ chainId: number
89
+ /** Unique match result. */
90
+ kind: 'selected'
91
+ /** Value found in the selected Zone. */
92
+ value: value
93
+ }
94
+ | {
95
+ /** Every failed Zone lookup. */
96
+ failures: readonly Extract<Probe<value>, { cause: unknown }>[]
97
+ /** Partial failure result. */
98
+ kind: 'failed'
99
+ }
100
+ | {
101
+ /** Ambiguous match result. */
102
+ kind: 'ambiguous'
103
+ }
104
+ | {
105
+ /** No-match result. */
106
+ kind: 'not_found'
107
+ }
108
+ }