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,6 +1,8 @@
1
1
  import type { Context } from 'hono'
2
2
  import type * as z from 'zod/mini'
3
3
 
4
+ import * as Tidx from './Tidx.js'
5
+
4
6
  /** Creates a JSON error response. */
5
7
  export function error<const status extends error.Status, const code extends string>(
6
8
  c: Context,
@@ -39,14 +41,34 @@ export function unsupportedChainId(c: Context, chainId: number, supported: Itera
39
41
  }
40
42
 
41
43
  /**
42
- * Maps an unexpected upstream failure to a stable 502 JSON error envelope.
44
+ * Maps upstream failures to 502, except TIDX query failures after the first positional page return 400.
43
45
  * Preserves `Error` causes for reporting and rethrows non-`Error` causes.
44
46
  */
45
- export function upstream(c: Context, cause: unknown) {
47
+ export function upstream(c: Context, cause: unknown): upstream.Response
48
+ export function upstream(
49
+ c: Context,
50
+ cause: unknown,
51
+ options: upstream.Options,
52
+ ): upstream.PageResponse
53
+ export function upstream(c: Context, cause: unknown, options?: upstream.Options) {
46
54
  if (cause instanceof Error) {
47
55
  // Preserve the original error for error-reporting middleware without
48
56
  // exposing provider URLs, payloads, or credentials in the response.
49
57
  c.error = cause
58
+ if (options?.page !== undefined && options.page > 1) {
59
+ if (Tidx.isQueryTimeout(cause))
60
+ return error(c, {
61
+ code: 'query_invalid',
62
+ message: 'The requested page timed out. Use cursor pagination for deep traversal.',
63
+ status: 400,
64
+ })
65
+ if (Tidx.isQueryRejection(cause))
66
+ return error(c, {
67
+ code: 'query_invalid',
68
+ message: 'The requested page was rejected. Use cursor pagination for deep traversal.',
69
+ status: 400,
70
+ })
71
+ }
50
72
  return error(c, {
51
73
  code: 'upstream_error',
52
74
  message: 'Upstream service could not complete the request',
@@ -56,6 +78,22 @@ export function upstream(c: Context, cause: unknown) {
56
78
  throw cause
57
79
  }
58
80
 
81
+ export declare namespace upstream {
82
+ /** Pagination context for classifying a deep-page query failure. */
83
+ type Options = {
84
+ /** Validated positional page number, when requested. */
85
+ page: number | undefined
86
+ }
87
+
88
+ /** Upstream response for routes that support positional pagination. */
89
+ type PageResponse =
90
+ | ReturnType<typeof error<400, 'query_invalid'>>
91
+ | ReturnType<typeof error<502, 'upstream_error'>>
92
+
93
+ /** Default upstream error response. */
94
+ type Response = ReturnType<typeof error<502, 'upstream_error'>>
95
+ }
96
+
59
97
  /**
60
98
  * Validates `value` against `schema`. Returns the parsed value on success or
61
99
  * throws a generic upstream error so the public response body never leaks Zod
@@ -104,7 +142,7 @@ export declare namespace error {
104
142
  }
105
143
 
106
144
  /** HTTP status code accepted by the public error helper. */
107
- type Status = 400 | 401 | 403 | 404 | 409 | 412 | 413 | 415 | 429 | 500 | 501 | 502 | 503
145
+ type Status = 400 | 401 | 403 | 404 | 409 | 412 | 413 | 415 | 429 | 500 | 501 | 502 | 503 | 504
108
146
 
109
147
  /** Options for creating a JSON error response. */
110
148
  type Options<status extends Status = Status, code extends string = string> = {
@@ -1,9 +1,13 @@
1
+ import * as z from 'zod/mini'
2
+
1
3
  import * as Schema from './Schema.js'
2
4
 
3
5
  describe('ChainId', () => {
4
6
  test('resolves aliases to their chain id', () => {
5
7
  expect(Schema.ChainId.parse('mainnet')).toMatchInlineSnapshot(`4217`)
6
8
  expect(Schema.ChainId.parse('testnet')).toMatchInlineSnapshot(`42431`)
9
+ expect(Schema.ChainId.parse('1424310001')).toMatchInlineSnapshot(`1424310003`)
10
+ expect(Schema.ChainId.parse(1_424_310_001)).toMatchInlineSnapshot(`1424310003`)
7
11
  })
8
12
 
9
13
  test('accepts numeric chain ids as numbers or strings', () => {
@@ -51,6 +55,20 @@ describe('Limit', () => {
51
55
  })
52
56
  })
53
57
 
58
+ describe('pageChecks', () => {
59
+ const Query = z
60
+ .object({ cursor: Schema.Cursor, limit: Schema.Limit, page: Schema.Page })
61
+ .check(...Schema.pageChecks())
62
+
63
+ test('accepts positional pages through the 500-row window', () => {
64
+ expect(Query.safeParse({ limit: '10', page: '50' }).success).toMatchInlineSnapshot(`true`)
65
+ })
66
+
67
+ test('rejects deeper positional pages', () => {
68
+ expect(Query.safeParse({ limit: '10', page: '51' }).success).toMatchInlineSnapshot(`false`)
69
+ })
70
+ })
71
+
54
72
  describe('timestampBound', () => {
55
73
  test('normalizes RFC 3339 offsets to UTC', () => {
56
74
  const bound = Schema.timestampBound('swaps', 'from')
@@ -90,12 +90,19 @@ export function tokenAddress(example: core_Hex.Hex) {
90
90
  )
91
91
  }
92
92
 
93
- /** Maps human-readable chain aliases to their Tempo chain id. */
93
+ /** Maps caller-facing chain aliases to their current Tempo chain id. */
94
94
  export const chainIdAlias = {
95
+ // TODO: Remove this alias after clients migrate to chain 1424310003.
96
+ 1_424_310_001: 1_424_310_003,
95
97
  mainnet: 4217,
96
98
  testnet: 42431,
97
99
  } as const
98
100
 
101
+ /** Resolves a numeric chain id through the caller-facing alias map. */
102
+ export function resolveChainId(chainId: number): number {
103
+ return chainIdAlias[chainId as keyof typeof chainIdAlias] ?? chainId
104
+ }
105
+
99
106
  /**
100
107
  * Tempo chain id. Accepts a chain alias (`mainnet`/`testnet`) or any positive
101
108
  * integer chain id (a number or numeric string), normalizing all forms to a
@@ -110,7 +117,10 @@ export const ChainId = z
110
117
  z.enum(['mainnet', 'testnet']),
111
118
  z.transform((alias) => chainIdAlias[alias]),
112
119
  ),
113
- z.coerce.number(),
120
+ z.pipe(
121
+ z.coerce.number(),
122
+ z.transform((chainId) => resolveChainId(chainId)),
123
+ ),
114
124
  ]),
115
125
  z.number().check(z.int(), z.positive()),
116
126
  )
@@ -191,6 +201,8 @@ export const ErrorDetail = z
191
201
  })
192
202
  .check(z.describe('A single problem with the request.'))
193
203
 
204
+ z.globalRegistry.add(ErrorDetail, { ...z.globalRegistry.get(ErrorDetail), ref: 'ErrorDetail' })
205
+
194
206
  /**
195
207
  * Builds the global error envelope, optionally enumerating `error.code` to a
196
208
  * fixed set of machine-readable codes. Pass the codes a given status can return
@@ -384,12 +396,10 @@ export const Cursor = z
384
396
 
385
397
  /**
386
398
  * Maximum page window (`page × limit` rows) accepted by positional pagination.
387
- * Mirrors the indexer's own 10k row ceiling, and the bounded-window convention
388
- * of comparable APIs (Elasticsearch `max_result_window`, Zendesk's 100-page
389
- * cap): shallow page-numbered access is served positionally, deep traversal
390
- * must use cursors.
399
+ * Stays below the indexer's own 10k row ceiling so large offsets do not reach
400
+ * the indexer. Deeper traversal must use cursors.
391
401
  */
392
- export const maxPageWindow = 10_000
402
+ export const maxPageWindow = 500
393
403
 
394
404
  /**
395
405
  * Page-number query parameter (1-indexed) shared by list endpoints that
@@ -443,8 +453,8 @@ export const NextCursor = z
443
453
  * count is computed by a capped subquery (`… LIMIT countCap`) so it can't blow
444
454
  * the indexer's execution budget on the 10⁹-plus row tables; when the bound is
445
455
  * hit the count is a lower bound, signalled by `Meta.totalCountCapped`. Mirrors the
446
- * indexer's own 10k row ceiling (see {@link maxPageWindow}) and the capped-count
447
- * conventions of comparable APIs (Stripe Search's 10k `total_count`,
456
+ * indexer's own 10k row ceiling and the capped-count conventions of comparable
457
+ * APIs (Stripe Search's 10k `total_count`,
448
458
  * Elasticsearch `track_total_hits`, Shopify's `Count.precision`).
449
459
  */
450
460
  export const countCap = 10_000
@@ -1,5 +1,7 @@
1
+ import { HonoRequest } from 'hono/request'
1
2
  import { Store } from 'tapimo'
2
3
  import * as TestStore from '../../test/Store.js'
4
+ import * as Timeout from './Timeout.js'
3
5
 
4
6
  describe('from', () => {
5
7
  const ops = {
@@ -754,6 +756,18 @@ describe('durableObject', () => {
754
756
  })
755
757
  })
756
758
 
759
+ describe('withRequest', () => {
760
+ test('preserves the source store contract', async () => {
761
+ const source = new ReceiverStore()
762
+ const store = Store.withRequest(source, new HonoRequest(new Request('https://api.tempo.xyz')))
763
+
764
+ await store.put('value', 'stored')
765
+
766
+ expect(store.type).toMatchInlineSnapshot(`"cache"`)
767
+ expect(await source.get('value')).toMatchInlineSnapshot(`"stored"`)
768
+ })
769
+ })
770
+
757
771
  describe('memoize', () => {
758
772
  test('coalesces concurrent cache misses for the same key', async () => {
759
773
  const store = Store.memory()
@@ -795,6 +809,183 @@ describe('memoize', () => {
795
809
  `)
796
810
  })
797
811
 
812
+ test('hands cache persistence to waitUntil without retaining the resolved flight', async () => {
813
+ const pending = deferred<void>()
814
+ const waited: Promise<unknown>[] = []
815
+ const source = Store.memory()
816
+ const store = Store.withRequest(
817
+ Store.from({
818
+ ...source,
819
+ put: () => pending.promise,
820
+ type: 'cache',
821
+ }),
822
+ new HonoRequest(new Request('https://api.tempo.xyz')),
823
+ { waitUntil: (promise) => void waited.push(promise) },
824
+ )
825
+ let calls = 0
826
+ const options = { key: 'memo:stalled-write', store, ttl: 60_000 }
827
+
828
+ const first = await Store.memoize(async () => ({ value: ++calls }), options)
829
+ const second = await Store.memoize(async () => ({ value: ++calls }), options)
830
+
831
+ expect(first).toEqual({ value: 1 })
832
+ expect(second).toEqual({ value: 2 })
833
+ expect(calls).toBe(2)
834
+ expect(waited).toHaveLength(2)
835
+
836
+ pending.resolve()
837
+ await Promise.all(waited)
838
+ })
839
+
840
+ test('ignores cache persistence failures without waitUntil', async () => {
841
+ const store = Store.from({
842
+ ...Store.memory(),
843
+ async put() {
844
+ throw new Error('cache unavailable')
845
+ },
846
+ type: 'cache',
847
+ })
848
+
849
+ await expect(
850
+ Store.memoize(async () => ({ value: 'fresh' }), {
851
+ key: 'memo:failed-write',
852
+ store,
853
+ ttl: 60_000,
854
+ }),
855
+ ).resolves.toEqual({ value: 'fresh' })
856
+ })
857
+
858
+ test('releases a no-cache flight after deletion fails', async () => {
859
+ let deletes = 0
860
+ let fetches = 0
861
+ const source = Store.from({
862
+ ...Store.memory(),
863
+ async delete() {
864
+ if (++deletes === 1) throw new Error('cache unavailable')
865
+ },
866
+ })
867
+ const store = Store.withRequest(
868
+ source,
869
+ new HonoRequest(
870
+ new Request('https://api.tempo.xyz', { headers: { 'cache-control': 'no-cache' } }),
871
+ ),
872
+ )
873
+ const options = { key: 'memo:failed-delete', store, ttl: 60_000 }
874
+
875
+ await expect(Store.memoize(async () => ({ value: ++fetches }), options)).rejects.toThrow(
876
+ 'cache unavailable',
877
+ )
878
+ await expect(Store.memoize(async () => ({ value: ++fetches }), options)).resolves.toEqual({
879
+ value: 1,
880
+ })
881
+ expect(deletes).toBe(2)
882
+ })
883
+
884
+ test('times out and evicts a stalled cache-miss flight', async () => {
885
+ vi.useFakeTimers()
886
+ try {
887
+ const store = Store.memory()
888
+ const stalled = deferred<{ value: string }>()
889
+ let calls = 0
890
+ let leaderSignal: AbortSignal | undefined
891
+ const options = {
892
+ flightTimeout: 100,
893
+ key: 'memo:test',
894
+ store,
895
+ ttl: 60_000,
896
+ }
897
+ const leader = Store.memoize(async (signal) => {
898
+ calls += 1
899
+ leaderSignal = signal
900
+ return stalled.promise
901
+ }, options)
902
+ await vi.advanceTimersByTimeAsync(0)
903
+ const follower = Store.memoize(async () => {
904
+ calls += 1
905
+ return { value: 'unexpected' }
906
+ }, options)
907
+ const failures = Promise.all([
908
+ expect(leader).rejects.toBeInstanceOf(Store.MemoizeTimeoutError),
909
+ expect(follower).rejects.toBeInstanceOf(Store.MemoizeTimeoutError),
910
+ ])
911
+
912
+ await vi.advanceTimersByTimeAsync(100)
913
+ await failures
914
+
915
+ expect(calls).toBe(1)
916
+ expect(leaderSignal?.aborted).toBe(true)
917
+ expect(leaderSignal?.reason).toMatchObject({ name: 'TimeoutError' })
918
+
919
+ const recovered = await Store.memoize(async () => {
920
+ calls += 1
921
+ return { value: 'fresh' }
922
+ }, options)
923
+ stalled.resolve({ value: 'stale' })
924
+ await stalled.promise
925
+ await Promise.resolve()
926
+
927
+ expect(recovered).toEqual({ value: 'fresh' })
928
+ expect(calls).toBe(2)
929
+ expect(await store.get('memo:test')).toBe('tempo-api:store:json:v2:{"value":"fresh"}')
930
+ } finally {
931
+ vi.useRealTimers()
932
+ }
933
+ })
934
+
935
+ test('retains a timed-out flight until a cache mutation settles', async () => {
936
+ vi.useFakeTimers()
937
+ try {
938
+ const source = Store.memory()
939
+ const store = Store.withRequest(
940
+ source,
941
+ new HonoRequest(
942
+ new Request('https://api.tempo.xyz', {
943
+ headers: { 'cache-control': 'no-cache' },
944
+ }),
945
+ ),
946
+ )
947
+ let calls = 0
948
+ const options = { flightTimeout: 100, key: 'memo:mutation', store, ttl: 60_000 }
949
+ const leader = Store.memoize(async () => ({ value: ++calls }), options)
950
+ const leaderFailure = expect(leader).rejects.toBeInstanceOf(Store.MemoizeTimeoutError)
951
+
952
+ // The first microtask enters the real in-memory store's async delete.
953
+ await Promise.resolve()
954
+ vi.advanceTimersByTime(100)
955
+ const followerFailure = expect(
956
+ Store.memoize(async () => ({ value: ++calls }), options),
957
+ ).rejects.toBeInstanceOf(Store.MemoizeTimeoutError)
958
+
959
+ await Promise.all([leaderFailure, followerFailure])
960
+ expect(calls).toBe(0)
961
+ await expect(Store.memoize(async () => ({ value: ++calls }), options)).resolves.toEqual({
962
+ value: 1,
963
+ })
964
+ } finally {
965
+ vi.useRealTimers()
966
+ }
967
+ })
968
+
969
+ test('defaults cache-miss flights to the API deadline', async () => {
970
+ vi.useFakeTimers()
971
+ try {
972
+ const store = Store.memory()
973
+ const stalled = deferred<{ value: string }>()
974
+ const failure = expect(
975
+ Store.memoize(() => stalled.promise, {
976
+ key: 'memo:default-timeout',
977
+ store,
978
+ ttl: 60_000,
979
+ }),
980
+ ).rejects.toBeInstanceOf(Store.MemoizeTimeoutError)
981
+
982
+ await vi.advanceTimersByTimeAsync(Timeout.duration)
983
+ await failure
984
+ } finally {
985
+ vi.useRealTimers()
986
+ }
987
+ })
988
+
798
989
  test('returns cached JSON values until the entry expires', async () => {
799
990
  const store = Store.memory()
800
991
  let calls = 0
@@ -836,6 +1027,126 @@ describe('memoize', () => {
836
1027
  `)
837
1028
  })
838
1029
 
1030
+ test('refreshes the entry when request headers send no-cache', async () => {
1031
+ const store = Store.memory()
1032
+ let calls = 0
1033
+ const fetch = async () => ({ value: ++calls })
1034
+
1035
+ await Store.memoize(fetch, { key: 'memo:test', store, ttl: 60_000 })
1036
+ const refreshed = await Store.memoize(fetch, {
1037
+ key: 'memo:test',
1038
+ store: Store.withRequest(
1039
+ store,
1040
+ new HonoRequest(
1041
+ new Request('https://api.tempo.xyz', {
1042
+ headers: { 'cache-control': 'no-cache' },
1043
+ }),
1044
+ ),
1045
+ ),
1046
+ ttl: 60_000,
1047
+ })
1048
+ const after = await Store.memoize(fetch, { key: 'memo:test', store, ttl: 60_000 })
1049
+
1050
+ expect(calls).toMatchInlineSnapshot(`2`)
1051
+ expect(refreshed).toMatchInlineSnapshot(`
1052
+ {
1053
+ "value": 2,
1054
+ }
1055
+ `)
1056
+ expect(after).toEqual(refreshed)
1057
+ })
1058
+
1059
+ test('propagates no-cache through nested memoizers', async () => {
1060
+ const source = Store.memory()
1061
+ let calls = 0
1062
+ const fetch = async () => ({ value: ++calls })
1063
+
1064
+ await Store.memoize(fetch, { key: 'memo:inner', store: source, ttl: 60_000 })
1065
+ const store = Store.withRequest(
1066
+ source,
1067
+ new HonoRequest(
1068
+ new Request('https://api.tempo.xyz', {
1069
+ headers: { 'cache-control': 'no-cache' },
1070
+ }),
1071
+ ),
1072
+ )
1073
+ const value = await Store.memoize(
1074
+ () => Store.memoize(fetch, { key: 'memo:inner', store, ttl: 60_000 }),
1075
+ { key: 'memo:outer', store, ttl: 60_000 },
1076
+ )
1077
+
1078
+ expect(calls).toMatchInlineSnapshot(`2`)
1079
+ expect(value).toMatchInlineSnapshot(`
1080
+ {
1081
+ "value": 2,
1082
+ }
1083
+ `)
1084
+ })
1085
+
1086
+ test('bypasses without replacing the entry when request headers send no-store', async () => {
1087
+ const store = Store.memory()
1088
+ let calls = 0
1089
+ const fetch = async () => ({ value: ++calls })
1090
+
1091
+ const first = await Store.memoize(fetch, { key: 'memo:test', store, ttl: 60_000 })
1092
+ const bypassed = await Store.memoize(fetch, {
1093
+ key: 'memo:test',
1094
+ store: Store.withRequest(
1095
+ store,
1096
+ new HonoRequest(
1097
+ new Request('https://api.tempo.xyz', {
1098
+ headers: { 'cache-control': 'no-store' },
1099
+ }),
1100
+ ),
1101
+ ),
1102
+ ttl: 60_000,
1103
+ })
1104
+ const after = await Store.memoize(fetch, { key: 'memo:test', store, ttl: 60_000 })
1105
+
1106
+ expect(calls).toMatchInlineSnapshot(`2`)
1107
+ expect(bypassed).toMatchInlineSnapshot(`
1108
+ {
1109
+ "value": 2,
1110
+ }
1111
+ `)
1112
+ expect(after).toEqual(first)
1113
+ })
1114
+
1115
+ test('honors Pragma no-cache only without Cache-Control', async () => {
1116
+ const store = Store.memory()
1117
+ let calls = 0
1118
+ const fetch = async () => ({ value: ++calls })
1119
+
1120
+ await Store.memoize(fetch, { key: 'memo:test', store, ttl: 60_000 })
1121
+ await Store.memoize(fetch, {
1122
+ key: 'memo:test',
1123
+ store: Store.withRequest(
1124
+ store,
1125
+ new HonoRequest(new Request('https://api.tempo.xyz', { headers: { pragma: 'no-cache' } })),
1126
+ ),
1127
+ ttl: 60_000,
1128
+ })
1129
+ const cached = await Store.memoize(fetch, {
1130
+ key: 'memo:test',
1131
+ store: Store.withRequest(
1132
+ store,
1133
+ new HonoRequest(
1134
+ new Request('https://api.tempo.xyz', {
1135
+ headers: { 'cache-control': 'max-age=0', pragma: 'no-cache' },
1136
+ }),
1137
+ ),
1138
+ ),
1139
+ ttl: 60_000,
1140
+ })
1141
+
1142
+ expect(calls).toMatchInlineSnapshot(`2`)
1143
+ expect(cached).toMatchInlineSnapshot(`
1144
+ {
1145
+ "value": 2,
1146
+ }
1147
+ `)
1148
+ })
1149
+
839
1150
  test('preserves bigint values and collision-shaped strings on cache hits', async () => {
840
1151
  const store = Store.memory()
841
1152
  let calls = 0
@@ -877,6 +1188,34 @@ describe('memoize', () => {
877
1188
  expect(calls).toBe(2)
878
1189
  })
879
1190
 
1191
+ test('coalesces values excluded by the cache predicate without storing them', async () => {
1192
+ const store = Store.memory()
1193
+ const pending = deferred<void>()
1194
+ let calls = 0
1195
+ const fetch = async () => {
1196
+ calls += 1
1197
+ await pending.promise
1198
+ return { cacheable: false, value: 'fresh' }
1199
+ }
1200
+ const options = {
1201
+ key: 'memo:test',
1202
+ shouldCache: (value: Awaited<ReturnType<typeof fetch>>) => value.cacheable,
1203
+ store,
1204
+ ttl: 60_000,
1205
+ }
1206
+ const requests = [Store.memoize(fetch, options), Store.memoize(fetch, options)]
1207
+
1208
+ await Promise.resolve()
1209
+ pending.resolve()
1210
+
1211
+ expect(await Promise.all(requests)).toStrictEqual([
1212
+ { cacheable: false, value: 'fresh' },
1213
+ { cacheable: false, value: 'fresh' },
1214
+ ])
1215
+ expect(await store.get('memo:test')).toBeNull()
1216
+ expect(calls).toBe(1)
1217
+ })
1218
+
880
1219
  test('refreshes legacy untagged cache entries', async () => {
881
1220
  const store = Store.memory({ entries: [['memo:test', '{"value":"123#__bigint"}']] })
882
1221
  let calls = 0
@@ -945,3 +1284,28 @@ function durableObjectStorage(): Store.durableObject.Storage & { cells: Map<stri
945
1284
  },
946
1285
  }
947
1286
  }
1287
+
1288
+ class ReceiverStore implements Store.Store {
1289
+ #cells = new Map<string, string>()
1290
+ type = 'cache' as const
1291
+
1292
+ async delete(key: string) {
1293
+ this.#cells.delete(key)
1294
+ }
1295
+
1296
+ async get(key: string) {
1297
+ return this.#cells.get(key) ?? null
1298
+ }
1299
+
1300
+ async list(options: { prefix?: string | undefined } = {}) {
1301
+ return {
1302
+ keys: [...this.#cells.keys()]
1303
+ .filter((key) => options.prefix === undefined || key.startsWith(options.prefix))
1304
+ .map((name) => ({ name })),
1305
+ }
1306
+ }
1307
+
1308
+ async put(key: string, value: string) {
1309
+ this.#cells.set(key, value)
1310
+ }
1311
+ }