tapimo 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (443) hide show
  1. package/dist/App.d.ts +6396 -4575
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +39 -4
  4. package/dist/App.js.map +1 -1
  5. package/dist/Assets.d.ts +15 -0
  6. package/dist/Assets.d.ts.map +1 -1
  7. package/dist/Assets.js +7 -0
  8. package/dist/Assets.js.map +1 -1
  9. package/dist/Scope.d.ts +2 -0
  10. package/dist/Scope.d.ts.map +1 -1
  11. package/dist/Scope.js +17 -0
  12. package/dist/Scope.js.map +1 -1
  13. package/dist/admin/App.d.ts +176 -78
  14. package/dist/admin/App.d.ts.map +1 -1
  15. package/dist/admin/apps/api-keys.d.ts +84 -4
  16. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  17. package/dist/admin/apps/api-keys.js +54 -0
  18. package/dist/admin/apps/api-keys.js.map +1 -1
  19. package/dist/admin/apps/earn-vaults.d.ts +123 -9
  20. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  21. package/dist/admin/apps/earn-vaults.js +60 -7
  22. package/dist/admin/apps/earn-vaults.js.map +1 -1
  23. package/dist/admin/apps/organizations.d.ts.map +1 -1
  24. package/dist/admin/apps/organizations.js +4 -2
  25. package/dist/admin/apps/organizations.js.map +1 -1
  26. package/dist/admin/apps/verified-tokens.d.ts +90 -90
  27. package/dist/admin/ui.generated.d.ts +1 -1
  28. package/dist/admin/ui.generated.js +71 -71
  29. package/dist/admin/ui.generated.js.map +1 -1
  30. package/dist/apps/Zones.d.ts +16 -16
  31. package/dist/apps/Zones.js +4 -4
  32. package/dist/apps/data/App.d.ts +1699 -749
  33. package/dist/apps/data/App.d.ts.map +1 -1
  34. package/dist/apps/data/App.js +58 -9
  35. package/dist/apps/data/App.js.map +1 -1
  36. package/dist/apps/data/ZoneSelection.d.ts +62 -0
  37. package/dist/apps/data/ZoneSelection.d.ts.map +1 -0
  38. package/dist/apps/data/ZoneSelection.js +44 -0
  39. package/dist/apps/data/ZoneSelection.js.map +1 -0
  40. package/dist/apps/data/routes/activities.d.ts +2417 -50
  41. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  42. package/dist/apps/data/routes/activities.js +1896 -1293
  43. package/dist/apps/data/routes/activities.js.map +1 -1
  44. package/dist/apps/data/routes/addresses.d.ts +471 -340
  45. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  46. package/dist/apps/data/routes/balances.d.ts +12 -12
  47. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  48. package/dist/apps/data/routes/balances.js +44 -17
  49. package/dist/apps/data/routes/balances.js.map +1 -1
  50. package/dist/apps/data/routes/blocks.d.ts +42 -42
  51. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  52. package/dist/apps/data/routes/blocks.js +22 -12
  53. package/dist/apps/data/routes/blocks.js.map +1 -1
  54. package/dist/apps/data/routes/coingecko.d.ts +179 -179
  55. package/dist/apps/data/routes/earn.d.ts +144 -19
  56. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  57. package/dist/apps/data/routes/earn.js +160 -28
  58. package/dist/apps/data/routes/earn.js.map +1 -1
  59. package/dist/apps/data/routes/exchanges.d.ts +719 -13
  60. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  61. package/dist/apps/data/routes/exchanges.js +16 -13
  62. package/dist/apps/data/routes/exchanges.js.map +1 -1
  63. package/dist/apps/data/routes/fee-amm.d.ts +2 -2
  64. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  65. package/dist/apps/data/routes/fee-amm.js +9 -11
  66. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  67. package/dist/apps/data/routes/indexer.d.ts +34 -34
  68. package/dist/apps/data/routes/receipts.d.ts +363 -263
  69. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  70. package/dist/apps/data/routes/receipts.js +29 -11
  71. package/dist/apps/data/routes/receipts.js.map +1 -1
  72. package/dist/apps/data/routes/rpc.js +24 -10
  73. package/dist/apps/data/routes/rpc.js.map +1 -1
  74. package/dist/apps/data/routes/tokenlist.d.ts +13 -13
  75. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  76. package/dist/apps/data/routes/tokenlist.js +16 -15
  77. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  78. package/dist/apps/data/routes/tokens.d.ts +112 -98
  79. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  80. package/dist/apps/data/routes/tokens.js +85 -35
  81. package/dist/apps/data/routes/tokens.js.map +1 -1
  82. package/dist/apps/data/routes/transactions.d.ts +7 -2
  83. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  84. package/dist/apps/data/routes/transactions.js +38 -18
  85. package/dist/apps/data/routes/transactions.js.map +1 -1
  86. package/dist/apps/data/routes/transfers.d.ts +1 -1
  87. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  88. package/dist/apps/data/routes/transfers.js +25 -21
  89. package/dist/apps/data/routes/transfers.js.map +1 -1
  90. package/dist/apps/data/routes/valuation.d.ts +1 -1
  91. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  92. package/dist/apps/data/routes/valuation.js +12 -7
  93. package/dist/apps/data/routes/valuation.js.map +1 -1
  94. package/dist/apps/data/routes/verified-tokens.d.ts +3 -3
  95. package/dist/apps/data/routes/webhooks.d.ts +15 -15
  96. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  97. package/dist/apps/data/routes/webhooks.js +2 -2
  98. package/dist/apps/data/routes/webhooks.js.map +1 -1
  99. package/dist/apps/data/routes/zones.d.ts +32 -32
  100. package/dist/apps/data/routes/zones.js +1 -1
  101. package/dist/apps/funding/App.d.ts +38 -27
  102. package/dist/apps/funding/App.d.ts.map +1 -1
  103. package/dist/apps/funding/routes/chains.d.ts.map +1 -1
  104. package/dist/apps/funding/routes/chains.js +5 -4
  105. package/dist/apps/funding/routes/chains.js.map +1 -1
  106. package/dist/apps/funding/routes/deposit-addresses.d.ts +16 -16
  107. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  108. package/dist/apps/funding/routes/deposit-addresses.js +24 -19
  109. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  110. package/dist/apps/funding/routes/providers.d.ts +13 -13
  111. package/dist/apps/funding/routes/providers.d.ts.map +1 -1
  112. package/dist/apps/funding/routes/providers.js +3 -2
  113. package/dist/apps/funding/routes/providers.js.map +1 -1
  114. package/dist/apps/funding/routes/quotes.d.ts.map +1 -1
  115. package/dist/apps/funding/routes/quotes.js +2 -2
  116. package/dist/apps/funding/routes/quotes.js.map +1 -1
  117. package/dist/apps/funding/routes/transfers.d.ts +60 -48
  118. package/dist/apps/funding/routes/transfers.d.ts.map +1 -1
  119. package/dist/apps/funding/routes/transfers.js +27 -19
  120. package/dist/apps/funding/routes/transfers.js.map +1 -1
  121. package/dist/apps/management/App.d.ts +4558 -3700
  122. package/dist/apps/management/App.d.ts.map +1 -1
  123. package/dist/apps/management/Billing.d.ts.map +1 -1
  124. package/dist/apps/management/Billing.js +19 -6
  125. package/dist/apps/management/Billing.js.map +1 -1
  126. package/dist/apps/management/routes/api-keys.d.ts +786 -175
  127. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  128. package/dist/apps/management/routes/api-keys.js +312 -34
  129. package/dist/apps/management/routes/api-keys.js.map +1 -1
  130. package/dist/apps/management/routes/billing.d.ts +103 -30
  131. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  132. package/dist/apps/management/routes/billing.js +91 -32
  133. package/dist/apps/management/routes/billing.js.map +1 -1
  134. package/dist/apps/management/routes/faucet.d.ts +35 -35
  135. package/dist/apps/management/routes/faucet.d.ts.map +1 -1
  136. package/dist/apps/management/routes/faucet.js +23 -12
  137. package/dist/apps/management/routes/faucet.js.map +1 -1
  138. package/dist/apps/management/routes/invitations.d.ts +46 -13
  139. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  140. package/dist/apps/management/routes/invitations.js +79 -29
  141. package/dist/apps/management/routes/invitations.js.map +1 -1
  142. package/dist/apps/management/routes/invite-links.d.ts +120 -75
  143. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  144. package/dist/apps/management/routes/invite-links.js +100 -41
  145. package/dist/apps/management/routes/invite-links.js.map +1 -1
  146. package/dist/apps/management/routes/me.d.ts +5 -5
  147. package/dist/apps/management/routes/me.d.ts.map +1 -1
  148. package/dist/apps/management/routes/me.js +14 -10
  149. package/dist/apps/management/routes/me.js.map +1 -1
  150. package/dist/apps/management/routes/members.d.ts +99 -78
  151. package/dist/apps/management/routes/members.d.ts.map +1 -1
  152. package/dist/apps/management/routes/members.js +37 -18
  153. package/dist/apps/management/routes/members.js.map +1 -1
  154. package/dist/apps/management/routes/orgs.d.ts +48 -8
  155. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  156. package/dist/apps/management/routes/orgs.js +48 -19
  157. package/dist/apps/management/routes/orgs.js.map +1 -1
  158. package/dist/apps/management/routes/projects.d.ts +108 -46
  159. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  160. package/dist/apps/management/routes/projects.js +72 -21
  161. package/dist/apps/management/routes/projects.js.map +1 -1
  162. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  163. package/dist/apps/management/routes/scopes.js +8 -5
  164. package/dist/apps/management/routes/scopes.js.map +1 -1
  165. package/dist/apps/management/routes/usage.d.ts +82 -82
  166. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  167. package/dist/apps/management/routes/usage.js +41 -31
  168. package/dist/apps/management/routes/usage.js.map +1 -1
  169. package/dist/apps/management/routes/verified-token-requests.d.ts +35 -7
  170. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
  171. package/dist/apps/management/routes/verified-token-requests.js +36 -17
  172. package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
  173. package/dist/apps/management/routes/webhooks.d.ts +200 -183
  174. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  175. package/dist/apps/management/routes/webhooks.js +80 -35
  176. package/dist/apps/management/routes/webhooks.js.map +1 -1
  177. package/dist/apps/mpp/internal/Adapter.d.ts +1 -1
  178. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  179. package/dist/apps/mpp/internal/Adapter.js +12 -0
  180. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  181. package/dist/db/Db.d.ts +2 -0
  182. package/dist/db/Db.d.ts.map +1 -1
  183. package/dist/db/Db.js +52 -1
  184. package/dist/db/Db.js.map +1 -1
  185. package/dist/db/Schema.d.ts +26 -3
  186. package/dist/db/Schema.d.ts.map +1 -1
  187. package/dist/db/Schema.js +24 -5
  188. package/dist/db/Schema.js.map +1 -1
  189. package/dist/db/tables/earnVaults.d.ts +5 -1
  190. package/dist/db/tables/earnVaults.d.ts.map +1 -1
  191. package/dist/db/tables/earnVaults.js +5 -0
  192. package/dist/db/tables/earnVaults.js.map +1 -1
  193. package/dist/db/tables/fundingCatalog.d.ts +4 -2
  194. package/dist/db/tables/fundingCatalog.d.ts.map +1 -1
  195. package/dist/db/tables/fundingCatalog.js +5 -1
  196. package/dist/db/tables/fundingCatalog.js.map +1 -1
  197. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -1
  198. package/dist/db/tables/webhookDeliveries.js +10 -0
  199. package/dist/db/tables/webhookDeliveries.js.map +1 -1
  200. package/dist/db/tables/webhookQueueCompletions.d.ts +15 -0
  201. package/dist/db/tables/webhookQueueCompletions.d.ts.map +1 -0
  202. package/dist/db/tables/webhookQueueCompletions.js +32 -0
  203. package/dist/db/tables/webhookQueueCompletions.js.map +1 -0
  204. package/dist/db/tables/webhookQueueEvents.d.ts +14 -20
  205. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
  206. package/dist/db/tables/webhookQueueEvents.js +68 -47
  207. package/dist/db/tables/webhookQueueEvents.js.map +1 -1
  208. package/dist/db/tables/webhookSubscriptions.d.ts +16 -5
  209. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  210. package/dist/db/tables/webhookSubscriptions.js +29 -5
  211. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  212. package/dist/handlers/internal/utils.d.ts.map +1 -1
  213. package/dist/handlers/internal/utils.js +9 -0
  214. package/dist/handlers/internal/utils.js.map +1 -1
  215. package/dist/internal/Auth.d.ts +11 -2
  216. package/dist/internal/Auth.d.ts.map +1 -1
  217. package/dist/internal/Auth.js +19 -6
  218. package/dist/internal/Auth.js.map +1 -1
  219. package/dist/internal/Cache.d.ts.map +1 -1
  220. package/dist/internal/Cache.js +11 -7
  221. package/dist/internal/Cache.js.map +1 -1
  222. package/dist/internal/EarnVaults.d.ts +43 -4
  223. package/dist/internal/EarnVaults.d.ts.map +1 -1
  224. package/dist/internal/EarnVaults.js +167 -0
  225. package/dist/internal/EarnVaults.js.map +1 -1
  226. package/dist/internal/Fetch.d.ts +23 -0
  227. package/dist/internal/Fetch.d.ts.map +1 -0
  228. package/dist/internal/Fetch.js +26 -0
  229. package/dist/internal/Fetch.js.map +1 -0
  230. package/dist/internal/Log.d.ts +3 -1
  231. package/dist/internal/Log.d.ts.map +1 -1
  232. package/dist/internal/Log.js +16 -3
  233. package/dist/internal/Log.js.map +1 -1
  234. package/dist/internal/OpenApi.d.ts +30 -24
  235. package/dist/internal/OpenApi.d.ts.map +1 -1
  236. package/dist/internal/OpenApi.js +140 -41
  237. package/dist/internal/OpenApi.js.map +1 -1
  238. package/dist/internal/Response.d.ts +14 -9
  239. package/dist/internal/Response.d.ts.map +1 -1
  240. package/dist/internal/Response.js +16 -5
  241. package/dist/internal/Response.js.map +1 -1
  242. package/dist/internal/Schema.d.ts +11 -10
  243. package/dist/internal/Schema.d.ts.map +1 -1
  244. package/dist/internal/Schema.js +14 -9
  245. package/dist/internal/Schema.js.map +1 -1
  246. package/dist/internal/Store.d.ts +28 -6
  247. package/dist/internal/Store.d.ts.map +1 -1
  248. package/dist/internal/Store.js +121 -25
  249. package/dist/internal/Store.js.map +1 -1
  250. package/dist/internal/Tidx.d.ts +2 -0
  251. package/dist/internal/Tidx.d.ts.map +1 -1
  252. package/dist/internal/Tidx.js +23 -6
  253. package/dist/internal/Tidx.js.map +1 -1
  254. package/dist/internal/Timeout.d.ts +36 -0
  255. package/dist/internal/Timeout.d.ts.map +1 -0
  256. package/dist/internal/Timeout.js +37 -0
  257. package/dist/internal/Timeout.js.map +1 -0
  258. package/dist/internal/Timing.d.ts +9 -0
  259. package/dist/internal/Timing.d.ts.map +1 -1
  260. package/dist/internal/Timing.js +7 -0
  261. package/dist/internal/Timing.js.map +1 -1
  262. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  263. package/dist/internal/WebhookDestination.js +3 -0
  264. package/dist/internal/WebhookDestination.js.map +1 -1
  265. package/dist/internal/Webhooks.d.ts +29 -12
  266. package/dist/internal/Webhooks.d.ts.map +1 -1
  267. package/dist/internal/Webhooks.js +37 -20
  268. package/dist/internal/Webhooks.js.map +1 -1
  269. package/dist/internal/funding/Action.d.ts +9 -0
  270. package/dist/internal/funding/Action.d.ts.map +1 -1
  271. package/dist/internal/funding/Action.js +16 -8
  272. package/dist/internal/funding/Action.js.map +1 -1
  273. package/dist/internal/funding/Catalog.d.ts +9 -2
  274. package/dist/internal/funding/Catalog.d.ts.map +1 -1
  275. package/dist/internal/funding/Catalog.js +19 -8
  276. package/dist/internal/funding/Catalog.js.map +1 -1
  277. package/dist/internal/funding/Deposit.d.ts +2 -2
  278. package/dist/internal/funding/Deposit.d.ts.map +1 -1
  279. package/dist/internal/funding/Deposit.js +9 -8
  280. package/dist/internal/funding/Deposit.js.map +1 -1
  281. package/dist/internal/funding/DepositAddress.d.ts +4 -4
  282. package/dist/internal/funding/DepositAddress.d.ts.map +1 -1
  283. package/dist/internal/funding/DepositAddress.js +9 -8
  284. package/dist/internal/funding/DepositAddress.js.map +1 -1
  285. package/dist/internal/funding/Provider.d.ts +68 -13
  286. package/dist/internal/funding/Provider.d.ts.map +1 -1
  287. package/dist/internal/funding/Provider.js +42 -20
  288. package/dist/internal/funding/Provider.js.map +1 -1
  289. package/dist/internal/funding/Transfer.d.ts +13 -12
  290. package/dist/internal/funding/Transfer.d.ts.map +1 -1
  291. package/dist/internal/funding/Transfer.js +23 -21
  292. package/dist/internal/funding/Transfer.js.map +1 -1
  293. package/dist/internal/funding/providers/stargate.d.ts +38 -0
  294. package/dist/internal/funding/providers/stargate.d.ts.map +1 -0
  295. package/dist/internal/funding/providers/stargate.js +277 -0
  296. package/dist/internal/funding/providers/stargate.js.map +1 -0
  297. package/dist/internal/index.d.ts +1 -0
  298. package/dist/internal/index.d.ts.map +1 -1
  299. package/dist/internal/index.js +1 -0
  300. package/dist/internal/index.js.map +1 -1
  301. package/dist/providers/index.d.ts +7 -0
  302. package/dist/providers/index.d.ts.map +1 -1
  303. package/dist/providers/index.js +3 -0
  304. package/dist/providers/index.js.map +1 -1
  305. package/package.json +3 -3
  306. package/src/App.test.ts +148 -0
  307. package/src/App.ts +45 -4
  308. package/src/Assets.test.ts +18 -0
  309. package/src/Assets.ts +22 -0
  310. package/src/Client.test-d.ts +311 -16
  311. package/src/Scope.test.ts +20 -0
  312. package/src/Scope.ts +16 -0
  313. package/src/admin/apps/api-keys.test.ts +75 -0
  314. package/src/admin/apps/api-keys.ts +64 -0
  315. package/src/admin/apps/earn-vaults.test.ts +143 -0
  316. package/src/admin/apps/earn-vaults.ts +84 -7
  317. package/src/admin/apps/organizations.ts +6 -2
  318. package/src/admin/ui/src/lib/api-keys.ts +19 -0
  319. package/src/admin/ui/src/routes/api-keys.tsx +125 -2
  320. package/src/admin/ui.generated.ts +71 -71
  321. package/src/apps/Zones.test.ts +4 -4
  322. package/src/apps/Zones.ts +4 -4
  323. package/src/apps/composition.test.ts +1 -1
  324. package/src/apps/data/App.test.ts +72 -0
  325. package/src/apps/data/App.ts +58 -10
  326. package/src/apps/data/ZoneSelection.test.ts +196 -0
  327. package/src/apps/data/ZoneSelection.ts +108 -0
  328. package/src/apps/data/routes/activities.test.ts +1843 -2
  329. package/src/apps/data/routes/activities.ts +2211 -1388
  330. package/src/apps/data/routes/balances.ts +134 -98
  331. package/src/apps/data/routes/blocks.test.ts +533 -0
  332. package/src/apps/data/routes/blocks.ts +36 -17
  333. package/src/apps/data/routes/earn.test.ts +187 -25
  334. package/src/apps/data/routes/earn.ts +228 -32
  335. package/src/apps/data/routes/earn.zone-access.test.ts +46 -0
  336. package/src/apps/data/routes/exchanges.test.ts +31 -1
  337. package/src/apps/data/routes/exchanges.ts +19 -15
  338. package/src/apps/data/routes/fee-amm.ts +18 -11
  339. package/src/apps/data/routes/receipts.ts +48 -17
  340. package/src/apps/data/routes/rpc.test.ts +75 -0
  341. package/src/apps/data/routes/rpc.ts +23 -9
  342. package/src/apps/data/routes/tokenlist.ts +21 -18
  343. package/src/apps/data/routes/tokens.test.ts +607 -0
  344. package/src/apps/data/routes/tokens.ts +312 -231
  345. package/src/apps/data/routes/transactions.ts +69 -30
  346. package/src/apps/data/routes/transfers.test.ts +424 -3
  347. package/src/apps/data/routes/transfers.ts +57 -36
  348. package/src/apps/data/routes/valuation.ts +94 -78
  349. package/src/apps/data/routes/webhooks.ts +6 -2
  350. package/src/apps/data/routes/zones.test.ts +21 -15
  351. package/src/apps/data/routes/zones.ts +1 -1
  352. package/src/apps/funding/routes/chains.test.ts +211 -7
  353. package/src/apps/funding/routes/chains.ts +19 -12
  354. package/src/apps/funding/routes/deposit-addresses.test.ts +416 -0
  355. package/src/apps/funding/routes/deposit-addresses.ts +101 -84
  356. package/src/apps/funding/routes/providers.ts +9 -5
  357. package/src/apps/funding/routes/quotes.test.ts +42 -0
  358. package/src/apps/funding/routes/quotes.ts +8 -5
  359. package/src/apps/funding/routes/transfers.test.ts +430 -40
  360. package/src/apps/funding/routes/transfers.ts +76 -59
  361. package/src/apps/management/Billing.test.ts +26 -0
  362. package/src/apps/management/Billing.ts +24 -7
  363. package/src/apps/management/routes/api-keys.test.ts +398 -0
  364. package/src/apps/management/routes/api-keys.ts +481 -145
  365. package/src/apps/management/routes/billing.test.ts +209 -0
  366. package/src/apps/management/routes/billing.ts +254 -177
  367. package/src/apps/management/routes/faucet.test.ts +39 -0
  368. package/src/apps/management/routes/faucet.ts +75 -41
  369. package/src/apps/management/routes/invitations.test.ts +216 -0
  370. package/src/apps/management/routes/invitations.ts +186 -109
  371. package/src/apps/management/routes/invite-links.test.ts +263 -1
  372. package/src/apps/management/routes/invite-links.ts +295 -214
  373. package/src/apps/management/routes/me.test.ts +49 -0
  374. package/src/apps/management/routes/me.ts +42 -32
  375. package/src/apps/management/routes/members.test.ts +124 -1
  376. package/src/apps/management/routes/members.ts +81 -51
  377. package/src/apps/management/routes/orgs.test.ts +176 -0
  378. package/src/apps/management/routes/orgs.ts +101 -59
  379. package/src/apps/management/routes/projects.test.ts +183 -0
  380. package/src/apps/management/routes/projects.ts +124 -60
  381. package/src/apps/management/routes/scopes.test.ts +44 -0
  382. package/src/apps/management/routes/scopes.ts +37 -28
  383. package/src/apps/management/routes/usage.test.ts +92 -0
  384. package/src/apps/management/routes/usage.ts +186 -151
  385. package/src/apps/management/routes/verified-token-requests.test.ts +114 -0
  386. package/src/apps/management/routes/verified-token-requests.ts +166 -133
  387. package/src/apps/management/routes/webhooks.test.ts +234 -0
  388. package/src/apps/management/routes/webhooks.ts +191 -78
  389. package/src/apps/mpp/internal/Adapter.ts +13 -1
  390. package/src/db/Db.test.ts +41 -0
  391. package/src/db/Db.ts +75 -1
  392. package/src/db/Schema.ts +33 -5
  393. package/src/db/tables/earnVaults.test.ts +22 -0
  394. package/src/db/tables/earnVaults.ts +11 -1
  395. package/src/db/tables/fundingCatalog.test.ts +16 -2
  396. package/src/db/tables/fundingCatalog.ts +9 -3
  397. package/src/db/tables/webhookDeliveries.ts +13 -0
  398. package/src/db/tables/webhookQueueCompletions.ts +55 -0
  399. package/src/db/tables/webhookQueueEvents.ts +95 -61
  400. package/src/db/tables/webhookSubscriptions.ts +45 -6
  401. package/src/handlers/internal/utils.test.ts +53 -0
  402. package/src/handlers/internal/utils.ts +15 -0
  403. package/src/internal/Auth.ts +35 -9
  404. package/src/internal/Cache.ts +14 -7
  405. package/src/internal/EarnVaults.capabilities.test.ts +33 -0
  406. package/src/internal/EarnVaults.test.ts +79 -0
  407. package/src/internal/EarnVaults.ts +277 -0
  408. package/src/internal/Fetch.test.ts +46 -0
  409. package/src/internal/Fetch.ts +56 -0
  410. package/src/internal/Log.test.ts +21 -0
  411. package/src/internal/Log.ts +20 -5
  412. package/src/internal/OpenApi.ts +177 -51
  413. package/src/internal/Response.test.ts +95 -0
  414. package/src/internal/Response.ts +41 -3
  415. package/src/internal/Schema.test.ts +18 -0
  416. package/src/internal/Schema.ts +19 -9
  417. package/src/internal/Store.test.ts +364 -0
  418. package/src/internal/Store.ts +153 -27
  419. package/src/internal/Tidx.test.ts +21 -1
  420. package/src/internal/Tidx.ts +23 -6
  421. package/src/internal/Timeout.test.ts +35 -0
  422. package/src/internal/Timeout.ts +73 -0
  423. package/src/internal/Timing.ts +16 -0
  424. package/src/internal/WebhookDestination.ts +3 -0
  425. package/src/internal/Webhooks.test.ts +122 -8
  426. package/src/internal/Webhooks.ts +59 -29
  427. package/src/internal/funding/Action.test.ts +41 -1
  428. package/src/internal/funding/Action.ts +69 -41
  429. package/src/internal/funding/Catalog.test.ts +34 -0
  430. package/src/internal/funding/Catalog.ts +28 -11
  431. package/src/internal/funding/Deposit.ts +71 -64
  432. package/src/internal/funding/DepositAddress.ts +50 -43
  433. package/src/internal/funding/Provider.test.ts +73 -0
  434. package/src/internal/funding/Provider.ts +246 -170
  435. package/src/internal/funding/Transfer.ts +133 -110
  436. package/src/internal/funding/providers/index.test.ts +22 -0
  437. package/src/internal/funding/providers/relay.test.ts +2 -2
  438. package/src/internal/funding/providers/stargate.test.ts +163 -0
  439. package/src/internal/funding/providers/stargate.ts +409 -0
  440. package/src/internal/index.test.ts +1 -0
  441. package/src/internal/index.ts +1 -0
  442. package/src/providers/index.test.ts +1 -0
  443. package/src/providers/index.ts +9 -0
@@ -1,5 +1,7 @@
1
1
  import { Json } from 'ox'
2
2
 
3
+ import * as Timeout from './Timeout.js'
4
+
3
5
  /** Key-to-value map used by typed stores. */
4
6
  export type StoreItemMap = Record<string, unknown>
5
7
 
@@ -575,26 +577,78 @@ export declare namespace durableObject {
575
577
  }
576
578
  }
577
579
 
580
+ /** Associates request cache directives with a store used by request handlers. */
581
+ export function withRequest(
582
+ store: Store,
583
+ request: withRequest.Request,
584
+ options: withRequest.Options = {},
585
+ ): Store {
586
+ const source = requestStores.get(store)?.store ?? store
587
+ const scoped = {
588
+ delete: source.delete.bind(source),
589
+ ...(source.deleteIf ? { deleteIf: source.deleteIf.bind(source) } : {}),
590
+ get: source.get.bind(source),
591
+ ...(source.increment ? { increment: source.increment.bind(source) } : {}),
592
+ list: source.list.bind(source),
593
+ put: source.put.bind(source),
594
+ ...(source.swap ? { swap: source.swap.bind(source) } : {}),
595
+ type: source.type,
596
+ }
597
+ requestStores.set(scoped, { request, store: source, waitUntil: options.waitUntil })
598
+ return scoped
599
+ }
600
+
601
+ export declare namespace withRequest {
602
+ /** Request-scoped cache behavior. */
603
+ export type Options = {
604
+ /** Keeps asynchronous cache persistence alive after the response returns. */
605
+ waitUntil?: ((promise: Promise<unknown>) => void) | undefined
606
+ }
607
+ /** Request surface needed to read cache directives. */
608
+ export type Request = {
609
+ /** Reads one request header. */
610
+ header(name: string): string | undefined
611
+ }
612
+ }
613
+
578
614
  /**
579
- * Wraps an async producer with store-backed caching. Returns the cached value if
580
- * present and valid; otherwise runs `fetch`, stores the JSON-encoded result
581
- * under `key` with `ttl` milliseconds, and returns it. Undefined results are
582
- * returned without being cached.
615
+ * Returns a cached value when present. Otherwise, runs `fetch` and stores its
616
+ * result unless undefined or rejected by `shouldCache`. Cache persistence is
617
+ * best-effort and never delays the fetched value.
583
618
  */
584
619
  export async function memoize<value>(
585
- fetch: () => Promise<value>,
586
- options: memoize.Options,
620
+ fetch: (signal?: AbortSignal) => Promise<value>,
621
+ options: memoize.Options<value>,
587
622
  ): Promise<value> {
588
- const { key, store, ttl } = options
623
+ const scoped = requestStores.get(options.store)
624
+ const { key, ttl } = options
625
+ const flightTimeout = options.flightTimeout ?? Timeout.duration
626
+ const request = scoped?.request
627
+ const store = scoped?.store ?? options.store
628
+ const waitUntil = scoped?.waitUntil
629
+
630
+ // Request cache directives follow the same semantics as the response cache:
631
+ // no-cache refreshes the entry, while no-store bypasses it entirely.
632
+ const cacheControl = request?.header('cache-control')
633
+ const directives = (cacheControl ?? request?.header('pragma') ?? '').toLowerCase()
634
+ const noStore = directives.includes('no-store')
635
+ const noCache = noStore || directives.includes('no-cache')
636
+ if (noStore)
637
+ return Timeout.run((signal) => fetch(signal), {
638
+ error: new MemoizeTimeoutError(flightTimeout),
639
+ timeout: flightTimeout,
640
+ })
589
641
 
590
- const raw = await store.get(key)
591
- // Old cache entries used ambiguous untagged bigint strings. Refresh them
592
- // instead of guessing whether a matching string was originally a bigint.
593
- if (raw?.startsWith(jsonCodecPrefix)) {
594
- try {
595
- return jsonDecode(raw) as value
596
- } catch {
597
- // Corrupt entries are treated as misses so the next call refreshes.
642
+ if (!noCache) {
643
+ const raw = await store.get(key)
644
+ // Old cache entries used ambiguous untagged bigint strings. Refresh them
645
+ // instead of guessing whether a matching string was originally a bigint.
646
+ if (raw?.startsWith(jsonCodecPrefix)) {
647
+ try {
648
+ return jsonDecode(raw) as value
649
+ } catch {
650
+ // Corrupt entries are treated as misses so the next call refreshes.
651
+ }
598
652
  }
599
653
  }
600
654
 
@@ -605,26 +659,81 @@ export async function memoize<value>(
605
659
  // Coalesce concurrent misses for this process. The store remains the cache
606
660
  // boundary; this only prevents a local cold-key stampede while the first
607
661
  // fetch is still in flight.
608
- const flight = (async () => {
609
- const value = await fetch()
610
- if (value === undefined) return value
611
- await store.put(key, jsonEncode(value), { ttl })
662
+ let mutating = noCache
663
+ let settled = false
664
+ const work = async (signal?: AbortSignal) => {
665
+ if (noCache) {
666
+ try {
667
+ await store.delete(key)
668
+ } finally {
669
+ mutating = false
670
+ }
671
+ }
672
+ signal?.throwIfAborted()
673
+ mutating = false
674
+ const value = await fetch(signal)
675
+ signal?.throwIfAborted()
676
+ if (value === undefined || options.shouldCache?.(value) === false) return value
677
+ mutating = true
678
+ if (store.type === 'cache') {
679
+ // A lossy cache write cannot turn a successful origin read into an error.
680
+ const persist = Promise.resolve()
681
+ .then(() => store.put(key, jsonEncode(value), { ttl }))
682
+ .catch(() => {})
683
+ if (waitUntil)
684
+ try {
685
+ waitUntil(persist)
686
+ mutating = false
687
+ return value
688
+ } catch {}
689
+ try {
690
+ await persist
691
+ } finally {
692
+ mutating = false
693
+ }
694
+ return value
695
+ }
696
+ try {
697
+ await store.put(key, jsonEncode(value), { ttl })
698
+ } finally {
699
+ mutating = false
700
+ }
612
701
  return value
613
- })()
614
- flights.set(key, flight)
615
-
616
- try {
617
- return await flight
618
- } finally {
619
- flights.delete(key)
620
702
  }
703
+ let flight!: Promise<value>
704
+ const release = () => {
705
+ // A canceled fetch cannot mutate the cache after its next abort check.
706
+ // Non-cancelable cache mutations retain ownership until they settle.
707
+ if ((settled || !mutating) && flights.get(key) === flight) flights.delete(key)
708
+ }
709
+ flight = Timeout.run(
710
+ async (signal) => {
711
+ signal.addEventListener('abort', release, { once: true })
712
+ try {
713
+ return await work(signal)
714
+ } finally {
715
+ settled = true
716
+ release()
717
+ }
718
+ },
719
+ {
720
+ error: new MemoizeTimeoutError(flightTimeout),
721
+ timeout: flightTimeout,
722
+ },
723
+ )
724
+ flights.set(key, flight)
725
+ return flight
621
726
  }
622
727
 
623
728
  export declare namespace memoize {
624
729
  /** Options for {@link memoize}. */
625
- type Options = {
730
+ type Options<value = unknown> = {
731
+ /** Maximum shared cache-miss flight duration in milliseconds. Defaults to 15 seconds. */
732
+ flightTimeout?: number | undefined
626
733
  /** Cache key. Callers are responsible for namespacing/versioning. */
627
734
  key: string
735
+ /** Returns whether a fetched value should be stored. Single-flight callers still share it. */
736
+ shouldCache?: ((value: value) => boolean) | undefined
628
737
  /** Store used to persist cache entries. */
629
738
  store: Store
630
739
  /** Time-to-live in milliseconds. */
@@ -632,6 +741,14 @@ export declare namespace memoize {
632
741
  }
633
742
  }
634
743
 
744
+ const requestStores = new WeakMap<
745
+ Store,
746
+ {
747
+ request: withRequest.Request
748
+ store: Store
749
+ waitUntil?: ((promise: Promise<unknown>) => void) | undefined
750
+ }
751
+ >()
635
752
  const flights = new WeakMap<Store, Map<string, Promise<unknown>>>()
636
753
 
637
754
  function flightsFor(store: Store) {
@@ -829,6 +946,15 @@ function isDurableObjectValue(value: unknown): value is DurableObjectValue {
829
946
  )
830
947
  }
831
948
 
949
+ /** Thrown when a shared memoized cache-miss flight exceeds its configured deadline. */
950
+ export class MemoizeTimeoutError extends Error {
951
+ override name = 'Store.MemoizeTimeoutError'
952
+
953
+ constructor(timeout: number) {
954
+ super(`Memoized cache-miss flight timed out after ${timeout}ms.`)
955
+ }
956
+ }
957
+
832
958
  /** Thrown when {@link update} exhausts its compare-and-swap attempts. */
833
959
  export class UpdateContentionError extends Error {
834
960
  override name = 'Store.UpdateContentionError'
@@ -59,10 +59,16 @@ describe('providerFailure', () => {
59
59
 
60
60
  test('classifies timeout and rate-limit statuses', () => {
61
61
  expect([
62
+ Tidx.providerFailure(appError('query timed out')),
62
63
  Tidx.providerFailure(appError('secret upstream detail', 408)),
63
64
  Tidx.providerFailure(appError('secret upstream detail', 429)),
64
65
  ]).toMatchInlineSnapshot(`
65
66
  [
67
+ {
68
+ "failure": "timeout",
69
+ "id": "tidx",
70
+ "operation": "query",
71
+ },
66
72
  {
67
73
  "failure": "timeout",
68
74
  "id": "tidx",
@@ -135,6 +141,19 @@ describe('isQueryRejection', () => {
135
141
  })
136
142
  })
137
143
 
144
+ describe('isQueryTimeout', () => {
145
+ test('matches explicit indexer query timeout failures only', () => {
146
+ expect([
147
+ Tidx.isQueryTimeout(appError('Request timeout', 408)),
148
+ Tidx.isQueryTimeout(appError('query timed out')),
149
+ Tidx.isQueryTimeout(appError('error sending request for url (...)')),
150
+ Tidx.isQueryTimeout(appError('db error')),
151
+ Tidx.isQueryTimeout(appError('Request timeout', 429)),
152
+ Tidx.isQueryTimeout(new DOMException('query timed out', 'TimeoutError')),
153
+ ]).toEqual([true, true, true, false, false, false])
154
+ })
155
+ })
156
+
138
157
  describe('escape', () => {
139
158
  test('doubles quotes for ANSI string literals, leaving backslashes alone', () => {
140
159
  expect(Tidx.escape('USD')).toMatchInlineSnapshot(`"USD"`)
@@ -212,7 +231,8 @@ describe('withTransientRetry', () => {
212
231
 
213
232
  await client.fetch({ chainId: 42431, query: 'SELECT 1' })
214
233
 
215
- expect(fetch.mock.calls[0]![0]).toMatchInlineSnapshot(`
234
+ const { signal: _signal, ...options } = fetch.mock.calls[0]![0]
235
+ expect(options).toMatchInlineSnapshot(`
216
236
  {
217
237
  "chainId": 42431,
218
238
  "query": "SELECT 1",
@@ -5,6 +5,7 @@ import type * as Auth from './Auth.js'
5
5
  import * as Credential from './Credential.js'
6
6
  import * as Errors from './Errors.js'
7
7
  import type * as Log from './Log.js'
8
+ import * as Timeout from './Timeout.js'
8
9
  import * as Viem from './Viem.js'
9
10
 
10
11
  /** Default Tempo indexer (TIDX) base URLs. */
@@ -142,8 +143,10 @@ const transientRetryDelay = 250
142
143
  * dropped at the server's execution cap — typically a cold object-storage
143
144
  * cache read that warms across attempts, so retrying genuinely helps.
144
145
  */
145
- const transientErrorPattern =
146
- /db error|timeout|timed out|connection reset|connection refused|error sending request/i
146
+ const transientErrorPattern = /db error|connection reset|connection refused/i
147
+
148
+ /** Indexer failures caused by the query execution deadline. */
149
+ const queryTimeoutPattern = /timeout|timed out|error sending request/i
147
150
 
148
151
  /**
149
152
  * Escapes a free-form string for safe embedding inside a single-quoted SQL
@@ -182,17 +185,21 @@ export function withTransientRetry(client: Client): Client {
182
185
  return {
183
186
  ...client,
184
187
  fetch: async (options) => {
188
+ const signal = Timeout.signal({ signal: options.signal })
185
189
  let lastError: unknown
186
190
  for (let attempt = 0; attempt <= transientRetryCount; attempt++) {
187
191
  try {
188
192
  // `retryCount: 1` caps the inner client at a single HTTP attempt so
189
193
  // the combined budget stays this wrapper's alone.
190
- return await fetch({ ...options, retryCount: 1 })
194
+ return await fetch({ ...options, retryCount: 1, signal })
191
195
  } catch (error) {
192
196
  if (!isTransientError(error)) throw error
193
197
  lastError = error
194
198
  if (attempt < transientRetryCount)
195
- await new Promise((resolve) => setTimeout(resolve, transientRetryDelay * 2 ** attempt))
199
+ await Timeout.wait({
200
+ milliseconds: transientRetryDelay * 2 ** attempt,
201
+ signal,
202
+ })
196
203
  }
197
204
  }
198
205
  throw lastError
@@ -239,8 +246,11 @@ export function providerFailure(cause: unknown): Log.ProviderFailure {
239
246
  return { ...base, failure: 'timeout' }
240
247
 
241
248
  const status = Errors.getStatus(cause)
249
+ if (isQueryTimeout(cause))
250
+ return status === 408
251
+ ? { ...base, failure: 'timeout', status }
252
+ : { ...base, failure: 'timeout' }
242
253
  if (status !== undefined && status >= 200 && status < 300) return { ...base, failure: 'payload' }
243
- if (status === 408) return { ...base, failure: 'timeout', status }
244
254
  if (status === 422) return { ...base, failure: 'query', status }
245
255
  if (status === 429) return { ...base, failure: 'rate_limit', status }
246
256
  if (status !== undefined) return { ...base, failure: 'http', status }
@@ -270,6 +280,13 @@ export function isQueryRejection(cause: unknown): boolean {
270
280
  return status === 400 || status === 422
271
281
  }
272
282
 
283
+ /** Whether a failed TIDX request exhausted its query execution deadline. */
284
+ export function isQueryTimeout(cause: unknown): boolean {
285
+ if (!(cause instanceof Tidx.FetchRequestError)) return false
286
+ if (cause.status === 408) return true
287
+ return cause.status >= 200 && cause.status < 300 && queryTimeoutPattern.test(cause.message)
288
+ }
289
+
273
290
  /**
274
291
  * True for deterministic indexer failures a retry cannot fix: a
275
292
  * `FetchRequestError` outside {@link isTransientError}'s transient classes,
@@ -294,7 +311,7 @@ export function isDeterministicError(error: unknown): boolean {
294
311
  */
295
312
  function isTransientError(error: unknown): boolean {
296
313
  if (!(error instanceof Tidx.FetchRequestError)) return false
297
- if (error.status === 408 || error.status === 429 || error.status >= 500) return true
314
+ if (isQueryTimeout(error) || error.status === 429 || error.status >= 500) return true
298
315
  return error.status >= 200 && error.status < 300 && transientErrorPattern.test(error.message)
299
316
  }
300
317
 
@@ -0,0 +1,35 @@
1
+ import * as Timeout from './Timeout.js'
2
+
3
+ describe('duration', () => {
4
+ test('uses a 15 second default', () => {
5
+ expect(Timeout.duration).toBe(15_000)
6
+ })
7
+ })
8
+
9
+ describe('signal', () => {
10
+ test('preserves a caller signal and otherwise creates a deadline', () => {
11
+ const caller = new AbortController().signal
12
+
13
+ expect(Timeout.signal({ signal: caller })).toBe(caller)
14
+ expect(Timeout.signal()).toBeInstanceOf(AbortSignal)
15
+ })
16
+ })
17
+
18
+ describe('wait', () => {
19
+ test('rejects with the abort reason and clears its timer', async () => {
20
+ vi.useFakeTimers()
21
+ try {
22
+ const controller = new AbortController()
23
+ const reason = new DOMException('deadline exceeded', 'TimeoutError')
24
+ const waiting = Timeout.wait({ milliseconds: 1_000, signal: controller.signal })
25
+ const rejection = expect(waiting).rejects.toBe(reason)
26
+
27
+ controller.abort(reason)
28
+
29
+ await rejection
30
+ expect(vi.getTimerCount()).toBe(0)
31
+ } finally {
32
+ vi.useRealTimers()
33
+ }
34
+ })
35
+ })
@@ -0,0 +1,73 @@
1
+ /** Default maximum duration for API dependency work. */
2
+ export const duration = 15_000
3
+
4
+ /** Returns a caller signal or a signal carrying the default deadline. */
5
+ export function signal(options: signal.Options = {}): AbortSignal {
6
+ return options.signal ?? AbortSignal.timeout(options.timeout ?? duration)
7
+ }
8
+
9
+ export declare namespace signal {
10
+ /** Options for {@link signal}. */
11
+ type Options = {
12
+ /** Existing caller signal. */
13
+ signal?: AbortSignal | null | undefined
14
+ /** Default maximum duration in milliseconds. */
15
+ timeout?: number | undefined
16
+ }
17
+ }
18
+
19
+ /** Waits for a duration, rejecting immediately when `signal` aborts. */
20
+ export function wait(options: wait.Options): Promise<void> {
21
+ options.signal.throwIfAborted()
22
+ return new Promise((resolve, reject) => {
23
+ const abort = () => {
24
+ clearTimeout(timer)
25
+ reject(options.signal.reason)
26
+ }
27
+ const timer = setTimeout(() => {
28
+ options.signal.removeEventListener('abort', abort)
29
+ resolve()
30
+ }, options.milliseconds)
31
+ options.signal.addEventListener('abort', abort, { once: true })
32
+ })
33
+ }
34
+
35
+ export declare namespace wait {
36
+ /** Options for {@link wait}. */
37
+ type Options = {
38
+ /** Duration to wait in milliseconds. */
39
+ milliseconds: number
40
+ /** Signal that cancels the wait. */
41
+ signal: AbortSignal
42
+ }
43
+ }
44
+
45
+ /** Runs asynchronous work under a hard deadline and aborts cooperative work. */
46
+ export function run<value>(
47
+ work: (signal: AbortSignal) => Promise<value>,
48
+ options: run.Options = {},
49
+ ): Promise<value> {
50
+ const timeout = options.timeout ?? duration
51
+ const controller = new AbortController()
52
+ const timeoutError = new DOMException(`Timed out after ${timeout}ms.`, 'TimeoutError')
53
+ const error = options.error ?? timeoutError
54
+ const timer = setTimeout(() => controller.abort(timeoutError), timeout)
55
+ const operation = Promise.resolve().then(() => work(controller.signal))
56
+
57
+ return Promise.race([
58
+ operation,
59
+ new Promise<never>((_, reject) => {
60
+ controller.signal.addEventListener('abort', () => reject(error), { once: true })
61
+ }),
62
+ ]).finally(() => clearTimeout(timer))
63
+ }
64
+
65
+ export declare namespace run {
66
+ /** Options for {@link run}. */
67
+ type Options = {
68
+ /** Error returned to the caller when the deadline expires. */
69
+ error?: Error | undefined
70
+ /** Maximum duration in milliseconds. */
71
+ timeout?: number | undefined
72
+ }
73
+ }
@@ -2,6 +2,8 @@ import type { Context, MiddlewareHandler } from 'hono'
2
2
 
3
3
  /** Hono variables used to collect Server-Timing metrics. */
4
4
  export type Variables = {
5
+ /** Operations that have started but not finished. */
6
+ activeTimings?: Active[] | undefined
5
7
  /** Metrics emitted in the `Server-Timing` response header. */
6
8
  serverTiming?: Metric[] | undefined
7
9
  }
@@ -19,12 +21,22 @@ export type Metric = {
19
21
  name: string
20
22
  }
21
23
 
24
+ /** One operation that has started but not finished. */
25
+ export type Active = {
26
+ /** Metric name. */
27
+ name: string
28
+ /** Monotonic start time. */
29
+ start: number
30
+ }
31
+
22
32
  /** Adds a `Server-Timing` header with total request duration. */
23
33
  export function middleware<
24
34
  environment extends Environment = Environment,
25
35
  >(): MiddlewareHandler<environment> {
26
36
  return async (c, next) => {
37
+ const active: Active[] = []
27
38
  const metrics: Metric[] = []
39
+ c.set('activeTimings', active)
28
40
  c.set('serverTiming', metrics)
29
41
 
30
42
  const start = performance.now()
@@ -44,9 +56,13 @@ export async function time<environment extends Environment, value>(
44
56
  fn: () => Promise<value> | value,
45
57
  ) {
46
58
  const start = performance.now()
59
+ const active = { name, start }
60
+ c.get('activeTimings')?.push(active)
47
61
  try {
48
62
  return await fn()
49
63
  } finally {
64
+ const activeTimings = c.get('activeTimings')
65
+ if (activeTimings) activeTimings.splice(activeTimings.indexOf(active), 1)
50
66
  c.get('serverTiming')?.push({ duration: performance.now() - start, name })
51
67
  }
52
68
  }
@@ -176,6 +176,9 @@ export async function send(options: send.Options): Promise<Result> {
176
176
  signal: controller.signal,
177
177
  })
178
178
  const durationMs = clock() - start
179
+ // The body is never read; an unreleased stream holds its buffer and
180
+ // connection in the isolate until GC, which stacks up during drains.
181
+ response.body?.cancel().catch(() => {})
179
182
  if (
180
183
  options.rejectRedirects &&
181
184
  (response.status === 0 || (response.status >= 300 && response.status < 400))