tapimo 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (422) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/dist/ApiKey.d.ts +65 -0
  4. package/dist/ApiKey.d.ts.map +1 -0
  5. package/dist/ApiKey.js +105 -0
  6. package/dist/ApiKey.js.map +1 -0
  7. package/dist/ApiKeySource.d.ts +166 -0
  8. package/dist/ApiKeySource.d.ts.map +1 -0
  9. package/dist/ApiKeySource.js +234 -0
  10. package/dist/ApiKeySource.js.map +1 -0
  11. package/dist/App.d.ts +19317 -0
  12. package/dist/App.d.ts.map +1 -0
  13. package/dist/App.js +612 -0
  14. package/dist/App.js.map +1 -0
  15. package/dist/Assets.d.ts +44 -0
  16. package/dist/Assets.d.ts.map +1 -0
  17. package/dist/Assets.js +23 -0
  18. package/dist/Assets.js.map +1 -0
  19. package/dist/Auth.d.ts +2 -0
  20. package/dist/Auth.d.ts.map +1 -0
  21. package/dist/Auth.js +2 -0
  22. package/dist/Auth.js.map +1 -0
  23. package/dist/Cli.d.ts +21 -0
  24. package/dist/Cli.d.ts.map +1 -0
  25. package/dist/Cli.js +13 -0
  26. package/dist/Cli.js.map +1 -0
  27. package/dist/Client.d.ts +20 -0
  28. package/dist/Client.d.ts.map +1 -0
  29. package/dist/Client.js +24 -0
  30. package/dist/Client.js.map +1 -0
  31. package/dist/Metrics.d.ts +70 -0
  32. package/dist/Metrics.d.ts.map +1 -0
  33. package/dist/Metrics.js +91 -0
  34. package/dist/Metrics.js.map +1 -0
  35. package/dist/Scope.d.ts +35 -0
  36. package/dist/Scope.d.ts.map +1 -0
  37. package/dist/Scope.js +38 -0
  38. package/dist/Scope.js.map +1 -0
  39. package/dist/Webhooks.d.ts +79 -0
  40. package/dist/Webhooks.d.ts.map +1 -0
  41. package/dist/Webhooks.js +107 -0
  42. package/dist/Webhooks.js.map +1 -0
  43. package/dist/admin/Access.d.ts +41 -0
  44. package/dist/admin/Access.d.ts.map +1 -0
  45. package/dist/admin/Access.js +75 -0
  46. package/dist/admin/Access.js.map +1 -0
  47. package/dist/admin/App.d.ts +1221 -0
  48. package/dist/admin/App.d.ts.map +1 -0
  49. package/dist/admin/App.js +113 -0
  50. package/dist/admin/App.js.map +1 -0
  51. package/dist/admin/apps/api-keys.d.ts +209 -0
  52. package/dist/admin/apps/api-keys.d.ts.map +1 -0
  53. package/dist/admin/apps/api-keys.js +129 -0
  54. package/dist/admin/apps/api-keys.js.map +1 -0
  55. package/dist/admin/apps/scopes.d.ts +46 -0
  56. package/dist/admin/apps/scopes.d.ts.map +1 -0
  57. package/dist/admin/apps/scopes.js +41 -0
  58. package/dist/admin/apps/scopes.js.map +1 -0
  59. package/dist/admin/apps/verified-tokens.d.ts +1206 -0
  60. package/dist/admin/apps/verified-tokens.d.ts.map +1 -0
  61. package/dist/admin/apps/verified-tokens.js +485 -0
  62. package/dist/admin/apps/verified-tokens.js.map +1 -0
  63. package/dist/admin/index.d.ts +3 -0
  64. package/dist/admin/index.d.ts.map +1 -0
  65. package/dist/admin/index.js +3 -0
  66. package/dist/admin/index.js.map +1 -0
  67. package/dist/admin/ui.generated.d.ts +11 -0
  68. package/dist/admin/ui.generated.d.ts.map +1 -0
  69. package/dist/admin/ui.generated.js +43 -0
  70. package/dist/admin/ui.generated.js.map +1 -0
  71. package/dist/apps/activities.d.ts +18725 -0
  72. package/dist/apps/activities.d.ts.map +1 -0
  73. package/dist/apps/activities.js +3138 -0
  74. package/dist/apps/activities.js.map +1 -0
  75. package/dist/apps/addresses.d.ts +3662 -0
  76. package/dist/apps/addresses.d.ts.map +1 -0
  77. package/dist/apps/addresses.js +22 -0
  78. package/dist/apps/addresses.js.map +1 -0
  79. package/dist/apps/balances.d.ts +342 -0
  80. package/dist/apps/balances.d.ts.map +1 -0
  81. package/dist/apps/balances.js +393 -0
  82. package/dist/apps/balances.js.map +1 -0
  83. package/dist/apps/blocks.d.ts +931 -0
  84. package/dist/apps/blocks.d.ts.map +1 -0
  85. package/dist/apps/blocks.js +689 -0
  86. package/dist/apps/blocks.js.map +1 -0
  87. package/dist/apps/coingecko.d.ts +1053 -0
  88. package/dist/apps/coingecko.d.ts.map +1 -0
  89. package/dist/apps/coingecko.js +1015 -0
  90. package/dist/apps/coingecko.js.map +1 -0
  91. package/dist/apps/exchanges.d.ts +3000 -0
  92. package/dist/apps/exchanges.d.ts.map +1 -0
  93. package/dist/apps/exchanges.js +3570 -0
  94. package/dist/apps/exchanges.js.map +1 -0
  95. package/dist/apps/fee-amm.d.ts +640 -0
  96. package/dist/apps/fee-amm.d.ts.map +1 -0
  97. package/dist/apps/fee-amm.js +815 -0
  98. package/dist/apps/fee-amm.js.map +1 -0
  99. package/dist/apps/indexer.d.ts +116 -0
  100. package/dist/apps/indexer.d.ts.map +1 -0
  101. package/dist/apps/indexer.js +270 -0
  102. package/dist/apps/indexer.js.map +1 -0
  103. package/dist/apps/receipts.d.ts +1438 -0
  104. package/dist/apps/receipts.d.ts.map +1 -0
  105. package/dist/apps/receipts.js +874 -0
  106. package/dist/apps/receipts.js.map +1 -0
  107. package/dist/apps/rpc.d.ts +173 -0
  108. package/dist/apps/rpc.d.ts.map +1 -0
  109. package/dist/apps/rpc.js +191 -0
  110. package/dist/apps/rpc.js.map +1 -0
  111. package/dist/apps/tokenlist.d.ts +192 -0
  112. package/dist/apps/tokenlist.d.ts.map +1 -0
  113. package/dist/apps/tokenlist.js +153 -0
  114. package/dist/apps/tokenlist.js.map +1 -0
  115. package/dist/apps/tokens.d.ts +2246 -0
  116. package/dist/apps/tokens.d.ts.map +1 -0
  117. package/dist/apps/tokens.js +1789 -0
  118. package/dist/apps/tokens.js.map +1 -0
  119. package/dist/apps/transactions.d.ts +2327 -0
  120. package/dist/apps/transactions.d.ts.map +1 -0
  121. package/dist/apps/transactions.js +975 -0
  122. package/dist/apps/transactions.js.map +1 -0
  123. package/dist/apps/transfers.d.ts +589 -0
  124. package/dist/apps/transfers.d.ts.map +1 -0
  125. package/dist/apps/transfers.js +769 -0
  126. package/dist/apps/transfers.js.map +1 -0
  127. package/dist/apps/verified-tokens.d.ts +544 -0
  128. package/dist/apps/verified-tokens.d.ts.map +1 -0
  129. package/dist/apps/verified-tokens.js +234 -0
  130. package/dist/apps/verified-tokens.js.map +1 -0
  131. package/dist/apps/webhooks.d.ts +7684 -0
  132. package/dist/apps/webhooks.d.ts.map +1 -0
  133. package/dist/apps/webhooks.js +2112 -0
  134. package/dist/apps/webhooks.js.map +1 -0
  135. package/dist/cloudflare.d.ts +32 -0
  136. package/dist/cloudflare.d.ts.map +1 -0
  137. package/dist/cloudflare.js +45 -0
  138. package/dist/cloudflare.js.map +1 -0
  139. package/dist/index.d.ts +16 -0
  140. package/dist/index.d.ts.map +1 -0
  141. package/dist/index.js +16 -0
  142. package/dist/index.js.map +1 -0
  143. package/dist/internal/Auth.d.ts +298 -0
  144. package/dist/internal/Auth.d.ts.map +1 -0
  145. package/dist/internal/Auth.js +618 -0
  146. package/dist/internal/Auth.js.map +1 -0
  147. package/dist/internal/Cache.d.ts +74 -0
  148. package/dist/internal/Cache.d.ts.map +1 -0
  149. package/dist/internal/Cache.js +215 -0
  150. package/dist/internal/Cache.js.map +1 -0
  151. package/dist/internal/Cursor.d.ts +79 -0
  152. package/dist/internal/Cursor.d.ts.map +1 -0
  153. package/dist/internal/Cursor.js +116 -0
  154. package/dist/internal/Cursor.js.map +1 -0
  155. package/dist/internal/EdgeCache.d.ts +59 -0
  156. package/dist/internal/EdgeCache.d.ts.map +1 -0
  157. package/dist/internal/EdgeCache.js +174 -0
  158. package/dist/internal/EdgeCache.js.map +1 -0
  159. package/dist/internal/Log.d.ts +104 -0
  160. package/dist/internal/Log.d.ts.map +1 -0
  161. package/dist/internal/Log.js +118 -0
  162. package/dist/internal/Log.js.map +1 -0
  163. package/dist/internal/MetricSink.d.ts +65 -0
  164. package/dist/internal/MetricSink.d.ts.map +1 -0
  165. package/dist/internal/MetricSink.js +146 -0
  166. package/dist/internal/MetricSink.js.map +1 -0
  167. package/dist/internal/Mpp.d.ts +71 -0
  168. package/dist/internal/Mpp.d.ts.map +1 -0
  169. package/dist/internal/Mpp.js +105 -0
  170. package/dist/internal/Mpp.js.map +1 -0
  171. package/dist/internal/OpenApi.d.ts +313 -0
  172. package/dist/internal/OpenApi.d.ts.map +1 -0
  173. package/dist/internal/OpenApi.fonts.d.ts +2 -0
  174. package/dist/internal/OpenApi.fonts.d.ts.map +1 -0
  175. package/dist/internal/OpenApi.fonts.js +39 -0
  176. package/dist/internal/OpenApi.fonts.js.map +1 -0
  177. package/dist/internal/OpenApi.js +335 -0
  178. package/dist/internal/OpenApi.js.map +1 -0
  179. package/dist/internal/OpenApi.logo.d.ts +6 -0
  180. package/dist/internal/OpenApi.logo.d.ts.map +1 -0
  181. package/dist/internal/OpenApi.logo.js +19 -0
  182. package/dist/internal/OpenApi.logo.js.map +1 -0
  183. package/dist/internal/Path.d.ts +5 -0
  184. package/dist/internal/Path.d.ts.map +1 -0
  185. package/dist/internal/Path.js +16 -0
  186. package/dist/internal/Path.js.map +1 -0
  187. package/dist/internal/RateLimit.d.ts +60 -0
  188. package/dist/internal/RateLimit.d.ts.map +1 -0
  189. package/dist/internal/RateLimit.js +48 -0
  190. package/dist/internal/RateLimit.js.map +1 -0
  191. package/dist/internal/Response.d.ts +132 -0
  192. package/dist/internal/Response.d.ts.map +1 -0
  193. package/dist/internal/Response.js +72 -0
  194. package/dist/internal/Response.js.map +1 -0
  195. package/dist/internal/Schema.d.ts +257 -0
  196. package/dist/internal/Schema.d.ts.map +1 -0
  197. package/dist/internal/Schema.js +360 -0
  198. package/dist/internal/Schema.js.map +1 -0
  199. package/dist/internal/Store.d.ts +204 -0
  200. package/dist/internal/Store.d.ts.map +1 -0
  201. package/dist/internal/Store.js +291 -0
  202. package/dist/internal/Store.js.map +1 -0
  203. package/dist/internal/Tidx.d.ts +120 -0
  204. package/dist/internal/Tidx.d.ts.map +1 -0
  205. package/dist/internal/Tidx.js +156 -0
  206. package/dist/internal/Tidx.js.map +1 -0
  207. package/dist/internal/Timing.d.ts +22 -0
  208. package/dist/internal/Timing.d.ts.map +1 -0
  209. package/dist/internal/Timing.js +32 -0
  210. package/dist/internal/Timing.js.map +1 -0
  211. package/dist/internal/Ttl.d.ts +25 -0
  212. package/dist/internal/Ttl.d.ts.map +1 -0
  213. package/dist/internal/Ttl.js +49 -0
  214. package/dist/internal/Ttl.js.map +1 -0
  215. package/dist/internal/Value.d.ts +47 -0
  216. package/dist/internal/Value.d.ts.map +1 -0
  217. package/dist/internal/Value.js +122 -0
  218. package/dist/internal/Value.js.map +1 -0
  219. package/dist/internal/VerifiedTokens.d.ts +228 -0
  220. package/dist/internal/VerifiedTokens.d.ts.map +1 -0
  221. package/dist/internal/VerifiedTokens.js +450 -0
  222. package/dist/internal/VerifiedTokens.js.map +1 -0
  223. package/dist/internal/Viem.d.ts +2082 -0
  224. package/dist/internal/Viem.d.ts.map +1 -0
  225. package/dist/internal/Viem.js +63 -0
  226. package/dist/internal/Viem.js.map +1 -0
  227. package/dist/internal/WebhookDestination.d.ts +198 -0
  228. package/dist/internal/WebhookDestination.d.ts.map +1 -0
  229. package/dist/internal/WebhookDestination.js +170 -0
  230. package/dist/internal/WebhookDestination.js.map +1 -0
  231. package/dist/internal/Webhooks.d.ts +433 -0
  232. package/dist/internal/Webhooks.d.ts.map +1 -0
  233. package/dist/internal/Webhooks.js +489 -0
  234. package/dist/internal/Webhooks.js.map +1 -0
  235. package/dist/internal/webhookDestinations/betterStack.d.ts +26 -0
  236. package/dist/internal/webhookDestinations/betterStack.d.ts.map +1 -0
  237. package/dist/internal/webhookDestinations/betterStack.js +76 -0
  238. package/dist/internal/webhookDestinations/betterStack.js.map +1 -0
  239. package/dist/internal/webhookDestinations/slack.d.ts +59 -0
  240. package/dist/internal/webhookDestinations/slack.d.ts.map +1 -0
  241. package/dist/internal/webhookDestinations/slack.js +422 -0
  242. package/dist/internal/webhookDestinations/slack.js.map +1 -0
  243. package/dist/internal/webhookDestinations/url.d.ts +17 -0
  244. package/dist/internal/webhookDestinations/url.d.ts.map +1 -0
  245. package/dist/internal/webhookDestinations/url.js +130 -0
  246. package/dist/internal/webhookDestinations/url.js.map +1 -0
  247. package/dist/openrpc.json +5302 -0
  248. package/package.json +46 -4
  249. package/seeds/31318/icons/0x20c0000000000000000000000000000000000000.svg +1 -0
  250. package/seeds/31318/icons/0x20c0000000000000000000000000000000000001.svg +1 -0
  251. package/seeds/31318/icons/0x20c0000000000000000000000000000000000002.svg +1 -0
  252. package/seeds/31318/icons/0x20c0000000000000000000000000000000000003.svg +1 -0
  253. package/seeds/31318/verified-tokens.json +30 -0
  254. package/seeds/4217/icons/0x20c0000000000000000000000000000000000000.svg +25 -0
  255. package/seeds/4217/icons/0x20c000000000000000000000048c8f36df1c9a4a.svg +1 -0
  256. package/seeds/4217/icons/0x20c0000000000000000000000520792dcccccccc.svg +1 -0
  257. package/seeds/4217/icons/0x20c0000000000000000000000a6da882d075a4c3.svg +4 -0
  258. package/seeds/4217/icons/0x20c000000000000000000000111111111e910f0f.svg +30 -0
  259. package/seeds/4217/icons/0x20c00000000000000000000014f22ca97301eb73.svg +1 -0
  260. package/seeds/4217/icons/0x20c0000000000000000000001621e21f71cf12fb.svg +1 -0
  261. package/seeds/4217/icons/0x20c0000000000000000000002f52d5cc21a3207b.svg +1 -0
  262. package/seeds/4217/icons/0x20c0000000000000000000003158081efd85bfc2.svg +11 -0
  263. package/seeds/4217/icons/0x20c0000000000000000000003554d28269e0f3c2.svg +1 -0
  264. package/seeds/4217/icons/0x20c000000000000000000000383a23bacb546ab9.svg +1 -0
  265. package/seeds/4217/icons/0x20c00000000000000000000042109aef2f8b28e1.png +0 -0
  266. package/seeds/4217/icons/0x20c0000000000000000000005c0bac7cef389a11.svg +1 -0
  267. package/seeds/4217/icons/0x20c0000000000000000000006fd9a167923ba194.png +0 -0
  268. package/seeds/4217/icons/0x20c0000000000000000000007f7ba549dd0251b9.svg +1 -0
  269. package/seeds/4217/icons/0x20c0000000000000000000008191667423f70e67.svg +5 -0
  270. package/seeds/4217/icons/0x20c0000000000000000000008ee4fcff88888888.svg +1 -0
  271. package/seeds/4217/icons/0x20c0000000000000000000009a4a4b17e0dc6651.svg +1 -0
  272. package/seeds/4217/icons/0x20c000000000000000000000ab02d39df30bd17e.svg +1 -0
  273. package/seeds/4217/icons/0x20c000000000000000000000ae247a1130450f09.svg +1 -0
  274. package/seeds/4217/icons/0x20c000000000000000000000aeed2ec36a54d0e5.svg +1 -0
  275. package/seeds/4217/icons/0x20c000000000000000000000b9537d11c60e8b50.svg +1 -0
  276. package/seeds/4217/icons/0x20c000000000000000000000bd95bfb69fbe6ce3.svg +1 -0
  277. package/seeds/4217/icons/0x20c000000000000000000000c412ec89d0c08be5.svg +1 -0
  278. package/seeds/4217/icons/0x20c000000000000000000000f047dd7018e50367.png +0 -0
  279. package/seeds/4217/verified-tokens.json +177 -0
  280. package/seeds/42431/icons/0x20c0000000000000000000000000000000000000.svg +25 -0
  281. package/seeds/42431/icons/0x20c0000000000000000000000000000000000001.svg +1 -0
  282. package/seeds/42431/icons/0x20c0000000000000000000000000000000000002.svg +1 -0
  283. package/seeds/42431/icons/0x20c0000000000000000000000000000000000003.svg +1 -0
  284. package/seeds/42431/icons/0x20c0000000000000000000009e8d7eb59b783726.svg +1 -0
  285. package/seeds/42431/icons/0x20c000000000000000000000d72572838bbee59c.svg +1 -0
  286. package/seeds/42431/verified-tokens.json +44 -0
  287. package/seeds/openrpc/README.md +27 -0
  288. package/seeds/openrpc/execution-apis.json +8989 -0
  289. package/src/ApiKey.test.ts +91 -0
  290. package/src/ApiKey.ts +122 -0
  291. package/src/ApiKeySource.test-d.ts +11 -0
  292. package/src/ApiKeySource.test.ts +295 -0
  293. package/src/ApiKeySource.ts +303 -0
  294. package/src/App.test-d.ts +38 -0
  295. package/src/App.test.ts +65927 -0
  296. package/src/App.ts +855 -0
  297. package/src/Assets.ts +58 -0
  298. package/src/Auth.ts +1 -0
  299. package/src/Cli.test.ts +81 -0
  300. package/src/Cli.ts +38 -0
  301. package/src/Client.test-d.ts +1438 -0
  302. package/src/Client.test.ts +134 -0
  303. package/src/Client.ts +45 -0
  304. package/src/Metrics.ts +154 -0
  305. package/src/Scope.ts +50 -0
  306. package/src/Webhooks.test.ts +49 -0
  307. package/src/Webhooks.ts +172 -0
  308. package/src/admin/Access.test.ts +130 -0
  309. package/src/admin/Access.ts +87 -0
  310. package/src/admin/App.test.ts +225 -0
  311. package/src/admin/App.ts +216 -0
  312. package/src/admin/apps/api-keys.test.ts +156 -0
  313. package/src/admin/apps/api-keys.ts +157 -0
  314. package/src/admin/apps/scopes.test.ts +52 -0
  315. package/src/admin/apps/scopes.ts +47 -0
  316. package/src/admin/apps/verified-tokens.test.ts +415 -0
  317. package/src/admin/apps/verified-tokens.ts +566 -0
  318. package/src/admin/index.ts +2 -0
  319. package/src/admin/ui/plugin.ts +135 -0
  320. package/src/admin/ui/src/components/Checkbox.tsx +22 -0
  321. package/src/admin/ui/src/components/Dialog.tsx +32 -0
  322. package/src/admin/ui/src/components/MobileProfile.tsx +31 -0
  323. package/src/admin/ui/src/components/Page.tsx +53 -0
  324. package/src/admin/ui/src/components/TempoLogo.tsx +37 -0
  325. package/src/admin/ui/src/fonts/Pilat-Demi.woff2 +0 -0
  326. package/src/admin/ui/src/fonts/Pilat-Regular.woff2 +0 -0
  327. package/src/admin/ui/src/lib/api-keys.ts +63 -0
  328. package/src/admin/ui/src/lib/client.ts +15 -0
  329. package/src/admin/ui/src/lib/config.ts +57 -0
  330. package/src/admin/ui/src/lib/query-client.ts +26 -0
  331. package/src/admin/ui/src/lib/scopes.ts +25 -0
  332. package/src/admin/ui/src/lib/verified-tokens.ts +89 -0
  333. package/src/admin/ui/src/lib/wagmi.ts +18 -0
  334. package/src/admin/ui/src/routeTree.gen.ts +104 -0
  335. package/src/admin/ui/src/router.tsx +25 -0
  336. package/src/admin/ui/src/routes/__root.tsx +219 -0
  337. package/src/admin/ui/src/routes/api-keys.tsx +329 -0
  338. package/src/admin/ui/src/routes/index.tsx +7 -0
  339. package/src/admin/ui/src/routes/verified-tokens.tsx +331 -0
  340. package/src/admin/ui/src/styles.css +20 -0
  341. package/src/admin/ui/tsconfig.json +16 -0
  342. package/src/admin/ui/vite.config.ts +29 -0
  343. package/src/admin/ui.generated.ts +60 -0
  344. package/src/apps/activities.test.ts +1020 -0
  345. package/src/apps/activities.ts +3934 -0
  346. package/src/apps/addresses.ts +24 -0
  347. package/src/apps/balances.test.ts +274 -0
  348. package/src/apps/balances.ts +533 -0
  349. package/src/apps/blocks.test.ts +385 -0
  350. package/src/apps/blocks.ts +896 -0
  351. package/src/apps/coingecko.test.ts +218 -0
  352. package/src/apps/coingecko.ts +1383 -0
  353. package/src/apps/exchanges.test.ts +958 -0
  354. package/src/apps/exchanges.ts +4773 -0
  355. package/src/apps/fee-amm.test.ts +321 -0
  356. package/src/apps/fee-amm.ts +1121 -0
  357. package/src/apps/indexer.test.ts +153 -0
  358. package/src/apps/indexer.ts +330 -0
  359. package/src/apps/receipts.test.ts +285 -0
  360. package/src/apps/receipts.ts +1193 -0
  361. package/src/apps/rpc.test.ts +302 -0
  362. package/src/apps/rpc.ts +222 -0
  363. package/src/apps/tokenlist.test.ts +80 -0
  364. package/src/apps/tokenlist.ts +207 -0
  365. package/src/apps/tokens.test.ts +1062 -0
  366. package/src/apps/tokens.ts +2292 -0
  367. package/src/apps/transactions.test.ts +408 -0
  368. package/src/apps/transactions.ts +1363 -0
  369. package/src/apps/transfers.test.ts +371 -0
  370. package/src/apps/transfers.ts +1116 -0
  371. package/src/apps/verified-tokens.test.ts +114 -0
  372. package/src/apps/verified-tokens.ts +295 -0
  373. package/src/apps/webhooks.test.ts +1937 -0
  374. package/src/apps/webhooks.ts +2926 -0
  375. package/src/cloudflare.ts +55 -0
  376. package/src/index.ts +15 -0
  377. package/src/internal/Auth.test.ts +980 -0
  378. package/src/internal/Auth.ts +1012 -0
  379. package/src/internal/Cache.test.ts +240 -0
  380. package/src/internal/Cache.ts +262 -0
  381. package/src/internal/Cursor.test.ts +100 -0
  382. package/src/internal/Cursor.ts +149 -0
  383. package/src/internal/EdgeCache.test.ts +234 -0
  384. package/src/internal/EdgeCache.ts +224 -0
  385. package/src/internal/Errors.ts +14 -0
  386. package/src/internal/Log.test.ts +244 -0
  387. package/src/internal/Log.ts +216 -0
  388. package/src/internal/MetricSink.ts +220 -0
  389. package/src/internal/Mpp.test.ts +64 -0
  390. package/src/internal/Mpp.ts +141 -0
  391. package/src/internal/OpenApi.fonts.ts +38 -0
  392. package/src/internal/OpenApi.logo.ts +18 -0
  393. package/src/internal/OpenApi.ts +488 -0
  394. package/src/internal/Path.test.ts +14 -0
  395. package/src/internal/Path.ts +15 -0
  396. package/src/internal/RateLimit.test.ts +93 -0
  397. package/src/internal/RateLimit.ts +93 -0
  398. package/src/internal/Response.ts +131 -0
  399. package/src/internal/Schema.test.ts +34 -0
  400. package/src/internal/Schema.ts +523 -0
  401. package/src/internal/Store.test.ts +545 -0
  402. package/src/internal/Store.ts +526 -0
  403. package/src/internal/Tidx.local.test.ts +33 -0
  404. package/src/internal/Tidx.test.ts +294 -0
  405. package/src/internal/Tidx.ts +238 -0
  406. package/src/internal/Timing.test.ts +22 -0
  407. package/src/internal/Timing.ts +62 -0
  408. package/src/internal/Ttl.test.ts +18 -0
  409. package/src/internal/Ttl.ts +59 -0
  410. package/src/internal/Value.ts +114 -0
  411. package/src/internal/VerifiedTokens.test.ts +333 -0
  412. package/src/internal/VerifiedTokens.ts +645 -0
  413. package/src/internal/Viem.test.ts +115 -0
  414. package/src/internal/Viem.ts +165 -0
  415. package/src/internal/WebhookDestination.test.ts +648 -0
  416. package/src/internal/WebhookDestination.ts +331 -0
  417. package/src/internal/Webhooks.test.ts +668 -0
  418. package/src/internal/Webhooks.ts +940 -0
  419. package/src/internal/webhookDestinations/betterStack.ts +91 -0
  420. package/src/internal/webhookDestinations/slack.ts +496 -0
  421. package/src/internal/webhookDestinations/url.ts +128 -0
  422. package/src/openrpc.json +5302 -0
@@ -0,0 +1,135 @@
1
+ import * as fs from 'node:fs'
2
+ import * as path from 'node:path'
3
+ import * as url from 'node:url'
4
+ import * as zlib from 'node:zlib'
5
+
6
+ import type { PluginOption } from 'vite'
7
+
8
+ // Vite plugin that turns the TanStack Start SPA build output (`dist/client`)
9
+ // into the shipped asset map `src/admin/ui.generated.ts` — the only thing the
10
+ // Hono admin app imports from the UI. The library `tsc`/`zile` build never sees
11
+ // the `.tsx` source (just this generated module), so the published bundle gains
12
+ // no React or TanStack runtime dependency.
13
+ //
14
+ // It hooks `buildApp` with `order: 'post'` because TanStack Start writes the
15
+ // prerendered `_shell.html` from its own `buildApp` post handler — which runs
16
+ // *after* every environment's `closeBundle`. Registering this plugin after
17
+ // `tanstackStart()` makes this handler run last, once the shell exists.
18
+
19
+ const here = path.dirname(url.fileURLToPath(import.meta.url))
20
+ const clientDir = path.join(here, 'dist', 'client')
21
+ const outFile = path.join(here, '..', 'ui.generated.ts')
22
+
23
+ // Total gzipped budget for the whole UI; the React + TanStack + Regen baseline
24
+ // is heavier than a hand-rolled SPA, so fail loudly before it bloats the
25
+ // package. Raise deliberately (and revisit code-splitting) if it trips.
26
+ const maxGzipBytes = 400_000
27
+
28
+ const contentTypes: Record<string, string> = {
29
+ '.css': 'text/css; charset=utf-8',
30
+ '.html': 'text/html; charset=utf-8',
31
+ '.ico': 'image/x-icon',
32
+ '.js': 'text/javascript; charset=utf-8',
33
+ '.json': 'application/json; charset=utf-8',
34
+ '.map': 'application/json; charset=utf-8',
35
+ '.png': 'image/png',
36
+ '.svg': 'image/svg+xml',
37
+ '.webp': 'image/webp',
38
+ '.woff': 'font/woff',
39
+ '.woff2': 'font/woff2',
40
+ }
41
+
42
+ // Text assets inline as UTF-8; anything else (fonts, images) base64-encodes.
43
+ const textExtensions = new Set(['.css', '.html', '.js', '.json', '.map', '.svg'])
44
+
45
+ type Asset = { content: string; contentType: string; encoding?: 'base64' }
46
+
47
+ function walk(dir: string): readonly string[] {
48
+ return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
49
+ const full = path.join(dir, entry.name)
50
+ return entry.isDirectory() ? walk(full) : [full]
51
+ })
52
+ }
53
+
54
+ function emitAssetMap(): void {
55
+ if (!fs.existsSync(clientDir))
56
+ throw new Error(`Missing ${clientDir}; the SPA client build did not run.`)
57
+
58
+ const shellPath = path.join(clientDir, '_shell.html')
59
+ if (!fs.existsSync(shellPath)) throw new Error(`Missing SPA shell at ${shellPath}.`)
60
+
61
+ // TanStack Start emits absolute `/./assets/...` URLs for the entry script and
62
+ // modulepreloads (CSS is already relative). Normalize to `./assets/...` so they
63
+ // resolve against the `<base href>` the Hono app injects when serving the shell
64
+ // — that's what makes the single artifact work path-mounted (e.g. `/admin`).
65
+ const shell = fs.readFileSync(shellPath, 'utf8').replaceAll('/./assets/', './assets/')
66
+
67
+ const assets: Record<string, Asset> = {}
68
+ let totalGzip = 0
69
+ for (const file of walk(clientDir)) {
70
+ if (file === shellPath) continue
71
+ const key = path.relative(clientDir, file).split(path.sep).join('/')
72
+ const ext = path.extname(file)
73
+ const buffer = fs.readFileSync(file)
74
+ totalGzip += zlib.gzipSync(buffer).length
75
+ assets[key] = {
76
+ content: textExtensions.has(ext) ? buffer.toString('utf8') : buffer.toString('base64'),
77
+ contentType: contentTypes[ext] ?? 'application/octet-stream',
78
+ ...(textExtensions.has(ext) ? {} : { encoding: 'base64' as const }),
79
+ }
80
+ }
81
+
82
+ totalGzip += zlib.gzipSync(Buffer.from(shell, 'utf8')).length
83
+ if (totalGzip > maxGzipBytes)
84
+ throw new Error(
85
+ `Admin UI bundle is ${(totalGzip / 1000).toFixed(0)} KB gzip, over the ${maxGzipBytes / 1000} KB budget.`,
86
+ )
87
+
88
+ const sortedAssets = Object.fromEntries(
89
+ Object.entries(assets).sort(([a], [b]) => a.localeCompare(b)),
90
+ )
91
+
92
+ const banner = `// Generated by src/admin/ui/plugin.ts — do not edit by hand.
93
+ // Run \`pnpm build:ui\` to regenerate from the TanStack Start SPA build.
94
+ /* eslint-disable */`
95
+
96
+ const body = `${banner}
97
+
98
+ /** A single built UI file: text inline as UTF-8, binary as base64. */
99
+ export type Asset = {
100
+ content: string
101
+ contentType: string
102
+ encoding?: 'base64'
103
+ }
104
+
105
+ /** The prerendered SPA shell HTML (assets normalized to relative URLs). */
106
+ export const shell = ${JSON.stringify(shell)}
107
+
108
+ /** Content-hashed UI assets, keyed by their path under the mount (e.g. \`assets/index-*.js\`). */
109
+ export const assets: Record<string, Asset> = ${JSON.stringify(sortedAssets, null, 2)}
110
+ `
111
+
112
+ fs.writeFileSync(outFile, body)
113
+ console.log(
114
+ `Wrote ${path.relative(path.join(here, '..', '..', '..'), outFile)} (${Object.keys(assets).length} assets, ${(totalGzip / 1000).toFixed(0)} KB gzip).`,
115
+ )
116
+ }
117
+
118
+ /**
119
+ * Emits `src/admin/ui.generated.ts` from the SPA build output. Register *after*
120
+ * `tanstackStart()` so its `buildApp` post handler (which writes `_shell.html`
121
+ * via prerender) runs first.
122
+ */
123
+ export function generated(): PluginOption {
124
+ return {
125
+ name: 'tempo-api-admin-ui-generated',
126
+ enforce: 'post',
127
+ buildApp: {
128
+ order: 'post',
129
+ async handler() {
130
+ emitAssetMap()
131
+ process.exit(0)
132
+ },
133
+ },
134
+ }
135
+ }
@@ -0,0 +1,22 @@
1
+ import { Checkbox as Base } from '@base-ui/react/checkbox'
2
+ import type { ComponentProps } from 'react'
3
+ import { Check } from 'lucide-react'
4
+ import { cx } from 'regen-ui'
5
+
6
+ export function Checkbox({ className, ...props }: ComponentProps<typeof Base.Root>) {
7
+ return (
8
+ <Base.Root
9
+ className={(state) =>
10
+ cx(
11
+ 'flex size-[18px] shrink-0 items-center justify-center rounded-button border-[2px] border-border bg-secondary text-on-invert outline-none transition-colors hover:bg-secondary-hover focus-visible:border-focus data-[checked]:border-[var(--background-color-invert)] data-[checked]:bg-invert',
12
+ typeof className === 'function' ? className(state) : className,
13
+ )
14
+ }
15
+ {...props}
16
+ >
17
+ <Base.Indicator className="flex data-[unchecked]:hidden">
18
+ <Check className="size-3" />
19
+ </Base.Indicator>
20
+ </Base.Root>
21
+ )
22
+ }
@@ -0,0 +1,32 @@
1
+ import { Dialog as Base } from '@base-ui/react/dialog'
2
+ import type { ComponentProps, ReactNode } from 'react'
3
+
4
+ /** Backdrop + centered popup shell. Children render inside; pair with Title/Description. */
5
+ function Popup(props: { children: ReactNode }) {
6
+ return (
7
+ <Base.Portal>
8
+ <Base.Backdrop className="fixed inset-0 z-40 bg-black/60 transition-opacity duration-150 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" />
9
+ <Base.Popup className="fixed left-1/2 top-1/2 z-50 w-[calc(100vw-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 border border-border bg-surface p-6 shadow-lg outline-none transition-opacity duration-150 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0">
10
+ {props.children}
11
+ </Base.Popup>
12
+ </Base.Portal>
13
+ )
14
+ }
15
+
16
+ function Title(props: ComponentProps<typeof Base.Title>) {
17
+ return <Base.Title className="text-heading-20 text-foreground" {...props} />
18
+ }
19
+
20
+ function Description(props: ComponentProps<typeof Base.Description>) {
21
+ return <Base.Description className="mt-1 text-copy-14 text-foreground-secondary" {...props} />
22
+ }
23
+
24
+ /** Base modal dialog (base-ui). `Root` manages open state via `Trigger`/`Close`. */
25
+ export const Dialog = {
26
+ Close: Base.Close,
27
+ Description,
28
+ Popup,
29
+ Root: Base.Root,
30
+ Title,
31
+ Trigger: Base.Trigger,
32
+ }
@@ -0,0 +1,31 @@
1
+ import { Bytes, Hash, type Address } from 'ox'
2
+ import { Identicon } from 'regen-ui'
3
+ import { LogOut } from 'lucide-react'
4
+
5
+ import * as Config from '../lib/config'
6
+
7
+ /** Mobile-only header profile: identicon + sign-out, shown when the sidebar is hidden. */
8
+ export function MobileProfile() {
9
+ const { data: config } = Config.use()
10
+ const identity = config?.auth.identity
11
+ if (!identity) return null
12
+ return (
13
+ <div className="flex items-center gap-2">
14
+ <Identicon address={identiconAddress(identity.email)} className="size-9 shrink-0" size={36} />
15
+ {config.auth.logoutUrl ? (
16
+ <a
17
+ aria-label="Sign out"
18
+ className="text-foreground-secondary hover:text-foreground"
19
+ href={config.auth.logoutUrl}
20
+ >
21
+ <LogOut className="size-[18px]" />
22
+ </a>
23
+ ) : null}
24
+ </div>
25
+ )
26
+ }
27
+
28
+ /** Derives a stable identicon seed address from an email. */
29
+ export function identiconAddress(email: string): Address.Address {
30
+ return Hash.keccak256(Bytes.fromString(email), { as: 'Hex' }).slice(0, 42) as Address.Address
31
+ }
@@ -0,0 +1,53 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { MobileProfile } from './MobileProfile'
4
+
5
+ /** Page header: title, optional description, and an optional right-aligned action. */
6
+ export function Page(props: {
7
+ title: string
8
+ description?: string
9
+ action?: ReactNode
10
+ children: ReactNode
11
+ }) {
12
+ return (
13
+ <section className="flex flex-col gap-6">
14
+ <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between md:gap-4">
15
+ <div className="flex min-w-0 flex-1 items-start gap-4">
16
+ <div className="min-w-0 flex-1">
17
+ <h1 className="text-heading-24 text-foreground">{props.title}</h1>
18
+ {props.description ? (
19
+ <p className="mt-1 text-copy-15 text-foreground-secondary">{props.description}</p>
20
+ ) : null}
21
+ </div>
22
+ <div className="shrink-0 md:hidden">
23
+ <MobileProfile />
24
+ </div>
25
+ </div>
26
+ {props.action ? (
27
+ <div className="flex items-center gap-2 max-sm:w-full [&>*]:max-sm:flex-1">
28
+ {props.action}
29
+ </div>
30
+ ) : null}
31
+ </div>
32
+ {props.children}
33
+ </section>
34
+ )
35
+ }
36
+
37
+ /** Bordered surface container used for lists and forms. */
38
+ export function Card(props: { children: ReactNode; className?: string }) {
39
+ return (
40
+ <div className={`border border-border bg-surface ${props.className ?? ''}`}>
41
+ {props.children}
42
+ </div>
43
+ )
44
+ }
45
+
46
+ /** Centered placeholder for loading / empty / error states inside a card. */
47
+ export function Notice(props: { children: ReactNode }) {
48
+ return (
49
+ <div className="flex items-center justify-center px-6 py-12 text-copy-14 text-foreground-secondary">
50
+ {props.children}
51
+ </div>
52
+ )
53
+ }
@@ -0,0 +1,37 @@
1
+ /** The Tempo "T" mark as an inline SVG. Inherits `currentColor` for fill. */
2
+ export function TempoMark(props: { className?: string }) {
3
+ return (
4
+ <svg
5
+ aria-label="Tempo"
6
+ className={props.className}
7
+ fill="none"
8
+ height="14"
9
+ role="img"
10
+ viewBox="0 0 13 14"
11
+ width="13"
12
+ >
13
+ <path d="M4.594 14H.944L4.327 3.173H0L.944 0H13l-.944 3.173H7.96z" fill="currentColor" />
14
+ </svg>
15
+ )
16
+ }
17
+
18
+ /** The Tempo wordmark as an inline SVG. Inherits `currentColor` for fill. */
19
+ export function TempoLogo(props: { className?: string }) {
20
+ return (
21
+ <svg
22
+ aria-label="Tempo"
23
+ className={props.className}
24
+ fill="none"
25
+ height="24"
26
+ role="img"
27
+ viewBox="0 0 107 24"
28
+ width="107"
29
+ >
30
+ <title>Tempo</title>
31
+ <path
32
+ d="M7.903 23.516h-6.28L7.445 5.593H0L1.624.34h20.739l-1.624 5.253h-7.046zM31.273 23.516H16.385L23.859.34h14.827l-1.409 4.419h-8.608l-1.562 4.975h8.332l-1.41 4.357h-8.362l-1.562 5.006h8.546zM38.011 23.516h-4.993L40.523.34h8.333l-.276 12.484L56.698.34h9.129l-7.475 23.176h-6.25l5.055-15.852-10.384 15.852h-3.707l.153-15.914zM72.856 4.635l-2.42 7.478h.674q2.297 0 3.829-1.081Q76.47 9.919 76.93 7.88q.398-1.761-.429-2.503-.826-.742-2.757-.742zm-6.066 18.88h-6.28L67.985.34h7.628q2.634 0 4.534.865 1.93.835 2.818 2.41.919 1.546.612 3.616-.398 2.72-2.082 4.79-1.686 2.07-4.381 3.213-2.665 1.113-5.974 1.113h-2.052zM98.546 22.033q-3.124 1.854-6.648 1.854h-.06q-3.126 0-5.27-1.39-2.114-1.422-3.033-3.833-.888-2.41-.428-5.284a16.3 16.3 0 0 1 2.665-6.674q2.082-3.06 5.207-4.883T97.658 0h.06q3.248 0 5.362 1.39 2.144 1.392 2.971 3.801.858 2.38.368 5.346-.582 3.492-2.665 6.582a16.3 16.3 0 0 1-5.208 4.914m-8.67-3.987q.828 1.576 2.88 1.576h.061q1.686 0 3.125-1.267 1.47-1.297 2.481-3.46 1.042-2.164 1.532-4.821.46-2.595-.368-4.172-.826-1.607-2.849-1.607h-.06q-1.563 0-3.034 1.298-1.44 1.298-2.511 3.492a18.8 18.8 0 0 0-1.563 4.759q-.49 2.595.307 4.202"
33
+ fill="currentColor"
34
+ />
35
+ </svg>
36
+ )
37
+ }
@@ -0,0 +1,63 @@
1
+ import * as ReactQuery from '@tanstack/react-query'
2
+ import type { InferRequestType, InferResponseType } from 'hono/client'
3
+
4
+ import { client } from './client'
5
+
6
+ /** A single API key record from the list endpoint. */
7
+ export type ApiKey = InferResponseType<(typeof client)['api-keys']['$get'], 200>['data'][number]
8
+
9
+ /** List API keys. */
10
+ export namespace get {
11
+ export const key = ['api-keys'] as const
12
+ export function fn() {
13
+ return client['api-keys'].$get().then((r) => r.json())
14
+ }
15
+ export function options() {
16
+ return ReactQuery.queryOptions({ queryFn: fn, queryKey: key, staleTime: 30_000 })
17
+ }
18
+ export function useQuery() {
19
+ return ReactQuery.useQuery(options())
20
+ }
21
+ }
22
+
23
+ /** Provision a new API key. */
24
+ export namespace provision {
25
+ export type Input = InferRequestType<(typeof client)['api-keys']['$post']>['json']
26
+ export function fn(json: Input) {
27
+ return client['api-keys'].$post({ json }).then((r) => {
28
+ if (!r.ok) throw new Error('Failed to provision key.')
29
+ return r.json()
30
+ })
31
+ }
32
+ export function useMutation() {
33
+ const queryClient = ReactQuery.useQueryClient()
34
+ return ReactQuery.useMutation({
35
+ mutationFn: fn,
36
+ onSuccess: ({ token: _token, ...record }) =>
37
+ queryClient.setQueryData(
38
+ get.key,
39
+ (previous: { data: ApiKey[] } | undefined) =>
40
+ previous && { data: [record, ...previous.data] },
41
+ ),
42
+ })
43
+ }
44
+ }
45
+
46
+ /** Revoke an API key by id. */
47
+ export namespace revoke {
48
+ export function fn(id: string) {
49
+ return client['api-keys'][':id'].$delete({ param: { id } })
50
+ }
51
+ export function useMutation() {
52
+ const queryClient = ReactQuery.useQueryClient()
53
+ return ReactQuery.useMutation({
54
+ mutationFn: fn,
55
+ onSuccess: (_response, id) =>
56
+ queryClient.setQueryData(
57
+ get.key,
58
+ (previous: { data: ApiKey[] } | undefined) =>
59
+ previous && { data: previous.data.filter((key) => key.id !== id) },
60
+ ),
61
+ })
62
+ }
63
+ }
@@ -0,0 +1,15 @@
1
+ import { hc } from 'hono/client'
2
+
3
+ import type { App } from '../../../App'
4
+
5
+ // Mount root for API calls: the shell injects `<base href="<mount>/">`, so use
6
+ // it when present. The Vite dev shell has none, so `document.baseURI` would be
7
+ // the current URL (breaking sub-routes); fall back to the origin root instead.
8
+ function baseUrl() {
9
+ if (typeof document === 'undefined') return '/'
10
+ const base = document.querySelector('base')
11
+ return base ? base.href : `${location.origin}/`
12
+ }
13
+
14
+ /** Typed admin API client (Hono RPC). */
15
+ export const client = hc<App>(baseUrl())
@@ -0,0 +1,57 @@
1
+ import { queryOptions, useQuery } from '@tanstack/react-query'
2
+
3
+ import { client } from './client'
4
+
5
+ /** The auth contract the SPA reads from `GET config.json` once loaded. */
6
+ export type Config = {
7
+ auth: {
8
+ /** The signed-in admin identity, or `null` when logged out (shell is public). */
9
+ identity: { email: string } | null
10
+ /** Where the deployer's sign-in page lives; shown when logged out. */
11
+ loginUrl?: string
12
+ /** Where to send the user to sign out (e.g. Cloudflare Access logout). */
13
+ logoutUrl?: string
14
+ }
15
+ }
16
+
17
+ declare global {
18
+ interface Window {
19
+ /** Auth config inlined into the shell `<head>` by the server (see App.ts). */
20
+ __TEMPO_API_CONFIG__?: Config
21
+ }
22
+ }
23
+
24
+ /** Query key for the bootstrap config. */
25
+ export const key = ['config'] as const
26
+
27
+ /** The config the server inlined into the shell, if present (synchronous). */
28
+ export function inlineConfig(): Config | undefined {
29
+ return typeof window === 'undefined' ? undefined : window.__TEMPO_API_CONFIG__
30
+ }
31
+
32
+ /** Admin UI bootstrap config: the inlined value, else fetched from `config.json`. */
33
+ export async function getConfig(): Promise<Config> {
34
+ const inlined = inlineConfig()
35
+ if (inlined) return inlined
36
+ const response = await client['config.json'].$get()
37
+ if (!response.ok) return { auth: { identity: null } }
38
+ return response.json() as Promise<Config>
39
+ }
40
+
41
+ /**
42
+ * Bootstrap config query. Seeded from the inlined value and never stale, so an
43
+ * authenticated load reads identity synchronously with no round trip.
44
+ */
45
+ export function options() {
46
+ return queryOptions({
47
+ queryKey: key,
48
+ queryFn: getConfig,
49
+ initialData: inlineConfig,
50
+ staleTime: Infinity,
51
+ })
52
+ }
53
+
54
+ /** Bootstrap config query hook. */
55
+ export function use() {
56
+ return useQuery(options())
57
+ }
@@ -0,0 +1,26 @@
1
+ import { defaultShouldDehydrateQuery, QueryClient } from '@tanstack/react-query'
2
+ import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'
3
+ import type { PersistQueryClientOptions } from '@tanstack/react-query-persist-client'
4
+ import { Json } from 'ox'
5
+
6
+ export const queryClient = new QueryClient({
7
+ defaultOptions: {
8
+ queries: { gcTime: 1000 * 60 * 60 * 24, retry: false, refetchOnWindowFocus: false },
9
+ },
10
+ })
11
+
12
+ const persister = createAsyncStoragePersister({
13
+ key: 'tempo-admin',
14
+ storage: typeof window === 'undefined' ? undefined : window.localStorage,
15
+ serialize: Json.stringify,
16
+ deserialize: Json.parse,
17
+ })
18
+
19
+ export const persistOptions: Omit<PersistQueryClientOptions, 'queryClient'> = {
20
+ maxAge: 1000 * 60 * 60 * 24,
21
+ persister,
22
+ dehydrateOptions: {
23
+ shouldDehydrateQuery: (query) =>
24
+ query.queryKey[0] !== 'config' && defaultShouldDehydrateQuery(query),
25
+ },
26
+ }
@@ -0,0 +1,25 @@
1
+ import * as ReactQuery from '@tanstack/react-query'
2
+ import type { InferResponseType } from 'hono/client'
3
+
4
+ import { client } from './client'
5
+
6
+ /** A single issuable API-key scope from the catalog endpoint. */
7
+ export type Scope = InferResponseType<(typeof client)['scopes']['$get'], 200>['data'][number]
8
+
9
+ /** List the issuable API-key scope catalog. */
10
+ export namespace get {
11
+ export const key = ['scopes'] as const
12
+ export function fn() {
13
+ return client.scopes.$get().then((r) => r.json())
14
+ }
15
+ export function options() {
16
+ return ReactQuery.queryOptions({
17
+ queryFn: fn,
18
+ queryKey: key,
19
+ staleTime: Number.POSITIVE_INFINITY,
20
+ })
21
+ }
22
+ export function useQuery() {
23
+ return ReactQuery.useQuery(options())
24
+ }
25
+ }
@@ -0,0 +1,89 @@
1
+ import * as ReactQuery from '@tanstack/react-query'
2
+ import type { InferRequestType, InferResponseType } from 'hono/client'
3
+
4
+ import { client } from './client'
5
+
6
+ /** The verified-token list endpoint's success body. */
7
+ type ListResponse = InferResponseType<(typeof client)['verified-tokens']['$get'], 200>
8
+
9
+ /** A single verified token record from the list endpoint. */
10
+ export type VerifiedToken = ListResponse['data'][number]
11
+
12
+ /** URL of a token's curated logo, served from the admin's asset store. */
13
+ export function logoUrl({ address, chainId }: { address: `0x${string}`; chainId: number }) {
14
+ return client['verified-tokens'][':address'].logo
15
+ .$url({ param: { address }, query: { chainId: String(chainId) } })
16
+ .toString()
17
+ }
18
+
19
+ /** List verified tokens for a chain. */
20
+ export namespace get {
21
+ export type Input = { chainId: number }
22
+ export function key({ chainId }: Input) {
23
+ return ['verified-tokens', chainId] as const
24
+ }
25
+ export async function fn({ chainId }: Input) {
26
+ const response = await client['verified-tokens'].$get({ query: { chainId: String(chainId) } })
27
+ return response.json() as Promise<ListResponse>
28
+ }
29
+ export function options(input: Input) {
30
+ return ReactQuery.queryOptions({
31
+ queryFn: () => fn(input),
32
+ queryKey: key(input),
33
+ staleTime: 30_000,
34
+ })
35
+ }
36
+ export function useQuery(input: Input) {
37
+ return ReactQuery.useQuery(options(input))
38
+ }
39
+ }
40
+
41
+ /** Create a verified token, optionally with an inline SVG logo. */
42
+ export namespace create {
43
+ type Json = InferRequestType<(typeof client)['verified-tokens']['$post']>['json']
44
+ // `chainId` validates through `Schema.ChainId`, whose `z.coerce.number()` input
45
+ // makes hono/client infer the wire type as `unknown`; narrow it back to the
46
+ // numeric id the UI sends.
47
+ export type Input = Omit<Json, 'chainId' | 'logo'> & {
48
+ chainId: number
49
+ logo?: File | null
50
+ }
51
+ export async function fn({ logo, ...json }: Input) {
52
+ const response = await client['verified-tokens'].$post({
53
+ json: { ...json, ...(logo ? { logo: await logo.text() } : {}) },
54
+ })
55
+ if (!response.ok) throw new Error('Failed to add token.')
56
+ return response.json()
57
+ }
58
+ export function useMutation() {
59
+ const queryClient = ReactQuery.useQueryClient()
60
+ return ReactQuery.useMutation({
61
+ mutationFn: fn,
62
+ onSuccess: (_data, input) =>
63
+ queryClient.invalidateQueries({
64
+ queryKey: get.key({ chainId: input.chainId }),
65
+ }),
66
+ })
67
+ }
68
+ }
69
+
70
+ /** Remove a verified token from a chain. */
71
+ export namespace remove {
72
+ export type Input = { address: `0x${string}`; chainId: number }
73
+ export async function fn({ address, chainId }: Input) {
74
+ const response = await client['verified-tokens'][':address'].$delete({
75
+ param: { address },
76
+ query: { chainId: String(chainId) },
77
+ })
78
+ if (!response.ok) throw new Error('Failed to remove token.')
79
+ return response.json()
80
+ }
81
+ export function useMutation() {
82
+ const queryClient = ReactQuery.useQueryClient()
83
+ return ReactQuery.useMutation({
84
+ mutationFn: fn,
85
+ onSuccess: (_data, input) =>
86
+ queryClient.invalidateQueries({ queryKey: get.key({ chainId: input.chainId }) }),
87
+ })
88
+ }
89
+ }
@@ -0,0 +1,18 @@
1
+ import { createConfig, http } from 'wagmi'
2
+ import { tempo, tempoTestnet } from 'wagmi/chains'
3
+
4
+ /** Read-only wagmi config for reading on-chain token metadata (no wallet). */
5
+ export const config = createConfig({
6
+ chains: [tempo, tempoTestnet],
7
+ ssr: true,
8
+ transports: {
9
+ [tempo.id]: http(),
10
+ [tempoTestnet.id]: http(),
11
+ },
12
+ })
13
+
14
+ declare module 'wagmi' {
15
+ interface Register {
16
+ config: typeof config
17
+ }
18
+ }