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,523 @@
1
+ import { Hex as core_Hex } from 'ox'
2
+ import { Addresses } from 'viem/tempo'
3
+ import * as z from 'zod/mini'
4
+
5
+ /**
6
+ * Attaches an OpenAPI description to an object/array schema that is later
7
+ * derived from via `z.partial`/`z.extend`. `zod/mini` exposes descriptions only
8
+ * through `.check(z.describe(...))`, but that adds a refinement which those
9
+ * derivations reject. Cloning and registering the description directly (as
10
+ * classic zod's `.describe()` does) keeps the schema refinement-free. Plain
11
+ * fields use `.check(z.describe(...))` directly.
12
+ */
13
+ export function describe<const schema extends z.ZodMiniType>(
14
+ schema: schema,
15
+ description: string,
16
+ ): schema {
17
+ const cloned = schema.clone()
18
+ z.globalRegistry.add(cloned, { ...z.globalRegistry.get(schema), description })
19
+ return cloned as schema
20
+ }
21
+
22
+ /** Representative account (EOA) address used as the default OpenAPI example. */
23
+ const accountExample = '0xbe058e1c4df8a4366a387bf595b284246a93039e'
24
+
25
+ // Pre-transform input for a 0x-prefixed 20-byte address. The OpenAPI example is
26
+ // attached here (pre-transform) via `z.meta` so it surfaces on path/query
27
+ // params; the lowercasing transform is applied after.
28
+ const address = z.templateLiteral(['0x', z.string().check(z.regex(/^[0-9a-fA-F]{40}$/))])
29
+
30
+ // TODO(ox/zod): replace with ox's `Address` zod schema once ox ships a `zod`
31
+ // entrypoint, so the wire format stays in lockstep with ox/viem.
32
+ /** Lowercase 0x-prefixed 20-byte account address. */
33
+ export const Address = z
34
+ .pipe(
35
+ address.check(z.meta({ examples: [accountExample] })),
36
+ // `String.prototype.toLowerCase` widens its receiver from `Hex.Hex` to
37
+ // `string`. Cast the result back so the schema's inferred output keeps the
38
+ // hex-literal type — this is sound because lowercasing preserves both the
39
+ // `0x` prefix and the upstream regex constraint.
40
+ z.transform((value) => value.toLowerCase() as core_Hex.Hex),
41
+ )
42
+ .check(
43
+ z.describe(
44
+ 'An account address — the `0x`-prefixed 20-byte identifier for a wallet or contract, returned in lowercase.',
45
+ ),
46
+ )
47
+
48
+ /**
49
+ * Lowercase 0x-prefixed 20-byte TIP-20 token contract address. The OpenAPI
50
+ * example must be attached to the inner pre-transform schema (path/query
51
+ * params read examples from the pipe input), so callers that need a different
52
+ * example per field build a fresh `TokenAddress` via `tokenAddress(example)`
53
+ * instead of overriding via an outer `.check(z.meta(...))`.
54
+ */
55
+ export const TokenAddress = tokenAddress(Addresses.pathUsd)
56
+
57
+ /**
58
+ * Builds a `TokenAddress`-shaped schema with the given OpenAPI example. Use
59
+ * when a path/query param wants a different example than the shared
60
+ * `TokenAddress` default (e.g. the two sides of a trading pair).
61
+ *
62
+ * The example must be a TIP-20 token address (`0x20c` prefix); a non-TIP-20
63
+ * example in the docs would be misleading because the route validates the
64
+ * value as a TIP-20 token contract at runtime.
65
+ */
66
+ export function tokenAddress(example: core_Hex.Hex) {
67
+ if (!example.toLowerCase().startsWith('0x20c'))
68
+ throw new Error(
69
+ `tokenAddress example ${example} is not a TIP-20 token (must start with 0x20c).`,
70
+ )
71
+ return z
72
+ .pipe(
73
+ address.check(z.meta({ examples: [example] })),
74
+ z.transform((value) => value.toLowerCase() as core_Hex.Hex),
75
+ )
76
+ .check(
77
+ z.describe(
78
+ 'A TIP-20 token contract address — the `0x`-prefixed 20-byte identifier for the token, returned in lowercase.',
79
+ ),
80
+ )
81
+ }
82
+
83
+ /** Maps human-readable chain aliases to their Tempo chain id. */
84
+ export const chainIdAlias = {
85
+ mainnet: 4217,
86
+ testnet: 42431,
87
+ } as const
88
+
89
+ /**
90
+ * Tempo chain id. Accepts a chain alias (`mainnet`/`testnet`) or any positive
91
+ * integer chain id (a number or numeric string), normalizing all forms to a
92
+ * numeric chain id. Arbitrary ids are allowed so a self-hosted deployment can
93
+ * serve a localnet (e.g. `31337`); the deployment must configure an `rpc`/`tidx`
94
+ * upstream for any chain beyond the built-in public defaults.
95
+ */
96
+ export const ChainId = z
97
+ .pipe(
98
+ z.union([
99
+ z.pipe(
100
+ z.enum(['mainnet', 'testnet']),
101
+ z.transform((alias) => chainIdAlias[alias]),
102
+ ),
103
+ z.coerce.number(),
104
+ ]),
105
+ z.number().check(z.int(), z.positive()),
106
+ )
107
+ .check(
108
+ z.describe(
109
+ 'Which Tempo network to query. Use the alias `mainnet` or `testnet`, or a numeric chain id (mainnet is `4217`).',
110
+ ),
111
+ z.meta({ examples: [4217] }),
112
+ )
113
+
114
+ /**
115
+ * Optional `chainId` query parameter shared across endpoints. Accepts a chain
116
+ * alias (`mainnet`/`testnet`) or a numeric chain id, normalizing both to a
117
+ * numeric {@link ChainId}.
118
+ */
119
+ export const ChainIdQuery = z
120
+ // The default is documented in the description, not the JSON Schema `default`
121
+ // keyword: zod drops `default`/`examples` from the `anyOf` this pipe produces
122
+ // in input mode, and only `description` survives onto the generated query
123
+ // parameter. The runtime fallback for an omitted `chainId` is the app's
124
+ // configured `defaultChainId` (mainnet unless overridden), not a schema value.
125
+ .optional(ChainId)
126
+ .check(
127
+ z.describe(
128
+ 'Which Tempo network to query. Use the alias `mainnet` or `testnet`, or a numeric chain id. Defaults to `mainnet` when omitted.',
129
+ ),
130
+ z.meta({ examples: [4217] }),
131
+ )
132
+
133
+ const booleanQueryBase = z.pipe(
134
+ z.enum(['true', 'false']),
135
+ z.transform((value) => value === 'true'),
136
+ )
137
+
138
+ /**
139
+ * Boolean query parameter. Query values arrive as the literal strings
140
+ * `"true"`/`"false"`, validated strictly and transformed to a real boolean.
141
+ * `z.boolean()` would reject the incoming string outright and
142
+ * `z.coerce.boolean()` is unsafe (`Boolean("false") === true`).
143
+ *
144
+ * The generated JSON Schema is overridden to a plain `boolean` so the parameter
145
+ * renders as a boolean — not a string — in the OpenAPI docs (and the generated
146
+ * CLI coerces it), while the wire format and strict `"true"`/`"false"`
147
+ * validation stay unchanged. The string `enum` that `z.enum` would emit is
148
+ * dropped (`enum: undefined`): left in place it makes consumers — e.g. the
149
+ * generated CLI — build a literal-`boolean` enum that then rejects the incoming
150
+ * string. Wrap with `z.optional(...)` / `z._default(..., value)` and describe
151
+ * with `.check(z.describe('…'))` at the call site — the override survives both.
152
+ * Returns a fresh clone per call so each call site is a distinct schema.
153
+ */
154
+ export function booleanQuery(): typeof booleanQueryBase {
155
+ const cloned = booleanQueryBase.clone()
156
+ z.globalRegistry.add(cloned, {
157
+ ...z.globalRegistry.get(booleanQueryBase),
158
+ enum: undefined,
159
+ type: 'boolean',
160
+ })
161
+ return cloned
162
+ }
163
+
164
+ /** One public API error detail. */
165
+ export const ErrorDetail = z
166
+ .object({
167
+ message: z
168
+ .string()
169
+ .check(
170
+ z.describe(
171
+ 'A specific thing that went wrong, in plain language (e.g. why a field failed validation).',
172
+ ),
173
+ ),
174
+ path: z
175
+ .optional(z.array(z.union([z.string(), z.number()])))
176
+ .check(
177
+ z.describe(
178
+ 'Where the problem is, as a path into your request (e.g. `["query", "limit"]`). Present for validation errors.',
179
+ ),
180
+ ),
181
+ })
182
+ .check(z.describe('A single problem with the request.'))
183
+
184
+ /**
185
+ * Builds the global error envelope, optionally enumerating `error.code` to a
186
+ * fixed set of machine-readable codes. Pass the codes a given status can return
187
+ * (e.g. `['token_not_found']` for a 404) so the reference and generated clients
188
+ * narrow the code to a literal union instead of an open `string`. Omit `codes`
189
+ * for the open-coded envelope.
190
+ */
191
+ export function errorResponse(codes?: readonly [string, ...string[]]) {
192
+ const code = (codes ? z.enum(codes) : z.string()).check(
193
+ z.describe('A short, stable code you can branch on in your code (e.g. `token_not_found`).'),
194
+ )
195
+ return z
196
+ .object({
197
+ error: z
198
+ .object({
199
+ code,
200
+ details: z
201
+ .optional(z.array(ErrorDetail))
202
+ .check(
203
+ z.describe(
204
+ 'A list of specific problems, when the error is about your request (e.g. invalid fields).',
205
+ ),
206
+ ),
207
+ message: z.string().check(z.describe('A human-readable explanation of what went wrong.')),
208
+ })
209
+ .check(z.describe('What went wrong.')),
210
+ requestId: z
211
+ .string()
212
+ .check(z.describe('The id of this request — include it when contacting support.')),
213
+ })
214
+ .check(z.describe('The standard shape returned for every error response.'))
215
+ }
216
+
217
+ /** Global error envelope with an open-coded `error.code`. */
218
+ export const ErrorResponse = errorResponse()
219
+
220
+ /** Representative 32-byte hash used as the default OpenAPI example. */
221
+ const hashExample = '0x515801d7f9a5ac705e793e85904c9c69b3f1694b465cc8fb6ba3f0298dc82665'
222
+
223
+ // TODO(ox/zod): replace with ox's `Hash` zod schema once ox ships a `zod`
224
+ // entrypoint, so the wire format stays in lockstep with ox/viem.
225
+ /**
226
+ * Lowercase 0x-prefixed 32-byte hash. The OpenAPI example is attached to the
227
+ * inner pre-transform schema (path/query params read examples from the pipe
228
+ * input), so every hash path param surfaces one without per-route overrides.
229
+ * Callers that need a different example per field build a fresh schema via
230
+ * `hash(example)` instead of overriding through an outer `.check(z.meta(...))`.
231
+ */
232
+ export const Hash = hash(hashExample)
233
+
234
+ /**
235
+ * Builds a {@link Hash}-shaped schema with the given OpenAPI example. Use when
236
+ * a path/query param wants a different example than the shared {@link Hash}
237
+ * default (e.g. a route that documents a specific real transaction).
238
+ *
239
+ * The example must be attached to the inner pre-transform schema because
240
+ * path/query params read examples from the pipe input.
241
+ */
242
+ export function hash(example: core_Hex.Hex) {
243
+ return z
244
+ .pipe(
245
+ z
246
+ .templateLiteral(['0x', z.string().check(z.regex(/^[0-9a-fA-F]{64}$/))])
247
+ .check(z.meta({ examples: [example] })),
248
+ z.transform((value) => value.toLowerCase() as core_Hex.Hex),
249
+ )
250
+ .check(
251
+ z.describe(
252
+ 'A 32-byte hash, `0x`-prefixed and returned in lowercase — for example a transaction or block hash.',
253
+ ),
254
+ )
255
+ }
256
+
257
+ // TODO(ox/zod): replace with ox's `Hex` zod schema once ox ships a `zod`
258
+ // entrypoint, so the wire format stays in lockstep with ox/viem.
259
+ /** Lowercase 0x-prefixed hex byte data (may be empty, `0x`). */
260
+ export const Hex = z
261
+ .pipe(
262
+ z.string().check(z.regex(/^0x[0-9a-fA-F]*$/)),
263
+ z.transform((value) => value.toLowerCase() as core_Hex.Hex),
264
+ )
265
+ .check(
266
+ z.describe(
267
+ 'Raw binary data as a `0x`-prefixed lowercase hex string (may be empty, just `0x`).',
268
+ ),
269
+ z.meta({ examples: ['0xdeadbeef'] }),
270
+ )
271
+
272
+ // TODO(ox/zod): replace with ox's `Quantity` zod schema once ox ships a `zod`
273
+ // entrypoint, so the wire format stays in lockstep with ox/viem.
274
+ /** Hex-encoded integer quantity (a `0x`-prefixed integer, e.g. `0x1a`). */
275
+ export const Quantity = z
276
+ .templateLiteral(['0x', z.string().check(z.regex(/^[0-9a-fA-F]+$/))])
277
+ .check(
278
+ z.describe('A whole number encoded as a `0x`-prefixed hexadecimal string (e.g. `0x1a` is 26).'),
279
+ z.meta({ examples: ['0x1a'] }),
280
+ )
281
+
282
+ /** Non-negative integer as a decimal string (preserves uint256 precision). */
283
+ export const DecimalString = z
284
+ .string()
285
+ .check(
286
+ z.regex(/^\d+$/),
287
+ z.describe(
288
+ 'A non-negative whole number, given as a decimal string so very large token amounts keep full precision. Expressed in the smallest unit of the token (e.g. `1000000` is 1.00 of a 6-decimal stablecoin).',
289
+ ),
290
+ z.meta({ examples: ['1000000'] }),
291
+ )
292
+
293
+ /**
294
+ * Minimum page size accepted across list endpoints. Floored at 5 because the
295
+ * indexer rejects signature-decoded `Transfer` queries with `LIMIT < 5`
296
+ * (HTTP 422); applying it globally keeps pagination uniform and removes the need
297
+ * for per-endpoint clamping.
298
+ */
299
+ export const minLimit = 5
300
+
301
+ /** Page-size query parameter shared across list endpoints. */
302
+ export const Limit = z
303
+ ._default(z.coerce.number().check(z.int(), z.gte(minLimit), z.lte(200)), 10)
304
+ .check(
305
+ z.describe('How many items to return per page (5\u2013200, default 10).'),
306
+ z.meta({ examples: [10] }),
307
+ )
308
+
309
+ /** Opaque keyset-pagination cursor query parameter shared across list endpoints. */
310
+ export const Cursor = z
311
+ .optional(z.string())
312
+ .check(
313
+ z.describe(
314
+ 'Opaque keyset cursor from a previous response (`nextCursor`); pass it back verbatim to fetch the next page. Omit for the first (head) page.',
315
+ ),
316
+ z.meta({ examples: ['WzIzNDU2Nzg5LDBd'] }),
317
+ )
318
+
319
+ /**
320
+ * Maximum page window (`page × limit` rows) accepted by positional pagination.
321
+ * Mirrors the indexer's own 10k row ceiling, and the bounded-window convention
322
+ * of comparable APIs (Elasticsearch `max_result_window`, Zendesk's 100-page
323
+ * cap): shallow page-numbered access is served positionally, deep traversal
324
+ * must use cursors.
325
+ */
326
+ export const maxPageWindow = 10_000
327
+
328
+ /**
329
+ * Page-number query parameter (1-indexed) shared by list endpoints that
330
+ * support shallow positional pagination alongside keyset cursors. Cursors
331
+ * remain the canonical deep-traversal mode; the page lane exists for
332
+ * page-numbered UIs that need random access into the head of a feed.
333
+ */
334
+ export const Page = z
335
+ .optional(z.coerce.number().check(z.int(), z.gte(1)))
336
+ .check(
337
+ z.describe(
338
+ 'Page number, 1-indexed (positional pagination for page-numbered access; `page=1` is ' +
339
+ 'the head page). Mutually exclusive with `cursor`, and `page × limit` must be at most ' +
340
+ `${maxPageWindow} rows — use cursor pagination for deeper traversal. Pages are ` +
341
+ 'positional, so rows arriving at the head of a live feed can shift page contents.',
342
+ ),
343
+ z.meta({ examples: [1] }),
344
+ )
345
+
346
+ /**
347
+ * Cross-field checks for list query schemas that accept both `cursor` and
348
+ * `page`: the two are mutually exclusive, and the page window is bounded by
349
+ * {@link maxPageWindow}. Spread into the query object's `.check(...)`.
350
+ */
351
+ export function pageChecks() {
352
+ type Query = { cursor?: string | undefined; limit: number; page?: number | undefined }
353
+ return [
354
+ z.refine<Query>((query) => query.cursor === undefined || query.page === undefined, {
355
+ error: '`cursor` and `page` are mutually exclusive; pass one or the other.',
356
+ path: ['page'],
357
+ }),
358
+ z.refine<Query>((query) => (query.page ?? 1) * query.limit <= maxPageWindow, {
359
+ error: `\`page × limit\` must be at most ${maxPageWindow} rows; use cursor pagination for deeper traversal.`,
360
+ path: ['page'],
361
+ }),
362
+ ] as const
363
+ }
364
+
365
+ /** Opaque next-page cursor response field shared across list endpoints. */
366
+ export const NextCursor = z
367
+ .nullable(z.string())
368
+ .check(
369
+ z.describe(
370
+ 'Pass this back as the `cursor` query parameter to fetch the next page. `null` once you have reached the end of the list.',
371
+ ),
372
+ z.meta({ examples: ['WzIzNDU2Nzg5LDBd'] }),
373
+ )
374
+
375
+ /**
376
+ * Upper bound on the matched-row count surfaced by `include=totalCount`. The
377
+ * count is computed by a capped subquery (`… LIMIT countCap`) so it can't blow
378
+ * the indexer's execution budget on the 10⁹-plus row tables; when the bound is
379
+ * hit the count is a lower bound, signalled by `Meta.totalCountCapped`. Mirrors the
380
+ * indexer's own 10k row ceiling (see {@link maxPageWindow}) and the capped-count
381
+ * conventions of comparable APIs (Stripe Search's 10k `total_count`,
382
+ * Elasticsearch `track_total_hits`, Shopify's `Count.precision`).
383
+ */
384
+ export const countCap = 10_000
385
+
386
+ /**
387
+ * Total matched-row count response field for list endpoints that support
388
+ * `include=totalCount`. Exact when {@link TotalCountCapped} is `false`; a lower
389
+ * bound ("at least this many") when `true`. Independent of pagination —
390
+ * `nextCursor` remains the only end-of-list signal.
391
+ */
392
+ export const TotalCount = z
393
+ .number()
394
+ .check(
395
+ z.int(),
396
+ z.nonnegative(),
397
+ z.describe(
398
+ 'Number of rows matching the query, exact when `totalCountCapped` is false and a lower ' +
399
+ `bound (at least this many, computed up to ${countCap}) when \`totalCountCapped\` is ` +
400
+ 'true. Independent of pagination: use `nextCursor` to page, not this count.',
401
+ ),
402
+ z.meta({ examples: [42] }),
403
+ )
404
+
405
+ /**
406
+ * Whether {@link TotalCount} hit the {@link countCap} bound. `true` means the
407
+ * count is a lower bound ("at least `totalCount` rows match"); `false` means it
408
+ * is exact.
409
+ */
410
+ export const TotalCountCapped = z
411
+ .boolean()
412
+ .check(
413
+ z.describe(
414
+ 'Whether `totalCount` hit the count cap. When true, `totalCount` is a lower bound rather ' +
415
+ 'than an exact total.',
416
+ ),
417
+ z.meta({ examples: [false] }),
418
+ )
419
+
420
+ /** Sort-direction (`asc`/`desc`) query parameter shared across list endpoints. */
421
+ export const Order = z
422
+ ._default(z.enum(['asc', 'desc']), 'desc')
423
+ .check(
424
+ z.describe('Sort order: `desc` for descending (the default), or `asc` for ascending.'),
425
+ z.meta({ examples: ['desc'] }),
426
+ )
427
+
428
+ /**
429
+ * Optional inclusive block-number bound query parameter (`blockNumber.from` /
430
+ * `blockNumber.to`). `noun` is the resource being listed (e.g. `transfers`) so
431
+ * the description reads naturally across endpoints.
432
+ */
433
+ export function blockNumberBound(noun: string, bound: 'from' | 'to') {
434
+ const direction = bound === 'from' ? 'at or after' : 'at or before'
435
+ return z
436
+ .optional(z.coerce.number().check(z.int(), z.nonnegative()))
437
+ .check(
438
+ z.describe(`Only include ${noun} ${direction} this block number.`),
439
+ z.meta({ examples: [bound === 'from' ? 23456789 : 23456999] }),
440
+ )
441
+ }
442
+
443
+ /**
444
+ * Optional inclusive ISO-8601 timestamp bound query parameter (`timestamp.from`
445
+ * / `timestamp.to`). `noun` is the resource being listed (e.g. `transfers`).
446
+ */
447
+ export function timestampBound(noun: string, bound: 'from' | 'to') {
448
+ const direction = bound === 'from' ? 'at or after' : 'at or before'
449
+ return z.optional(z.iso.datetime({ offset: true })).check(
450
+ z.describe(`Only include ${noun} ${direction} this ISO 8601 timestamp.`),
451
+ z.meta({
452
+ examples: [bound === 'from' ? '2024-01-01T00:00:00Z' : '2024-12-31T23:59:59Z'],
453
+ }),
454
+ )
455
+ }
456
+
457
+ /**
458
+ * Builds the schema for a comma-separated opt-in query parameter (e.g.
459
+ * `?include=token,feeToken`), parsed into a validated array of the given enum's
460
+ * members. Absent or empty values yield `[]`. Centralizes the splitting,
461
+ * trimming, and OpenAPI array-enum metadata that every list endpoint otherwise
462
+ * repeats.
463
+ *
464
+ * A repeated parameter (`?include=token&include=feeToken`) arrives from the
465
+ * validator as a `string[]`, so the input accepts both forms and each entry is
466
+ * still comma-split — the two styles compose freely.
467
+ *
468
+ * Pass the endpoint's `Include` enum — kept local so its members drive both the
469
+ * parsed type and the docs — plus the param description.
470
+ */
471
+ export function includeQuery<const T extends Readonly<Record<string, string>>>(
472
+ member: z.ZodMiniEnum<T>,
473
+ description: string,
474
+ ) {
475
+ return z
476
+ .pipe(
477
+ z.pipe(
478
+ // `optional(unknown)` keeps the parameter optional in object inputs
479
+ // while staying opaque to JSON-schema generation — a structural
480
+ // `string | string[]` union would leak a contradictory `anyOf` next to
481
+ // the explicit `meta` below, which is the documented contract.
482
+ z.optional(z.unknown()),
483
+ z.transform((value) => {
484
+ const parts = value === undefined ? [] : Array.isArray(value) ? value : [value]
485
+ return parts
486
+ .flatMap((entry) => String(entry).split(','))
487
+ .map((entry) => entry.trim())
488
+ .filter(Boolean)
489
+ }),
490
+ ),
491
+ z.array(member),
492
+ )
493
+ .check(
494
+ z.meta({
495
+ type: 'array',
496
+ items: { type: 'string', enum: member.options },
497
+ description,
498
+ examples: [member.options],
499
+ }),
500
+ )
501
+ }
502
+
503
+ /**
504
+ * Ready-made `include` query parameter for list endpoints whose only optional
505
+ * resource is the capped total count (`?include=totalCount`). Endpoints that
506
+ * embed additional resources define their own enum that also lists `totalCount`
507
+ * (e.g. transfers' `memo,token,totalCount`).
508
+ */
509
+ export const totalCountInclude = includeQuery(
510
+ z.enum(['totalCount']).check(z.describe('Optional resources to embed via `include`.')),
511
+ 'Comma-separated optional resources to embed, e.g. `totalCount`.',
512
+ )
513
+
514
+ /**
515
+ * Response-wide `meta` object for list endpoints whose only embeddable resource
516
+ * is the capped total count. Present only when `include=totalCount` was
517
+ * requested; omitted otherwise. Endpoints that embed additional response-wide
518
+ * resources alongside the count define their own `Meta` that also carries
519
+ * {@link TotalCount}/{@link TotalCountCapped}.
520
+ */
521
+ export const CountMeta = z
522
+ .object({ totalCountCapped: TotalCountCapped, totalCount: TotalCount })
523
+ .check(z.describe('Response-wide resources embedded on demand via `include`.'))