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
@@ -12,6 +12,7 @@ const entry = {
12
12
  requestId: 'req-1',
13
13
  route: '/v1/transactions',
14
14
  status: 200,
15
+ timings: { transactions: 42.7, transactions_count: 7.1 },
15
16
  } satisfies Log.Entry
16
17
 
17
18
  const clickHouse = {
@@ -42,6 +43,7 @@ const row = {
42
43
  service: 'api',
43
44
  status: 200,
44
45
  timestamp: '2026-01-01 00:00:00.000',
46
+ timings: { transactions: 42.7, transactions_count: 7.1 },
45
47
  } satisfies Analytics.Event
46
48
 
47
49
  afterEach(() => vi.unstubAllGlobals())
@@ -160,8 +162,8 @@ describe('clickhouse', () => {
160
162
  await Analytics.clickhouse(clickHouse).migrate()
161
163
 
162
164
  const bodies = fetch.mock.calls.map((call) => String(call[1]?.body))
163
- const guarded = Analytics.migrations.find((migration) => migration.guard)!
164
- expect(bodies).not.toContain(guarded.sql)
165
+ for (const migration of Analytics.migrations.filter((migration) => migration.guard))
166
+ expect(bodies).not.toContain(migration.sql)
165
167
  })
166
168
 
167
169
  test('migrate throws MigrateError on a non-2xx response', async () => {
@@ -180,6 +182,7 @@ describe('migrations', () => {
180
182
  // that predate a column (e.g. billing columns for existing production).
181
183
  const sql = Analytics.migrations.map((migration) => migration.sql).join('\n')
182
184
  for (const column of Object.keys(row)) expect(sql).toContain(column)
185
+ expect(sql).toContain('timings Map(String, Float64)')
183
186
  })
184
187
  })
185
188
 
@@ -220,6 +223,7 @@ describe('createQueueSink', () => {
220
223
  service: row.service,
221
224
  status: row.status,
222
225
  timestamp: '<timestamp>',
226
+ timings: row.timings,
223
227
  }).toMatchInlineSnapshot(`
224
228
  {
225
229
  "billing_active": null,
@@ -241,10 +245,23 @@ describe('createQueueSink', () => {
241
245
  "service": "api",
242
246
  "status": 200,
243
247
  "timestamp": "<timestamp>",
248
+ "timings": {
249
+ "transactions": 42.7,
250
+ "transactions_count": 7.1,
251
+ },
244
252
  }
245
253
  `)
246
254
  })
247
255
 
256
+ test('stores an empty timing map when the request has no operation timings', async () => {
257
+ const send = vi.fn<(message: Analytics.Event) => Promise<void>>().mockResolvedValue(undefined)
258
+ const sink = Analytics.createQueueSink({ send })(context)
259
+
260
+ await sink({ ...entry, timings: undefined })
261
+
262
+ expect(send.mock.calls[0]![0].timings).toMatchInlineSnapshot(`{}`)
263
+ })
264
+
248
265
  test('retries a failed send once with the same row', async () => {
249
266
  const send = vi
250
267
  .fn<(message: Analytics.Event) => Promise<void>>()
@@ -369,31 +386,73 @@ describe('handleQueue', () => {
369
386
 
370
387
  test('inserts the batch and acks each message', async () => {
371
388
  const { insert, message, store } = fixture()
389
+ const onResult = vi.fn()
372
390
 
373
- const handled = await Analytics.handleQueue(store, {
374
- messages: [message],
375
- queue: Analytics.queueName,
376
- })
391
+ const handled = await Analytics.handleQueue(
392
+ store,
393
+ {
394
+ messages: [message],
395
+ queue: Analytics.queueName,
396
+ },
397
+ { onResult },
398
+ )
377
399
 
378
400
  expect(handled).toBe(true)
379
401
  expect(insert).toHaveBeenCalledWith('request_events', [row])
380
402
  expect(message.ack).toHaveBeenCalledTimes(1)
381
403
  expect(message.retry).not.toHaveBeenCalled()
404
+ expect(onResult).toHaveBeenCalledWith({ messages: 1, outcome: 'acked' })
382
405
  })
383
406
 
384
407
  test('retries every message when the insert fails', async () => {
385
408
  vi.spyOn(console, 'error').mockImplementation(() => {})
386
409
  const { insert, message, store } = fixture()
410
+ const onResult = vi.fn()
387
411
  insert.mockRejectedValueOnce(new Error('clickhouse down'))
388
412
 
389
- const handled = await Analytics.handleQueue(store, {
390
- messages: [message],
391
- queue: Analytics.queueName,
392
- })
413
+ const handled = await Analytics.handleQueue(
414
+ store,
415
+ {
416
+ messages: [message],
417
+ queue: Analytics.queueName,
418
+ },
419
+ { onResult },
420
+ )
393
421
 
394
422
  expect(handled).toBe(true)
395
423
  expect(message.ack).not.toHaveBeenCalled()
396
424
  expect(message.retry).toHaveBeenCalledTimes(1)
425
+ expect(onResult).toHaveBeenCalledWith({
426
+ cause: expect.objectContaining({ message: 'clickhouse down' }),
427
+ messages: 1,
428
+ outcome: 'retried',
429
+ })
430
+ })
431
+
432
+ test('does not retry acknowledged messages when the result callback fails', async () => {
433
+ vi.spyOn(console, 'error').mockImplementation(() => {})
434
+ const { message, store } = fixture()
435
+
436
+ const handled = await Analytics.handleQueue(
437
+ store,
438
+ {
439
+ messages: [message],
440
+ queue: Analytics.queueName,
441
+ },
442
+ {
443
+ onResult() {
444
+ throw new Error('metrics failed')
445
+ },
446
+ },
447
+ )
448
+
449
+ expect(handled).toBe(true)
450
+ expect(message.ack).toHaveBeenCalledTimes(1)
451
+ expect(message.retry).not.toHaveBeenCalled()
452
+ expect(console.error).toHaveBeenCalledWith(
453
+ 'Analytics queue result callback failed',
454
+ expect.objectContaining({ message: 'metrics failed' }),
455
+ )
397
456
  })
398
457
 
399
458
  test('resolves factory sources at the leaf', async () => {
@@ -135,7 +135,8 @@ export const migrations: readonly Migration[] = [
135
135
  rpc_error_data_code Nullable(String),
136
136
  rpc_error_count UInt16 DEFAULT 0,
137
137
  request_id Nullable(String),
138
- billing_active Nullable(UInt8)
138
+ billing_active Nullable(UInt8),
139
+ timings Map(String, Float64)
139
140
  )
140
141
  ENGINE = MergeTree
141
142
  ORDER BY (timestamp)
@@ -176,6 +177,21 @@ export const migrations: readonly Migration[] = [
176
177
  ADD COLUMN IF NOT EXISTS rpc_error_count UInt16 DEFAULT 0
177
178
  `,
178
179
  },
180
+ {
181
+ name: '0004_request_events_timings',
182
+ // Patches tables created before request timings entered the baseline. Fresh
183
+ // tables skip this ALTER, allowing scoped preview users to migrate.
184
+ guard: `
185
+ SELECT toUInt8(count() = 1) FROM system.columns
186
+ WHERE database = currentDatabase()
187
+ AND table = 'request_events'
188
+ AND name = 'timings'
189
+ `,
190
+ sql: `
191
+ ALTER TABLE request_events
192
+ ADD COLUMN IF NOT EXISTS timings Map(String, Float64)
193
+ `,
194
+ },
179
195
  ]
180
196
 
181
197
  /**
@@ -292,6 +308,7 @@ export async function handleQueue(
292
308
  await RequestEvents.insertMessages(
293
309
  get(source),
294
310
  batch.messages as readonly RequestEvents.insertMessages.Message[],
311
+ { onResult: options.onResult },
295
312
  )
296
313
  return true
297
314
  }
@@ -299,6 +316,8 @@ export async function handleQueue(
299
316
  export declare namespace handleQueue {
300
317
  /** Options for {@link handleQueue}. */
301
318
  type Options = {
319
+ /** Receives the final insert disposition for metrics and error reporting. */
320
+ onResult?: RequestEvents.insertMessages.Options['onResult']
302
321
  /** Queue name to match instead of {@link queueName} (e.g. a per-preview queue). */
303
322
  queue?: string | undefined
304
323
  }
@@ -46,6 +46,8 @@ export type Table = {
46
46
  status: number
47
47
  /** UTC request completion timestamp formatted for ClickHouse DateTime64. */
48
48
  timestamp: string
49
+ /** Longest Server-Timing operation duration per metric name. */
50
+ timings: Record<string, number>
49
51
  }
50
52
 
51
53
  /** One request attribution term for usage reads. */
@@ -214,6 +216,7 @@ export declare namespace createQueueSink {
214
216
  export async function insertMessages(
215
217
  analytics: Analytics.Analytics,
216
218
  messages: readonly insertMessages.Message[],
219
+ options: insertMessages.Options = {},
217
220
  ): Promise<void> {
218
221
  if (messages.length === 0) return
219
222
 
@@ -223,9 +226,19 @@ export async function insertMessages(
223
226
  messages.map((message) => message.body),
224
227
  )
225
228
  for (const message of messages) message.ack()
229
+ reportResult({ messages: messages.length, outcome: 'acked' })
226
230
  } catch (error) {
227
231
  console.error('ClickHouse analytics insert failed', error)
228
232
  for (const message of messages) message.retry()
233
+ reportResult({ cause: error, messages: messages.length, outcome: 'retried' })
234
+ }
235
+
236
+ function reportResult(result: insertMessages.Result) {
237
+ try {
238
+ options.onResult?.(result)
239
+ } catch (error) {
240
+ console.error('Analytics queue result callback failed', error)
241
+ }
229
242
  }
230
243
  }
231
244
 
@@ -239,6 +252,29 @@ export declare namespace insertMessages {
239
252
  /** Marks the message for redelivery. */
240
253
  retry(): void
241
254
  }
255
+
256
+ /** Queue insert observability options. */
257
+ type Options = {
258
+ /** Receives one bounded batch result after messages are acknowledged or retried. */
259
+ onResult?: ((result: Result) => void) | undefined
260
+ }
261
+
262
+ /** Outcome of one analytics insert batch. */
263
+ type Result =
264
+ | {
265
+ /** Number of messages acknowledged. */
266
+ messages: number
267
+ /** Successful queue disposition. */
268
+ outcome: 'acked'
269
+ }
270
+ | {
271
+ /** Original insert failure. */
272
+ cause: unknown
273
+ /** Number of messages marked for retry. */
274
+ messages: number
275
+ /** Failed queue disposition. */
276
+ outcome: 'retried'
277
+ }
242
278
  }
243
279
 
244
280
  /**
@@ -257,7 +293,7 @@ export async function readLastUsedAt(
257
293
  formatDateTime(max(timestamp), '%Y-%m-%dT%H:%i:%S.000Z', 'UTC') AS lastUsedAt
258
294
  FROM ${table}
259
295
  WHERE principal_type = 'api_key'
260
- AND key_id IN (${apiKeyIds.map(literal).join(', ')})
296
+ AND key_id IN (${apiKeyIds.map(ClickHouseValue.literal).join(', ')})
261
297
  GROUP BY key_id
262
298
  `,
263
299
  )
@@ -347,33 +383,33 @@ export async function readProjectUsage(
347
383
  return {
348
384
  byKey: byKey.map((row) => ({
349
385
  apiKeyId: String(row.key_id),
350
- averageDurationMs: number(row.averageDurationMs),
351
- errors: number(row.errors),
352
- requests: number(row.requests),
386
+ averageDurationMs: ClickHouseValue.number(row.averageDurationMs),
387
+ errors: ClickHouseValue.number(row.errors),
388
+ requests: ClickHouseValue.number(row.requests),
353
389
  })),
354
390
  byRoute: byRoute.map((row) => ({
355
- averageDurationMs: number(row.averageDurationMs),
356
- errors: number(row.errors),
357
- requests: number(row.requests),
391
+ averageDurationMs: ClickHouseValue.number(row.averageDurationMs),
392
+ errors: ClickHouseValue.number(row.errors),
393
+ requests: ClickHouseValue.number(row.requests),
358
394
  route: String(row.route),
359
395
  })),
360
396
  byStatus: byStatus.map((row) => ({
361
- requests: number(row.requests),
362
- status: number(row.status),
397
+ requests: ClickHouseValue.number(row.requests),
398
+ status: ClickHouseValue.number(row.status),
363
399
  })),
364
400
  from: options.from,
365
401
  interval: options.interval,
366
402
  series: series.map((row) => ({
367
- errors: number(row.errors),
368
- requests: number(row.requests),
403
+ errors: ClickHouseValue.number(row.errors),
404
+ requests: ClickHouseValue.number(row.requests),
369
405
  time: String(row.time),
370
406
  })),
371
407
  to: options.to,
372
408
  totals: totals[0]
373
409
  ? {
374
- averageDurationMs: number(totals[0].averageDurationMs),
375
- errors: number(totals[0].errors),
376
- requests: number(totals[0].requests),
410
+ averageDurationMs: ClickHouseValue.number(totals[0].averageDurationMs),
411
+ errors: ClickHouseValue.number(totals[0].errors),
412
+ requests: ClickHouseValue.number(totals[0].requests),
377
413
  }
378
414
  : { averageDurationMs: 0, errors: 0, requests: 0 },
379
415
  }
@@ -401,7 +437,10 @@ export async function readErrorBreakdown(
401
437
  LIMIT 25
402
438
  `,
403
439
  )
404
- return rows.map((row) => ({ code: String(row.code), requests: number(row.requests) }))
440
+ return rows.map((row) => ({
441
+ code: String(row.code),
442
+ requests: ClickHouseValue.number(row.requests),
443
+ }))
405
444
  }
406
445
 
407
446
  /** One org's deduped billable request count for a single UTC hour. */
@@ -449,16 +488,16 @@ export async function readBillableCounts(
449
488
  WHERE principal_type = 'api_key'
450
489
  AND org_id IS NOT NULL
451
490
  AND request_id IS NOT NULL
452
- AND key_environment = ${literal(options.environment)}
491
+ AND key_environment = ${ClickHouseValue.literal(options.environment)}
453
492
  ${sandboxGate}
454
- AND timestamp >= parseDateTime64BestEffort(${literal(options.from)}, 3, 'UTC')
455
- AND timestamp < parseDateTime64BestEffort(${literal(options.to)}, 3, 'UTC')
493
+ AND timestamp >= parseDateTime64BestEffort(${ClickHouseValue.literal(options.from)}, 3, 'UTC')
494
+ AND timestamp < parseDateTime64BestEffort(${ClickHouseValue.literal(options.to)}, 3, 'UTC')
456
495
  GROUP BY org_id, toStartOfHour(timestamp)
457
496
  `,
458
497
  )
459
498
  return rows.map((row) => ({
460
499
  bucketStart: String(row.bucketStart),
461
- count: number(row.count),
500
+ count: ClickHouseValue.number(row.count),
462
501
  orgId: String(row.orgId),
463
502
  }))
464
503
  }
@@ -535,7 +574,8 @@ function event(entry: Log.Entry, context: Metrics.cloudflare.Context): Table {
535
574
  rpc_error_data_code: entry.rpc?.dataCode ?? null,
536
575
  service: context.service ?? 'unknown',
537
576
  status: entry.status,
538
- timestamp: timestamp(),
577
+ timestamp: ClickHouseValue.timestamp(),
578
+ timings: entry.timings ?? {},
539
579
  }
540
580
  }
541
581
 
@@ -548,8 +588,8 @@ function usageWhere(options: ProjectUsageOptions) {
548
588
  return [
549
589
  `principal_type = 'api_key'`,
550
590
  `(${attributions})`,
551
- `timestamp >= parseDateTime64BestEffort(${literal(options.from)}, 3, 'UTC')`,
552
- `timestamp <= parseDateTime64BestEffort(${literal(options.to)}, 3, 'UTC')`,
591
+ `timestamp >= parseDateTime64BestEffort(${ClickHouseValue.literal(options.from)}, 3, 'UTC')`,
592
+ `timestamp <= parseDateTime64BestEffort(${ClickHouseValue.literal(options.to)}, 3, 'UTC')`,
553
593
  ].join(' AND ')
554
594
  }
555
595
 
@@ -558,7 +598,7 @@ function attributionWhere(attribution: Attribution, options: ProjectUsageOptions
558
598
  if (!attribution.apiKeyIds?.length) return '0'
559
599
  return [
560
600
  `project_id IS NULL`,
561
- `key_id IN (${attribution.apiKeyIds.map(literal).join(', ')})`,
601
+ `key_id IN (${attribution.apiKeyIds.map(ClickHouseValue.literal).join(', ')})`,
562
602
  ...(attribution.environment === undefined
563
603
  ? []
564
604
  : [keyEnvironmentWhere(attribution.environment, true)]),
@@ -568,10 +608,10 @@ function attributionWhere(attribution: Attribution, options: ProjectUsageOptions
568
608
  // Absent `projectId` scopes to the whole organization (any project).
569
609
  if (attribution.projectId === undefined) {
570
610
  return [
571
- `org_id = ${literal(options.orgId)}`,
611
+ `org_id = ${ClickHouseValue.literal(options.orgId)}`,
572
612
  ...(attribution.apiKeyIds === undefined
573
613
  ? []
574
- : [`key_id IN (${attribution.apiKeyIds.map(literal).join(', ')})`]),
614
+ : [`key_id IN (${attribution.apiKeyIds.map(ClickHouseValue.literal).join(', ')})`]),
575
615
  ...(attribution.environment === undefined
576
616
  ? []
577
617
  : [keyEnvironmentWhere(attribution.environment, false)]),
@@ -579,11 +619,11 @@ function attributionWhere(attribution: Attribution, options: ProjectUsageOptions
579
619
  }
580
620
 
581
621
  return [
582
- `org_id = ${literal(options.orgId)}`,
583
- `project_id = ${literal(attribution.projectId)}`,
622
+ `org_id = ${ClickHouseValue.literal(options.orgId)}`,
623
+ `project_id = ${ClickHouseValue.literal(attribution.projectId)}`,
584
624
  ...(attribution.apiKeyIds === undefined
585
625
  ? []
586
- : [`key_id IN (${attribution.apiKeyIds.map(literal).join(', ')})`]),
626
+ : [`key_id IN (${attribution.apiKeyIds.map(ClickHouseValue.literal).join(', ')})`]),
587
627
  ...(attribution.environment === undefined
588
628
  ? []
589
629
  : [keyEnvironmentWhere(attribution.environment, false)]),
@@ -591,19 +631,21 @@ function attributionWhere(attribution: Attribution, options: ProjectUsageOptions
591
631
  }
592
632
 
593
633
  function keyEnvironmentWhere(environment: Environment, allowLegacyNull: boolean) {
594
- const exact = `key_environment = ${literal(environment)}`
634
+ const exact = `key_environment = ${ClickHouseValue.literal(environment)}`
595
635
  if (!allowLegacyNull) return exact
596
636
  return `(${exact} OR key_environment IS NULL)`
597
637
  }
598
638
 
599
- function literal(value: string) {
600
- return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'")}'`
601
- }
639
+ namespace ClickHouseValue {
640
+ export function literal(value: string) {
641
+ return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'")}'`
642
+ }
602
643
 
603
- function number(value: number | string) {
604
- return Number(value)
605
- }
644
+ export function number(value: number | string) {
645
+ return Number(value)
646
+ }
606
647
 
607
- function timestamp() {
608
- return new Date().toISOString().replace('T', ' ').replace('Z', '')
648
+ export function timestamp() {
649
+ return new Date().toISOString().replace('T', ' ').replace('Z', '')
650
+ }
609
651
  }
@@ -0,0 +1,33 @@
1
+ import * as Zones from './Zones.js'
2
+
3
+ describe('chains', () => {
4
+ test('defines hosted zones', () => {
5
+ expect(Zones.chains).toMatchObject([
6
+ {
7
+ contracts: {
8
+ messenger: { address: '0x254356112cCf6f32fAd84F16CC5E0A0cCA17Beb7' },
9
+ portal: { address: '0x59831A17340EE14FE136d751EfbeA8b630470fD2' },
10
+ },
11
+ id: 421_700_001,
12
+ rpcUrls: {
13
+ default: { http: ['https://rpc-zone-e.testnet.tempo.xyz'] },
14
+ internal: { http: ['https://rpc-zone-e.testnet.tempo.xyz'] },
15
+ },
16
+ sourceId: 42_431,
17
+ },
18
+ {
19
+ contracts: {
20
+ messenger: { address: '0x5A4d000000000000000000000000000000000000' },
21
+ portal: { address: '0x5aD0000000000000000000000000000000000006' },
22
+ },
23
+ id: 421_700_006,
24
+ rpcUrls: {
25
+ default: { http: ['https://rpc-zone-stable-public.devnet.tempoxyz.dev'] },
26
+ internal: { http: ['https://rpc-zone-stable.devnet.tempoxyz.dev'] },
27
+ tidx: { http: ['https://tidx-zone-stable.devnet.tempoxyz.dev'] },
28
+ },
29
+ sourceId: 31_318,
30
+ },
31
+ ])
32
+ })
33
+ })
@@ -0,0 +1,40 @@
1
+ import { defineChain } from 'viem'
2
+ import { tempoDevnet, tempoTestnet } from 'viem/tempo/chains'
3
+
4
+ /** Zone E on Tempo testnet. */
5
+ export const zoneE = defineChain({
6
+ ...tempoTestnet,
7
+ contracts: {
8
+ ...tempoTestnet.contracts,
9
+ messenger: { address: '0x254356112cCf6f32fAd84F16CC5E0A0cCA17Beb7' },
10
+ portal: { address: '0x59831A17340EE14FE136d751EfbeA8b630470fD2' },
11
+ },
12
+ id: 421_700_001,
13
+ name: 'zone-e',
14
+ rpcUrls: {
15
+ default: { http: ['https://rpc-zone-e.testnet.tempo.xyz'] },
16
+ internal: { http: ['https://rpc-zone-e.testnet.tempo.xyz'] },
17
+ },
18
+ sourceId: tempoTestnet.id,
19
+ })
20
+
21
+ /** Stable hosted Zone on Tempo devnet. */
22
+ export const zoneStable = defineChain({
23
+ ...tempoDevnet,
24
+ contracts: {
25
+ ...tempoDevnet.contracts,
26
+ messenger: { address: '0x5A4d000000000000000000000000000000000000' },
27
+ portal: { address: '0x5aD0000000000000000000000000000000000006' },
28
+ },
29
+ id: 421_700_006,
30
+ name: 'zone-stable',
31
+ rpcUrls: {
32
+ default: { http: ['https://rpc-zone-stable-public.devnet.tempoxyz.dev'] },
33
+ internal: { http: ['https://rpc-zone-stable.devnet.tempoxyz.dev'] },
34
+ tidx: { http: ['https://tidx-zone-stable.devnet.tempoxyz.dev'] },
35
+ },
36
+ sourceId: tempoDevnet.id,
37
+ })
38
+
39
+ /** Hosted Zone chains served by the API and admin. */
40
+ export const chains = [zoneE, zoneStable] as const
@@ -3,6 +3,7 @@ import { data, management, mpp, relay } from 'tapimo/apps'
3
3
  import { Hono } from 'hono'
4
4
  import { describeRoute } from 'hono-openapi'
5
5
  import * as TestApp from '../../test/App.js'
6
+ import * as Relay from '../../test/Relay.js'
6
7
 
7
8
  // Each test mounts one group and asserts its routes exist while omitted groups
8
9
  // are absent (404 and not in the document). The management case also locks its
@@ -167,6 +168,7 @@ describe('data()', () => {
167
168
  defaultChainId: 333,
168
169
  rpc,
169
170
  supportedChainIds: [444],
171
+ zones: true,
170
172
  })
171
173
  .route('/', data())
172
174
  .route('/', context)
@@ -183,10 +185,91 @@ describe('data()', () => {
183
185
  444,
184
186
  4217,
185
187
  42431,
188
+ 421700001,
189
+ 421700006,
186
190
  ],
187
191
  }
188
192
  `)
189
193
  })
194
+
195
+ test('keeps RPC and TIDX chain capabilities separate', async () => {
196
+ const both = 421_700_005
197
+ const rpcOnly = 31_318
198
+ const tidxOnly = 421_700_006
199
+ const server = await Relay.createServer((request, response) => {
200
+ response.writeHead(200, { 'content-type': 'application/json' })
201
+ response.end(
202
+ JSON.stringify(
203
+ request.method === 'POST'
204
+ ? { id: 1, jsonrpc: '2.0', result: '0x7a56' }
205
+ : { columns: [], ok: true, row_count: 0, rows: [] },
206
+ ),
207
+ )
208
+ })
209
+
210
+ try {
211
+ const context = new Hono<App.Environment>().get('/context', (c) =>
212
+ c.json({ supportedChainIds: [...c.get('supportedChainIds')].sort((a, b) => a - b) }),
213
+ )
214
+ const app = App.create({
215
+ auth: false,
216
+ db: TestApp.database(),
217
+ rpc: {
218
+ publicZoneUrl: JSON.stringify({
219
+ 421_700_007: 'https://zone-only.public-rpc.test',
220
+ }),
221
+ url: JSON.stringify({ [both]: server.url, [rpcOnly]: server.url }),
222
+ },
223
+ })
224
+ .route(
225
+ '/',
226
+ data({
227
+ tidx: {
228
+ baseUrl: JSON.stringify({ [both]: server.url, [tidxOnly]: server.url }),
229
+ },
230
+ }),
231
+ )
232
+ .route('/', context)
233
+
234
+ expect(await (await app.request('/context')).json()).toMatchInlineSnapshot(`
235
+ {
236
+ "supportedChainIds": [
237
+ 4217,
238
+ 31318,
239
+ 42431,
240
+ 421700005,
241
+ 421700006,
242
+ ],
243
+ }
244
+ `)
245
+
246
+ for (const chainId of [rpcOnly, tidxOnly]) {
247
+ const response = await app.request(`/v1/blocks/latest?chainId=${chainId}`)
248
+ const body = (await response.json()) as { error: { code: string } }
249
+ expect(response.status).toBe(400)
250
+ expect(body.error.code).toBe('chain_id_unsupported')
251
+ }
252
+
253
+ const response_both = await app.request(`/v1/blocks/not-a-block?chainId=${both}`)
254
+ const body_both = (await response_both.json()) as { error: { code: string } }
255
+ expect(response_both.status).toBe(400)
256
+ expect(body_both.error.code).toBe('block_invalid')
257
+
258
+ const response_rpc = await app.request(`/rpc/${rpcOnly}`, {
259
+ body: JSON.stringify({ id: 1, jsonrpc: '2.0', method: 'eth_chainId' }),
260
+ headers: { 'content-type': 'application/json' },
261
+ method: 'POST',
262
+ })
263
+ expect(response_rpc.status).toBe(200)
264
+
265
+ const response_tidx = await app.request(
266
+ `/v1/indexer/query?chainId=${tidxOnly}&sql=select%201`,
267
+ )
268
+ expect(response_tidx.status).toBe(200)
269
+ } finally {
270
+ await server.closeAsync()
271
+ }
272
+ })
190
273
  })
191
274
 
192
275
  describe('relay()', () => {
@@ -211,7 +294,7 @@ describe('relay()', () => {
211
294
 
212
295
  describe('mpp()', () => {
213
296
  test('mounts documented MPP routes independently', async () => {
214
- const app = App.create({ db: TestApp.database() }).route('/', mpp())
297
+ const app = App.create({ db: TestApp.database() }).route('/', mpp({ state: Store.memory() }))
215
298
 
216
299
  expect((await paths(app)).some((path) => path.startsWith('/v1/mpp'))).toBe(true)
217
300
  expect((await app.request('/rpc/relay')).status).toBe(404)