tapimo 0.4.4 → 0.5.1
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.
- package/dist/App.d.ts +4701 -3416
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +24 -2
- package/dist/App.js.map +1 -1
- package/dist/Assets.js +3 -3
- package/dist/Assets.js.map +1 -1
- package/dist/Scope.d.ts +18 -1
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +23 -3
- package/dist/Scope.js.map +1 -1
- package/dist/Webhooks.d.ts +1 -1
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +5 -10
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +6 -34
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +3 -3
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +4 -1
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/scopes.d.ts +6 -34
- package/dist/admin/apps/scopes.d.ts.map +1 -1
- package/dist/admin/apps/scopes.js +2 -2
- package/dist/admin/apps/scopes.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +57 -57
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.js +33 -33
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/apps/data/App.d.ts +4574 -4277
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +155 -77
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts +109 -0
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -0
- package/dist/apps/data/FundingQuoteProviders.js +464 -0
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -0
- package/dist/apps/data/index.d.ts +1 -1
- package/dist/apps/data/index.js +1 -1
- package/dist/apps/data/routes/activities.d.ts +26 -26
- package/dist/apps/data/routes/addresses.d.ts +38 -38
- package/dist/apps/data/routes/balances.d.ts +45 -45
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +67 -149
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +2 -3
- package/dist/apps/data/routes/blocks.d.ts.map +1 -1
- package/dist/apps/data/routes/blocks.js +3 -5
- package/dist/apps/data/routes/blocks.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +177 -176
- package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
- package/dist/apps/data/routes/coingecko.js +3 -8
- package/dist/apps/data/routes/coingecko.js.map +1 -1
- package/dist/apps/data/routes/funding.d.ts +131 -228
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +152 -219
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +34 -34
- package/dist/apps/data/routes/indexer.d.ts.map +1 -1
- package/dist/apps/data/routes/indexer.js +9 -2
- package/dist/apps/data/routes/indexer.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +228 -228
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +86 -16
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +12 -12
- package/dist/apps/data/routes/verified-tokens.d.ts +5 -5
- package/dist/apps/data/routes/webhooks.d.ts +340 -0
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +13 -1
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +1 -1
- package/dist/apps/index.js +1 -1
- package/dist/apps/management/App.d.ts +1833 -851
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +4 -0
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +41 -41
- package/dist/apps/management/routes/api-keys.js +2 -2
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +48 -48
- package/dist/apps/management/routes/invitations.d.ts +132 -132
- package/dist/apps/management/routes/invite-links.d.ts +1100 -0
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -0
- package/dist/apps/management/routes/invite-links.js +411 -0
- package/dist/apps/management/routes/invite-links.js.map +1 -0
- package/dist/apps/management/routes/members.d.ts +41 -41
- package/dist/apps/management/routes/orgs.d.ts +92 -92
- package/dist/apps/management/routes/projects.d.ts +9 -9
- package/dist/apps/management/routes/scopes.d.ts.map +1 -1
- package/dist/apps/management/routes/scopes.js +2 -2
- package/dist/apps/management/routes/scopes.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts +24 -24
- package/dist/apps/mcp.js +2 -2
- package/dist/apps/mcp.js.map +1 -1
- package/dist/apps/relay/App.d.ts +2 -2
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +44 -6
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/db/Db.d.ts +3 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +57 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +31 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +31 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/inviteLinks.d.ts +42 -0
- package/dist/db/tables/inviteLinks.d.ts.map +1 -0
- package/dist/db/tables/inviteLinks.js +148 -0
- package/dist/db/tables/inviteLinks.js.map +1 -0
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +2 -0
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +6 -2
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +13 -3
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +9 -1
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +138 -10
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts +3 -1
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +17 -2
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/{FundingRoutes.d.ts → FundingQuotes.d.ts} +240 -369
- package/dist/internal/FundingQuotes.d.ts.map +1 -0
- package/dist/internal/{FundingRoutes.js → FundingQuotes.js} +144 -183
- package/dist/internal/FundingQuotes.js.map +1 -0
- package/dist/internal/Log.d.ts +18 -12
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +2 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/Tidx.d.ts +9 -3
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +13 -7
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Viem.d.ts +17 -2
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +30 -3
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal/index.js +1 -1
- package/package.json +2 -2
- package/src/ApiKeys.test.ts +25 -0
- package/src/App.test-d.ts +2 -0
- package/src/App.test.ts +13 -2
- package/src/App.ts +37 -5
- package/src/Assets.ts +3 -3
- package/src/Client.test-d.ts +21 -11
- package/src/Scope.test.ts +1 -0
- package/src/Scope.ts +32 -4
- package/src/Webhooks.ts +5 -10
- package/src/admin/apps/api-keys.test.ts +27 -0
- package/src/admin/apps/api-keys.ts +8 -1
- package/src/admin/apps/scopes.test.ts +7 -2
- package/src/admin/apps/scopes.ts +2 -2
- package/src/admin/ui/src/components/Dialog.tsx +8 -2
- package/src/admin/ui/src/lib/scopes.test.ts +19 -0
- package/src/admin/ui/src/lib/scopes.ts +12 -0
- package/src/admin/ui/src/routes/api-keys.tsx +128 -27
- package/src/admin/ui.generated.ts +33 -33
- package/src/apps/composition.test.ts +77 -0
- package/src/apps/data/App.test.ts +354 -0
- package/src/apps/data/App.ts +178 -91
- package/src/apps/data/FundingQuoteProviders.test.ts +577 -0
- package/src/apps/data/FundingQuoteProviders.ts +633 -0
- package/src/apps/data/index.ts +1 -1
- package/src/apps/data/routes/balances.test.ts +64 -18
- package/src/apps/data/routes/balances.ts +76 -177
- package/src/apps/data/routes/blocks.ts +3 -5
- package/src/apps/data/routes/coingecko.ts +3 -8
- package/src/apps/data/routes/funding.test.ts +304 -192
- package/src/apps/data/routes/funding.ts +166 -286
- package/src/apps/data/routes/indexer.test.ts +173 -15
- package/src/apps/data/routes/indexer.ts +8 -2
- package/src/apps/data/routes/rpc.test.ts +219 -0
- package/src/apps/data/routes/rpc.ts +92 -17
- package/src/apps/data/routes/webhooks.test.ts +21 -0
- package/src/apps/data/routes/webhooks.ts +13 -1
- package/src/apps/index.ts +1 -1
- package/src/apps/management/App.ts +4 -0
- package/src/apps/management/Billing.test.ts +2 -2
- package/src/apps/management/routes/api-keys.test.ts +47 -3
- package/src/apps/management/routes/api-keys.ts +2 -2
- package/src/apps/management/routes/invite-links.test.ts +385 -0
- package/src/apps/management/routes/invite-links.ts +570 -0
- package/src/apps/management/routes/scopes.test.ts +3 -2
- package/src/apps/management/routes/scopes.ts +4 -2
- package/src/apps/mcp.test.ts +18 -0
- package/src/apps/mcp.ts +2 -2
- package/src/apps/relay/App.test.ts +328 -7
- package/src/apps/relay/App.ts +42 -6
- package/src/apps/relay/Sponsorships.test.ts +2 -2
- package/src/db/Db.test.ts +5 -5
- package/src/db/Db.ts +65 -0
- package/src/db/Schema.ts +39 -0
- package/src/db/tables/billingSettings.test.ts +2 -2
- package/src/db/tables/inviteLinks.ts +187 -0
- package/src/db/tables/organizations.test.ts +2 -2
- package/src/db/tables/organizations.ts +2 -0
- package/src/db/tables/sponsoredTransactions.test.ts +19 -2
- package/src/db/tables/sponsoredTransactions.ts +21 -14
- package/src/db/tables/stripeCustomers.test.ts +2 -2
- package/src/handlers/relay.ts +16 -4
- package/src/internal/Auth.test.ts +132 -22
- package/src/internal/Auth.ts +181 -14
- package/src/internal/EdgeCache.test.ts +24 -3
- package/src/internal/EdgeCache.ts +18 -2
- package/src/internal/FundingQuotes.test.ts +268 -0
- package/src/internal/{FundingRoutes.ts → FundingQuotes.ts} +216 -277
- package/src/internal/Log.ts +21 -14
- package/src/internal/Tidx.test.ts +48 -0
- package/src/internal/Tidx.ts +21 -7
- package/src/internal/Viem.test.ts +46 -0
- package/src/internal/Viem.ts +48 -6
- package/src/internal/index.test.ts +1 -1
- package/src/internal/index.ts +1 -1
- package/dist/apps/data/FundingRouteProviders.d.ts +0 -36
- package/dist/apps/data/FundingRouteProviders.d.ts.map +0 -1
- package/dist/apps/data/FundingRouteProviders.js +0 -245
- package/dist/apps/data/FundingRouteProviders.js.map +0 -1
- package/dist/internal/FundingRoutes.d.ts.map +0 -1
- package/dist/internal/FundingRoutes.js.map +0 -1
- package/src/apps/data/FundingRouteProviders.test.ts +0 -225
- package/src/apps/data/FundingRouteProviders.ts +0 -312
- package/src/internal/FundingRoutes.test.ts +0 -213
package/src/apps/data/App.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { Hono } from 'hono'
|
|
1
|
+
import { type Context, Hono } from 'hono'
|
|
2
|
+
import { matchedRoutes } from 'hono/route'
|
|
3
|
+
import { ZoneRpcAuthentication } from 'ox/tempo'
|
|
2
4
|
import * as z from 'zod/mini'
|
|
3
5
|
|
|
4
6
|
import type * as Assets from '../../Assets.js'
|
|
5
7
|
import type * as App from '../../App.js'
|
|
6
|
-
import * as Metadata from '../metadata.js'
|
|
7
8
|
import * as Auth from '../../internal/Auth.js'
|
|
9
|
+
import * as EdgeCache from '../../internal/EdgeCache.js'
|
|
8
10
|
import * as Path from '../../internal/Path.js'
|
|
9
11
|
import * as Response from '../../internal/Response.js'
|
|
10
12
|
import * as Schema from '../../internal/Schema.js'
|
|
11
13
|
import * as Tidx from '../../internal/Tidx.js'
|
|
12
14
|
import * as Viem from '../../internal/Viem.js'
|
|
15
|
+
import * as Scope from '../../Scope.js'
|
|
16
|
+
import * as Metadata from '../metadata.js'
|
|
13
17
|
|
|
14
18
|
import { transactions as transactionActivities } from './routes/activities.js'
|
|
15
19
|
import { addresses } from './routes/addresses.js'
|
|
@@ -29,102 +33,111 @@ import { verifiedTokens } from './routes/verified-tokens.js'
|
|
|
29
33
|
import { schema as webhookSchema, webhooks } from './routes/webhooks.js'
|
|
30
34
|
|
|
31
35
|
/**
|
|
32
|
-
* The chain-data route group
|
|
33
|
-
*
|
|
34
|
-
* configuration and publishes the chain clients on request context.
|
|
36
|
+
* The chain-data route group extends app context with TIDX, assets, zones,
|
|
37
|
+
* verified tokens, and webhooks, and exposes indexed and RPC-backed reads.
|
|
35
38
|
*
|
|
36
39
|
* ```ts
|
|
37
40
|
* App.create(options).route('/', data())
|
|
38
41
|
* ```
|
|
39
42
|
*/
|
|
40
43
|
export function data(options: data.Options = {}) {
|
|
41
|
-
const { assets,
|
|
44
|
+
const { assets, tidx } = options
|
|
42
45
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const supportedChainIds = new Set<number>([
|
|
47
|
-
...Object.keys(Viem.url).map(Number),
|
|
48
|
-
...Object.keys(Tidx.url).map(Number),
|
|
49
|
-
defaultChainId,
|
|
50
|
-
...(options.supportedChainIds ?? []),
|
|
51
|
-
])
|
|
46
|
+
// Zone endpoints are explicit trust boundaries; the API never derives them.
|
|
47
|
+
const zones = new Map((options.zones ?? []).map((zone) => [zone.chainId, zone]))
|
|
48
|
+
const dataRouteHandlers = new Set<unknown>()
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
// Keying on the resolved output (`url`+`basicAuth`+`chainId`), not the
|
|
55
|
-
// principal, bounds cardinality by the number of distinct upstreams.
|
|
56
|
-
const clients = new Map<string, ReturnType<typeof Viem.getClient>>()
|
|
57
|
-
const getClient = (chainId = defaultChainId, principal: Auth.Principal | null = null) => {
|
|
58
|
-
const { url, basicAuth } = Viem.resolve(rpc_option, { chainId, principal })
|
|
59
|
-
const cacheKey = `${url}|${basicAuth ?? ''}|${chainId}`
|
|
60
|
-
const existing = clients.get(cacheKey)
|
|
61
|
-
if (existing) return existing
|
|
62
|
-
const client = Viem.getClient({ chainId, principal, rpc: rpc_option })
|
|
63
|
-
clients.set(cacheKey, client)
|
|
64
|
-
return client
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Memoize TIDX clients per `chainId` so the base URL resolver runs once per
|
|
68
|
-
// chain instead of on every request.
|
|
69
|
-
const getTidx = Tidx.createGetClient({ defaultChainId, tidx })
|
|
50
|
+
const getTidx = Tidx.createGetClient({ tidx })
|
|
70
51
|
|
|
71
52
|
const app = new Hono<App.Environment>()
|
|
72
53
|
// Publish the chain-data context vars for this group's handlers. Runs after
|
|
73
54
|
// `App.create`'s middleware, so `getClient`/`getTidx` can key on the
|
|
74
55
|
// resolved principal and `getAsset` can read `basePath` off context.
|
|
75
56
|
.use('*', async (c, next) => {
|
|
76
|
-
c.
|
|
57
|
+
const getClient = c.get('getClient')
|
|
58
|
+
const supportedChainIds = new Set<number>([
|
|
59
|
+
...c.get('supportedChainIds'),
|
|
60
|
+
...Object.keys(Tidx.url).map(Number),
|
|
61
|
+
...zones.keys(),
|
|
62
|
+
])
|
|
77
63
|
c.set('getAsset', createGetAsset({ assets, basePath: c.get('basePath'), origin: new URL(c.req.url).origin })) // prettier-ignore
|
|
78
|
-
c.set('getClient', (chainId) => getClient(chainId
|
|
79
|
-
c.set('getTidx', (chainId) => getTidx(chainId, Auth.getPrincipal(c)))
|
|
80
|
-
c.set('rpc', rpc_option)
|
|
64
|
+
c.set('getClient', (chainId) => getClient(chainId ?? c.get('chainId')))
|
|
65
|
+
c.set('getTidx', (chainId) => getTidx(chainId ?? c.get('chainId'), Auth.getPrincipal(c)))
|
|
81
66
|
c.set('supportedChainIds', supportedChainIds)
|
|
82
67
|
c.set('tidx', tidx)
|
|
83
68
|
c.set('verifiedTokens', options.verifiedTokens === false ? undefined : (options.verifiedTokens ?? {})) // prettier-ignore
|
|
84
69
|
c.set('webhook', options.webhook === false ? undefined : (options.webhook ?? {}))
|
|
70
|
+
c.set('zones', zones)
|
|
85
71
|
await next()
|
|
86
72
|
})
|
|
87
|
-
//
|
|
88
|
-
|
|
73
|
+
// Resolve one chain for every data route before auth and handlers use it.
|
|
74
|
+
.use('*', async (c, next) => {
|
|
75
|
+
const defaultChainId = c.get('chainId')
|
|
76
|
+
const supportedChainIds = c.get('supportedChainIds')
|
|
77
|
+
const selection = resolveChainSelector({
|
|
78
|
+
c,
|
|
79
|
+
defaultChainId,
|
|
80
|
+
handlers: dataRouteHandlers,
|
|
81
|
+
})
|
|
82
|
+
if (!selection.matched) return next()
|
|
83
|
+
if (selection.conflict || selection.invalid)
|
|
84
|
+
return Response.error(c, {
|
|
85
|
+
code: 'chain_id_invalid',
|
|
86
|
+
message: selection.conflict ? 'Conflicting chain ids' : 'Invalid chain id',
|
|
87
|
+
status: 400,
|
|
88
|
+
})
|
|
89
|
+
if (!supportedChainIds.has(selection.chainId))
|
|
90
|
+
return Response.unsupportedChainId(c, selection.chainId, supportedChainIds)
|
|
91
|
+
c.set('chainId', selection.chainId)
|
|
92
|
+
return next()
|
|
93
|
+
})
|
|
94
|
+
// Zone data requires an issued scope. Raw RPC may instead forward the
|
|
95
|
+
// caller's Zone token to the node that enforces account scoping.
|
|
89
96
|
.use('*', async (c, next) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
if (zones.size === 0) return next()
|
|
98
|
+
const selection = resolveChainSelector({
|
|
99
|
+
c,
|
|
100
|
+
defaultChainId: c.get('chainId'),
|
|
101
|
+
handlers: dataRouteHandlers,
|
|
94
102
|
})
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
103
|
+
if (!selection.matched) return next()
|
|
104
|
+
const chainId = c.get('chainId')
|
|
105
|
+
if (!zones.has(chainId)) return next()
|
|
106
|
+
|
|
107
|
+
const principal = Auth.getPrincipal(c)
|
|
108
|
+
const scopes = principal?.type === 'api_key' ? principal.apiKey.scopes : undefined
|
|
109
|
+
const allowed =
|
|
110
|
+
scopes?.includes(Scope.wildcard) ||
|
|
111
|
+
scopes?.includes(`zone:${chainId}:read`) ||
|
|
112
|
+
(selection.rpc && Boolean(c.req.header(ZoneRpcAuthentication.headerName)?.trim()))
|
|
113
|
+
if (!allowed)
|
|
114
|
+
return Response.error(c, {
|
|
115
|
+
code: 'api_key_forbidden',
|
|
116
|
+
message: selection.rpc
|
|
117
|
+
? `Chain id ${chainId} is a zone. Use an API key granting \`zone:${chainId}:read\`, or pass a Zone token via \`X-Authorization-Token\`.`
|
|
118
|
+
: `Chain id ${chainId} is a zone. Use an API key granting \`zone:${chainId}:read\`.`,
|
|
119
|
+
status: 403,
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
await next()
|
|
123
|
+
// Defense in depth for cache misses; pre-auth lookups are disabled by
|
|
124
|
+
// the route eligibility predicate below.
|
|
125
|
+
c.set('edgeCache', undefined)
|
|
101
126
|
})
|
|
102
127
|
// Sandbox keys are testnet-only. A chain-scoped data route defaults to
|
|
103
128
|
// mainnet, so a sandbox key that omits `chainId` (or targets mainnet) is
|
|
104
129
|
// refused with a clear message telling the caller to pass a testnet
|
|
105
|
-
// `chainId`.
|
|
106
|
-
// query, so it is skipped and enforces the rule in its sponsor validation.
|
|
130
|
+
// `chainId`.
|
|
107
131
|
.use('*', async (c, next) => {
|
|
108
|
-
const rpc = Path.join(c.get('basePath') ?? '', 'rpc')
|
|
109
|
-
const relay = Path.join(rpc, 'relay')
|
|
110
|
-
if (c.req.path === relay || c.req.path.startsWith(`${relay}/`)) return next()
|
|
111
|
-
|
|
112
132
|
const principal = Auth.getPrincipal(c)
|
|
113
133
|
if (principal?.type !== 'api_key' || principal.environment !== 'sandbox') return next()
|
|
114
134
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
135
|
+
const selection = resolveChainSelector({
|
|
136
|
+
c,
|
|
137
|
+
defaultChainId: c.get('chainId'),
|
|
138
|
+
handlers: dataRouteHandlers,
|
|
119
139
|
})
|
|
120
|
-
|
|
121
|
-
// stays with the route's own validator rather than the sandbox message.
|
|
122
|
-
const chainId = (() => {
|
|
123
|
-
if (raw === undefined) return defaultChainId
|
|
124
|
-
const parsed = Schema.ChainId.safeParse(raw)
|
|
125
|
-
return parsed.success ? parsed.data : undefined
|
|
126
|
-
})()
|
|
127
|
-
if (chainId === undefined || !Viem.isMainnet(chainId)) return next()
|
|
140
|
+
if (!selection.matched || !Viem.isMainnet(c.get('chainId'))) return next()
|
|
128
141
|
|
|
129
142
|
return Response.error(c, {
|
|
130
143
|
code: 'api_key_forbidden',
|
|
@@ -149,7 +162,7 @@ export function data(options: data.Options = {}) {
|
|
|
149
162
|
.route('/', blocks())
|
|
150
163
|
.route('/', exchanges())
|
|
151
164
|
.route('/', feeAmm())
|
|
152
|
-
.route('/', funding(options.
|
|
165
|
+
.route('/', funding(options.funding))
|
|
153
166
|
.route('/', indexer())
|
|
154
167
|
.route('/', receipts())
|
|
155
168
|
.route('/', tokenlist())
|
|
@@ -162,19 +175,28 @@ export function data(options: data.Options = {}) {
|
|
|
162
175
|
.route('/', rpc())
|
|
163
176
|
.route('/', coingecko())
|
|
164
177
|
.route('/', blocksByTimestampCompat())
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
+
const edgeCacheEligible = (c: Context<App.Environment>) => {
|
|
179
|
+
const selection = resolveChainSelector({
|
|
180
|
+
c,
|
|
181
|
+
defaultChainId: c.get('chainId'),
|
|
182
|
+
handlers: dataRouteHandlers,
|
|
183
|
+
})
|
|
184
|
+
return (
|
|
185
|
+
selection.matched &&
|
|
186
|
+
!selection.conflict &&
|
|
187
|
+
!selection.invalid &&
|
|
188
|
+
!zones.has(selection.chainId)
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
for (const route of app.routes) {
|
|
192
|
+
if (route.method === 'ALL') continue
|
|
193
|
+
dataRouteHandlers.add(route.handler)
|
|
194
|
+
if (zones.size > 0) EdgeCache.setEligibility(route.handler, edgeCacheEligible)
|
|
195
|
+
}
|
|
196
|
+
return Metadata.attach(app, {
|
|
197
|
+
...openapi,
|
|
198
|
+
supportedChainIds: [...Object.keys(Tidx.url).map(Number), ...zones.keys()],
|
|
199
|
+
})
|
|
178
200
|
}
|
|
179
201
|
|
|
180
202
|
export declare namespace data {
|
|
@@ -182,20 +204,27 @@ export declare namespace data {
|
|
|
182
204
|
type Options = {
|
|
183
205
|
/** Static API asset store for the current runtime (e.g. `Assets.cloudflareR2(...)`). Omit to skip static assets — token logo URIs go unresolved. */
|
|
184
206
|
assets?: Assets.Assets | undefined
|
|
185
|
-
/**
|
|
186
|
-
|
|
187
|
-
/** Funding route provider adapter configuration. Omit to serve static inventory only. */
|
|
188
|
-
fundingRoutes?: funding.Options | undefined
|
|
189
|
-
/** Tempo RPC options: a static config, or a per-request resolver that routes by request principal to a separate (e.g. public, no-auth) RPC. */
|
|
190
|
-
rpc?: Viem.getClient.Rpc | undefined
|
|
191
|
-
/** Extra chain ids this deployment serves, beyond the built-in public chains and `defaultChainId`. A `chainId` outside this set is rejected with a 400. */
|
|
192
|
-
supportedChainIds?: readonly number[] | undefined
|
|
207
|
+
/** Funding quote provider configuration. */
|
|
208
|
+
funding?: funding.Options | undefined
|
|
193
209
|
/** TIDX query client options. */
|
|
194
210
|
tidx?: Tidx.getClient.Tidx | undefined
|
|
195
211
|
/** Verified-token feature configuration. Enabled by default (token rows live in `db`; empty until published); pass `false` to always serve an empty verified list. */
|
|
196
212
|
verifiedTokens?: VerifiedTokens | false | undefined
|
|
197
213
|
/** Webhook feature configuration. Enabled by default (rows live in `db`); pass `false` to disable, leaving `/webhooks` mounted but returning `404` and hidden from the OpenAPI document. */
|
|
198
214
|
webhook?: Webhook | false | undefined
|
|
215
|
+
/**
|
|
216
|
+
* Zone chains served by this deployment. REST and TIDX require a
|
|
217
|
+
* `zone:<chainId>:read` scope; raw RPC may forward a Zone token instead.
|
|
218
|
+
*/
|
|
219
|
+
zones?: readonly Zone[] | undefined
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** One zone chain served by this deployment. */
|
|
223
|
+
type Zone = {
|
|
224
|
+
/** Zone chain id. Consumer-supplied literal; the API never derives zone chain ids. */
|
|
225
|
+
chainId: number
|
|
226
|
+
/** Zone RPC used when forwarding a caller-supplied Zone token. */
|
|
227
|
+
forwardRpcUrl: string
|
|
199
228
|
}
|
|
200
229
|
|
|
201
230
|
/** Verified-token feature configuration. */
|
|
@@ -219,6 +248,66 @@ export declare namespace data {
|
|
|
219
248
|
}
|
|
220
249
|
}
|
|
221
250
|
|
|
251
|
+
function resolveChainSelector(options: {
|
|
252
|
+
c: Context<App.Environment>
|
|
253
|
+
defaultChainId: Viem.ChainId
|
|
254
|
+
handlers: ReadonlySet<unknown>
|
|
255
|
+
}) {
|
|
256
|
+
let matched = false
|
|
257
|
+
let path: string | undefined
|
|
258
|
+
let rpc = false
|
|
259
|
+
for (const route of matchedRoutes(options.c)) {
|
|
260
|
+
if (!options.handlers.has(route.handler)) continue
|
|
261
|
+
matched = true
|
|
262
|
+
const selector = pathChainSelector(route.path, options.c.req.path)
|
|
263
|
+
if (selector.name === undefined) continue
|
|
264
|
+
path = selector.value
|
|
265
|
+
rpc = selector.name === 'chain'
|
|
266
|
+
break
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (!matched)
|
|
270
|
+
return {
|
|
271
|
+
chainId: options.defaultChainId,
|
|
272
|
+
conflict: false,
|
|
273
|
+
invalid: false,
|
|
274
|
+
matched: false,
|
|
275
|
+
rpc: false,
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const search = new URL(options.c.req.url).searchParams
|
|
279
|
+
const raw = [
|
|
280
|
+
...(path === undefined ? [] : [path]),
|
|
281
|
+
...(rpc ? [] : search.getAll('chainId')),
|
|
282
|
+
...(rpc ? [] : search.getAll('chain_id')),
|
|
283
|
+
]
|
|
284
|
+
const parsed = raw.map((value) => Schema.ChainId.safeParse(value))
|
|
285
|
+
const chainIds = [...new Set(parsed.flatMap((result) => (result.success ? [result.data] : [])))]
|
|
286
|
+
return {
|
|
287
|
+
chainId: chainIds[0] ?? options.defaultChainId,
|
|
288
|
+
conflict: chainIds.length > 1,
|
|
289
|
+
invalid: parsed.some((result) => !result.success),
|
|
290
|
+
matched: true,
|
|
291
|
+
rpc,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function pathChainSelector(routePath: string, requestPath: string) {
|
|
296
|
+
const route = routePath.split('/')
|
|
297
|
+
const request = requestPath.split('/')
|
|
298
|
+
for (let index = 0; index < route.length; index++) {
|
|
299
|
+
const segment = route[index] ?? ''
|
|
300
|
+
for (const name of ['chainId', 'chain'] as const) {
|
|
301
|
+
const prefix = `:${name}`
|
|
302
|
+
if (!segment.startsWith(prefix)) continue
|
|
303
|
+
const suffix = segment.slice(prefix.length)
|
|
304
|
+
if (suffix !== '' && suffix !== '?' && !suffix.startsWith('{')) continue
|
|
305
|
+
return { name, value: request[index] || undefined }
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return { name: undefined, value: undefined }
|
|
309
|
+
}
|
|
310
|
+
|
|
222
311
|
/**
|
|
223
312
|
* The OpenAPI metadata this group owns: its operation tags and the outbound
|
|
224
313
|
* `webhooks` block. Tagged onto the {@link data} instance so `App.create`
|
|
@@ -231,8 +320,7 @@ const openapi = {
|
|
|
231
320
|
{ name: 'Blocks', description: 'The ordered batches of transactions making up the chain.' },
|
|
232
321
|
{ name: 'Exchange', description: "Tempo's built-in stablecoin exchange: pairs, swaps, orders, prices." }, // prettier-ignore
|
|
233
322
|
{ name: 'Fee AMM', description: 'Pools that convert stablecoins to pay fees.' },
|
|
234
|
-
{ name: 'Funding', description: '
|
|
235
|
-
{ name: 'Providers', description: 'Provider metadata, capabilities, and integration status.' },
|
|
323
|
+
{ name: 'Funding', description: 'Live quotes and supported inputs for funding Tempo.' },
|
|
236
324
|
{ name: 'Tokens', description: 'TIP-20 token details, supply, and holders.' },
|
|
237
325
|
{ name: 'Transactions', description: 'Transactions submitted to Tempo, and their receipts.' },
|
|
238
326
|
{ name: 'Transfers', description: 'Token movements from executing transactions.' },
|
|
@@ -252,7 +340,6 @@ const openapi = {
|
|
|
252
340
|
'Exchange',
|
|
253
341
|
'Fee AMM',
|
|
254
342
|
'Funding',
|
|
255
|
-
'Providers',
|
|
256
343
|
'Tokens',
|
|
257
344
|
'Transactions',
|
|
258
345
|
'Transfers',
|