tapimo 0.5.2 → 0.6.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 (299) hide show
  1. package/dist/App.d.ts +13987 -5755
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js.map +1 -1
  4. package/dist/admin/App.d.ts +910 -412
  5. package/dist/admin/App.d.ts.map +1 -1
  6. package/dist/admin/App.js +4 -0
  7. package/dist/admin/App.js.map +1 -1
  8. package/dist/admin/apps/early-access.d.ts +148 -0
  9. package/dist/admin/apps/early-access.d.ts.map +1 -0
  10. package/dist/admin/apps/early-access.js +133 -0
  11. package/dist/admin/apps/early-access.js.map +1 -0
  12. package/dist/admin/apps/verified-tokens.d.ts +643 -118
  13. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  14. package/dist/admin/apps/verified-tokens.js +214 -1
  15. package/dist/admin/apps/verified-tokens.js.map +1 -1
  16. package/dist/admin/ui.generated.d.ts +1 -1
  17. package/dist/admin/ui.generated.d.ts.map +1 -1
  18. package/dist/admin/ui.generated.js +45 -33
  19. package/dist/admin/ui.generated.js.map +1 -1
  20. package/dist/apps/data/App.d.ts +3733 -2428
  21. package/dist/apps/data/App.d.ts.map +1 -1
  22. package/dist/apps/data/App.js +11 -6
  23. package/dist/apps/data/App.js.map +1 -1
  24. package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
  25. package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
  26. package/dist/apps/data/FundingQuoteProviders.js +193 -2
  27. package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
  28. package/dist/apps/data/FxOracle.d.ts +71 -0
  29. package/dist/apps/data/FxOracle.d.ts.map +1 -0
  30. package/dist/apps/data/FxOracle.js +97 -0
  31. package/dist/apps/data/FxOracle.js.map +1 -0
  32. package/dist/apps/data/index.d.ts +1 -0
  33. package/dist/apps/data/index.d.ts.map +1 -1
  34. package/dist/apps/data/index.js +1 -0
  35. package/dist/apps/data/index.js.map +1 -1
  36. package/dist/apps/data/routes/activities.d.ts +3575 -1358
  37. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  38. package/dist/apps/data/routes/activities.js +230 -88
  39. package/dist/apps/data/routes/activities.js.map +1 -1
  40. package/dist/apps/data/routes/addresses.d.ts +963 -342
  41. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  42. package/dist/apps/data/routes/addresses.js +11 -9
  43. package/dist/apps/data/routes/addresses.js.map +1 -1
  44. package/dist/apps/data/routes/balances.d.ts +108 -57
  45. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  46. package/dist/apps/data/routes/balances.js +88 -45
  47. package/dist/apps/data/routes/balances.js.map +1 -1
  48. package/dist/apps/data/routes/coingecko.d.ts +169 -169
  49. package/dist/apps/data/routes/exchanges.d.ts +952 -201
  50. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  51. package/dist/apps/data/routes/exchanges.js +518 -76
  52. package/dist/apps/data/routes/exchanges.js.map +1 -1
  53. package/dist/apps/data/routes/fee-amm.d.ts +24 -24
  54. package/dist/apps/data/routes/funding.d.ts +8 -2
  55. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  56. package/dist/apps/data/routes/funding.js +32 -6
  57. package/dist/apps/data/routes/funding.js.map +1 -1
  58. package/dist/apps/data/routes/indexer.d.ts +5 -5
  59. package/dist/apps/data/routes/receipts.d.ts +392 -315
  60. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  61. package/dist/apps/data/routes/receipts.js +152 -77
  62. package/dist/apps/data/routes/receipts.js.map +1 -1
  63. package/dist/apps/data/routes/tokens.d.ts +166 -173
  64. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  65. package/dist/apps/data/routes/tokens.js +14 -12
  66. package/dist/apps/data/routes/tokens.js.map +1 -1
  67. package/dist/apps/data/routes/transactions.d.ts +277 -536
  68. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  69. package/dist/apps/data/routes/transactions.js +96 -77
  70. package/dist/apps/data/routes/transactions.js.map +1 -1
  71. package/dist/apps/data/routes/transfers.d.ts +82 -17
  72. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  73. package/dist/apps/data/routes/transfers.js +70 -13
  74. package/dist/apps/data/routes/transfers.js.map +1 -1
  75. package/dist/apps/data/routes/valuation.d.ts +307 -0
  76. package/dist/apps/data/routes/valuation.d.ts.map +1 -0
  77. package/dist/apps/data/routes/valuation.js +292 -0
  78. package/dist/apps/data/routes/valuation.js.map +1 -0
  79. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  80. package/dist/apps/data/routes/verified-tokens.js +7 -5
  81. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  82. package/dist/apps/data/routes/webhooks.d.ts +459 -479
  83. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  84. package/dist/apps/data/routes/webhooks.js +124 -25
  85. package/dist/apps/data/routes/webhooks.js.map +1 -1
  86. package/dist/apps/index.d.ts +1 -1
  87. package/dist/apps/index.d.ts.map +1 -1
  88. package/dist/apps/index.js +1 -1
  89. package/dist/apps/index.js.map +1 -1
  90. package/dist/apps/management/App.d.ts +8606 -1681
  91. package/dist/apps/management/App.d.ts.map +1 -1
  92. package/dist/apps/management/App.js +12 -1
  93. package/dist/apps/management/App.js.map +1 -1
  94. package/dist/apps/management/routes/api-keys.d.ts +23 -0
  95. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  96. package/dist/apps/management/routes/api-keys.js +5 -3
  97. package/dist/apps/management/routes/api-keys.js.map +1 -1
  98. package/dist/apps/management/routes/billing.d.ts +88 -48
  99. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  100. package/dist/apps/management/routes/billing.js +10 -2
  101. package/dist/apps/management/routes/billing.js.map +1 -1
  102. package/dist/apps/management/routes/faucet.d.ts +218 -0
  103. package/dist/apps/management/routes/faucet.d.ts.map +1 -0
  104. package/dist/apps/management/routes/faucet.js +139 -0
  105. package/dist/apps/management/routes/faucet.js.map +1 -0
  106. package/dist/apps/management/routes/invitations.d.ts +121 -121
  107. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  108. package/dist/apps/management/routes/invitations.js +3 -0
  109. package/dist/apps/management/routes/invitations.js.map +1 -1
  110. package/dist/apps/management/routes/invite-links.d.ts +197 -168
  111. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  112. package/dist/apps/management/routes/invite-links.js +26 -1
  113. package/dist/apps/management/routes/invite-links.js.map +1 -1
  114. package/dist/apps/management/routes/me.d.ts +2 -0
  115. package/dist/apps/management/routes/me.d.ts.map +1 -1
  116. package/dist/apps/management/routes/me.js +4 -0
  117. package/dist/apps/management/routes/me.js.map +1 -1
  118. package/dist/apps/management/routes/members.d.ts +49 -49
  119. package/dist/apps/management/routes/orgs.d.ts +91 -91
  120. package/dist/apps/management/routes/projects.d.ts +115 -115
  121. package/dist/apps/management/routes/usage.d.ts +35 -32
  122. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  123. package/dist/apps/management/routes/usage.js +4 -0
  124. package/dist/apps/management/routes/usage.js.map +1 -1
  125. package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
  126. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
  127. package/dist/apps/management/routes/verified-token-requests.js +271 -0
  128. package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
  129. package/dist/apps/management/routes/webhooks.d.ts +6977 -0
  130. package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
  131. package/dist/apps/management/routes/webhooks.js +573 -0
  132. package/dist/apps/management/routes/webhooks.js.map +1 -0
  133. package/dist/apps/mcp.d.ts +9 -2
  134. package/dist/apps/mcp.d.ts.map +1 -1
  135. package/dist/apps/mcp.js +9 -4
  136. package/dist/apps/mcp.js.map +1 -1
  137. package/dist/cli/Cli.d.ts.map +1 -1
  138. package/dist/cli/Cli.js +7 -2
  139. package/dist/cli/Cli.js.map +1 -1
  140. package/dist/db/Db.d.ts +4 -0
  141. package/dist/db/Db.d.ts.map +1 -1
  142. package/dist/db/Db.js +83 -0
  143. package/dist/db/Db.js.map +1 -1
  144. package/dist/db/Schema.d.ts +41 -0
  145. package/dist/db/Schema.d.ts.map +1 -1
  146. package/dist/db/Schema.js +45 -0
  147. package/dist/db/Schema.js.map +1 -1
  148. package/dist/db/tables/earlyAccess.d.ts +50 -0
  149. package/dist/db/tables/earlyAccess.d.ts.map +1 -0
  150. package/dist/db/tables/earlyAccess.js +63 -0
  151. package/dist/db/tables/earlyAccess.js.map +1 -0
  152. package/dist/db/tables/invitations.d.ts +12 -1
  153. package/dist/db/tables/invitations.d.ts.map +1 -1
  154. package/dist/db/tables/invitations.js +23 -0
  155. package/dist/db/tables/invitations.js.map +1 -1
  156. package/dist/db/tables/inviteLinks.d.ts +10 -2
  157. package/dist/db/tables/inviteLinks.d.ts.map +1 -1
  158. package/dist/db/tables/inviteLinks.js +10 -1
  159. package/dist/db/tables/inviteLinks.js.map +1 -1
  160. package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
  161. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  162. package/dist/db/tables/sponsoredTransactions.js +2 -0
  163. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  164. package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
  165. package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
  166. package/dist/db/tables/verifiedTokenRequests.js +120 -0
  167. package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
  168. package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
  169. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  170. package/dist/db/tables/webhookSubscriptions.js +16 -0
  171. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  172. package/dist/internal/Auth.d.ts +43 -2
  173. package/dist/internal/Auth.d.ts.map +1 -1
  174. package/dist/internal/Auth.js +60 -45
  175. package/dist/internal/Auth.js.map +1 -1
  176. package/dist/internal/FundingQuotes.d.ts +69 -15
  177. package/dist/internal/FundingQuotes.d.ts.map +1 -1
  178. package/dist/internal/FundingQuotes.js +74 -25
  179. package/dist/internal/FundingQuotes.js.map +1 -1
  180. package/dist/internal/Log.d.ts +19 -1
  181. package/dist/internal/Log.d.ts.map +1 -1
  182. package/dist/internal/Log.js +2 -0
  183. package/dist/internal/Log.js.map +1 -1
  184. package/dist/internal/MetricSink.d.ts.map +1 -1
  185. package/dist/internal/MetricSink.js +9 -0
  186. package/dist/internal/MetricSink.js.map +1 -1
  187. package/dist/internal/OpenApi.d.ts +2 -2
  188. package/dist/internal/OpenApi.d.ts.map +1 -1
  189. package/dist/internal/OpenApi.js +3 -0
  190. package/dist/internal/OpenApi.js.map +1 -1
  191. package/dist/internal/Schema.d.ts +14 -5
  192. package/dist/internal/Schema.d.ts.map +1 -1
  193. package/dist/internal/Schema.js +23 -5
  194. package/dist/internal/Schema.js.map +1 -1
  195. package/dist/internal/Value.d.ts +18 -0
  196. package/dist/internal/Value.d.ts.map +1 -1
  197. package/dist/internal/Value.js +11 -1
  198. package/dist/internal/Value.js.map +1 -1
  199. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  200. package/dist/internal/VerifiedTokens.js +10 -1
  201. package/dist/internal/VerifiedTokens.js.map +1 -1
  202. package/dist/internal/Viem.d.ts +1 -1
  203. package/dist/internal/Webhooks.d.ts +24 -3
  204. package/dist/internal/Webhooks.d.ts.map +1 -1
  205. package/dist/internal/Webhooks.js +34 -8
  206. package/dist/internal/Webhooks.js.map +1 -1
  207. package/package.json +2 -2
  208. package/src/App.ts +9 -1
  209. package/src/Client.test-d.ts +638 -6
  210. package/src/admin/App.ts +4 -0
  211. package/src/admin/apps/early-access.test.ts +125 -0
  212. package/src/admin/apps/early-access.ts +175 -0
  213. package/src/admin/apps/verified-tokens.test.ts +201 -0
  214. package/src/admin/apps/verified-tokens.ts +532 -286
  215. package/src/admin/ui/plugin.ts +2 -1
  216. package/src/admin/ui/src/lib/early-access.ts +63 -0
  217. package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
  218. package/src/admin/ui/src/routeTree.gen.ts +33 -2
  219. package/src/admin/ui/src/routes/__root.tsx +2 -1
  220. package/src/admin/ui/src/routes/early-access.tsx +157 -0
  221. package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
  222. package/src/admin/ui.generated.ts +48 -33
  223. package/src/apps/data/App.ts +22 -14
  224. package/src/apps/data/FundingQuoteProviders.test.ts +298 -0
  225. package/src/apps/data/FundingQuoteProviders.ts +257 -4
  226. package/src/apps/data/FxOracle.test.ts +118 -0
  227. package/src/apps/data/FxOracle.ts +153 -0
  228. package/src/apps/data/index.ts +1 -0
  229. package/src/apps/data/routes/activities.test.ts +173 -3
  230. package/src/apps/data/routes/activities.ts +403 -132
  231. package/src/apps/data/routes/addresses.ts +19 -9
  232. package/src/apps/data/routes/balances.test.ts +144 -11
  233. package/src/apps/data/routes/balances.ts +140 -51
  234. package/src/apps/data/routes/exchanges.test.ts +540 -9
  235. package/src/apps/data/routes/exchanges.ts +690 -103
  236. package/src/apps/data/routes/funding.test.ts +84 -0
  237. package/src/apps/data/routes/funding.ts +38 -6
  238. package/src/apps/data/routes/receipts.test.ts +125 -23
  239. package/src/apps/data/routes/receipts.ts +205 -100
  240. package/src/apps/data/routes/tokens.test.ts +43 -0
  241. package/src/apps/data/routes/tokens.ts +27 -12
  242. package/src/apps/data/routes/transactions.test.ts +72 -19
  243. package/src/apps/data/routes/transactions.ts +162 -92
  244. package/src/apps/data/routes/transfers.test.ts +146 -4
  245. package/src/apps/data/routes/transfers.ts +91 -13
  246. package/src/apps/data/routes/valuation.test.ts +422 -0
  247. package/src/apps/data/routes/valuation.ts +423 -0
  248. package/src/apps/data/routes/verified-tokens.ts +14 -2
  249. package/src/apps/data/routes/webhooks.test.ts +56 -8
  250. package/src/apps/data/routes/webhooks.ts +144 -27
  251. package/src/apps/index.ts +1 -1
  252. package/src/apps/management/App.ts +13 -0
  253. package/src/apps/management/routes/api-keys.test.ts +87 -0
  254. package/src/apps/management/routes/api-keys.ts +4 -3
  255. package/src/apps/management/routes/billing.test.ts +112 -1
  256. package/src/apps/management/routes/billing.ts +7 -2
  257. package/src/apps/management/routes/faucet.test.ts +79 -0
  258. package/src/apps/management/routes/faucet.ts +185 -0
  259. package/src/apps/management/routes/invitations.test.ts +172 -0
  260. package/src/apps/management/routes/invitations.ts +3 -0
  261. package/src/apps/management/routes/invite-links.test.ts +117 -0
  262. package/src/apps/management/routes/invite-links.ts +43 -1
  263. package/src/apps/management/routes/me.test.ts +140 -88
  264. package/src/apps/management/routes/me.ts +6 -0
  265. package/src/apps/management/routes/usage.test.ts +6 -0
  266. package/src/apps/management/routes/usage.ts +7 -0
  267. package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
  268. package/src/apps/management/routes/verified-token-requests.ts +397 -0
  269. package/src/apps/management/routes/webhooks.test.ts +426 -0
  270. package/src/apps/management/routes/webhooks.ts +672 -0
  271. package/src/apps/mcp.test.ts +13 -0
  272. package/src/apps/mcp.ts +18 -5
  273. package/src/cli/Cli.test.ts +36 -0
  274. package/src/cli/Cli.ts +7 -2
  275. package/src/db/Db.test.ts +19 -0
  276. package/src/db/Db.ts +95 -0
  277. package/src/db/Schema.ts +53 -0
  278. package/src/db/tables/earlyAccess.ts +86 -0
  279. package/src/db/tables/invitations.ts +26 -1
  280. package/src/db/tables/inviteLinks.ts +22 -3
  281. package/src/db/tables/sponsoredTransactions.ts +4 -0
  282. package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
  283. package/src/db/tables/verifiedTokenRequests.ts +182 -0
  284. package/src/db/tables/webhookSubscriptions.ts +31 -0
  285. package/src/internal/Auth.ts +73 -45
  286. package/src/internal/FundingQuotes.test.ts +143 -1
  287. package/src/internal/FundingQuotes.ts +95 -28
  288. package/src/internal/Log.test-d.ts +21 -0
  289. package/src/internal/Log.test.ts +50 -0
  290. package/src/internal/Log.ts +24 -1
  291. package/src/internal/MetricSink.test.ts +160 -0
  292. package/src/internal/MetricSink.ts +10 -0
  293. package/src/internal/OpenApi.ts +3 -0
  294. package/src/internal/Schema.ts +50 -5
  295. package/src/internal/Value.test.ts +20 -0
  296. package/src/internal/Value.ts +24 -1
  297. package/src/internal/VerifiedTokens.ts +9 -1
  298. package/src/internal/Webhooks.test.ts +140 -0
  299. package/src/internal/Webhooks.ts +53 -9
@@ -23,7 +23,8 @@ const outFile = path.join(here, '..', 'ui.generated.ts')
23
23
  // Total gzipped budget for the whole UI; the React + TanStack + Regen baseline
24
24
  // is heavier than a hand-rolled SPA, so fail loudly before it bloats the
25
25
  // package. Raise deliberately (and revisit code-splitting) if it trips.
26
- const maxGzipBytes = 405_000
26
+ // Raised from 405 KB for the early-access page.
27
+ const maxGzipBytes = 415_000
27
28
 
28
29
  const contentTypes: Record<string, string> = {
29
30
  '.css': 'text/css; charset=utf-8',
@@ -0,0 +1,63 @@
1
+ import * as ReactQuery from '@tanstack/react-query'
2
+ import type { InferResponseType } from 'hono/client'
3
+
4
+ import { client } from './client'
5
+
6
+ /** A stored allowlist entry (domain or exact email) from the list endpoint. */
7
+ export type Entry = InferResponseType<(typeof client)['early-access']['$get'], 200>['data'][number]
8
+
9
+ /** List early-access allowlist entries. */
10
+ export namespace list {
11
+ export const key = ['early-access'] as const
12
+ export async function fn() {
13
+ const response = await client['early-access'].$get()
14
+ if (!response.ok) throw new Error('Failed to load entries.')
15
+ return response.json()
16
+ }
17
+ export function options() {
18
+ return ReactQuery.queryOptions({ queryFn: fn, queryKey: key, staleTime: 30_000 })
19
+ }
20
+ export function useQuery() {
21
+ return ReactQuery.useQuery(options())
22
+ }
23
+ }
24
+
25
+ /** Add an allowlist entry: a bare domain or a full email. */
26
+ export namespace add {
27
+ export type Input = { entry: string }
28
+ export async function fn(input: Input) {
29
+ const response = await client['early-access'].$post({ json: input })
30
+ if (!response.ok) throw new Error(await errorMessage(response, 'Failed to add entry.'))
31
+ return response.json()
32
+ }
33
+ export function useMutation() {
34
+ const queryClient = ReactQuery.useQueryClient()
35
+ return ReactQuery.useMutation({
36
+ mutationFn: fn,
37
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: list.key }),
38
+ })
39
+ }
40
+ }
41
+
42
+ /** Remove an allowlist entry. */
43
+ export namespace remove {
44
+ export type Input = { entry: string }
45
+ export async function fn({ entry }: Input) {
46
+ const response = await client['early-access'].$delete({ json: { entry } })
47
+ if (!response.ok) throw new Error(await errorMessage(response, 'Failed to remove entry.'))
48
+ return response.json()
49
+ }
50
+ export function useMutation() {
51
+ const queryClient = ReactQuery.useQueryClient()
52
+ return ReactQuery.useMutation({
53
+ mutationFn: fn,
54
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: list.key }),
55
+ })
56
+ }
57
+ }
58
+
59
+ /** Server error-envelope message, with a fallback for non-JSON bodies. */
60
+ async function errorMessage(response: { json(): Promise<unknown> }, fallback: string) {
61
+ const body = (await response.json().catch(() => null)) as { error?: { message?: string } } | null
62
+ return body?.error?.message ?? fallback
63
+ }
@@ -1,8 +1,14 @@
1
1
  import * as ReactQuery from '@tanstack/react-query'
2
2
  import type { InferRequestType, InferResponseType } from 'hono/client'
3
+ import * as z from 'zod/mini'
3
4
 
4
5
  import { client } from './client'
5
6
 
7
+ /** Route search: the active page tab. */
8
+ export const search = z.object({
9
+ tab: z.catch(z.optional(z.enum(['pending', 'verified'])), undefined),
10
+ })
11
+
6
12
  /** The verified-token list endpoint's success body. */
7
13
  type ListResponse = InferResponseType<(typeof client)['verified-tokens']['$get'], 200>
8
14
 
@@ -67,6 +73,79 @@ export namespace create {
67
73
  }
68
74
  }
69
75
 
76
+ /** Review queue over organization verification requests. */
77
+ export namespace requests {
78
+ /** A verification request record from the queue endpoint. */
79
+ export type VerifiedTokenRequest = InferResponseType<
80
+ (typeof client)['verified-tokens']['requests']['$get'],
81
+ 200
82
+ >['data'][number]
83
+
84
+ export namespace list {
85
+ export function key() {
86
+ return ['verified-token-requests'] as const
87
+ }
88
+ export async function fn() {
89
+ const response = await client['verified-tokens'].requests.$get({ query: {} })
90
+ if (!response.ok) throw new Error('Failed to load requests.')
91
+ return response.json()
92
+ }
93
+ export function options() {
94
+ return ReactQuery.queryOptions({ queryFn: fn, queryKey: key(), staleTime: 30_000 })
95
+ }
96
+ export function useQuery() {
97
+ return ReactQuery.useQuery(options())
98
+ }
99
+ }
100
+
101
+ export namespace approve {
102
+ export type Input = { chainId: number; requestId: string }
103
+ export async function fn({ requestId }: Input) {
104
+ const response = await client['verified-tokens'].requests[':requestId'].approve.$post({
105
+ param: { requestId },
106
+ })
107
+ if (!response.ok) throw new Error(await errorMessage(response, 'Failed to approve request.'))
108
+ return response.json()
109
+ }
110
+ export function useMutation() {
111
+ const queryClient = ReactQuery.useQueryClient()
112
+ return ReactQuery.useMutation({
113
+ mutationFn: fn,
114
+ onSuccess: (_data, input) => {
115
+ void queryClient.invalidateQueries({ queryKey: list.key() })
116
+ // Approval publishes the token onto the chain's verified list.
117
+ void queryClient.invalidateQueries({ queryKey: get.key({ chainId: input.chainId }) })
118
+ },
119
+ })
120
+ }
121
+ }
122
+
123
+ export namespace deny {
124
+ export type Input = { requestId: string; reviewNote?: string }
125
+ export async function fn({ requestId, reviewNote }: Input) {
126
+ const response = await client['verified-tokens'].requests[':requestId'].deny.$post({
127
+ json: reviewNote ? { reviewNote } : {},
128
+ param: { requestId },
129
+ })
130
+ if (!response.ok) throw new Error(await errorMessage(response, 'Failed to deny request.'))
131
+ return response.json()
132
+ }
133
+ export function useMutation() {
134
+ const queryClient = ReactQuery.useQueryClient()
135
+ return ReactQuery.useMutation({
136
+ mutationFn: fn,
137
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: list.key() }),
138
+ })
139
+ }
140
+ }
141
+ }
142
+
143
+ /** Server error-envelope message, with a fallback for non-JSON bodies. */
144
+ async function errorMessage(response: { json(): Promise<unknown> }, fallback: string) {
145
+ const body = (await response.json().catch(() => null)) as { error?: { message?: string } } | null
146
+ return body?.error?.message ?? fallback
147
+ }
148
+
70
149
  /** Remove a verified token from a chain. */
71
150
  export namespace remove {
72
151
  export type Input = { address: `0x${string}`; chainId: number }
@@ -11,6 +11,7 @@
11
11
  import { Route as rootRouteImport } from './routes/__root'
12
12
  import { Route as VerifiedTokensRouteImport } from './routes/verified-tokens'
13
13
  import { Route as OrganizationsRouteImport } from './routes/organizations'
14
+ import { Route as EarlyAccessRouteImport } from './routes/early-access'
14
15
  import { Route as ApiKeysRouteImport } from './routes/api-keys'
15
16
  import { Route as IndexRouteImport } from './routes/index'
16
17
  import { Route as OrganizationsOrgIdRouteImport } from './routes/organizations_.$orgId'
@@ -25,6 +26,11 @@ const OrganizationsRoute = OrganizationsRouteImport.update({
25
26
  path: '/organizations',
26
27
  getParentRoute: () => rootRouteImport,
27
28
  } as any)
29
+ const EarlyAccessRoute = EarlyAccessRouteImport.update({
30
+ id: '/early-access',
31
+ path: '/early-access',
32
+ getParentRoute: () => rootRouteImport,
33
+ } as any)
28
34
  const ApiKeysRoute = ApiKeysRouteImport.update({
29
35
  id: '/api-keys',
30
36
  path: '/api-keys',
@@ -44,6 +50,7 @@ const OrganizationsOrgIdRoute = OrganizationsOrgIdRouteImport.update({
44
50
  export interface FileRoutesByFullPath {
45
51
  '/': typeof IndexRoute
46
52
  '/api-keys': typeof ApiKeysRoute
53
+ '/early-access': typeof EarlyAccessRoute
47
54
  '/organizations': typeof OrganizationsRoute
48
55
  '/verified-tokens': typeof VerifiedTokensRoute
49
56
  '/organizations/$orgId': typeof OrganizationsOrgIdRoute
@@ -51,6 +58,7 @@ export interface FileRoutesByFullPath {
51
58
  export interface FileRoutesByTo {
52
59
  '/': typeof IndexRoute
53
60
  '/api-keys': typeof ApiKeysRoute
61
+ '/early-access': typeof EarlyAccessRoute
54
62
  '/organizations': typeof OrganizationsRoute
55
63
  '/verified-tokens': typeof VerifiedTokensRoute
56
64
  '/organizations/$orgId': typeof OrganizationsOrgIdRoute
@@ -59,19 +67,33 @@ export interface FileRoutesById {
59
67
  __root__: typeof rootRouteImport
60
68
  '/': typeof IndexRoute
61
69
  '/api-keys': typeof ApiKeysRoute
70
+ '/early-access': typeof EarlyAccessRoute
62
71
  '/organizations': typeof OrganizationsRoute
63
72
  '/verified-tokens': typeof VerifiedTokensRoute
64
73
  '/organizations_/$orgId': typeof OrganizationsOrgIdRoute
65
74
  }
66
75
  export interface FileRouteTypes {
67
76
  fileRoutesByFullPath: FileRoutesByFullPath
68
- fullPaths: '/' | '/api-keys' | '/organizations' | '/verified-tokens' | '/organizations/$orgId'
77
+ fullPaths:
78
+ | '/'
79
+ | '/api-keys'
80
+ | '/early-access'
81
+ | '/organizations'
82
+ | '/verified-tokens'
83
+ | '/organizations/$orgId'
69
84
  fileRoutesByTo: FileRoutesByTo
70
- to: '/' | '/api-keys' | '/organizations' | '/verified-tokens' | '/organizations/$orgId'
85
+ to:
86
+ | '/'
87
+ | '/api-keys'
88
+ | '/early-access'
89
+ | '/organizations'
90
+ | '/verified-tokens'
91
+ | '/organizations/$orgId'
71
92
  id:
72
93
  | '__root__'
73
94
  | '/'
74
95
  | '/api-keys'
96
+ | '/early-access'
75
97
  | '/organizations'
76
98
  | '/verified-tokens'
77
99
  | '/organizations_/$orgId'
@@ -80,6 +102,7 @@ export interface FileRouteTypes {
80
102
  export interface RootRouteChildren {
81
103
  IndexRoute: typeof IndexRoute
82
104
  ApiKeysRoute: typeof ApiKeysRoute
105
+ EarlyAccessRoute: typeof EarlyAccessRoute
83
106
  OrganizationsRoute: typeof OrganizationsRoute
84
107
  VerifiedTokensRoute: typeof VerifiedTokensRoute
85
108
  OrganizationsOrgIdRoute: typeof OrganizationsOrgIdRoute
@@ -101,6 +124,13 @@ declare module '@tanstack/react-router' {
101
124
  preLoaderRoute: typeof OrganizationsRouteImport
102
125
  parentRoute: typeof rootRouteImport
103
126
  }
127
+ '/early-access': {
128
+ id: '/early-access'
129
+ path: '/early-access'
130
+ fullPath: '/early-access'
131
+ preLoaderRoute: typeof EarlyAccessRouteImport
132
+ parentRoute: typeof rootRouteImport
133
+ }
104
134
  '/api-keys': {
105
135
  id: '/api-keys'
106
136
  path: '/api-keys'
@@ -128,6 +158,7 @@ declare module '@tanstack/react-router' {
128
158
  const rootRouteChildren: RootRouteChildren = {
129
159
  IndexRoute: IndexRoute,
130
160
  ApiKeysRoute: ApiKeysRoute,
161
+ EarlyAccessRoute: EarlyAccessRoute,
131
162
  OrganizationsRoute: OrganizationsRoute,
132
163
  VerifiedTokensRoute: VerifiedTokensRoute,
133
164
  OrganizationsOrgIdRoute: OrganizationsOrgIdRoute,
@@ -10,7 +10,7 @@ import type { QueryClient } from '@tanstack/react-query'
10
10
  import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'
11
11
  import { type ComponentType } from 'react'
12
12
  import { Button, Identicon } from 'regen-ui'
13
- import { BadgeCheck, Building2, KeyRound, LogOut } from 'lucide-react'
13
+ import { BadgeCheck, Building2, KeyRound, LogOut, Ticket } from 'lucide-react'
14
14
  import { WagmiProvider } from 'wagmi'
15
15
 
16
16
  import appCss from '../styles.css?url'
@@ -115,6 +115,7 @@ const nav = [
115
115
  { exact: false, href: '/organizations', icon: Building2, label: 'Organizations' },
116
116
  { exact: false, href: '/api-keys', icon: KeyRound, label: 'API Keys' },
117
117
  { exact: false, href: '/verified-tokens', icon: BadgeCheck, label: 'Verified Tokens' },
118
+ { exact: false, href: '/early-access', icon: Ticket, label: 'Early Access' },
118
119
  ] as const
119
120
 
120
121
  function Sidebar(props: { email: string; logoutUrl?: string }) {
@@ -0,0 +1,157 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { useState } from 'react'
3
+ import { Button, Fields, Input } from 'regen-ui'
4
+ import { Plus, Trash2 } from 'lucide-react'
5
+
6
+ import { Card, Notice, Page } from '../components/Page'
7
+ import { Dialog } from '../components/Dialog'
8
+ import * as EarlyAccess from '../lib/early-access'
9
+
10
+ export const Route = createFileRoute('/early-access')({
11
+ loader: ({ context }) => context.queryClient.prefetchQuery(EarlyAccess.list.options()),
12
+ component: RouteComponent,
13
+ })
14
+
15
+ function RouteComponent() {
16
+ const [open, setOpen] = useState(false)
17
+ const entries = EarlyAccess.list.useQuery()
18
+ const add = EarlyAccess.add.useMutation()
19
+
20
+ return (
21
+ <Dialog.Root onOpenChange={setOpen} open={open}>
22
+ <Page
23
+ title="Early Access"
24
+ description="Manage which accounts have early access"
25
+ action={
26
+ <Dialog.Trigger
27
+ render={
28
+ <Button variant="primary">
29
+ <Plus className="size-4" />
30
+ Add entry
31
+ </Button>
32
+ }
33
+ />
34
+ }
35
+ >
36
+ <EntryList
37
+ entries={entries.data?.data ?? []}
38
+ error={entries.error}
39
+ loading={entries.isPending}
40
+ />
41
+ <Dialog.Popup>
42
+ <AddEntryForm
43
+ onSubmit={(input) =>
44
+ add.mutate(input, {
45
+ onError: (error) => alert(error.message),
46
+ onSuccess: () => setOpen(false),
47
+ })
48
+ }
49
+ pending={add.isPending}
50
+ />
51
+ </Dialog.Popup>
52
+ </Page>
53
+ </Dialog.Root>
54
+ )
55
+ }
56
+
57
+ function AddEntryForm(props: {
58
+ onSubmit: (input: EarlyAccess.add.Input) => void
59
+ pending: boolean
60
+ }) {
61
+ function onSubmit(event: React.FormEvent<HTMLFormElement>) {
62
+ event.preventDefault()
63
+ const entry = new FormData(event.currentTarget).get('entry')
64
+ if (typeof entry !== 'string' || !entry.trim()) return
65
+ props.onSubmit({ entry: entry.trim() })
66
+ }
67
+
68
+ return (
69
+ <>
70
+ <Dialog.Title>Add Entry</Dialog.Title>
71
+ <Dialog.Description>
72
+ Grant early access to a whole domain or a single email
73
+ </Dialog.Description>
74
+ <form className="mt-6 flex flex-col gap-8" onSubmit={onSubmit}>
75
+ <Fields className="gap-6" variant="default">
76
+ <Input
77
+ autoComplete="off"
78
+ label="Domain or email"
79
+ name="entry"
80
+ placeholder="example.org or user@example.org"
81
+ required
82
+ spellCheck={false}
83
+ />
84
+ </Fields>
85
+ <div className="flex justify-end gap-2">
86
+ <Dialog.Close render={<Button type="button">Cancel</Button>} />
87
+ <Button loading={props.pending} type="submit" variant="primary">
88
+ Add entry
89
+ </Button>
90
+ </div>
91
+ </form>
92
+ </>
93
+ )
94
+ }
95
+
96
+ function EntryList(props: {
97
+ entries: readonly EarlyAccess.Entry[]
98
+ error: Error | null
99
+ loading: boolean
100
+ }) {
101
+ return (
102
+ <Card>
103
+ {props.loading ? (
104
+ <Notice>Loading entries…</Notice>
105
+ ) : props.error ? (
106
+ <Notice>{props.error.message}</Notice>
107
+ ) : props.entries.length === 0 ? (
108
+ <Notice>No entries yet.</Notice>
109
+ ) : (
110
+ <ul className="divide-y divide-border">
111
+ {props.entries.map((entry) => (
112
+ <EntryRow entry={entry} key={entry.entry} />
113
+ ))}
114
+ </ul>
115
+ )}
116
+ </Card>
117
+ )
118
+ }
119
+
120
+ function EntryRow(props: { entry: EarlyAccess.Entry }) {
121
+ const { entry } = props
122
+ const remove = EarlyAccess.remove.useMutation()
123
+
124
+ function onRemove() {
125
+ if (!confirm(`Remove ${entry.entry}? Matching users lose early access.`)) return
126
+ remove.mutate({ entry: entry.entry }, { onError: (error) => alert(error.message) })
127
+ }
128
+
129
+ return (
130
+ <li className="flex items-center justify-between gap-4 px-5 py-2.5">
131
+ <div className="flex min-w-0 flex-col gap-1">
132
+ <span className="truncate text-label-14 text-foreground">{entry.entry}</span>
133
+ <span className="text-label-12 text-foreground-secondary">
134
+ Added by {entry.createdBy} · {formatDate(entry.createdAt)}
135
+ </span>
136
+ </div>
137
+ <Button.Icon
138
+ className="text-foreground-secondary hover:text-negative"
139
+ disabled={remove.isPending}
140
+ onClick={onRemove}
141
+ size="lg"
142
+ title="Remove entry"
143
+ variant="plain"
144
+ >
145
+ <Trash2 />
146
+ </Button.Icon>
147
+ </li>
148
+ )
149
+ }
150
+
151
+ function formatDate(iso: string) {
152
+ return new Date(iso).toLocaleDateString(undefined, {
153
+ day: 'numeric',
154
+ month: 'short',
155
+ year: 'numeric',
156
+ })
157
+ }