tapimo 0.1.0 → 0.3.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 (520) hide show
  1. package/README.md +57 -16
  2. package/dist/ApiKey.d.ts +4 -1
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +6 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +98 -3
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +150 -1
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +7917 -2315
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +141 -329
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +20 -4
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +23 -4
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/Webhooks.d.ts +2 -2
  19. package/dist/Webhooks.d.ts.map +1 -1
  20. package/dist/Webhooks.js +2 -2
  21. package/dist/Webhooks.js.map +1 -1
  22. package/dist/admin/App.d.ts +203 -120
  23. package/dist/admin/App.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.d.ts +111 -6
  25. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  26. package/dist/admin/apps/api-keys.js +67 -0
  27. package/dist/admin/apps/api-keys.js.map +1 -1
  28. package/dist/admin/apps/scopes.d.ts +12 -1
  29. package/dist/admin/apps/scopes.d.ts.map +1 -1
  30. package/dist/admin/apps/scopes.js +3 -0
  31. package/dist/admin/apps/scopes.js.map +1 -1
  32. package/dist/admin/apps/verified-tokens.d.ts +116 -116
  33. package/dist/admin/apps/verified-tokens.js +1 -1
  34. package/dist/admin/apps/verified-tokens.js.map +1 -1
  35. package/dist/admin/ui.generated.d.ts +1 -1
  36. package/dist/admin/ui.generated.js +13 -13
  37. package/dist/admin/ui.generated.js.map +1 -1
  38. package/dist/analytics/Analytics.d.ts +151 -0
  39. package/dist/analytics/Analytics.d.ts.map +1 -0
  40. package/dist/analytics/Analytics.js +212 -0
  41. package/dist/analytics/Analytics.js.map +1 -0
  42. package/dist/analytics/tables/requestEvents.d.ts +215 -0
  43. package/dist/analytics/tables/requestEvents.d.ts.map +1 -0
  44. package/dist/analytics/tables/requestEvents.js +264 -0
  45. package/dist/analytics/tables/requestEvents.js.map +1 -0
  46. package/dist/apps/data/App.d.ts +19576 -0
  47. package/dist/apps/data/App.d.ts.map +1 -0
  48. package/dist/apps/data/App.js +272 -0
  49. package/dist/apps/data/App.js.map +1 -0
  50. package/dist/apps/data/index.d.ts +3 -0
  51. package/dist/apps/data/index.d.ts.map +1 -0
  52. package/dist/apps/data/index.js +3 -0
  53. package/dist/apps/data/index.js.map +1 -0
  54. package/dist/apps/{activities.d.ts → data/routes/activities.d.ts} +32 -32
  55. package/dist/apps/{activities.d.ts.map → data/routes/activities.d.ts.map} +1 -1
  56. package/dist/apps/{activities.js → data/routes/activities.js} +13 -13
  57. package/dist/apps/data/routes/activities.js.map +1 -0
  58. package/dist/apps/{addresses.d.ts → data/routes/addresses.d.ts} +22 -22
  59. package/dist/apps/{addresses.d.ts.map → data/routes/addresses.d.ts.map} +1 -1
  60. package/dist/apps/{addresses.js → data/routes/addresses.js} +5 -5
  61. package/dist/apps/data/routes/addresses.js.map +1 -0
  62. package/dist/apps/{balances.d.ts → data/routes/balances.d.ts} +4 -4
  63. package/dist/apps/data/routes/balances.d.ts.map +1 -0
  64. package/dist/apps/{balances.js → data/routes/balances.js} +42 -11
  65. package/dist/apps/data/routes/balances.js.map +1 -0
  66. package/dist/apps/{blocks.d.ts → data/routes/blocks.d.ts} +47 -47
  67. package/dist/apps/data/routes/blocks.d.ts.map +1 -0
  68. package/dist/apps/{blocks.js → data/routes/blocks.js} +13 -13
  69. package/dist/apps/data/routes/blocks.js.map +1 -0
  70. package/dist/apps/{coingecko.d.ts → data/routes/coingecko.d.ts} +8 -8
  71. package/dist/apps/data/routes/coingecko.d.ts.map +1 -0
  72. package/dist/apps/{coingecko.js → data/routes/coingecko.js} +13 -13
  73. package/dist/apps/data/routes/coingecko.js.map +1 -0
  74. package/dist/apps/{exchanges.d.ts → data/routes/exchanges.d.ts} +108 -108
  75. package/dist/apps/data/routes/exchanges.d.ts.map +1 -0
  76. package/dist/apps/{exchanges.js → data/routes/exchanges.js} +19 -19
  77. package/dist/apps/data/routes/exchanges.js.map +1 -0
  78. package/dist/apps/{fee-amm.d.ts → data/routes/fee-amm.d.ts} +39 -39
  79. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -0
  80. package/dist/apps/{fee-amm.js → data/routes/fee-amm.js} +17 -17
  81. package/dist/apps/data/routes/fee-amm.js.map +1 -0
  82. package/dist/apps/data/routes/funding.d.ts +765 -0
  83. package/dist/apps/data/routes/funding.d.ts.map +1 -0
  84. package/dist/apps/data/routes/funding.js +383 -0
  85. package/dist/apps/data/routes/funding.js.map +1 -0
  86. package/dist/apps/{indexer.d.ts → data/routes/indexer.d.ts} +4 -4
  87. package/dist/apps/data/routes/indexer.d.ts.map +1 -0
  88. package/dist/apps/{indexer.js → data/routes/indexer.js} +13 -9
  89. package/dist/apps/data/routes/indexer.js.map +1 -0
  90. package/dist/apps/{receipts.d.ts → data/routes/receipts.d.ts} +49 -49
  91. package/dist/apps/data/routes/receipts.d.ts.map +1 -0
  92. package/dist/apps/{receipts.js → data/routes/receipts.js} +14 -20
  93. package/dist/apps/data/routes/receipts.js.map +1 -0
  94. package/dist/apps/{rpc.d.ts → data/routes/rpc.d.ts} +33 -40
  95. package/dist/apps/data/routes/rpc.d.ts.map +1 -0
  96. package/dist/apps/{rpc.js → data/routes/rpc.js} +35 -7
  97. package/dist/apps/data/routes/rpc.js.map +1 -0
  98. package/dist/apps/{tokenlist.d.ts → data/routes/tokenlist.d.ts} +40 -40
  99. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -0
  100. package/dist/apps/{tokenlist.js → data/routes/tokenlist.js} +8 -8
  101. package/dist/apps/data/routes/tokenlist.js.map +1 -0
  102. package/dist/apps/{tokens.d.ts → data/routes/tokens.d.ts} +468 -468
  103. package/dist/apps/data/routes/tokens.d.ts.map +1 -0
  104. package/dist/apps/{tokens.js → data/routes/tokens.js} +19 -19
  105. package/dist/apps/data/routes/tokens.js.map +1 -0
  106. package/dist/apps/{transactions.d.ts → data/routes/transactions.d.ts} +304 -304
  107. package/dist/apps/data/routes/transactions.d.ts.map +1 -0
  108. package/dist/apps/{transactions.js → data/routes/transactions.js} +13 -13
  109. package/dist/apps/data/routes/transactions.js.map +1 -0
  110. package/dist/apps/{transfers.d.ts → data/routes/transfers.d.ts} +62 -62
  111. package/dist/apps/data/routes/transfers.d.ts.map +1 -0
  112. package/dist/apps/{transfers.js → data/routes/transfers.js} +13 -13
  113. package/dist/apps/data/routes/transfers.js.map +1 -0
  114. package/dist/apps/{verified-tokens.d.ts → data/routes/verified-tokens.d.ts} +6 -6
  115. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -0
  116. package/dist/apps/{verified-tokens.js → data/routes/verified-tokens.js} +9 -9
  117. package/dist/apps/data/routes/verified-tokens.js.map +1 -0
  118. package/dist/apps/{webhooks.d.ts → data/routes/webhooks.d.ts} +17 -17
  119. package/dist/apps/{webhooks.d.ts.map → data/routes/webhooks.d.ts.map} +1 -1
  120. package/dist/apps/{webhooks.js → data/routes/webhooks.js} +38 -34
  121. package/dist/apps/data/routes/webhooks.js.map +1 -0
  122. package/dist/apps/docs/App.d.ts +29 -0
  123. package/dist/apps/docs/App.d.ts.map +1 -0
  124. package/dist/apps/docs/App.js +54 -0
  125. package/dist/apps/docs/App.js.map +1 -0
  126. package/dist/{internal/OpenApi.fonts.d.ts → apps/docs/fonts.d.ts} +1 -1
  127. package/dist/apps/docs/fonts.d.ts.map +1 -0
  128. package/dist/{internal/OpenApi.fonts.js → apps/docs/fonts.js} +1 -1
  129. package/dist/apps/docs/fonts.js.map +1 -0
  130. package/dist/apps/docs/index.d.ts +2 -0
  131. package/dist/apps/docs/index.d.ts.map +1 -0
  132. package/dist/apps/docs/index.js +2 -0
  133. package/dist/apps/docs/index.js.map +1 -0
  134. package/dist/{internal/OpenApi.logo.d.ts → apps/docs/logo.d.ts} +1 -1
  135. package/dist/apps/docs/logo.d.ts.map +1 -0
  136. package/dist/{internal/OpenApi.logo.js → apps/docs/logo.js} +1 -1
  137. package/dist/apps/docs/logo.js.map +1 -0
  138. package/dist/apps/docs/reference.d.ts +21 -0
  139. package/dist/apps/docs/reference.d.ts.map +1 -0
  140. package/dist/apps/docs/reference.js +112 -0
  141. package/dist/apps/docs/reference.js.map +1 -0
  142. package/dist/apps/index.d.ts +5 -0
  143. package/dist/apps/index.d.ts.map +1 -0
  144. package/dist/apps/index.js +5 -0
  145. package/dist/apps/index.js.map +1 -0
  146. package/dist/apps/mcp.d.ts +76 -0
  147. package/dist/apps/mcp.d.ts.map +1 -0
  148. package/dist/apps/mcp.js +188 -0
  149. package/dist/apps/mcp.js.map +1 -0
  150. package/dist/apps/metadata.d.ts +7 -0
  151. package/dist/apps/metadata.d.ts.map +1 -0
  152. package/dist/apps/metadata.js +15 -0
  153. package/dist/apps/metadata.js.map +1 -0
  154. package/dist/apps/platform/App.d.ts +5262 -0
  155. package/dist/apps/platform/App.d.ts.map +1 -0
  156. package/dist/apps/platform/App.js +84 -0
  157. package/dist/apps/platform/App.js.map +1 -0
  158. package/dist/apps/platform/Billing.d.ts +279 -0
  159. package/dist/apps/platform/Billing.d.ts.map +1 -0
  160. package/dist/apps/platform/Billing.js +477 -0
  161. package/dist/apps/platform/Billing.js.map +1 -0
  162. package/dist/apps/platform/index.d.ts +3 -0
  163. package/dist/apps/platform/index.d.ts.map +1 -0
  164. package/dist/apps/platform/index.js +3 -0
  165. package/dist/apps/platform/index.js.map +1 -0
  166. package/dist/apps/platform/routes/api-keys.d.ts +973 -0
  167. package/dist/apps/platform/routes/api-keys.d.ts.map +1 -0
  168. package/dist/apps/platform/routes/api-keys.js +430 -0
  169. package/dist/apps/platform/routes/api-keys.js.map +1 -0
  170. package/dist/apps/platform/routes/billing.d.ts +1520 -0
  171. package/dist/apps/platform/routes/billing.d.ts.map +1 -0
  172. package/dist/apps/platform/routes/billing.js +795 -0
  173. package/dist/apps/platform/routes/billing.js.map +1 -0
  174. package/dist/apps/platform/routes/invitations.d.ts +851 -0
  175. package/dist/apps/platform/routes/invitations.d.ts.map +1 -0
  176. package/dist/apps/platform/routes/invitations.js +471 -0
  177. package/dist/apps/platform/routes/invitations.js.map +1 -0
  178. package/dist/apps/platform/routes/me.d.ts +95 -0
  179. package/dist/apps/platform/routes/me.d.ts.map +1 -0
  180. package/dist/apps/platform/routes/me.js +81 -0
  181. package/dist/apps/platform/routes/me.js.map +1 -0
  182. package/dist/apps/platform/routes/members.d.ts +554 -0
  183. package/dist/apps/platform/routes/members.d.ts.map +1 -0
  184. package/dist/apps/platform/routes/members.js +251 -0
  185. package/dist/apps/platform/routes/members.js.map +1 -0
  186. package/dist/apps/platform/routes/orgs.d.ts +596 -0
  187. package/dist/apps/platform/routes/orgs.d.ts.map +1 -0
  188. package/dist/apps/platform/routes/orgs.js +276 -0
  189. package/dist/apps/platform/routes/orgs.js.map +1 -0
  190. package/dist/apps/platform/routes/projects.d.ts +740 -0
  191. package/dist/apps/platform/routes/projects.d.ts.map +1 -0
  192. package/dist/apps/platform/routes/projects.js +286 -0
  193. package/dist/apps/platform/routes/projects.js.map +1 -0
  194. package/dist/apps/platform/routes/scopes.d.ts +107 -0
  195. package/dist/apps/platform/routes/scopes.d.ts.map +1 -0
  196. package/dist/apps/platform/routes/scopes.js +66 -0
  197. package/dist/apps/platform/routes/scopes.js.map +1 -0
  198. package/dist/apps/platform/routes/usage.d.ts +588 -0
  199. package/dist/apps/platform/routes/usage.d.ts.map +1 -0
  200. package/dist/apps/platform/routes/usage.js +391 -0
  201. package/dist/apps/platform/routes/usage.js.map +1 -0
  202. package/dist/apps/relay/App.d.ts +44 -0
  203. package/dist/apps/relay/App.d.ts.map +1 -0
  204. package/dist/apps/relay/App.js +211 -0
  205. package/dist/apps/relay/App.js.map +1 -0
  206. package/dist/apps/relay/Sponsorships.d.ts +107 -0
  207. package/dist/apps/relay/Sponsorships.d.ts.map +1 -0
  208. package/dist/apps/relay/Sponsorships.js +194 -0
  209. package/dist/apps/relay/Sponsorships.js.map +1 -0
  210. package/dist/apps/relay/index.d.ts +3 -0
  211. package/dist/apps/relay/index.d.ts.map +1 -0
  212. package/dist/apps/relay/index.js +3 -0
  213. package/dist/apps/relay/index.js.map +1 -0
  214. package/dist/cli/Cli.d.ts +9 -2
  215. package/dist/cli/Cli.d.ts.map +1 -1
  216. package/dist/cli/Cli.js +12 -4
  217. package/dist/cli/Cli.js.map +1 -1
  218. package/dist/cli/commands/admin.d.ts +5 -1
  219. package/dist/cli/commands/admin.d.ts.map +1 -1
  220. package/dist/cli/commands/admin.js +82 -3
  221. package/dist/cli/commands/admin.js.map +1 -1
  222. package/dist/db/Db.d.ts +17 -0
  223. package/dist/db/Db.d.ts.map +1 -1
  224. package/dist/db/Db.js +254 -0
  225. package/dist/db/Db.js.map +1 -1
  226. package/dist/db/Schema.d.ts +159 -0
  227. package/dist/db/Schema.d.ts.map +1 -1
  228. package/dist/db/Schema.js +187 -2
  229. package/dist/db/Schema.js.map +1 -1
  230. package/dist/db/tables/billingSettings.d.ts +55 -0
  231. package/dist/db/tables/billingSettings.d.ts.map +1 -0
  232. package/dist/db/tables/billingSettings.js +70 -0
  233. package/dist/db/tables/billingSettings.js.map +1 -0
  234. package/dist/db/tables/invitations.d.ts +84 -0
  235. package/dist/db/tables/invitations.d.ts.map +1 -0
  236. package/dist/db/tables/invitations.js +165 -0
  237. package/dist/db/tables/invitations.js.map +1 -0
  238. package/dist/db/tables/memberships.d.ts +108 -0
  239. package/dist/db/tables/memberships.d.ts.map +1 -0
  240. package/dist/db/tables/memberships.js +153 -0
  241. package/dist/db/tables/memberships.js.map +1 -0
  242. package/dist/db/tables/organizations.d.ts +48 -0
  243. package/dist/db/tables/organizations.d.ts.map +1 -1
  244. package/dist/db/tables/organizations.js +97 -2
  245. package/dist/db/tables/organizations.js.map +1 -1
  246. package/dist/db/tables/projects.d.ts +65 -0
  247. package/dist/db/tables/projects.d.ts.map +1 -0
  248. package/dist/db/tables/projects.js +75 -0
  249. package/dist/db/tables/projects.js.map +1 -0
  250. package/dist/db/tables/requestUsage.d.ts +121 -0
  251. package/dist/db/tables/requestUsage.d.ts.map +1 -0
  252. package/dist/db/tables/requestUsage.js +150 -0
  253. package/dist/db/tables/requestUsage.js.map +1 -0
  254. package/dist/db/tables/sponsoredTransactions.d.ts +239 -0
  255. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -0
  256. package/dist/db/tables/sponsoredTransactions.js +314 -0
  257. package/dist/db/tables/sponsoredTransactions.js.map +1 -0
  258. package/dist/db/tables/stripeCustomers.d.ts +81 -0
  259. package/dist/db/tables/stripeCustomers.d.ts.map +1 -0
  260. package/dist/db/tables/stripeCustomers.js +120 -0
  261. package/dist/db/tables/stripeCustomers.js.map +1 -0
  262. package/dist/db/tables/users.d.ts +48 -0
  263. package/dist/db/tables/users.d.ts.map +1 -0
  264. package/dist/db/tables/users.js +65 -0
  265. package/dist/db/tables/users.js.map +1 -0
  266. package/dist/handlers/internal/executionError.d.ts.map +1 -1
  267. package/dist/handlers/internal/executionError.js +2 -0
  268. package/dist/handlers/internal/executionError.js.map +1 -1
  269. package/dist/handlers/internal/multisig.d.ts +2 -6
  270. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  271. package/dist/handlers/internal/multisig.js +11 -36
  272. package/dist/handlers/internal/multisig.js.map +1 -1
  273. package/dist/handlers/internal/sponsorship.d.ts +35 -2
  274. package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
  275. package/dist/handlers/internal/sponsorship.js +53 -14
  276. package/dist/handlers/internal/sponsorship.js.map +1 -1
  277. package/dist/handlers/internal/utils.d.ts +10 -3
  278. package/dist/handlers/internal/utils.d.ts.map +1 -1
  279. package/dist/handlers/internal/utils.js +14 -6
  280. package/dist/handlers/internal/utils.js.map +1 -1
  281. package/dist/handlers/relay.d.ts +6 -2
  282. package/dist/handlers/relay.d.ts.map +1 -1
  283. package/dist/handlers/relay.js +16 -2
  284. package/dist/handlers/relay.js.map +1 -1
  285. package/dist/index.d.ts +1 -0
  286. package/dist/index.d.ts.map +1 -1
  287. package/dist/index.js +1 -0
  288. package/dist/index.js.map +1 -1
  289. package/dist/internal/Auth.d.ts +222 -6
  290. package/dist/internal/Auth.d.ts.map +1 -1
  291. package/dist/internal/Auth.js +625 -74
  292. package/dist/internal/Auth.js.map +1 -1
  293. package/dist/internal/Cache.d.ts.map +1 -1
  294. package/dist/internal/Cache.js +4 -1
  295. package/dist/internal/Cache.js.map +1 -1
  296. package/dist/internal/EdgeCache.d.ts +10 -0
  297. package/dist/internal/EdgeCache.d.ts.map +1 -1
  298. package/dist/internal/EdgeCache.js +39 -8
  299. package/dist/internal/EdgeCache.js.map +1 -1
  300. package/dist/internal/Fees.d.ts +27 -0
  301. package/dist/internal/Fees.d.ts.map +1 -0
  302. package/dist/internal/Fees.js +48 -0
  303. package/dist/internal/Fees.js.map +1 -0
  304. package/dist/internal/FundingRoutes.d.ts +183 -0
  305. package/dist/internal/FundingRoutes.d.ts.map +1 -0
  306. package/dist/internal/FundingRoutes.js +490 -0
  307. package/dist/internal/FundingRoutes.js.map +1 -0
  308. package/dist/internal/Id.d.ts +15 -0
  309. package/dist/internal/Id.d.ts.map +1 -0
  310. package/dist/internal/Id.js +22 -0
  311. package/dist/internal/Id.js.map +1 -0
  312. package/dist/internal/Log.d.ts +9 -3
  313. package/dist/internal/Log.d.ts.map +1 -1
  314. package/dist/internal/Log.js +7 -0
  315. package/dist/internal/Log.js.map +1 -1
  316. package/dist/internal/OpenApi.d.ts +10 -20
  317. package/dist/internal/OpenApi.d.ts.map +1 -1
  318. package/dist/internal/OpenApi.js +8 -58
  319. package/dist/internal/OpenApi.js.map +1 -1
  320. package/dist/internal/RateLimit.d.ts +25 -0
  321. package/dist/internal/RateLimit.d.ts.map +1 -1
  322. package/dist/internal/RateLimit.js +51 -0
  323. package/dist/internal/RateLimit.js.map +1 -1
  324. package/dist/internal/Response.d.ts +1 -1
  325. package/dist/internal/Response.d.ts.map +1 -1
  326. package/dist/internal/Schema.d.ts +8 -0
  327. package/dist/internal/Schema.d.ts.map +1 -1
  328. package/dist/internal/Schema.js +7 -0
  329. package/dist/internal/Schema.js.map +1 -1
  330. package/dist/internal/Store.d.ts +7 -1
  331. package/dist/internal/Store.d.ts.map +1 -1
  332. package/dist/internal/Store.js +16 -2
  333. package/dist/internal/Store.js.map +1 -1
  334. package/dist/internal/Viem.d.ts +84 -0
  335. package/dist/internal/Viem.d.ts.map +1 -1
  336. package/dist/internal/Webhooks.d.ts +1 -1
  337. package/dist/internal/Webhooks.d.ts.map +1 -1
  338. package/dist/internal/Webhooks.js +3 -3
  339. package/dist/internal/Webhooks.js.map +1 -1
  340. package/package.json +33 -6
  341. package/src/ApiKey.ts +10 -2
  342. package/src/ApiKeys.test.ts +155 -1
  343. package/src/ApiKeys.ts +203 -1
  344. package/src/App.test.ts +64 -75741
  345. package/src/App.ts +218 -420
  346. package/src/Client.test-d.ts +657 -15
  347. package/src/Scope.ts +26 -4
  348. package/src/Webhooks.ts +2 -2
  349. package/src/admin/apps/api-keys.test.ts +51 -0
  350. package/src/admin/apps/api-keys.ts +84 -0
  351. package/src/admin/apps/scopes.test.ts +11 -1
  352. package/src/admin/apps/scopes.ts +3 -0
  353. package/src/admin/apps/verified-tokens.ts +1 -1
  354. package/src/admin/ui/src/components/Page.tsx +2 -3
  355. package/src/admin/ui/src/routes/__root.tsx +2 -2
  356. package/src/admin/ui/src/routes/api-keys.tsx +2 -2
  357. package/src/admin/ui.generated.ts +13 -13
  358. package/src/analytics/Analytics.test.ts +527 -0
  359. package/src/analytics/Analytics.ts +318 -0
  360. package/src/analytics/tables/requestEvents.ts +523 -0
  361. package/src/apps/composition.test.ts +66 -0
  362. package/src/apps/data/App.test.ts +72 -0
  363. package/src/apps/data/App.ts +330 -0
  364. package/src/apps/data/index.ts +2 -0
  365. package/src/apps/{activities.test.ts → data/routes/activities.test.ts} +3 -3
  366. package/src/apps/{activities.ts → data/routes/activities.ts} +15 -15
  367. package/src/apps/{addresses.ts → data/routes/addresses.ts} +6 -6
  368. package/src/apps/{balances.test.ts → data/routes/balances.test.ts} +2 -2
  369. package/src/apps/{balances.ts → data/routes/balances.ts} +46 -12
  370. package/src/apps/{blocks.test.ts → data/routes/blocks.test.ts} +3 -3
  371. package/src/apps/{blocks.ts → data/routes/blocks.ts} +14 -14
  372. package/src/apps/{coingecko.test.ts → data/routes/coingecko.test.ts} +2 -2
  373. package/src/apps/{coingecko.ts → data/routes/coingecko.ts} +14 -14
  374. package/src/apps/{exchanges.test.ts → data/routes/exchanges.test.ts} +1 -1
  375. package/src/apps/{exchanges.ts → data/routes/exchanges.ts} +20 -20
  376. package/src/apps/{fee-amm.test.ts → data/routes/fee-amm.test.ts} +3 -3
  377. package/src/apps/{fee-amm.ts → data/routes/fee-amm.ts} +18 -18
  378. package/src/apps/data/routes/funding.test.ts +214 -0
  379. package/src/apps/data/routes/funding.ts +584 -0
  380. package/src/apps/{indexer.test.ts → data/routes/indexer.test.ts} +26 -5
  381. package/src/apps/{indexer.ts → data/routes/indexer.ts} +13 -10
  382. package/src/apps/{receipts.test.ts → data/routes/receipts.test.ts} +3 -3
  383. package/src/apps/{receipts.ts → data/routes/receipts.ts} +15 -22
  384. package/src/apps/{rpc.test.ts → data/routes/rpc.test.ts} +122 -7
  385. package/src/apps/{rpc.ts → data/routes/rpc.ts} +38 -8
  386. package/src/apps/{tokenlist.test.ts → data/routes/tokenlist.test.ts} +3 -3
  387. package/src/apps/{tokenlist.ts → data/routes/tokenlist.ts} +9 -9
  388. package/src/apps/{tokens.test.ts → data/routes/tokens.test.ts} +2 -2
  389. package/src/apps/{tokens.ts → data/routes/tokens.ts} +20 -20
  390. package/src/apps/{transactions.test.ts → data/routes/transactions.test.ts} +3 -3
  391. package/src/apps/{transactions.ts → data/routes/transactions.ts} +15 -15
  392. package/src/apps/{transfers.test.ts → data/routes/transfers.test.ts} +2 -2
  393. package/src/apps/{transfers.ts → data/routes/transfers.ts} +15 -15
  394. package/src/apps/{verified-tokens.test.ts → data/routes/verified-tokens.test.ts} +3 -3
  395. package/src/apps/{verified-tokens.ts → data/routes/verified-tokens.ts} +10 -10
  396. package/src/apps/{webhooks.test.ts → data/routes/webhooks.test.ts} +7 -7
  397. package/src/apps/{webhooks.ts → data/routes/webhooks.ts} +50 -43
  398. package/src/apps/docs/App.ts +65 -0
  399. package/src/apps/docs/index.ts +1 -0
  400. package/src/apps/docs/reference.ts +132 -0
  401. package/src/apps/index.ts +4 -0
  402. package/src/apps/mcp.test.ts +206 -0
  403. package/src/apps/mcp.ts +250 -0
  404. package/src/apps/metadata.ts +23 -0
  405. package/src/apps/platform/App.ts +169 -0
  406. package/src/apps/platform/Billing.test.ts +530 -0
  407. package/src/apps/platform/Billing.ts +682 -0
  408. package/src/apps/platform/index.ts +2 -0
  409. package/src/apps/platform/routes/api-keys.test.ts +493 -0
  410. package/src/apps/platform/routes/api-keys.ts +543 -0
  411. package/src/apps/platform/routes/billing.test.ts +1100 -0
  412. package/src/apps/platform/routes/billing.ts +966 -0
  413. package/src/apps/platform/routes/invitations.test.ts +409 -0
  414. package/src/apps/platform/routes/invitations.ts +587 -0
  415. package/src/apps/platform/routes/me.test.ts +351 -0
  416. package/src/apps/platform/routes/me.ts +106 -0
  417. package/src/apps/platform/routes/members.test.ts +195 -0
  418. package/src/apps/platform/routes/members.ts +313 -0
  419. package/src/apps/platform/routes/orgs.test.ts +313 -0
  420. package/src/apps/platform/routes/orgs.ts +365 -0
  421. package/src/apps/platform/routes/projects.test.ts +181 -0
  422. package/src/apps/platform/routes/projects.ts +367 -0
  423. package/src/apps/platform/routes/scopes.test.ts +29 -0
  424. package/src/apps/platform/routes/scopes.ts +85 -0
  425. package/src/apps/platform/routes/usage.test.ts +422 -0
  426. package/src/apps/platform/routes/usage.ts +527 -0
  427. package/src/apps/relay/App.test.ts +933 -0
  428. package/src/apps/relay/App.ts +236 -0
  429. package/src/apps/relay/Sponsorships.test.ts +375 -0
  430. package/src/apps/relay/Sponsorships.ts +306 -0
  431. package/src/apps/relay/index.ts +2 -0
  432. package/src/cli/Cli.test.ts +25 -2
  433. package/src/cli/Cli.ts +18 -3
  434. package/src/cli/commands/admin.test.ts +83 -0
  435. package/src/cli/commands/admin.ts +91 -3
  436. package/src/db/Db.ts +296 -0
  437. package/src/db/Schema.ts +241 -2
  438. package/src/db/tables/billingSettings.test.ts +87 -0
  439. package/src/db/tables/billingSettings.ts +108 -0
  440. package/src/db/tables/invitations.ts +198 -0
  441. package/src/db/tables/memberships.ts +208 -0
  442. package/src/db/tables/organizations.test.ts +38 -2
  443. package/src/db/tables/organizations.ts +117 -2
  444. package/src/db/tables/projects.ts +107 -0
  445. package/src/db/tables/requestUsage.ts +231 -0
  446. package/src/db/tables/sponsoredTransactions.test.ts +325 -0
  447. package/src/db/tables/sponsoredTransactions.ts +464 -0
  448. package/src/db/tables/stripeCustomers.test.ts +109 -0
  449. package/src/db/tables/stripeCustomers.ts +162 -0
  450. package/src/db/tables/users.ts +85 -0
  451. package/src/handlers/internal/executionError.ts +2 -0
  452. package/src/handlers/internal/multisig.test.ts +84 -10
  453. package/src/handlers/internal/multisig.ts +15 -50
  454. package/src/handlers/internal/sponsorship.ts +106 -20
  455. package/src/handlers/internal/utils.ts +19 -7
  456. package/src/handlers/{internal/relay.localnet.test.ts → relay.test.ts} +2 -2
  457. package/src/handlers/relay.ts +23 -5
  458. package/src/index.ts +1 -0
  459. package/src/internal/Auth.test.ts +491 -25
  460. package/src/internal/Auth.ts +839 -84
  461. package/src/internal/Cache.ts +5 -1
  462. package/src/internal/Cursor.test.ts +3 -2
  463. package/src/internal/EdgeCache.test.ts +27 -4
  464. package/src/internal/EdgeCache.ts +47 -9
  465. package/src/internal/Fees.test.ts +32 -0
  466. package/src/internal/Fees.ts +51 -0
  467. package/src/internal/FundingRoutes.ts +583 -0
  468. package/src/internal/Id.test.ts +17 -0
  469. package/src/internal/Id.ts +24 -0
  470. package/src/internal/Log.test.ts +2 -1
  471. package/src/internal/Log.ts +16 -3
  472. package/src/internal/MetricSink.ts +1 -1
  473. package/src/internal/OpenApi.ts +12 -60
  474. package/src/internal/RateLimit.test.ts +84 -0
  475. package/src/internal/RateLimit.ts +70 -0
  476. package/src/internal/Response.ts +1 -1
  477. package/src/internal/Schema.ts +8 -0
  478. package/src/internal/Store.test.ts +52 -0
  479. package/src/internal/Store.ts +24 -5
  480. package/src/internal/Tidx.local.test.ts +1 -1
  481. package/src/internal/VerifiedTokens.test.ts +1 -1
  482. package/src/internal/WebhookDestination.test.ts +1 -1
  483. package/src/internal/Webhooks.test.ts +7 -7
  484. package/src/internal/Webhooks.ts +4 -4
  485. package/dist/apps/activities.js.map +0 -1
  486. package/dist/apps/addresses.js.map +0 -1
  487. package/dist/apps/balances.d.ts.map +0 -1
  488. package/dist/apps/balances.js.map +0 -1
  489. package/dist/apps/blocks.d.ts.map +0 -1
  490. package/dist/apps/blocks.js.map +0 -1
  491. package/dist/apps/coingecko.d.ts.map +0 -1
  492. package/dist/apps/coingecko.js.map +0 -1
  493. package/dist/apps/exchanges.d.ts.map +0 -1
  494. package/dist/apps/exchanges.js.map +0 -1
  495. package/dist/apps/fee-amm.d.ts.map +0 -1
  496. package/dist/apps/fee-amm.js.map +0 -1
  497. package/dist/apps/indexer.d.ts.map +0 -1
  498. package/dist/apps/indexer.js.map +0 -1
  499. package/dist/apps/receipts.d.ts.map +0 -1
  500. package/dist/apps/receipts.js.map +0 -1
  501. package/dist/apps/rpc.d.ts.map +0 -1
  502. package/dist/apps/rpc.js.map +0 -1
  503. package/dist/apps/tokenlist.d.ts.map +0 -1
  504. package/dist/apps/tokenlist.js.map +0 -1
  505. package/dist/apps/tokens.d.ts.map +0 -1
  506. package/dist/apps/tokens.js.map +0 -1
  507. package/dist/apps/transactions.d.ts.map +0 -1
  508. package/dist/apps/transactions.js.map +0 -1
  509. package/dist/apps/transfers.d.ts.map +0 -1
  510. package/dist/apps/transfers.js.map +0 -1
  511. package/dist/apps/verified-tokens.d.ts.map +0 -1
  512. package/dist/apps/verified-tokens.js.map +0 -1
  513. package/dist/apps/webhooks.js.map +0 -1
  514. package/dist/internal/OpenApi.fonts.d.ts.map +0 -1
  515. package/dist/internal/OpenApi.fonts.js.map +0 -1
  516. package/dist/internal/OpenApi.logo.d.ts.map +0 -1
  517. package/dist/internal/OpenApi.logo.js.map +0 -1
  518. package/src/handlers/internal/multisig.localnet.test.ts +0 -146
  519. /package/src/{internal/OpenApi.fonts.ts → apps/docs/fonts.ts} +0 -0
  520. /package/src/{internal/OpenApi.logo.ts → apps/docs/logo.ts} +0 -0
package/src/App.ts CHANGED
@@ -1,19 +1,17 @@
1
- import type { Context, MiddlewareHandler } from 'hono'
1
+ import type { Context } from 'hono'
2
2
  import { Hono } from 'hono'
3
3
  import { compress as hono_compress } from 'hono/compress'
4
4
  import { cors as hono_cors } from 'hono/cors'
5
5
  import { HTTPException } from 'hono/http-exception'
6
6
  import { requestId, type RequestIdVariables } from 'hono/request-id'
7
7
  import { generateSpecs } from 'hono-openapi'
8
- import { Handler as vocs_Handler } from 'vocs/server'
9
- import * as z from 'zod/mini'
10
8
 
9
+ import type * as Analytics from './analytics/Analytics.js'
11
10
  import * as ApiKey from './ApiKey.js'
12
11
  import * as Assets from './Assets.js'
13
12
  import * as Auth from './internal/Auth.js'
14
13
  import * as Db from './db/Db.js'
15
14
  import * as EdgeCache from './internal/EdgeCache.js'
16
- import * as Handler from './Handler.js'
17
15
  import * as Log from './internal/Log.js'
18
16
  import * as MetricSink from './internal/MetricSink.js'
19
17
  import type * as Metrics from './Metrics.js'
@@ -21,34 +19,30 @@ import * as OpenApi from './internal/OpenApi.js'
21
19
  import * as Store from './internal/Store.js'
22
20
  import * as Path from './internal/Path.js'
23
21
  import * as Response from './internal/Response.js'
24
- import * as Schema from './internal/Schema.js'
25
- import * as Tidx from './internal/Tidx.js'
22
+ import type * as Tidx from './internal/Tidx.js'
26
23
  import * as Timing from './internal/Timing.js'
27
- import * as VerifiedTokens from './internal/VerifiedTokens.js'
28
24
  import * as Viem from './internal/Viem.js'
29
25
 
30
26
  import openrpcSpec from './openrpc.json' with { type: 'json' }
31
27
 
32
- import { transactions as transactionActivities } from './apps/activities.js'
33
- import { addresses } from './apps/addresses.js'
34
- import { blocks, blocksByTimestampCompat } from './apps/blocks.js'
35
- import { coingecko } from './apps/coingecko.js'
36
- import { exchanges } from './apps/exchanges.js'
37
- import { feeAmm } from './apps/fee-amm.js'
38
- import { indexer } from './apps/indexer.js'
39
- import { receipts } from './apps/receipts.js'
40
- import { rpc as rpcApp } from './apps/rpc.js'
41
- import { tokens } from './apps/tokens.js'
42
- import { transactions } from './apps/transactions.js'
43
- import { transfers } from './apps/transfers.js'
44
- import { verifiedTokens } from './apps/verified-tokens.js'
45
- import { tokenlist } from './apps/tokenlist.js'
46
- import { schema as webhookSchema, webhooks } from './apps/webhooks.js'
28
+ import * as Metadata from './apps/metadata.js'
29
+ import * as Data from './apps/data/App.js'
30
+ import * as Platform from './apps/platform/App.js'
31
+
32
+ export import data = Data.data
33
+ export import platform = Platform.platform
34
+
35
+ /** The chain-data route group; see {@link data}. */
36
+ export type DataApp = ReturnType<typeof data>
37
+ /** The tenant-platform route group; see {@link platform}. */
38
+ export type PlatformApp = ReturnType<typeof platform>
47
39
 
48
40
  /** Hono environment variables set by the Tempo API app. */
49
41
  export type Environment = {
50
42
  Variables: Auth.Variables &
51
43
  RequestIdVariables & {
44
+ /** ClickHouse-backed analytics store, or a per-request factory; undefined when usage analytics is unconfigured. Resolve at the leaf with `Analytics.get`. */
45
+ analytics: Analytics.Source | undefined
52
46
  /** Base path for this API app. */
53
47
  basePath: string
54
48
  /** Default Tempo chain id for this API app. */
@@ -83,15 +77,18 @@ export type Environment = {
83
77
  }
84
78
 
85
79
  /**
86
- * Tempo API Hono app with shared API dependencies. Inferred from `create`.
87
- * The `path` generic is pinned to `'/'` (its default) so the resulting Hono
88
- * `BasePath` is a concrete literal; without the explicit type argument
89
- * `ReturnType<typeof create>` would resolve `path` to its constraint
90
- * (`string`), and Hono's `MergePath<string, '/foo'>` would surface every
91
- * endpoint key as `` `… ${string}/foo` `` — which can be satisfied but never
92
- * autocompleted.
80
+ * The canonical fully-composed Tempo API app ({@link create} with both route
81
+ * groups). {@link Client} and the reference worker target this type; a subset
82
+ * consumer infers its own narrower type from its own composition chain.
93
83
  */
94
- export type App = ReturnType<typeof create<'/'>>
84
+ export type App = ReturnType<typeof compose>
85
+
86
+ // Type anchor only — never invoked. Expresses the canonical composition so
87
+ // `App` (and thus `Client`) reflect the full route surface; real consumers
88
+ // compose explicitly.
89
+ function compose(options: create.Options) {
90
+ return create(options).route('/', data()).route('/', platform())
91
+ }
95
92
 
96
93
  /** Node.js request listener for `node:http` and compatible interfaces. */
97
94
  export type Listener = (incoming: unknown, outgoing: unknown) => Promise<void>
@@ -99,6 +96,12 @@ export type Listener = (incoming: unknown, outgoing: unknown) => Promise<void>
99
96
  /** HTTP endpoints owned by Tempo API handlers, used for typed auth overrides. */
100
97
  export type Endpoint = Auth.Endpoint<App>
101
98
 
99
+ /** Stripe billing capability for platform billing routes; owned by {@link platform}. */
100
+ export type Billing = Platform.Billing
101
+
102
+ /** Transactional email sender for platform emails; owned by {@link platform}. */
103
+ export type Email = Platform.Email
104
+
102
105
  /** One static API asset resolved from packaged data. */
103
106
  export type Asset = {
104
107
  /** Loaded asset response. */
@@ -118,7 +121,7 @@ const infoDescription = 'REST API for reading and interacting with Tempo'
118
121
 
119
122
  /** Creates the Tempo API Hono app. */
120
123
  export function create<const path extends string = '/'>(options: create.Options<path>) {
121
- const { assets, defaultChainId = Viem.defaultChainId, path = '/' as path, rpc } = options
124
+ const { path = '/' as path } = options
122
125
 
123
126
  // Capture as the literal generic so `Hono.basePath(...)` preserves the
124
127
  // typed prefix. testClient's `Client<T, ...>` inference collapses to a
@@ -136,31 +139,6 @@ export function create<const path extends string = '/'>(options: create.Options<
136
139
  // `options.db`, API-key records in `options.kv`.
137
140
  const store = options.cache?.store ?? Store.memory()
138
141
 
139
- // Memoize one viem client per resolved upstream. Clients are stateless HTTP
140
- // transports, so reusing them avoids per-request construction cost. The cache
141
- // key is the resolved output (`url` + `basicAuth` + `chainId`), not the
142
- // principal, so a resolver `rpc` may branch on any principal field while
143
- // client cardinality stays bounded by the number of distinct upstreams —
144
- // callers that resolve to the same upstream share a client.
145
- const clients = new Map<string, ReturnType<typeof Viem.getClient>>()
146
- const getClient = (chainId = defaultChainId, principal: Auth.Principal | null = null) => {
147
- // Resolve to derive the cache key; `Viem.getClient` re-resolves to build the
148
- // client on a miss. `resolve` is pure and cheap, so the extra call is free.
149
- const { url, basicAuth } = Viem.resolve(rpc, { chainId, principal })
150
- const cacheKey = `${url}|${basicAuth ?? ''}|${chainId}`
151
- const existing = clients.get(cacheKey)
152
- if (existing) return existing
153
- const client = Viem.getClient({ chainId, principal, rpc })
154
- clients.set(cacheKey, client)
155
- return client
156
- }
157
-
158
- // Memoize TIDX clients per `chainId` so the base URL resolver runs once per
159
- // chain instead of on every request. The same factory backs the scheduled
160
- // webhook poller (`Webhooks.createPoller`), keeping client construction in
161
- // one place.
162
- const getTidx = Tidx.createGetClient({ defaultChainId, tidx: options.tidx })
163
-
164
142
  // Build the app in two phases: register middleware imperatively, then chain
165
143
  // route mounts so the merged Hono schema flows through the return type. The
166
144
  // chained type is what makes `testClient(create())` produce typed path
@@ -217,69 +195,35 @@ export function create<const path extends string = '/'>(options: create.Options<
217
195
  },
218
196
  }),
219
197
  )
220
- // The chain ids this deployment serves: the built-in public chains plus the
221
- // configured `defaultChainId` and any explicit `supportedChainIds`. Exposed on
222
- // context so mounted apps with a path `chainId` (e.g. GeckoTerminal) can guard
223
- // it too.
224
- const supportedChainIds = new Set<number>([
225
- ...Object.keys(Viem.url).map(Number),
226
- ...Object.keys(Tidx.url).map(Number),
227
- defaultChainId,
228
- ...(options.supportedChainIds ?? []),
229
- ])
230
198
 
231
199
  // Normalize the `db` option: the plain form is `{ source }` with no cached
232
200
  // side; `cached` falls back to `source` so consumers never branch.
233
201
  const db = 'source' in options.db ? options.db : { source: options.db }
234
202
 
203
+ // Normalize the `analytics` option: accept the bare source or `{ source }`,
204
+ // mirroring `db`. Undefined leaves usage analytics unconfigured (501).
205
+ const analytics =
206
+ options.analytics === undefined
207
+ ? undefined
208
+ : 'source' in options.analytics
209
+ ? options.analytics.source
210
+ : options.analytics
211
+
212
+ // Built-in auth: the session surface (mounted last) plus the enforcement
213
+ // middleware (installed below), wired together in `Auth.install`.
214
+ const auth = Auth.install({ auth: options.auth, db: db.source, kv: options.kv })
215
+
235
216
  base.use('*', Timing.middleware())
236
217
  base.use('*', async (c, next) => {
237
- // Put app-level dependencies on Hono context so mounted handlers only
238
- // receive request-local state from `c`.
218
+ c.set('analytics', analytics)
239
219
  c.set('basePath', basePath)
240
- c.set('chainId', defaultChainId)
241
220
  c.set('db', db.source)
242
221
  c.set('dbCached', db.cached ?? db.source)
243
- c.set('getAsset', createGetAsset({ assets, basePath, origin: new URL(c.req.url).origin }))
244
- c.set('getClient', (chainId) => getClient(chainId, Auth.getPrincipal(c)))
245
- c.set('getTidx', (chainId) => getTidx(chainId, Auth.getPrincipal(c)))
246
222
  c.set('kv', options.kv)
247
- c.set('rpc', rpc)
248
223
  c.set('store', store)
249
- c.set('supportedChainIds', supportedChainIds)
250
- c.set('tidx', options.tidx)
251
- // Feature configs default to enabled empty configs; `false` disables.
252
- c.set('verifiedTokens', options.verifiedTokens === false ? undefined : (options.verifiedTokens ?? {})) // prettier-ignore
253
- c.set('webhook', options.webhook === false ? undefined : (options.webhook ?? {}))
254
224
  await next()
255
225
  })
256
226
 
257
- // Reject a syntactically valid `chainId` this deployment does not serve before
258
- // it reaches an upstream — an unknown chain otherwise hits the configured
259
- // RPC/indexer (a static `tidx.baseUrl` answers for any chain id) and comes
260
- // back as an opaque `upstream_error`.
261
- base.use('*', async (c, next) => {
262
- const raw = c.req.query('chainId') ?? c.req.query('chain_id')
263
- if (raw === undefined) return next()
264
- // Only reject a well-formed-but-unsupported chain here; malformed values
265
- // (e.g. `abc`, `0`) fall through to the route's own query validation.
266
- const parsed = Schema.ChainId.safeParse(raw)
267
- if (!parsed.success || supportedChainIds.has(parsed.data)) return next()
268
- return Response.unsupportedChainId(c, parsed.data, supportedChainIds)
269
- })
270
- // Skip the static asset route entirely when no store is configured; token
271
- // logo URIs simply go unresolved.
272
- if (assets)
273
- base.use('/assets/*', async (c, next) => {
274
- const key = stripAssetPath(c.req.path, basePath).replace(/^\/+/, '')
275
- const asset = key ? await assets.get(key) : undefined
276
- if (!asset) return next()
277
- return c.body(asset.body, 200, {
278
- 'Cache-Control': 'public, max-age=86400',
279
- 'Content-Type': asset.contentType,
280
- })
281
- })
282
-
283
227
  // Safety net: any non-2xx response (auth/validation errors, MPP `402`
284
228
  // challenges, rate-limit `429`s, upstream `502`s, etc.) must never be
285
229
  // cached. This wraps endpoint middleware and handlers registered below.
@@ -295,106 +239,79 @@ export function create<const path extends string = '/'>(options: create.Options<
295
239
  // latency.
296
240
  if (options.cache?.edge !== false) base.use('*', EdgeCache.middleware<Environment>({ store }))
297
241
 
298
- const base_routed = base.get('/health', OpenApi.describeRoute({ hide: true }), (c) =>
242
+ const app = base.get('/health', OpenApi.describeRoute({ hide: true }), (c) =>
299
243
  c.json({ status: 'ok' }, 200),
300
244
  )
301
245
 
302
- for (const middleware of options.middleware ?? []) base_routed.use('*', middleware)
303
-
304
- const app = base_routed
305
- .route('/v1/addresses', addresses())
306
- .route('/v1/blocks', blocks())
307
- .route('/v1/exchange', exchanges())
308
- .route('/v1/fee-amm', feeAmm())
309
- .route('/v1/indexer', indexer())
310
- .route('/v1/tokenlist', tokenlist())
311
- .route('/v1/tokens', tokens())
312
- .route('/v1/transactions', receipts())
313
- .route('/v1/transactions', transactions())
314
- .route('/v1/transactions', transactionActivities())
315
- .route('/v1/transfers', transfers())
316
- .route('/v1/verified-tokens', verifiedTokens())
317
- .route('/v1/webhooks', webhooks({ enabled: options.webhook !== false }))
318
- .route('/rpc', rpcApp())
319
- .use(
320
- '/rpc/relay',
321
- Auth.policy({ apiKey: { scopes: ['rpc-relay'] }, mpp: false, public: false }),
322
- OpenApi.describeRoute({ hide: true, summary: 'Relay RPC' }),
323
- )
324
- .use(
325
- '/rpc/relay/*',
326
- Auth.policy({ apiKey: { scopes: ['rpc-relay'] }, mpp: false, public: false }),
327
- OpenApi.describeRoute({ hide: true, summary: 'Relay RPC' }),
328
- )
329
- .route(
330
- '/rpc/relay',
331
- Handler.relay({
332
- cache: store,
333
- getClient: (chainId) => getClient(chainId as Viem.ChainId | undefined),
334
- ...(options.verifiedTokens === false
335
- ? {}
336
- : {
337
- resolveTokens: async (chainId: number) => {
338
- const snapshot = await VerifiedTokens.read(Db.get(db.cached ?? db.source), chainId)
339
- return snapshot?.list.map((token) => token.address) ?? []
340
- },
341
- }),
342
- }),
246
+ // Built-in enforcement: default-closed policies over OpenAPI-registered
247
+ // routes. `auth: false` leaves policies unenforced (tests only).
248
+ if (auth.middleware) app.use('*', auth.middleware)
249
+
250
+ // Collect each mounted group's OpenAPI metadata: Hono's `.route()` drops
251
+ // sub-app metadata, so a group attaches it to its instance (a WeakMap) and we
252
+ // read it back here. Patching the runtime method, not the type, keeps `hc`.
253
+ const metadata: create.Metadata[] = []
254
+ const route = app.route.bind(app)
255
+ ;(app as unknown as { route: typeof route }).route = ((path, sub) => {
256
+ const entry = Metadata.read(sub)
257
+ if (entry) metadata.push(entry)
258
+ return route(path, sub)
259
+ }) as typeof route
260
+
261
+ // Register the JSON error envelopes eagerly (they don't depend on mounted
262
+ // routes) so error handling is live before the first request and a consumer's
263
+ // `withSentry(app)` sees them already in place.
264
+ app.notFound((c) =>
265
+ Response.error(c, { code: 'not_found', message: 'Route not found', status: 404 }),
266
+ )
267
+ app.onError((cause, c) => {
268
+ if (cause instanceof HTTPException) return errorFromException(c, cause)
269
+
270
+ // Redact any leaked API-key token from the logged error/stack.
271
+ console.error(
272
+ ApiKey.redact(cause instanceof Error ? (cause.stack ?? cause.message) : String(cause)),
343
273
  )
344
- .route('/gecko', coingecko())
345
- // Hidden compatibility route for the prior Tempo API's
346
- // `GET /chains/:chainId/blocks/by-timestamp` (chain id in the path).
347
- .route('/chains', blocksByTimestampCompat())
348
-
349
- const spec = (async () => {
350
- // OAS 3.1 `webhooks`: document the signed envelope Tempo API POSTs to subscriber
351
- // URLs (an outbound payload, not an endpoint of this API). Only when enabled.
352
- const webhooksDoc = (() => {
353
- if (options.webhook === false) return {}
354
- // `io: 'output'` documents the delivered (serialized) shape; `unrepresentable: 'any'`
355
- // tolerates the transaction payload's transforms (e.g. lazy fee-token metadata),
356
- // which have no JSON-Schema form, by emitting `{}` for those nodes rather than throwing.
357
- const envelope = z.toJSONSchema(webhookSchema.Envelope, {
358
- io: 'output',
359
- target: 'draft-2020-12',
360
- unrepresentable: 'any',
361
- })
362
- delete envelope.$schema
363
- const header = (name: string, description: string) => ({
364
- description,
365
- in: 'header' as const,
366
- name,
367
- required: true,
368
- schema: { type: 'string' as const },
369
- })
370
- return {
371
- webhooks: {
372
- event: {
373
- post: {
374
- description:
375
- 'When an event you subscribed to happens, Tempo sends this signed message to your webhook URL as an HTTP POST (the same shape is used by `POST /webhooks/:id/ping` so you can test your endpoint). Always verify the `tempo-signature` header before trusting the body, then reply with any 2xx status to confirm you received it. If your endpoint returns a non-2xx status, times out, or redirects, Tempo retries with increasing delays; an endpoint that keeps failing is eventually disabled.',
376
- parameters: [
377
- header(
378
- 'tempo-signature',
379
- 'Signature proving the message really came from Tempo. An HMAC-SHA256 of the body using your webhook secret, formatted `t=<unix>,v1=<hex>`. Verify this before trusting the payload.',
380
- ),
381
- header(
382
- 'tempo-event-id',
383
- 'A unique, stable id for this event (`evt_…`). The same event may be delivered more than once, so use this id to skip duplicates.',
384
- ),
385
- header('tempo-event-type', 'What happened: `token:transfer`, `transaction:included`, `log:emitted`, `block:created`, or `ping`.'), // prettier-ignore
386
- ],
387
- requestBody: {
388
- content: { 'application/json': { schema: envelope } },
389
- required: true,
390
- },
391
- responses: { '2xx': { description: 'Delivery acknowledged.' } },
392
- summary: 'Webhook event delivery',
393
- tags: ['Webhooks'],
394
- },
395
- },
396
- },
397
- }
274
+ return Response.error(c, {
275
+ code: 'internal_error',
276
+ message: 'Internal server error',
277
+ status: 500,
278
+ })
279
+ })
280
+
281
+ // Mount the OpenAPI/OpenRPC documents and docs reference lazily on the first
282
+ // request, so the document sees the full route surface without a `seal()`
283
+ // step. The patched `fetch` runs this before Hono builds its matcher.
284
+ //
285
+ // Spec generation stays lazy: ordinary API traffic only installs the routes,
286
+ // while `/openapi.json` and the Vocs handler start the memoized build.
287
+ let spec: ReturnType<typeof buildSpec> | undefined
288
+ const getSpec = () => (spec ??= buildSpec())
289
+ const buildSpec = async () => {
290
+ // Merge each mounted group's contributed OpenAPI metadata (tags, security
291
+ // schemes, webhooks block). Unused tags/schemes don't render, so a subset
292
+ // app's document carries only what its groups contributed.
293
+ // The built-in session surface's metadata appends after every mounted
294
+ // group's, so consumer-mounted groups lead the document order.
295
+ const metadata_all = (() => {
296
+ const entry = auth.app ? Metadata.read(auth.app) : undefined
297
+ return entry ? [...metadata, entry] : metadata
298
+ })()
299
+ const contributedSchemes = Object.assign({}, ...metadata_all.map((m) => m.securitySchemes ?? {})) // prettier-ignore
300
+ const tags = metadata_all.flatMap((m) => m.tags ?? [])
301
+ // Tag groups contributed under the same name merge into one sidebar group,
302
+ // deduped and filtered to defined tags (a group may list a tag another
303
+ // surface defines, e.g. `Auth` from the built-in session surface).
304
+ const tagGroups = (() => {
305
+ const defined = new Set(tags.map((tag) => tag.name))
306
+ const groups = new Map<string, { name: string; tags: string[] }>()
307
+ for (const { name, tags: members } of metadata_all.flatMap((m) => m['x-tagGroups'] ?? []))
308
+ groups.set(name, { name, tags: [...(groups.get(name)?.tags ?? []), ...members] })
309
+ return [...groups.values()]
310
+ .map((group) => ({
311
+ ...group,
312
+ tags: [...new Set(group.tags)].filter((tag) => defined.has(tag)),
313
+ })) // prettier-ignore
314
+ .filter((group) => group.tags.length > 0)
398
315
  })()
399
316
  const generated = await generateSpecs(app, {
400
317
  documentation: {
@@ -414,6 +331,7 @@ export function create<const path extends string = '/'>(options: create.Options<
414
331
  scheme: 'bearer',
415
332
  type: 'http',
416
333
  },
334
+ ...contributedSchemes,
417
335
  },
418
336
  },
419
337
  info: {
@@ -427,71 +345,24 @@ export function create<const path extends string = '/'>(options: create.Options<
427
345
  { url: basePath || '/', description: 'Relative to the host serving this document.' },
428
346
  ]),
429
347
  ],
430
- tags: [
431
- {
432
- name: 'Activities',
433
- description: 'A readable feed of what an account did onchain.',
434
- },
435
- {
436
- name: 'Balances',
437
- description: 'How much of each token an account holds.',
438
- },
439
- {
440
- name: 'Blocks',
441
- description: 'The ordered batches of transactions making up the chain.',
442
- },
443
- {
444
- name: 'Exchange',
445
- description: "Tempo's built-in stablecoin exchange: pairs, swaps, orders, prices.",
446
- },
447
- {
448
- name: 'Fee AMM',
449
- description: 'Pools that convert stablecoins to pay fees.',
450
- },
451
- {
452
- name: 'Tokens',
453
- description: 'TIP-20 token details, supply, and holders.',
454
- },
455
- {
456
- name: 'Transactions',
457
- description: 'Transactions submitted to Tempo, and their receipts.',
458
- },
459
- {
460
- name: 'Transfers',
461
- description: 'Token movements from executing transactions.',
462
- },
463
- {
464
- name: 'Verified Tokens',
465
- description: 'A curated, trusted list of TIP-20 tokens.',
466
- },
467
- ...(options.webhook !== false
468
- ? [
469
- {
470
- name: 'Webhooks',
471
- description: 'Get signed callbacks when onchain events happen.',
472
- },
473
- ]
474
- : []),
475
- {
476
- name: 'Indexer',
477
- description: "Run read-only SQL queries against Tempo's indexed data.",
478
- },
479
- {
480
- name: 'RPC',
481
- description:
482
- 'Direct access to the chain over Ethereum JSON-RPC. Not part of the stable API contract; best-effort support only. No compatibility, latency, availability, or data-freshness guarantees. Breaking changes may happen with limited notice.',
483
- },
484
- {
485
- name: 'CoinGecko',
486
- description: "Exchange data in CoinGecko's GeckoTerminal format.",
487
- },
488
- ],
348
+ tags,
349
+ ...(tagGroups.length ? { 'x-tagGroups': tagGroups } : {}),
489
350
  },
490
351
  })
491
- // Set per-operation `security` and the `402` payment-challenge response from
492
- // each route's resolved auth policy (the single source of truth), so the
493
- // anonymous option and `402` appear only where the public/MPP lanes are
494
- // enabled not on every operation via the document default.
352
+ // Document the outbound `webhooks` block only when the webhook routes are
353
+ // actually mounted; a disabled feature hides its routes, so it must not
354
+ // advertise deliveries.
355
+ const hasWebhookRoutes = Object.keys(generated.paths).some((path) =>
356
+ /\/webhooks(\/|$)/.test(path),
357
+ )
358
+ const webhookBlocks = hasWebhookRoutes ? metadata_all.flatMap((m) => (m.webhooks ? [m.webhooks()] : [])) : [] // prettier-ignore
359
+ const webhooksDoc = webhookBlocks.length
360
+ ? { webhooks: Object.assign({}, ...webhookBlocks) }
361
+ : {}
362
+ // Set per-operation `security` and the `402` payment-challenge response
363
+ // from each route's resolved auth policy (the single source of truth), so
364
+ // the anonymous option and `402` appear only where the public/MPP lanes
365
+ // are enabled, not on every operation via the document default.
495
366
  applyAccess(generated.paths, Auth.describeAccess(app))
496
367
  // Point the `/rpc` operation at the OpenRPC document via `x-openrpc`.
497
368
  applyOpenrpcLink(generated.paths, basePath)
@@ -501,53 +372,34 @@ export function create<const path extends string = '/'>(options: create.Options<
501
372
  // tag and preserves document path order within a tag, so reordering here
502
373
  // drives the sidebar sub-item order.
503
374
  return { ...generated, ...webhooksDoc, paths: sortPaths(generated.paths) }
504
- })()
375
+ }
376
+ let finalized = false
377
+ const finalize = () => {
378
+ if (finalized) return
379
+ finalized = true
505
380
 
506
- app.get('/openapi.json', async (c) => c.json(await spec))
507
-
508
- // The OpenRPC document is a committed build artifact (no runtime generator);
509
- // see scripts/openrpc/build.ts and `pnpm openrpc:build`.
510
- app.get('/openrpc.json', (c) => c.json(openrpcSpec))
511
-
512
- if (options.docs !== false)
513
- app.route(
514
- '/',
515
- vocs_Handler.openApi(
516
- {
517
- // Inline the OpenRPC doc so vocs expands it without a self-subrequest
518
- // (see `inlineOpenrpc`); the public `/openapi.json` keeps the URL ref.
519
- spec: spec.then(inlineOpenrpc),
520
- sidebar: { collapsed: true },
521
- vocs: { logoUrl: OpenApi.logoUrl, title: 'Tempo API Reference', ...options.docs },
522
- },
523
- { fallback: 'next', css: OpenApi.css },
524
- ),
525
- )
381
+ app.get('/openapi.json', async (c) => c.json(await getSpec()))
526
382
 
527
- app.notFound((c) =>
528
- Response.error(c, { code: 'not_found', message: 'Route not found', status: 404 }),
529
- )
383
+ // The OpenRPC document is a committed build artifact (no runtime generator);
384
+ // see scripts/openrpc/build.ts and `pnpm openrpc:build`.
385
+ app.get('/openrpc.json', (c) => c.json(openrpcSpec))
530
386
 
531
- app.onError((cause, c) => {
532
- if (cause instanceof HTTPException) return errorFromException(c, cause)
387
+ // Mount each docs group's reference factory (see `docs()` in `tapimo/docs`)
388
+ // last, so its catch-all sits behind every API route and the documents
389
+ // above — regardless of where the group sat in the composition chain.
390
+ for (const entry of metadata) if (entry.docs) app.route('/', entry.docs({ spec: getSpec }))
391
+ }
533
392
 
534
- // Redact any leaked API-key token from the logged error/stack.
535
- console.error(
536
- ApiKey.redact(cause instanceof Error ? (cause.stack ?? cause.message) : String(cause)),
537
- )
538
- return Response.error(c, {
539
- code: 'internal_error',
540
- message: 'Internal server error',
541
- status: 500,
542
- })
543
- })
393
+ // Patch `fetch` to finalize once before dispatch. `request()` reads
394
+ // `this.fetch` dynamically so it picks up the patch, and the captured
395
+ // `originalFetch` still dispatches as a bare value (used by `App.listener`).
396
+ const originalFetch = app.fetch
397
+ ;(app as unknown as { fetch: typeof originalFetch }).fetch = ((request, ...rest) => {
398
+ finalize()
399
+ return originalFetch(request, ...rest)
400
+ }) as typeof originalFetch
544
401
 
545
- // Return the typed chained Hono directly. Spreading `store`/`listener` onto
546
- // the app would intersect the inferred Hono type and breaks `testClient`'s
547
- // schema inference for downstream consumers. The cache `store` is owned by
548
- // the caller (pass `options.cache.store`), and a Node listener is produced on
549
- // demand via `App.listener(app)`.
550
- return app
402
+ return route('/', auth.app ?? new Hono<Environment>())
551
403
  }
552
404
 
553
405
  /**
@@ -561,10 +413,16 @@ export function listener(app: { fetch: NodeFetch }): Listener {
561
413
  }
562
414
 
563
415
  export declare namespace create {
564
- /** Options for creating the Tempo API Hono app. */
416
+ /**
417
+ * Options for creating the Tempo API Hono app — the shared core:
418
+ * db/cache/kv/auth capabilities and cross-cutting middleware. Chain-data
419
+ * configuration belongs to {@link data}; email to {@link platform}.
420
+ */
565
421
  type Options<path extends string = '/'> = {
566
- /** Static API asset store for the current runtime (e.g. `Assets.cloudflareR2(...)`). Omit to skip static assetstoken logo URIs go unresolved. */
567
- assets?: Assets | undefined
422
+ /** Analytics store for usage reads (e.g. `Analytics.clickhouse(...)`), or a per-request factory. Accepts `{ source }` to mirror `db`. Omit to leave usage analytics unconfigured usage routes answer 501. Ingest happens outside this app (queue consumer via `Analytics.handleQueue`). */
423
+ analytics?: Analytics.Source | { source: Analytics.Source } | undefined
424
+ /** Authentication: lane defaults, quotas, and credentials for the built-in enforcement middleware, plus the `session` sign-in surface. Omit for default-closed policies with in-memory rate limiting; pass false to leave policies unenforced (tests only). */
425
+ auth?: Auth.install.Options['auth'] | false | undefined
568
426
  /** Caching configuration: the cache store plus the edge response cache toggle. */
569
427
  cache?: Cache | undefined
570
428
  /** Response compression for API handlers. Disabled by default; pass true for defaults or a config object to customize. Leave disabled when fronted by a proxy/CDN that already compresses. */
@@ -573,32 +431,16 @@ export declare namespace create {
573
431
  cors?: boolean | Cors | undefined
574
432
  /** Authoritative Postgres store backing stateful features (webhooks, verified tokens). Pass a long-lived `Db.postgres(...)` singleton on Node, or a factory (`() => Db.postgres(...)`) on Workers so each request builds a fresh Hyperdrive-pooled connection. Pass `{ source, cached }` to route staleness-tolerant reads (verified tokens) through a second, query-caching Hyperdrive config; `source` stays uncached for read-after-write correctness. Apply migrations out of band via `tapimo admin migrate`. */
575
433
  db: Db.Source | { cached?: Db.Source | undefined; source: Db.Source }
576
- /** Default Tempo chain id for requests that omit `chainId`. */
577
- defaultChainId?: Viem.ChainId | undefined
578
434
  /** KV state store backing API-key records (e.g. `Store.cloudflareKv(...)`). Omit to leave API-key auth closed — every token resolves to `null`. */
579
435
  kv?: Kv | undefined
580
- /** Vocs API reference options. Set to false to disable the `/` docs page. */
581
- docs?: Docs | false | undefined
582
436
  /** Request logging. Disabled by default. Pass `true` to emit one canonical structured log entry per request through the level-matched console method (indexed by Workers Logs); a level (e.g. `'warn'`) to emit only that level and above (dropping successful-request info lines); or an emit function for a custom sink. */
583
437
  logger?: boolean | Log.Level | Logger | undefined
584
438
  /** Metrics backend. Disabled by default; pass a backend (e.g. `Metrics.cloudflare()`) to emit request (HTTP) metrics per response. Pass the same backend to the webhook poller/queue handlers so they emit over it too. */
585
439
  metrics?: Metrics.Metrics | undefined
586
- /** Hono middleware to run before API handlers mount. */
587
- middleware?: readonly MiddlewareHandler[] | undefined
588
440
  /** Base path to mount API handlers under. Provided as a literal via the `path` generic so the resulting Hono schema keeps typed route paths for `testClient`. */
589
441
  path?: path | undefined
590
442
  /** OpenAPI `servers` for the generated document. Defaults to a single relative server (the host serving the doc), so the reference targets the deployment it is served from. Set the canonical public URL(s) here, e.g. `[{ url: 'https://api.tempo.xyz' }]`. */
591
443
  servers?: readonly Server[] | undefined
592
- /** Extra Tempo chain ids this deployment serves, in addition to the built-in public chains and the configured `defaultChainId`. A request for a `chainId` outside this set is rejected with a clear 400 instead of reaching an upstream. */
593
- supportedChainIds?: readonly number[] | undefined
594
- /** Tempo RPC options. */
595
- rpc?: Rpc | undefined
596
- /** TIDX query client options. */
597
- tidx?: Tidx.getClient.Tidx | undefined
598
- /** Verified-token feature configuration. Enabled by default (token rows live in `db`; empty until published); pass `false` to always serve an empty verified list. */
599
- verifiedTokens?: VerifiedTokens | false | undefined
600
- /** Webhook feature configuration. Enabled by default (subscription/delivery rows live in `db`). Pass `false` to disable: the `/webhooks` routes stay mounted (for a stable schema and typed test client) but return `404` and are hidden from the OpenAPI document. */
601
- webhook?: Webhook | false | undefined
602
444
  }
603
445
 
604
446
  /** KV state-store configuration. */
@@ -620,27 +462,6 @@ export declare namespace create {
620
462
  store?: Store.Store | undefined
621
463
  }
622
464
 
623
- /** Verified-token feature configuration. */
624
- type VerifiedTokens = {
625
- /**
626
- * Per-isolate soft-refresh window in milliseconds. Within this window
627
- * verified-token lookups are served from the in-memory snapshot with no
628
- * database I/O; after it, the next lookup re-checks the head version
629
- * (single-flight) and recompiles only when it changed. Defaults to 10_000.
630
- */
631
- refreshMs?: number | undefined
632
- }
633
-
634
- /** Webhook feature configuration. */
635
- type Webhook = {
636
- /**
637
- * Maximum active subscriptions a single owner may hold. Creation is rejected
638
- * with `403 limit_exceeded` once reached. Defaults to 100; bounds the
639
- * spam/SSRF surface and unbounded downstream delivery cost per owner.
640
- */
641
- maxPerOwner?: number | undefined
642
- }
643
-
644
465
  /** Binary asset store for static API assets (e.g. `Assets.cloudflareR2(...)`). */
645
466
  type Assets = Assets.Assets
646
467
 
@@ -650,8 +471,14 @@ export declare namespace create {
650
471
  /** CORS middleware options. */
651
472
  type Cors = NonNullable<Parameters<typeof hono_cors>[0]>
652
473
 
653
- /** Vocs API reference options (theme, top navigation, logo, socials, …). */
654
- type Docs = NonNullable<Parameters<typeof vocs_Handler.openApi>[0]['vocs']>
474
+ /** Reference-UI factory a docs group carries via {@link Metadata} (see `docs()` in `tapimo/docs`): given the app's OpenAPI document builder, returns an app that {@link create} mounts at the root on finalize. */
475
+ type Docs = (context: DocsContext) => Hono<any, any, any>
476
+
477
+ /** Context the app provides to a docs group's reference factory. */
478
+ type DocsContext = {
479
+ /** Memoized OpenAPI document builder — the same document served at `/openapi.json`. */
480
+ spec: () => Promise<{ paths: Record<string, unknown> }>
481
+ }
655
482
 
656
483
  /** Custom request-log sink, receiving one canonical entry per request. */
657
484
  type Logger = Log.Emit
@@ -665,10 +492,39 @@ export declare namespace create {
665
492
  }
666
493
 
667
494
  /**
668
- * Tempo RPC options: a static config, or a per-request resolver function that
669
- * routes by request principal to a separate (e.g. public, no-auth) RPC.
495
+ * What a route group contributes to the composed app beyond its routes:
496
+ * OpenAPI document metadata (tags, security schemes, outbound webhooks block)
497
+ * and an optional docs-UI factory. `create` collects these off each mounted
498
+ * group (via {@link Metadata}); unused entries don't render.
670
499
  */
671
- type Rpc = Viem.getClient.Rpc
500
+ type Metadata = {
501
+ /** Reference-UI factory mounted at the root on finalize (see `docs()` in `tapimo/docs`). */
502
+ docs?: Docs | undefined
503
+ /** Security scheme definitions this group's routes reference (e.g. the session cookie). */
504
+ securitySchemes?: Record<string, unknown> | undefined
505
+ /** Root-level OpenAPI tag definitions for this group's operations. */
506
+ tags?: readonly Tag[] | undefined
507
+ /** Builds the OAS 3.1 `webhooks` block documenting outbound deliveries, emitted only when the group's webhook routes are mounted. Called during spec generation only, keeping schema conversion off isolate startup. */
508
+ webhooks?: (() => Record<string, unknown>) | undefined
509
+ /** Vocs tag-group metadata for grouping root tags in the reference. */
510
+ 'x-tagGroups'?: readonly TagGroup[] | undefined
511
+ }
512
+
513
+ /** One root-level OpenAPI tag definition. */
514
+ type Tag = {
515
+ /** Human-readable summary shown in the reference sidebar. */
516
+ description: string
517
+ /** Tag name referenced by operations. */
518
+ name: string
519
+ }
520
+
521
+ /** One Vocs OpenAPI tag group. */
522
+ type TagGroup = {
523
+ /** Section name shown by tag-group-aware references. */
524
+ name: string
525
+ /** Root tag names in this group. */
526
+ tags: readonly string[]
527
+ }
672
528
  }
673
529
 
674
530
  function getRequestId(c: Context<Environment>) {
@@ -746,10 +602,11 @@ function sortPaths(paths: PathsObject): PathsObject {
746
602
 
747
603
  /**
748
604
  * Sets per-operation `security` and the `402` payment-challenge response from
749
- * each route's resolved access lanes (see {@link Auth.describeAccess}). The
750
- * anonymous (`{}`) security option and the `402` response are emitted only where
751
- * the route's policy enables the public and MPP lanes respectively; required
752
- * API-key scopes are surfaced as the `x-required-scopes` extension.
605
+ * each route's resolved access lanes (see {@link Auth.describeAccess}).
606
+ * Security options compose from the enabled lanes API keys (header +
607
+ * bearer), sessions (cookie + bearer token), anonymous (`{}`) and the `402`
608
+ * response is emitted only where the MPP lane is enabled; required API-key
609
+ * scopes are surfaced as the `x-required-scopes` extension.
753
610
  */
754
611
  function applyAccess(paths: PathsObject, access: Record<string, Auth.OperationAccess>) {
755
612
  for (const item of Object.values(paths)) {
@@ -757,7 +614,12 @@ function applyAccess(paths: PathsObject, access: Record<string, Auth.OperationAc
757
614
  if (!isMutableOperation(op)) continue
758
615
  const lanes = access[op.operationId]
759
616
  if (!lanes) continue
760
- op.security = [{ apiKey: [] }, { bearerAuth: [] }, ...(lanes.public ? [{}] : [])]
617
+ const security = [
618
+ ...(lanes.apiKey ? [{ apiKey: [] }, { bearerAuth: [] }] : []),
619
+ ...(lanes.session ? [{ session: [] }, ...(lanes.apiKey ? [] : [{ bearerAuth: [] }])] : []),
620
+ ...(lanes.public ? [{}] : []),
621
+ ]
622
+ if (security.length > 0) op.security = security
761
623
  if (lanes.scopes.length > 0) op['x-required-scopes'] = [...lanes.scopes]
762
624
  if (lanes.mpp) op.responses = { ...op.responses, 402: OpenApi.paymentChallengeRef }
763
625
  else if (op.responses) delete op.responses['402']
@@ -772,7 +634,7 @@ function applyAccess(paths: PathsObject, access: Record<string, Auth.OperationAc
772
634
  * method/param/return schemas it accepts.
773
635
  *
774
636
  * The public `/openapi.json` keeps a URL reference (small, conventional). The
775
- * docs handler instead receives the document inlined — see `inlineOpenrpc`.
637
+ * docs handler instead inlines the document — see `inlineOpenrpc` in `tapimo/docs`.
776
638
  */
777
639
  function applyOpenrpcLink(paths: PathsObject, basePath: string) {
778
640
  // `basePath` is `/` at the root mount and `/api` etc. otherwise; strip any
@@ -783,31 +645,6 @@ function applyOpenrpcLink(paths: PathsObject, basePath: string) {
783
645
  if (isMutableOperation(op) && isRpcOperation(op)) op['x-openrpc'] = url
784
646
  }
785
647
 
786
- /**
787
- * Returns a shallow copy of `spec` with the JSON-RPC passthrough operation's
788
- * `x-openrpc` replaced by the inline OpenRPC document, for the docs handler.
789
- *
790
- * Vocs expands `x-openrpc` at request time. A URL reference (as kept in the
791
- * public `/openapi.json`) would make the docs worker fetch its own
792
- * `/openrpc.json` — a self-subrequest that is unreliable on Cloudflare Workers
793
- * and silently falls back to a single, unexpanded operation. Inlining the
794
- * committed artifact keeps expansion deterministic across local and deployed
795
- * environments, without bloating the public spec. Only the affected path/op are
796
- * cloned; the rest of the (large) document is shared by reference.
797
- */
798
- function inlineOpenrpc<spec extends { paths: Record<string, unknown> }>(spec: spec): spec {
799
- const paths: Record<string, unknown> = {}
800
- for (const [pathname, item] of Object.entries(spec.paths)) {
801
- let next = item
802
- if (isRecord(item))
803
- for (const [method, op] of Object.entries(item))
804
- if (isMutableOperation(op) && isRpcOperation(op))
805
- next = { ...item, [method]: { ...op, 'x-openrpc': openrpcSpec } }
806
- paths[pathname] = next
807
- }
808
- return { ...spec, paths }
809
- }
810
-
811
648
  type PathsObject = Awaited<ReturnType<typeof generateSpecs>>['paths']
812
649
  type PathItem = PathsObject[string]
813
650
  type Operation = { summary?: string | undefined }
@@ -839,45 +676,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
839
676
  return !!value && typeof value === 'object' && !Array.isArray(value)
840
677
  }
841
678
 
842
- function createGetAsset(options: createGetAsset.Options): GetAsset {
843
- const { assets, basePath, origin } = options
844
- // Without an asset store, every lookup misses so callers fall back to their
845
- // "no static data" behavior (undefined logo URIs).
846
- if (!assets) return () => undefined
847
- return async (chainId, path) => {
848
- // Public URLs include `/assets/:chainId`, but the store is keyed by
849
- // `:chainId/:path` (e.g. an R2 object key), decoupled from the URL shape.
850
- // `path` may be absolute (`Path.join` returns a leading slash); strip it so
851
- // the key is `:chainId/:path`, not `:chainId//:path`.
852
- const pathname = Path.join(basePath, 'assets', String(chainId), path)
853
- const key = `${chainId}/${path.replace(/^\/+/, '')}`
854
- const asset = await assets.get(key)
855
- if (!asset) return undefined
856
- // Return an absolute public URL (scheme + host) against the request origin
857
- // so logo URLs work for any consumer regardless of the API's domain.
858
- return {
859
- response: new globalThis.Response(asset.body, {
860
- headers: { 'Content-Type': asset.contentType },
861
- }),
862
- uri: new URL(pathname, origin).toString(),
863
- }
864
- }
865
- }
866
-
867
- declare namespace createGetAsset {
868
- type Options = {
869
- assets?: create.Assets | undefined
870
- basePath: string
871
- origin: string
872
- }
873
- }
874
-
875
- function stripAssetPath(path: string, basePath: string) {
876
- for (const prefix of [`${Path.join(basePath, 'assets')}/`, '/assets/'])
877
- if (path.startsWith(prefix)) return `/${path.slice(prefix.length)}`
878
- return path
879
- }
880
-
881
679
  type GetNodeRequestListener = (typeof import('@hono/node-server'))['getRequestListener']
882
680
  type NodeFetch = Parameters<GetNodeRequestListener>[0]
883
681
  type NodeRequestListener = ReturnType<GetNodeRequestListener>