tapimo 0.5.3 → 0.7.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 (376) hide show
  1. package/dist/App.d.ts +15830 -7220
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +9 -1
  4. package/dist/App.js.map +1 -1
  5. package/dist/Scope.d.ts +4 -0
  6. package/dist/Scope.d.ts.map +1 -1
  7. package/dist/Scope.js +5 -0
  8. package/dist/Scope.js.map +1 -1
  9. package/dist/admin/App.d.ts +1011 -412
  10. package/dist/admin/App.d.ts.map +1 -1
  11. package/dist/admin/App.js +4 -0
  12. package/dist/admin/App.js.map +1 -1
  13. package/dist/admin/apps/api-keys.d.ts +2 -1
  14. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  15. package/dist/admin/apps/early-access.d.ts +148 -0
  16. package/dist/admin/apps/early-access.d.ts.map +1 -0
  17. package/dist/admin/apps/early-access.js +133 -0
  18. package/dist/admin/apps/early-access.js.map +1 -0
  19. package/dist/admin/apps/organizations.d.ts +124 -1
  20. package/dist/admin/apps/organizations.d.ts.map +1 -1
  21. package/dist/admin/apps/organizations.js +97 -6
  22. package/dist/admin/apps/organizations.js.map +1 -1
  23. package/dist/admin/apps/verified-tokens.d.ts +526 -1
  24. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  25. package/dist/admin/apps/verified-tokens.js +214 -1
  26. package/dist/admin/apps/verified-tokens.js.map +1 -1
  27. package/dist/admin/ui.generated.d.ts +1 -1
  28. package/dist/admin/ui.generated.d.ts.map +1 -1
  29. package/dist/admin/ui.generated.js +95 -75
  30. package/dist/admin/ui.generated.js.map +1 -1
  31. package/dist/analytics/Analytics.d.ts.map +1 -1
  32. package/dist/analytics/Analytics.js +20 -0
  33. package/dist/analytics/Analytics.js.map +1 -1
  34. package/dist/analytics/tables/requestEvents.d.ts +18 -0
  35. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  36. package/dist/analytics/tables/requestEvents.js +36 -7
  37. package/dist/analytics/tables/requestEvents.js.map +1 -1
  38. package/dist/apps/data/App.d.ts +6260 -4924
  39. package/dist/apps/data/App.d.ts.map +1 -1
  40. package/dist/apps/data/App.js +11 -6
  41. package/dist/apps/data/App.js.map +1 -1
  42. package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
  43. package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
  44. package/dist/apps/data/FundingQuoteProviders.js +194 -16
  45. package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
  46. package/dist/apps/data/FxOracle.d.ts +71 -0
  47. package/dist/apps/data/FxOracle.d.ts.map +1 -0
  48. package/dist/apps/data/FxOracle.js +97 -0
  49. package/dist/apps/data/FxOracle.js.map +1 -0
  50. package/dist/apps/data/index.d.ts +1 -0
  51. package/dist/apps/data/index.d.ts.map +1 -1
  52. package/dist/apps/data/index.js +1 -0
  53. package/dist/apps/data/index.js.map +1 -1
  54. package/dist/apps/data/routes/activities.d.ts +3599 -1382
  55. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  56. package/dist/apps/data/routes/activities.js +250 -88
  57. package/dist/apps/data/routes/activities.js.map +1 -1
  58. package/dist/apps/data/routes/addresses.d.ts +872 -251
  59. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  60. package/dist/apps/data/routes/addresses.js +11 -9
  61. package/dist/apps/data/routes/addresses.js.map +1 -1
  62. package/dist/apps/data/routes/balances.d.ts +77 -26
  63. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  64. package/dist/apps/data/routes/balances.js +88 -45
  65. package/dist/apps/data/routes/balances.js.map +1 -1
  66. package/dist/apps/data/routes/blocks.d.ts +39 -39
  67. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  68. package/dist/apps/data/routes/exchanges.d.ts +856 -105
  69. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  70. package/dist/apps/data/routes/exchanges.js +518 -76
  71. package/dist/apps/data/routes/exchanges.js.map +1 -1
  72. package/dist/apps/data/routes/fee-amm.d.ts +81 -67
  73. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  74. package/dist/apps/data/routes/fee-amm.js +76 -91
  75. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  76. package/dist/apps/data/routes/funding.d.ts +80 -36
  77. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  78. package/dist/apps/data/routes/funding.js +65 -31
  79. package/dist/apps/data/routes/funding.js.map +1 -1
  80. package/dist/apps/data/routes/receipts.d.ts +392 -315
  81. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  82. package/dist/apps/data/routes/receipts.js +152 -77
  83. package/dist/apps/data/routes/receipts.js.map +1 -1
  84. package/dist/apps/data/routes/tokens.d.ts +167 -174
  85. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  86. package/dist/apps/data/routes/tokens.js +15 -13
  87. package/dist/apps/data/routes/tokens.js.map +1 -1
  88. package/dist/apps/data/routes/transactions.d.ts +277 -536
  89. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  90. package/dist/apps/data/routes/transactions.js +96 -77
  91. package/dist/apps/data/routes/transactions.js.map +1 -1
  92. package/dist/apps/data/routes/transfers.d.ts +157 -81
  93. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  94. package/dist/apps/data/routes/transfers.js +272 -130
  95. package/dist/apps/data/routes/transfers.js.map +1 -1
  96. package/dist/apps/data/routes/valuation.d.ts +307 -0
  97. package/dist/apps/data/routes/valuation.d.ts.map +1 -0
  98. package/dist/apps/data/routes/valuation.js +292 -0
  99. package/dist/apps/data/routes/valuation.js.map +1 -0
  100. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  101. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  102. package/dist/apps/data/routes/verified-tokens.js +7 -5
  103. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  104. package/dist/apps/data/routes/webhooks.d.ts +103 -123
  105. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  106. package/dist/apps/data/routes/webhooks.js +124 -25
  107. package/dist/apps/data/routes/webhooks.js.map +1 -1
  108. package/dist/apps/index.d.ts +2 -1
  109. package/dist/apps/index.d.ts.map +1 -1
  110. package/dist/apps/index.js +2 -1
  111. package/dist/apps/index.js.map +1 -1
  112. package/dist/apps/management/App.d.ts +8554 -1692
  113. package/dist/apps/management/App.d.ts.map +1 -1
  114. package/dist/apps/management/App.js +12 -1
  115. package/dist/apps/management/App.js.map +1 -1
  116. package/dist/apps/management/routes/api-keys.d.ts +7 -0
  117. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  118. package/dist/apps/management/routes/api-keys.js +17 -3
  119. package/dist/apps/management/routes/api-keys.js.map +1 -1
  120. package/dist/apps/management/routes/billing.d.ts +157 -162
  121. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  122. package/dist/apps/management/routes/billing.js +31 -23
  123. package/dist/apps/management/routes/billing.js.map +1 -1
  124. package/dist/apps/management/routes/faucet.d.ts +232 -0
  125. package/dist/apps/management/routes/faucet.d.ts.map +1 -0
  126. package/dist/apps/management/routes/faucet.js +154 -0
  127. package/dist/apps/management/routes/faucet.js.map +1 -0
  128. package/dist/apps/management/routes/invitations.d.ts +60 -60
  129. package/dist/apps/management/routes/invite-links.d.ts +49 -20
  130. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  131. package/dist/apps/management/routes/invite-links.js +26 -1
  132. package/dist/apps/management/routes/invite-links.js.map +1 -1
  133. package/dist/apps/management/routes/me.d.ts +6 -6
  134. package/dist/apps/management/routes/members.d.ts +6 -6
  135. package/dist/apps/management/routes/orgs.d.ts +42 -42
  136. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  137. package/dist/apps/management/routes/orgs.js +5 -0
  138. package/dist/apps/management/routes/orgs.js.map +1 -1
  139. package/dist/apps/management/routes/projects.d.ts +44 -44
  140. package/dist/apps/management/routes/usage.d.ts +3 -0
  141. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  142. package/dist/apps/management/routes/usage.js +4 -0
  143. package/dist/apps/management/routes/usage.js.map +1 -1
  144. package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
  145. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
  146. package/dist/apps/management/routes/verified-token-requests.js +271 -0
  147. package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
  148. package/dist/apps/management/routes/webhooks.d.ts +6977 -0
  149. package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
  150. package/dist/apps/management/routes/webhooks.js +573 -0
  151. package/dist/apps/management/routes/webhooks.js.map +1 -0
  152. package/dist/apps/mpp/App.d.ts +363 -0
  153. package/dist/apps/mpp/App.d.ts.map +1 -0
  154. package/dist/apps/mpp/App.js +72 -0
  155. package/dist/apps/mpp/App.js.map +1 -0
  156. package/dist/apps/mpp/Mpp.d.ts +178 -0
  157. package/dist/apps/mpp/Mpp.d.ts.map +1 -0
  158. package/dist/apps/mpp/Mpp.js +183 -0
  159. package/dist/apps/mpp/Mpp.js.map +1 -0
  160. package/dist/apps/mpp/index.d.ts +3 -0
  161. package/dist/apps/mpp/index.d.ts.map +1 -0
  162. package/dist/apps/mpp/index.js +3 -0
  163. package/dist/apps/mpp/index.js.map +1 -0
  164. package/dist/apps/relay/App.d.ts.map +1 -1
  165. package/dist/apps/relay/App.js +56 -9
  166. package/dist/apps/relay/App.js.map +1 -1
  167. package/dist/db/Db.d.ts +6 -0
  168. package/dist/db/Db.d.ts.map +1 -1
  169. package/dist/db/Db.js +110 -0
  170. package/dist/db/Db.js.map +1 -1
  171. package/dist/db/Schema.d.ts +53 -0
  172. package/dist/db/Schema.d.ts.map +1 -1
  173. package/dist/db/Schema.js +56 -0
  174. package/dist/db/Schema.js.map +1 -1
  175. package/dist/db/tables/earlyAccess.d.ts +50 -0
  176. package/dist/db/tables/earlyAccess.d.ts.map +1 -0
  177. package/dist/db/tables/earlyAccess.js +63 -0
  178. package/dist/db/tables/earlyAccess.js.map +1 -0
  179. package/dist/db/tables/enabledBillingSources.d.ts +73 -0
  180. package/dist/db/tables/enabledBillingSources.d.ts.map +1 -0
  181. package/dist/db/tables/enabledBillingSources.js +69 -0
  182. package/dist/db/tables/enabledBillingSources.js.map +1 -0
  183. package/dist/db/tables/invitations.d.ts.map +1 -1
  184. package/dist/db/tables/invitations.js +3 -0
  185. package/dist/db/tables/invitations.js.map +1 -1
  186. package/dist/db/tables/inviteLinks.d.ts +10 -2
  187. package/dist/db/tables/inviteLinks.d.ts.map +1 -1
  188. package/dist/db/tables/inviteLinks.js +10 -1
  189. package/dist/db/tables/inviteLinks.js.map +1 -1
  190. package/dist/db/tables/organizations.d.ts +5 -2
  191. package/dist/db/tables/organizations.d.ts.map +1 -1
  192. package/dist/db/tables/organizations.js +13 -2
  193. package/dist/db/tables/organizations.js.map +1 -1
  194. package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
  195. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  196. package/dist/db/tables/sponsoredTransactions.js +2 -0
  197. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  198. package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
  199. package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
  200. package/dist/db/tables/verifiedTokenRequests.js +120 -0
  201. package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
  202. package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
  203. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  204. package/dist/db/tables/webhookSubscriptions.js +16 -0
  205. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  206. package/dist/handlers/internal/utils.d.ts +1 -16
  207. package/dist/handlers/internal/utils.d.ts.map +1 -1
  208. package/dist/handlers/internal/utils.js +17 -6
  209. package/dist/handlers/internal/utils.js.map +1 -1
  210. package/dist/handlers/relay.d.ts.map +1 -1
  211. package/dist/handlers/relay.js +37 -5
  212. package/dist/handlers/relay.js.map +1 -1
  213. package/dist/internal/Auth.d.ts +11 -2
  214. package/dist/internal/Auth.d.ts.map +1 -1
  215. package/dist/internal/Auth.js +14 -47
  216. package/dist/internal/Auth.js.map +1 -1
  217. package/dist/internal/FundingQuotes.d.ts +147 -47
  218. package/dist/internal/FundingQuotes.d.ts.map +1 -1
  219. package/dist/internal/FundingQuotes.js +119 -33
  220. package/dist/internal/FundingQuotes.js.map +1 -1
  221. package/dist/internal/Log.d.ts +37 -5
  222. package/dist/internal/Log.d.ts.map +1 -1
  223. package/dist/internal/Log.js +52 -3
  224. package/dist/internal/Log.js.map +1 -1
  225. package/dist/internal/MetricSink.d.ts.map +1 -1
  226. package/dist/internal/MetricSink.js +24 -0
  227. package/dist/internal/MetricSink.js.map +1 -1
  228. package/dist/internal/OpenApi.d.ts +2 -2
  229. package/dist/internal/OpenApi.d.ts.map +1 -1
  230. package/dist/internal/OpenApi.js +3 -0
  231. package/dist/internal/OpenApi.js.map +1 -1
  232. package/dist/internal/Response.d.ts +2 -2
  233. package/dist/internal/Response.d.ts.map +1 -1
  234. package/dist/internal/Response.js +12 -4
  235. package/dist/internal/Response.js.map +1 -1
  236. package/dist/internal/Schema.d.ts +14 -5
  237. package/dist/internal/Schema.d.ts.map +1 -1
  238. package/dist/internal/Schema.js +23 -5
  239. package/dist/internal/Schema.js.map +1 -1
  240. package/dist/internal/Value.d.ts +18 -0
  241. package/dist/internal/Value.d.ts.map +1 -1
  242. package/dist/internal/Value.js +11 -1
  243. package/dist/internal/Value.js.map +1 -1
  244. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  245. package/dist/internal/VerifiedTokens.js +10 -1
  246. package/dist/internal/VerifiedTokens.js.map +1 -1
  247. package/dist/internal/Webhooks.d.ts +24 -3
  248. package/dist/internal/Webhooks.d.ts.map +1 -1
  249. package/dist/internal/Webhooks.js +34 -8
  250. package/dist/internal/Webhooks.js.map +1 -1
  251. package/package.json +7 -2
  252. package/src/App.test.ts +9 -4
  253. package/src/App.ts +23 -3
  254. package/src/Client.test-d.ts +733 -20
  255. package/src/Scope.ts +5 -0
  256. package/src/admin/App.test.ts +4 -0
  257. package/src/admin/App.ts +4 -0
  258. package/src/admin/apps/early-access.test.ts +125 -0
  259. package/src/admin/apps/early-access.ts +176 -0
  260. package/src/admin/apps/organizations.test.ts +86 -2
  261. package/src/admin/apps/organizations.ts +155 -31
  262. package/src/admin/apps/scopes.test.ts +5 -0
  263. package/src/admin/apps/verified-tokens.test.ts +201 -0
  264. package/src/admin/apps/verified-tokens.ts +532 -286
  265. package/src/admin/ui/plugin.ts +2 -1
  266. package/src/admin/ui/src/lib/early-access.ts +63 -0
  267. package/src/admin/ui/src/lib/organizations.test.ts +81 -1
  268. package/src/admin/ui/src/lib/organizations.ts +92 -0
  269. package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
  270. package/src/admin/ui/src/routeTree.gen.ts +33 -2
  271. package/src/admin/ui/src/routes/__root.tsx +2 -1
  272. package/src/admin/ui/src/routes/api-keys.tsx +1 -1
  273. package/src/admin/ui/src/routes/early-access.tsx +162 -0
  274. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +103 -0
  275. package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
  276. package/src/admin/ui.generated.ts +95 -94
  277. package/src/analytics/Analytics.test.ts +83 -0
  278. package/src/analytics/Analytics.ts +20 -0
  279. package/src/analytics/tables/requestEvents.ts +60 -7
  280. package/src/apps/composition.test.ts +11 -2
  281. package/src/apps/data/App.test.ts +1 -1
  282. package/src/apps/data/App.ts +22 -14
  283. package/src/apps/data/FundingQuoteProviders.test.ts +297 -4
  284. package/src/apps/data/FundingQuoteProviders.ts +255 -29
  285. package/src/apps/data/FxOracle.test.ts +118 -0
  286. package/src/apps/data/FxOracle.ts +153 -0
  287. package/src/apps/data/index.ts +1 -0
  288. package/src/apps/data/routes/activities.test.ts +177 -3
  289. package/src/apps/data/routes/activities.ts +441 -132
  290. package/src/apps/data/routes/addresses.ts +19 -9
  291. package/src/apps/data/routes/balances.test.ts +148 -11
  292. package/src/apps/data/routes/balances.ts +140 -51
  293. package/src/apps/data/routes/exchanges.test.ts +544 -9
  294. package/src/apps/data/routes/exchanges.ts +690 -103
  295. package/src/apps/data/routes/fee-amm.test.ts +47 -23
  296. package/src/apps/data/routes/fee-amm.ts +98 -119
  297. package/src/apps/data/routes/funding.test.ts +113 -8
  298. package/src/apps/data/routes/funding.ts +77 -51
  299. package/src/apps/data/routes/receipts.test.ts +129 -23
  300. package/src/apps/data/routes/receipts.ts +205 -100
  301. package/src/apps/data/routes/tokens.test.ts +43 -0
  302. package/src/apps/data/routes/tokens.ts +28 -13
  303. package/src/apps/data/routes/transactions.test.ts +72 -19
  304. package/src/apps/data/routes/transactions.ts +162 -92
  305. package/src/apps/data/routes/transfers.test.ts +341 -31
  306. package/src/apps/data/routes/transfers.ts +358 -158
  307. package/src/apps/data/routes/valuation.test.ts +437 -0
  308. package/src/apps/data/routes/valuation.ts +423 -0
  309. package/src/apps/data/routes/verified-tokens.ts +14 -2
  310. package/src/apps/data/routes/webhooks.test.ts +56 -8
  311. package/src/apps/data/routes/webhooks.ts +144 -27
  312. package/src/apps/index.ts +2 -1
  313. package/src/apps/management/App.ts +13 -0
  314. package/src/apps/management/routes/api-keys.test.ts +14 -0
  315. package/src/apps/management/routes/api-keys.ts +27 -3
  316. package/src/apps/management/routes/billing.test.ts +152 -20
  317. package/src/apps/management/routes/billing.ts +34 -18
  318. package/src/apps/management/routes/faucet.test.ts +87 -0
  319. package/src/apps/management/routes/faucet.ts +201 -0
  320. package/src/apps/management/routes/invite-links.test.ts +117 -0
  321. package/src/apps/management/routes/invite-links.ts +43 -1
  322. package/src/apps/management/routes/me.test.ts +9 -99
  323. package/src/apps/management/routes/orgs.test.ts +45 -2
  324. package/src/apps/management/routes/orgs.ts +6 -0
  325. package/src/apps/management/routes/scopes.test.ts +1 -0
  326. package/src/apps/management/routes/usage.test.ts +6 -0
  327. package/src/apps/management/routes/usage.ts +7 -0
  328. package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
  329. package/src/apps/management/routes/verified-token-requests.ts +397 -0
  330. package/src/apps/management/routes/webhooks.test.ts +426 -0
  331. package/src/apps/management/routes/webhooks.ts +672 -0
  332. package/src/apps/mpp/App.ts +86 -0
  333. package/src/apps/mpp/Mpp.test.ts +193 -0
  334. package/src/apps/mpp/Mpp.ts +353 -0
  335. package/src/apps/mpp/index.ts +2 -0
  336. package/src/apps/mpp/internal/Adapter.ts +11 -0
  337. package/src/apps/mpp/internal/Error.ts +9 -0
  338. package/src/apps/mpp/internal/Idempotency.ts +7 -0
  339. package/src/apps/mpp/internal/Screening.ts +10 -0
  340. package/src/apps/relay/App.test.ts +88 -6
  341. package/src/apps/relay/App.ts +61 -9
  342. package/src/db/Db.test.ts +19 -0
  343. package/src/db/Db.ts +125 -0
  344. package/src/db/Schema.ts +68 -0
  345. package/src/db/tables/earlyAccess.ts +86 -0
  346. package/src/db/tables/enabledBillingSources.test.ts +303 -0
  347. package/src/db/tables/enabledBillingSources.ts +118 -0
  348. package/src/db/tables/invitations.ts +3 -0
  349. package/src/db/tables/inviteLinks.ts +22 -3
  350. package/src/db/tables/organizations.test.ts +103 -0
  351. package/src/db/tables/organizations.ts +18 -2
  352. package/src/db/tables/sponsoredTransactions.ts +4 -0
  353. package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
  354. package/src/db/tables/verifiedTokenRequests.ts +182 -0
  355. package/src/db/tables/webhookSubscriptions.ts +31 -0
  356. package/src/handlers/internal/utils.ts +22 -6
  357. package/src/handlers/relay.errors.test.ts +153 -0
  358. package/src/handlers/relay.ts +42 -7
  359. package/src/internal/Auth.test.ts +3 -3
  360. package/src/internal/Auth.ts +15 -47
  361. package/src/internal/FundingQuotes.test.ts +161 -6
  362. package/src/internal/FundingQuotes.ts +141 -39
  363. package/src/internal/Log.test-d.ts +21 -0
  364. package/src/internal/Log.test.ts +141 -0
  365. package/src/internal/Log.ts +93 -6
  366. package/src/internal/MetricSink.test.ts +215 -0
  367. package/src/internal/MetricSink.ts +24 -0
  368. package/src/internal/OpenApi.ts +3 -0
  369. package/src/internal/Response.test.ts +28 -0
  370. package/src/internal/Response.ts +12 -4
  371. package/src/internal/Schema.ts +50 -5
  372. package/src/internal/Value.test.ts +20 -0
  373. package/src/internal/Value.ts +24 -1
  374. package/src/internal/VerifiedTokens.ts +9 -1
  375. package/src/internal/Webhooks.test.ts +140 -0
  376. package/src/internal/Webhooks.ts +53 -9
@@ -397,6 +397,7 @@ export async function usage(db: Db.Db, options: usage.Options): Promise<usage.Bu
397
397
  .select([
398
398
  sql<string>`to_char(${bucket}, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`.as('timestamp'),
399
399
  sql<string>`count(*)`.as('count'),
400
+ sql<string>`count(*) filter (where status = 'failed')`.as('failed'),
400
401
  sql<string>`coalesce(sum(case when status = 'finalized' then fee_amount::numeric when status = 'pending' then fee_max::numeric else 0 end), 0)`.as('feeTotal'), // prettier-ignore
401
402
  ])
402
403
  .where('orgId', '=', orgId)
@@ -410,6 +411,7 @@ export async function usage(db: Db.Db, options: usage.Options): Promise<usage.Bu
410
411
  const rows = await query.execute()
411
412
  return rows.map((row) => ({
412
413
  count: Number(row.count),
414
+ failed: Number(row.failed),
413
415
  feeTotal: BigInt(row.feeTotal),
414
416
  timestamp: row.timestamp,
415
417
  }))
@@ -420,6 +422,8 @@ export declare namespace usage {
420
422
  type Bucket = {
421
423
  /** Sponsored transactions recorded in the bucket, any status. */
422
424
  count: number
425
+ /** Sponsored transactions in the bucket whose status is `failed`. */
426
+ failed: number
423
427
  /** Committed fees in fee-token base units: finalized fees plus pending caps. */
424
428
  feeTotal: bigint
425
429
  /** Bucket start (ISO 8601), aligned to UTC calendar boundaries. */
@@ -0,0 +1,200 @@
1
+ import * as TestApp from '../../../test/App.js'
2
+ import * as Organizations from './organizations.js'
3
+ import * as VerifiedTokenRequests from './verifiedTokenRequests.js'
4
+
5
+ const input = {
6
+ address: '0x20c00000000000000000000000000000000000aa',
7
+ chainId: 42431,
8
+ currency: 'USD',
9
+ decimals: 6,
10
+ name: 'Test USD',
11
+ orgId: 'org_1a2b3c4d5e6f7g8h9j0k1m2n',
12
+ requestedBy: 'usr_1a2b3c4d5e6f7g8h9j0k1m2n',
13
+ symbol: 'tUSD',
14
+ } as const
15
+
16
+ describe('create', () => {
17
+ test('inserts a pending request', async () => {
18
+ const db = TestApp.database()
19
+ const record = await VerifiedTokenRequests.create(db, { ...input, note: 'We are the issuer.' })
20
+ expect(record).toBeDefined()
21
+ const { createdAt, id, updatedAt, ...rest } = record!
22
+ expect(id).toMatch(/^vtr_/)
23
+ expect(Date.parse(createdAt)).not.toBeNaN()
24
+ expect(updatedAt).toBe(createdAt)
25
+ expect(rest).toMatchInlineSnapshot(`
26
+ {
27
+ "address": "0x20c00000000000000000000000000000000000aa",
28
+ "chainId": 42431,
29
+ "currency": "USD",
30
+ "decimals": 6,
31
+ "logo": null,
32
+ "logoUri": null,
33
+ "name": "Test USD",
34
+ "note": "We are the issuer.",
35
+ "orgId": "org_1a2b3c4d5e6f7g8h9j0k1m2n",
36
+ "requestedBy": "usr_1a2b3c4d5e6f7g8h9j0k1m2n",
37
+ "reviewNote": null,
38
+ "reviewedAt": null,
39
+ "reviewedBy": null,
40
+ "status": "pending",
41
+ "symbol": "tUSD",
42
+ }
43
+ `)
44
+ })
45
+
46
+ test('a duplicate pending (chain, address) yields undefined, even cross-org', async () => {
47
+ const db = TestApp.database()
48
+ await VerifiedTokenRequests.create(db, input)
49
+ const duplicate = await VerifiedTokenRequests.create(db, {
50
+ ...input,
51
+ orgId: 'org_2b3c4d5e6f7g8h9j0k1m2n3p',
52
+ })
53
+ expect(duplicate).toBeUndefined()
54
+ })
55
+
56
+ test('a reviewed request frees the (chain, address) slot', async () => {
57
+ const db = TestApp.database()
58
+ const first = await VerifiedTokenRequests.create(db, input)
59
+ await VerifiedTokenRequests.review(db, first!.id, {
60
+ reviewedBy: 'admin@tempo.xyz',
61
+ status: 'denied',
62
+ })
63
+ const second = await VerifiedTokenRequests.create(db, input)
64
+ expect(second).toBeDefined()
65
+ })
66
+
67
+ test('the same address on another chain is independent', async () => {
68
+ const db = TestApp.database()
69
+ await VerifiedTokenRequests.create(db, input)
70
+ const other = await VerifiedTokenRequests.create(db, { ...input, chainId: 4217 })
71
+ expect(other).toBeDefined()
72
+ })
73
+ })
74
+
75
+ describe('list', () => {
76
+ test('returns only the organization, newest first', async () => {
77
+ const db = TestApp.database()
78
+ const first = await VerifiedTokenRequests.create(db, input)
79
+ const second = await VerifiedTokenRequests.create(db, {
80
+ ...input,
81
+ address: '0x20c00000000000000000000000000000000000bb',
82
+ symbol: 'tEUR',
83
+ })
84
+ await VerifiedTokenRequests.create(db, {
85
+ ...input,
86
+ address: '0x20c00000000000000000000000000000000000cc',
87
+ orgId: 'org_2b3c4d5e6f7g8h9j0k1m2n3p',
88
+ symbol: 'tGBP',
89
+ })
90
+ const records = await VerifiedTokenRequests.list(db, input.orgId)
91
+ expect(records.map(({ id }) => id).sort()).toEqual([first!.id, second!.id].sort())
92
+ expect(records.every(({ orgId }) => orgId === input.orgId)).toBe(true)
93
+ })
94
+ })
95
+
96
+ describe('listByStatus', () => {
97
+ test('filters by status and joins the current org name', async () => {
98
+ const db = TestApp.database()
99
+ const org = await Organizations.create(db, { name: 'Acme' })
100
+ const pending = await VerifiedTokenRequests.create(db, { ...input, orgId: org.id })
101
+ const denied = await VerifiedTokenRequests.create(db, {
102
+ ...input,
103
+ address: '0x20c00000000000000000000000000000000000bb',
104
+ symbol: 'tEUR',
105
+ })
106
+ await VerifiedTokenRequests.review(db, denied!.id, {
107
+ reviewedBy: 'admin@tempo.xyz',
108
+ status: 'denied',
109
+ })
110
+
111
+ const queue = await VerifiedTokenRequests.listByStatus(db, 'pending')
112
+ expect(queue.map(({ id, orgName }) => ({ id, orgName }))).toEqual([
113
+ { id: pending!.id, orgName: 'Acme' },
114
+ ])
115
+ // The denied row's org has no organizations row; the join yields null.
116
+ const reviewed = await VerifiedTokenRequests.listByStatus(db, 'denied')
117
+ expect(reviewed.map(({ id, orgName }) => ({ id, orgName }))).toEqual([
118
+ { id: denied!.id, orgName: null },
119
+ ])
120
+ })
121
+ })
122
+
123
+ describe('countPending', () => {
124
+ test('counts only the organization pending requests', async () => {
125
+ const db = TestApp.database()
126
+ await VerifiedTokenRequests.create(db, input)
127
+ const denied = await VerifiedTokenRequests.create(db, {
128
+ ...input,
129
+ address: '0x20c00000000000000000000000000000000000bb',
130
+ symbol: 'tEUR',
131
+ })
132
+ await VerifiedTokenRequests.review(db, denied!.id, {
133
+ reviewedBy: 'admin@tempo.xyz',
134
+ status: 'denied',
135
+ })
136
+ await VerifiedTokenRequests.create(db, {
137
+ ...input,
138
+ address: '0x20c00000000000000000000000000000000000cc',
139
+ orgId: 'org_2b3c4d5e6f7g8h9j0k1m2n3p',
140
+ symbol: 'tGBP',
141
+ })
142
+ expect(await VerifiedTokenRequests.countPending(db, input.orgId)).toBe(1)
143
+ })
144
+ })
145
+
146
+ describe('remove', () => {
147
+ test('deletes only in-org pending requests', async () => {
148
+ const db = TestApp.database()
149
+ const record = await VerifiedTokenRequests.create(db, input)
150
+ expect(
151
+ await VerifiedTokenRequests.remove(db, 'org_2b3c4d5e6f7g8h9j0k1m2n3p', record!.id),
152
+ ).toBeUndefined()
153
+ expect(await VerifiedTokenRequests.remove(db, input.orgId, record!.id)).toBeDefined()
154
+ expect(await VerifiedTokenRequests.get(db, record!.id)).toBeUndefined()
155
+ })
156
+
157
+ test('leaves reviewed requests in place', async () => {
158
+ const db = TestApp.database()
159
+ const record = await VerifiedTokenRequests.create(db, input)
160
+ await VerifiedTokenRequests.review(db, record!.id, {
161
+ reviewedBy: 'admin@tempo.xyz',
162
+ status: 'approved',
163
+ })
164
+ expect(await VerifiedTokenRequests.remove(db, input.orgId, record!.id)).toBeUndefined()
165
+ expect(await VerifiedTokenRequests.get(db, record!.id)).toBeDefined()
166
+ })
167
+ })
168
+
169
+ describe('review', () => {
170
+ test('marks a pending request with reviewer identity', async () => {
171
+ const db = TestApp.database()
172
+ const record = await VerifiedTokenRequests.create(db, input)
173
+ const reviewed = await VerifiedTokenRequests.review(db, record!.id, {
174
+ reviewNote: 'Logo unreachable.',
175
+ reviewedBy: 'admin@tempo.xyz',
176
+ status: 'denied',
177
+ })
178
+ expect(reviewed).toMatchObject({
179
+ reviewNote: 'Logo unreachable.',
180
+ reviewedBy: 'admin@tempo.xyz',
181
+ status: 'denied',
182
+ })
183
+ expect(Date.parse(reviewed!.reviewedAt!)).not.toBeNaN()
184
+ })
185
+
186
+ test('yields undefined once reviewed', async () => {
187
+ const db = TestApp.database()
188
+ const record = await VerifiedTokenRequests.create(db, input)
189
+ await VerifiedTokenRequests.review(db, record!.id, {
190
+ reviewedBy: 'admin@tempo.xyz',
191
+ status: 'approved',
192
+ })
193
+ expect(
194
+ await VerifiedTokenRequests.review(db, record!.id, {
195
+ reviewedBy: 'admin@tempo.xyz',
196
+ status: 'denied',
197
+ }),
198
+ ).toBeUndefined()
199
+ })
200
+ })
@@ -0,0 +1,182 @@
1
+ import { type Selectable, sql } from 'kysely'
2
+
3
+ import * as Id from '../../internal/Id.js'
4
+ import type * as Db from '../Db.js'
5
+ import type * as db_Schema from '../Schema.js'
6
+
7
+ /** Columns of the `verified_token_requests` table. */
8
+ export type Table = db_Schema.VerifiedTokenRequest
9
+ /** A stored verification request. */
10
+ export type Record = Selectable<Table>
11
+ /** Review status of a request. */
12
+ export type Status = Record['status']
13
+
14
+ /**
15
+ * Inserts a pending request; `undefined` when a pending request for
16
+ * (chainId, address) already exists.
17
+ */
18
+ export function create(db: Db.Db, input: create.Input): Promise<Record | undefined> {
19
+ const now = new Date().toISOString()
20
+ return db.kysely
21
+ .insertInto('verified_token_requests')
22
+ .values({
23
+ address: input.address,
24
+ chainId: input.chainId,
25
+ createdAt: now,
26
+ currency: input.currency,
27
+ decimals: input.decimals,
28
+ id: Id.generate('vtr'),
29
+ logo: input.logo ?? null,
30
+ logoUri: input.logoUri ?? null,
31
+ name: input.name,
32
+ note: input.note ?? null,
33
+ orgId: input.orgId,
34
+ requestedBy: input.requestedBy,
35
+ reviewNote: null,
36
+ reviewedAt: null,
37
+ reviewedBy: null,
38
+ status: 'pending',
39
+ symbol: input.symbol,
40
+ updatedAt: now,
41
+ })
42
+ .onConflict((oc) =>
43
+ oc
44
+ .columns(['chainId', 'address'])
45
+ // `sql.lit` keeps the predicate literal; a bound parameter would
46
+ // defeat partial-index inference for the conflict target.
47
+ .where('status', '=', sql.lit('pending'))
48
+ .doNothing(),
49
+ )
50
+ .returningAll()
51
+ .executeTakeFirst()
52
+ }
53
+
54
+ export declare namespace create {
55
+ /** Fields accepted when inserting a request. */
56
+ type Input = {
57
+ /** Requested token contract address (lowercase). */
58
+ address: string
59
+ /** Chain the token belongs to. */
60
+ chainId: number
61
+ /** Display currency, e.g. `USD`. */
62
+ currency: string
63
+ /** Decimal precision. */
64
+ decimals: number
65
+ /** Inline SVG logo markup uploaded by the requester. */
66
+ logo?: string | undefined
67
+ /** HTTPS logo URL from chain metadata. */
68
+ logoUri?: string | undefined
69
+ /** Display name. */
70
+ name: string
71
+ /** Requester note to reviewers. */
72
+ note?: string | undefined
73
+ /** Requesting organization id (`org_…`). */
74
+ orgId: string
75
+ /** User id that submitted the request, or `super_admin`. */
76
+ requestedBy: string
77
+ /** Ticker symbol. */
78
+ symbol: string
79
+ }
80
+ }
81
+
82
+ /** Lists an organization's requests, newest first. */
83
+ export function list(db: Db.Db, orgId: string): Promise<Record[]> {
84
+ return db.kysely
85
+ .selectFrom('verified_token_requests')
86
+ .selectAll()
87
+ .where('orgId', '=', orgId)
88
+ .orderBy('createdAt', 'desc')
89
+ .execute()
90
+ }
91
+
92
+ /**
93
+ * Lists requests in one status globally, oldest first (review-queue order),
94
+ * with the requesting organization's current name when it still exists.
95
+ */
96
+ export function listByStatus(
97
+ db: Db.Db,
98
+ status: Status,
99
+ ): Promise<(Record & { orgName: string | null })[]> {
100
+ return db.kysely
101
+ .selectFrom('verified_token_requests')
102
+ .leftJoin('organizations', 'organizations.id', 'verified_token_requests.orgId')
103
+ .selectAll('verified_token_requests')
104
+ .select('organizations.name as orgName')
105
+ .where('status', '=', status)
106
+ .orderBy('verified_token_requests.createdAt', 'asc')
107
+ .execute()
108
+ }
109
+
110
+ /** Gets a request by id. */
111
+ export function get(db: Db.Db, id: string): Promise<Record | undefined> {
112
+ return db.kysely
113
+ .selectFrom('verified_token_requests')
114
+ .selectAll()
115
+ .where('id', '=', id)
116
+ .executeTakeFirst()
117
+ }
118
+
119
+ /** Counts an organization's pending requests. */
120
+ export async function countPending(db: Db.Db, orgId: string): Promise<number> {
121
+ const row = await db.kysely
122
+ .selectFrom('verified_token_requests')
123
+ .select(({ fn }) => fn.countAll<string>().as('count'))
124
+ .where('orgId', '=', orgId)
125
+ .where('status', '=', 'pending')
126
+ .executeTakeFirstOrThrow()
127
+ return Number(row.count)
128
+ }
129
+
130
+ /** Hard-deletes an org-scoped request while pending; `undefined` otherwise. */
131
+ export function remove(db: Db.Db, orgId: string, id: string): Promise<Record | undefined> {
132
+ return db.kysely
133
+ .deleteFrom('verified_token_requests')
134
+ .where('id', '=', id)
135
+ .where('orgId', '=', orgId)
136
+ .where('status', '=', 'pending')
137
+ .returningAll()
138
+ .executeTakeFirst()
139
+ }
140
+
141
+ /**
142
+ * Marks a pending request approved or denied with reviewer identity;
143
+ * `undefined` when absent or already reviewed.
144
+ */
145
+ export function review(db: Db.Db, id: string, input: review.Input): Promise<Record | undefined> {
146
+ const now = new Date().toISOString()
147
+ return db.kysely
148
+ .updateTable('verified_token_requests')
149
+ .set({
150
+ reviewNote: input.reviewNote ?? null,
151
+ reviewedAt: now,
152
+ reviewedBy: input.reviewedBy,
153
+ status: input.status,
154
+ updatedAt: now,
155
+ })
156
+ .where('id', '=', id)
157
+ .where('status', '=', 'pending')
158
+ .returningAll()
159
+ .executeTakeFirst()
160
+ }
161
+
162
+ export declare namespace review {
163
+ /** Review outcome fields. */
164
+ type Input = {
165
+ /** Reviewer note shown on denial. */
166
+ reviewNote?: string | undefined
167
+ /** Reviewing admin email. */
168
+ reviewedBy: string
169
+ /** Review outcome. */
170
+ status: 'approved' | 'denied'
171
+ }
172
+ }
173
+
174
+ /** Maps a stored row to the wire shape (null `logo`/`logoUri` map to absent). */
175
+ export function toRequest(record: Record) {
176
+ const { logo, logoUri, ...rest } = record
177
+ return {
178
+ ...rest,
179
+ ...(logo === null ? {} : { logo }),
180
+ ...(logoUri === null ? {} : { logoUri }),
181
+ }
182
+ }
@@ -5,6 +5,8 @@ import type * as Webhooks from '../../internal/Webhooks.js'
5
5
  import type * as Db from '../Db.js'
6
6
  import type * as db_Schema from '../Schema.js'
7
7
 
8
+ const subscriptionLimitLockClass = 1464353612
9
+
8
10
  /** Columns of the `webhook_subscriptions` table, derived from `Schema.WebhookSubscription`. */
9
11
  export type Table = db_Schema.WebhookSubscription
10
12
 
@@ -69,6 +71,35 @@ export async function insert(db: Db.Db, subscription: Webhooks.Subscription): Pr
69
71
  .execute()
70
72
  }
71
73
 
74
+ /**
75
+ * Inserts a subscription when its owner remains below the configured cap.
76
+ * An owner-scoped transaction lock serializes the count and insert.
77
+ */
78
+ export async function insertWithinLimit(
79
+ db: Db.Db,
80
+ subscription: Webhooks.Subscription,
81
+ options: insertWithinLimit.Options,
82
+ ): Promise<boolean> {
83
+ return db.transaction(async (tx) => {
84
+ const owner = `${subscription.owner.type}:${ownerId(subscription.owner)}`
85
+ await sql`select pg_advisory_xact_lock(${subscriptionLimitLockClass}, hashtext(${owner}))`.execute(tx.kysely) // prettier-ignore
86
+ const existing = await count(tx, subscription.owner, options.now)
87
+ if (existing >= options.maxPerOwner) return false
88
+ await insert(tx, subscription)
89
+ return true
90
+ })
91
+ }
92
+
93
+ export declare namespace insertWithinLimit {
94
+ /** Options for an atomic capped insert. */
95
+ type Options = {
96
+ /** Maximum live subscriptions the owner may hold. */
97
+ maxPerOwner: number
98
+ /** ISO timestamp used to exclude expired rows from the count. */
99
+ now: string
100
+ }
101
+ }
102
+
72
103
  /**
73
104
  * Reads an owner's subscription by id; expired rows never match (query-time
74
105
  * expiry, same read semantics as the old store TTL).
@@ -3,6 +3,8 @@ import { KeyAuthorization, Transaction as core_Transaction, TxEnvelopeTempo } fr
3
3
  import { type Client, BaseError } from 'viem'
4
4
  import * as z from 'zod/mini'
5
5
 
6
+ import * as ApiResponse from '../../internal/Response.js'
7
+
6
8
  export function resolveChainId(value: unknown) {
7
9
  if (typeof value === 'number') return value
8
10
  if (typeof value === 'bigint') return Number(value)
@@ -97,24 +99,38 @@ export function rpcErrorJson(request: RpcRequest.RpcRequest, error: unknown) {
97
99
  { request },
98
100
  )
99
101
 
100
- if ((error as { name?: string | undefined }).name === 'ZodError')
102
+ if (error instanceof z.core.$ZodError)
101
103
  return RpcResponse.from(
102
104
  {
103
105
  error: {
104
106
  code: RpcResponse.InvalidParamsError.code,
105
- message: (error as Error).message,
107
+ data: {
108
+ code: 'invalid_params',
109
+ issues: ApiResponse.validationDetails(error.issues.slice(0, 10)),
110
+ },
111
+ message: 'Invalid params.',
106
112
  },
107
113
  },
108
114
  { request },
109
115
  )
110
116
 
111
117
  const inner = resolveError(error)
112
- const message = inner.message ?? (error as Error).message
113
- const code = inner.code ?? -32603
114
- const data = inner.data
118
+ if (inner.code === undefined || inner.message === undefined)
119
+ return RpcResponse.from(
120
+ {
121
+ error: {
122
+ code: RpcResponse.InternalError.code,
123
+ data: { code: 'internal_error' },
124
+ message: 'Internal error',
125
+ },
126
+ },
127
+ { request },
128
+ )
129
+
130
+ const { code, data, message } = inner
115
131
  return RpcResponse.from(
116
132
  {
117
- error: { code, message, ...(data ? { data } : {}) },
133
+ error: { code, message, ...(data === undefined ? {} : { data }) },
118
134
  },
119
135
  { request },
120
136
  )
@@ -0,0 +1,153 @@
1
+ import * as z from 'zod/mini'
2
+
3
+ import * as Relay from '../../test/Relay.js'
4
+
5
+ describe('request errors', () => {
6
+ test('returns Parse error for invalid JSON', async () => {
7
+ const server = await Relay.createServer((await Relay.relay()).listener)
8
+
9
+ try {
10
+ const response = await fetch(server.url, {
11
+ body: '{',
12
+ headers: { 'Content-Type': 'application/json' },
13
+ method: 'POST',
14
+ })
15
+
16
+ expect(await response.json()).toMatchInlineSnapshot(`
17
+ {
18
+ "error": {
19
+ "code": -32700,
20
+ "message": "Parse error",
21
+ },
22
+ "id": null,
23
+ "jsonrpc": "2.0",
24
+ }
25
+ `)
26
+ } finally {
27
+ await server.closeAsync()
28
+ }
29
+ })
30
+
31
+ test.each([
32
+ ['non-object request', 'null'],
33
+ ['invalid version', JSON.stringify({ id: 1, jsonrpc: '1.0', method: 'eth_chainId' })],
34
+ ['empty batch', '[]'],
35
+ ])('returns Invalid Request for %s', async (_name, body) => {
36
+ const server = await Relay.createServer((await Relay.relay()).listener)
37
+
38
+ try {
39
+ const response = await fetch(server.url, {
40
+ body,
41
+ headers: { 'Content-Type': 'application/json' },
42
+ method: 'POST',
43
+ })
44
+
45
+ expect(await response.json()).toMatchInlineSnapshot(`
46
+ {
47
+ "error": {
48
+ "code": -32600,
49
+ "message": "Invalid Request",
50
+ },
51
+ "id": null,
52
+ "jsonrpc": "2.0",
53
+ }
54
+ `)
55
+ } finally {
56
+ await server.closeAsync()
57
+ }
58
+ })
59
+
60
+ test('returns one Invalid Request error for a malformed batch member', async () => {
61
+ const server = await Relay.createServer(
62
+ (
63
+ await Relay.relay({
64
+ getClient: () => {
65
+ throw new Error('transport credential must not leak')
66
+ },
67
+ })
68
+ ).listener,
69
+ )
70
+
71
+ try {
72
+ const response = await fetch(server.url, {
73
+ body: JSON.stringify([
74
+ { id: 1, jsonrpc: '2.0', method: 'eth_chainId' },
75
+ { id: 2, jsonrpc: '1.0', method: 'eth_chainId' },
76
+ ]),
77
+ headers: { 'Content-Type': 'application/json' },
78
+ method: 'POST',
79
+ })
80
+
81
+ expect(await response.json()).toMatchInlineSnapshot(`
82
+ [
83
+ {
84
+ "error": {
85
+ "code": -32603,
86
+ "data": {
87
+ "code": "internal_error",
88
+ },
89
+ "message": "Internal error",
90
+ },
91
+ "id": 1,
92
+ "jsonrpc": "2.0",
93
+ },
94
+ {
95
+ "error": {
96
+ "code": -32600,
97
+ "message": "Invalid Request",
98
+ },
99
+ "id": null,
100
+ "jsonrpc": "2.0",
101
+ },
102
+ ]
103
+ `)
104
+ } finally {
105
+ await server.closeAsync()
106
+ }
107
+ })
108
+
109
+ test('returns bounded structured issues for invalid params', async () => {
110
+ const schema = z.object({ value: z.string() })
111
+ const server = await Relay.createServer(
112
+ (
113
+ await Relay.relay({
114
+ onRequest: async () => {
115
+ schema.parse({ value: 1 })
116
+ },
117
+ })
118
+ ).listener,
119
+ )
120
+
121
+ try {
122
+ const response = await fetch(server.url, {
123
+ body: JSON.stringify({ id: 1, jsonrpc: '2.0', method: 'eth_chainId' }),
124
+ headers: { 'Content-Type': 'application/json' },
125
+ method: 'POST',
126
+ })
127
+
128
+ expect(await response.json()).toMatchInlineSnapshot(`
129
+ {
130
+ "error": {
131
+ "code": -32602,
132
+ "data": {
133
+ "code": "invalid_params",
134
+ "issues": [
135
+ {
136
+ "message": "Invalid input",
137
+ "path": [
138
+ "value",
139
+ ],
140
+ },
141
+ ],
142
+ },
143
+ "message": "Invalid params.",
144
+ },
145
+ "id": 1,
146
+ "jsonrpc": "2.0",
147
+ }
148
+ `)
149
+ } finally {
150
+ await server.closeAsync()
151
+ }
152
+ })
153
+ })