tapimo 0.5.0 → 0.5.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.
- package/dist/App.d.ts +4854 -4829
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +20 -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.map +1 -1
- package/dist/Scope.js +1 -2
- 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 +2 -2
- 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 +1398 -1405
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +25 -38
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts +108 -3
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.js +409 -2
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +245 -245
- package/dist/apps/data/routes/blocks.d.ts +123 -123
- package/dist/apps/data/routes/funding.d.ts +236 -146
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +23 -12
- package/dist/apps/data/routes/funding.js.map +1 -1
- 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/rpc.d.ts +31 -31
- package/dist/apps/data/routes/tokenlist.d.ts +36 -36
- package/dist/apps/data/routes/transactions.d.ts +281 -281
- package/dist/apps/data/routes/transfers.d.ts +66 -73
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +21 -27
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
- package/dist/apps/data/routes/webhooks.d.ts +35 -35
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +176 -42
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/management/App.d.ts +520 -504
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +5 -4
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +120 -120
- package/dist/apps/management/routes/billing.d.ts +211 -211
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +1 -1
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/invitations.d.ts +72 -72
- package/dist/apps/management/routes/invite-links.d.ts +159 -159
- package/dist/apps/management/routes/me.d.ts +17 -17
- package/dist/apps/management/routes/members.d.ts +80 -80
- package/dist/apps/management/routes/orgs.d.ts +59 -43
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +18 -1
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +109 -109
- package/dist/apps/management/routes/scopes.d.ts +11 -11
- package/dist/apps/management/routes/usage.d.ts +79 -79
- 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.js +2 -2
- package/dist/apps/relay/Sponsorships.d.ts +3 -0
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +15 -1
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +4 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.js +1 -1
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +6 -0
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +26 -0
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/requestUsage.d.ts +2 -11
- package/dist/db/tables/requestUsage.d.ts.map +1 -1
- package/dist/db/tables/requestUsage.js +1 -20
- package/dist/db/tables/requestUsage.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +2 -1
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +52 -10
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/internal/Auth.d.ts +4 -0
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +15 -8
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +9 -1
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +12 -3
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +176 -56
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +100 -5
- package/dist/internal/FundingQuotes.js.map +1 -1
- 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/RateLimit.d.ts +2 -0
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +4 -4
- package/dist/internal/RateLimit.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 +14 -1
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +19 -1
- package/dist/internal/Viem.js.map +1 -1
- package/package.json +7 -2
- package/src/ApiKeys.test.ts +2 -0
- package/src/App.test.ts +15 -4
- package/src/App.ts +31 -5
- package/src/Assets.ts +3 -3
- package/src/Client.test-d.ts +30 -3
- package/src/Scope.ts +4 -2
- 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.ts +25 -45
- package/src/apps/data/FundingQuoteProviders.test.ts +615 -5
- package/src/apps/data/FundingQuoteProviders.ts +570 -4
- package/src/apps/data/routes/funding.test.ts +181 -7
- package/src/apps/data/routes/funding.ts +27 -12
- package/src/apps/data/routes/indexer.test.ts +82 -20
- package/src/apps/data/routes/indexer.ts +8 -2
- package/src/apps/data/routes/tokens.test.ts +54 -0
- package/src/apps/data/routes/transfers.test.ts +73 -1
- package/src/apps/data/routes/transfers.ts +24 -30
- package/src/apps/data/routes/webhooks.test.ts +203 -0
- package/src/apps/data/routes/webhooks.ts +191 -54
- package/src/apps/management/Billing.test.ts +52 -3
- package/src/apps/management/Billing.ts +5 -4
- package/src/apps/management/routes/billing.ts +6 -1
- package/src/apps/management/routes/orgs.ts +19 -1
- package/src/apps/mcp.test.ts +18 -0
- package/src/apps/mcp.ts +2 -2
- package/src/apps/relay/App.test.ts +6 -5
- package/src/apps/relay/App.ts +2 -2
- package/src/apps/relay/Sponsorships.test.ts +2 -2
- package/src/apps/relay/Sponsorships.ts +24 -1
- package/src/db/Db.test.ts +5 -5
- package/src/db/Db.ts +4 -0
- package/src/db/Schema.ts +1 -1
- package/src/db/tables/billingSettings.test.ts +2 -2
- package/src/db/tables/organizations.test.ts +32 -2
- package/src/db/tables/organizations.ts +28 -0
- package/src/db/tables/requestUsage.ts +3 -23
- package/src/db/tables/sponsoredTransactions.test.ts +60 -2
- package/src/db/tables/sponsoredTransactions.ts +67 -21
- package/src/db/tables/stripeCustomers.test.ts +2 -2
- package/src/internal/Auth.test.ts +63 -10
- package/src/internal/Auth.ts +21 -9
- package/src/internal/Cache.test.ts +19 -0
- package/src/internal/Cache.ts +13 -1
- package/src/internal/EdgeCache.test.ts +40 -0
- package/src/internal/EdgeCache.ts +11 -3
- package/src/internal/FundingQuotes.test.ts +130 -3
- package/src/internal/FundingQuotes.ts +113 -6
- package/src/internal/Log.ts +21 -14
- package/src/internal/RateLimit.test.ts +12 -0
- package/src/internal/RateLimit.ts +4 -4
- 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 +34 -1
|
@@ -130,6 +130,18 @@ describe('edge', () => {
|
|
|
130
130
|
expect(ip.limit).toHaveBeenCalledWith({ key: '2001:db8:abcd:12' })
|
|
131
131
|
})
|
|
132
132
|
|
|
133
|
+
test('normalizes equivalent IPv6 addresses to the same /64 prefix', () => {
|
|
134
|
+
expect([
|
|
135
|
+
RateLimit.normalizeIp('2001:0db8:abcd:0012::1'),
|
|
136
|
+
RateLimit.normalizeIp('2001:db8:abcd:12:ffff::2'),
|
|
137
|
+
]).toMatchInlineSnapshot(`
|
|
138
|
+
[
|
|
139
|
+
"2001:db8:abcd:12",
|
|
140
|
+
"2001:db8:abcd:12",
|
|
141
|
+
]
|
|
142
|
+
`)
|
|
143
|
+
})
|
|
144
|
+
|
|
133
145
|
test('returns 429 when any layer denies', async () => {
|
|
134
146
|
const response = await RateLimit.edge(request({ asn: 64512, ip: '203.0.113.7' }), {
|
|
135
147
|
asn: binding(false),
|
|
@@ -139,12 +139,12 @@ type CfProperties = { asn?: number | undefined }
|
|
|
139
139
|
function clientKey(request: Request): string {
|
|
140
140
|
const ip = request.headers.get('cf-connecting-ip')
|
|
141
141
|
if (!ip) return 'unknown'
|
|
142
|
-
|
|
143
|
-
return ipv6Prefix(ip)
|
|
142
|
+
return normalizeIp(ip)
|
|
144
143
|
}
|
|
145
144
|
|
|
146
|
-
/**
|
|
147
|
-
function
|
|
145
|
+
/** Normalizes an IPv4 address or IPv6 /64 prefix for per-client quotas. */
|
|
146
|
+
export function normalizeIp(ip: string): string {
|
|
147
|
+
if (ip.includes('.')) return ip
|
|
148
148
|
const [address = ''] = ip.split('%')
|
|
149
149
|
const [head = '', tail = ''] = address.split('::')
|
|
150
150
|
const left = head ? head.split(':') : []
|
|
@@ -203,6 +203,21 @@ describe('resolve', () => {
|
|
|
203
203
|
`)
|
|
204
204
|
})
|
|
205
205
|
|
|
206
|
+
test('resolves Bearer auth', () => {
|
|
207
|
+
expect(
|
|
208
|
+
Tidx.resolve(
|
|
209
|
+
{ baseUrl: 'https://internal.indexer', bearerAuth: 'zone-secret' },
|
|
210
|
+
{ chainId: 4217, principal: apiKeyPrincipal },
|
|
211
|
+
),
|
|
212
|
+
).toMatchInlineSnapshot(`
|
|
213
|
+
{
|
|
214
|
+
"baseUrl": "https://internal.indexer",
|
|
215
|
+
"basicAuth": undefined,
|
|
216
|
+
"bearerAuth": "zone-secret",
|
|
217
|
+
}
|
|
218
|
+
`)
|
|
219
|
+
})
|
|
220
|
+
|
|
206
221
|
test('the resolver form routes anonymous callers to a separate upstream', () => {
|
|
207
222
|
const tidx = ({ principal }: Viem.resolve.Context) =>
|
|
208
223
|
principal?.type === 'public'
|
|
@@ -243,6 +258,28 @@ describe('resolve', () => {
|
|
|
243
258
|
})
|
|
244
259
|
})
|
|
245
260
|
|
|
261
|
+
describe('getClient', () => {
|
|
262
|
+
test('sends Bearer auth', async () => {
|
|
263
|
+
const fetch = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
|
|
264
|
+
new Response(JSON.stringify({ columns: [], ok: true, row_count: 0, rows: [] }), {
|
|
265
|
+
headers: { 'content-type': 'application/json' },
|
|
266
|
+
}),
|
|
267
|
+
)
|
|
268
|
+
try {
|
|
269
|
+
const client = Tidx.getClient({
|
|
270
|
+
chainId: 4217,
|
|
271
|
+
tidx: { baseUrl: 'https://internal.indexer', bearerAuth: 'zone-secret' },
|
|
272
|
+
})
|
|
273
|
+
await client.fetch({ query: 'select 1' })
|
|
274
|
+
|
|
275
|
+
const upstream = fetch.mock.calls[0]![0] as Request
|
|
276
|
+
expect(upstream.headers.get('authorization')).toBe('Bearer zone-secret')
|
|
277
|
+
} finally {
|
|
278
|
+
fetch.mockRestore()
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
|
|
246
283
|
describe('createGetClient', () => {
|
|
247
284
|
test('memoizes one client per resolved upstream', () => {
|
|
248
285
|
const getTidx = Tidx.createGetClient({
|
|
@@ -267,6 +304,17 @@ describe('createGetClient', () => {
|
|
|
267
304
|
expect(getTidx(4217, null)).toBe(getTidx(4217, publicPrincipal))
|
|
268
305
|
})
|
|
269
306
|
|
|
307
|
+
test('does not share clients across Bearer credentials', () => {
|
|
308
|
+
const getTidx = Tidx.createGetClient({
|
|
309
|
+
tidx: ({ principal }) => ({
|
|
310
|
+
baseUrl: 'https://internal.indexer',
|
|
311
|
+
bearerAuth: principal?.type === 'public' ? 'public-secret' : 'private-secret',
|
|
312
|
+
}),
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
expect(getTidx(4217, publicPrincipal)).not.toBe(getTidx(4217, apiKeyPrincipal))
|
|
316
|
+
})
|
|
317
|
+
|
|
270
318
|
test('consults the resolver on every call but builds one client per upstream', () => {
|
|
271
319
|
const seen: (string | undefined)[] = []
|
|
272
320
|
const getTidx = Tidx.createGetClient({
|
package/src/internal/Tidx.ts
CHANGED
|
@@ -29,8 +29,8 @@ export type UrlResolver = (chainId: Viem.ChainId) => string | undefined
|
|
|
29
29
|
* receives a {@link Viem.resolve.Context} (`chainId` plus the request
|
|
30
30
|
* `principal`), so callers can route traffic per caller — e.g. send anonymous
|
|
31
31
|
* (`principal.type === 'public'`) traffic to a separate, no-auth indexer. A
|
|
32
|
-
* missing `baseUrl` falls back to the built-in public host map ({@link url});
|
|
33
|
-
* missing
|
|
32
|
+
* missing `baseUrl` falls back to the built-in public host map ({@link url});
|
|
33
|
+
* missing auth fields send no Authorization header.
|
|
34
34
|
*/
|
|
35
35
|
export function resolve(
|
|
36
36
|
tidx: getClient.Tidx | undefined,
|
|
@@ -42,6 +42,7 @@ export function resolve(
|
|
|
42
42
|
(typeof config?.baseUrl === 'function' ? config.baseUrl(context.chainId) : config?.baseUrl) ??
|
|
43
43
|
url[context.chainId],
|
|
44
44
|
basicAuth: config?.basicAuth,
|
|
45
|
+
...(config?.bearerAuth ? { bearerAuth: config.bearerAuth } : {}),
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -56,13 +57,22 @@ export declare namespace resolve {
|
|
|
56
57
|
baseUrl: string | undefined
|
|
57
58
|
/** Basic auth credentials, or undefined to send no Basic auth. */
|
|
58
59
|
basicAuth?: string | undefined
|
|
60
|
+
/** Bearer auth credential, or undefined to send no Bearer auth. */
|
|
61
|
+
bearerAuth?: string | undefined
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
export function getClient(options: getClient.Options): Client {
|
|
63
66
|
const { chainId = Viem.defaultChainId, principal = null, tidx } = options
|
|
64
|
-
const { baseUrl, basicAuth } = resolve(tidx, { chainId, principal })
|
|
65
|
-
return withTransientRetry(
|
|
67
|
+
const { baseUrl, basicAuth, bearerAuth } = resolve(tidx, { chainId, principal })
|
|
68
|
+
return withTransientRetry(
|
|
69
|
+
Tidx.create({
|
|
70
|
+
baseUrl,
|
|
71
|
+
basicAuth,
|
|
72
|
+
bearerAuth,
|
|
73
|
+
chainId,
|
|
74
|
+
}),
|
|
75
|
+
)
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
/**
|
|
@@ -72,7 +82,7 @@ export function getClient(options: getClient.Options): Client {
|
|
|
72
82
|
* output (`baseUrl` + `basicAuth` + `chainId`), not the principal, so a resolver
|
|
73
83
|
* `tidx` may branch on any principal field while client cardinality stays
|
|
74
84
|
* bounded by the number of distinct upstreams — callers that resolve to the same
|
|
75
|
-
* upstream share a client. Shared by `
|
|
85
|
+
* upstream share a client. Shared by `data()` (per-request reads) and
|
|
76
86
|
* `Webhooks.createPoller` (the scheduled poller) so the resolver logic lives in
|
|
77
87
|
* one place.
|
|
78
88
|
*/
|
|
@@ -83,8 +93,8 @@ export function createGetClient(options: createGetClient.Options = {}): GetClien
|
|
|
83
93
|
return (chainId = defaultChainId, principal = null) => {
|
|
84
94
|
// Resolve to derive the cache key; `getClient` re-resolves to build the
|
|
85
95
|
// client on a miss. `resolve` is pure and cheap, so the extra call is free.
|
|
86
|
-
const { baseUrl, basicAuth } = resolve(tidx, { chainId, principal })
|
|
87
|
-
const cacheKey = `${baseUrl}|${basicAuth ?? ''}|${chainId}`
|
|
96
|
+
const { baseUrl, basicAuth, bearerAuth } = resolve(tidx, { chainId, principal })
|
|
97
|
+
const cacheKey = `${baseUrl}|${basicAuth ?? ''}|${bearerAuth ?? ''}|${chainId}`
|
|
88
98
|
const existing = clients.get(cacheKey)
|
|
89
99
|
if (existing) return existing
|
|
90
100
|
|
|
@@ -218,12 +228,16 @@ export declare namespace getClient {
|
|
|
218
228
|
baseUrl?: UrlResolver | string | undefined
|
|
219
229
|
/** Basic auth credentials for TIDX requests. */
|
|
220
230
|
basicAuth?: string | undefined
|
|
231
|
+
/** Bearer auth credential for TIDX requests. */
|
|
232
|
+
bearerAuth?: string | undefined
|
|
221
233
|
}
|
|
222
234
|
| ((context: Viem.resolve.Context) => {
|
|
223
235
|
/** TIDX base URL to use; falls back to the built-in public host when omitted. */
|
|
224
236
|
baseUrl?: string | undefined
|
|
225
237
|
/** Basic auth credentials for TIDX requests, or undefined for none. */
|
|
226
238
|
basicAuth?: string | undefined
|
|
239
|
+
/** Bearer auth credential for TIDX requests, or undefined for none. */
|
|
240
|
+
bearerAuth?: string | undefined
|
|
227
241
|
})
|
|
228
242
|
}
|
|
229
243
|
|
|
@@ -113,3 +113,49 @@ describe('resolve', () => {
|
|
|
113
113
|
`)
|
|
114
114
|
})
|
|
115
115
|
})
|
|
116
|
+
|
|
117
|
+
describe('createGetClient', () => {
|
|
118
|
+
test('memoizes one client per resolved upstream', () => {
|
|
119
|
+
const getClient = Viem.createGetClient({
|
|
120
|
+
rpc: ({ principal }) =>
|
|
121
|
+
principal?.type === 'public'
|
|
122
|
+
? { url: 'https://rpc.tempo.xyz' }
|
|
123
|
+
: { basicAuth: 'user:pass', url: 'https://internal.rpc' },
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
expect(getClient(4217, apiKeyPrincipal)).toBe(getClient(4217, apiKeyPrincipal))
|
|
127
|
+
expect(getClient(4217, publicPrincipal)).toBe(getClient(4217, publicPrincipal))
|
|
128
|
+
expect(getClient(4217, publicPrincipal)).not.toBe(getClient(4217, apiKeyPrincipal))
|
|
129
|
+
expect(getClient(4217, apiKeyPrincipal)).not.toBe(getClient(42431, apiKeyPrincipal))
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test('shares a client across principals when they resolve identically', () => {
|
|
133
|
+
const getClient = Viem.createGetClient()
|
|
134
|
+
|
|
135
|
+
expect(getClient(4217, publicPrincipal)).toBe(getClient(4217, apiKeyPrincipal))
|
|
136
|
+
expect(getClient(4217, null)).toBe(getClient(4217, publicPrincipal))
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('consults the resolver on cache hits', () => {
|
|
140
|
+
const seen: (string | undefined)[] = []
|
|
141
|
+
const getClient = Viem.createGetClient({
|
|
142
|
+
rpc: ({ principal }) => {
|
|
143
|
+
seen.push(principal?.type)
|
|
144
|
+
return { url: 'https://internal.rpc' }
|
|
145
|
+
},
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const first = getClient(4217, apiKeyPrincipal)
|
|
149
|
+
const second = getClient(4217, apiKeyPrincipal)
|
|
150
|
+
getClient(4217, publicPrincipal)
|
|
151
|
+
|
|
152
|
+
expect(seen).toMatchInlineSnapshot(`
|
|
153
|
+
[
|
|
154
|
+
"api_key",
|
|
155
|
+
"api_key",
|
|
156
|
+
"public",
|
|
157
|
+
]
|
|
158
|
+
`)
|
|
159
|
+
expect(first).toBe(second)
|
|
160
|
+
})
|
|
161
|
+
})
|
package/src/internal/Viem.ts
CHANGED
|
@@ -58,7 +58,7 @@ export type UrlResolver = (chainId: ChainId) => string | undefined
|
|
|
58
58
|
* webhook poller). A missing `url` falls back to the built-in public host map
|
|
59
59
|
* ({@link url}); a missing `basicAuth` means no Basic auth is sent.
|
|
60
60
|
*
|
|
61
|
-
* Memoization is keyed on the resolved output (see
|
|
61
|
+
* Memoization is keyed on the resolved output (see {@link createGetClient} and
|
|
62
62
|
* {@link Tidx.createGetClient}), not the context, so a resolver may branch on
|
|
63
63
|
* any principal field without unbounded client cardinality: callers that
|
|
64
64
|
* resolve to the same upstream share a client. Pass the result to
|
|
@@ -130,6 +130,39 @@ export function getClient(options: getClient.Options): getClient.ReturnType {
|
|
|
130
130
|
.extend(tempoActions())
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
/** Builds a memoized Tempo client resolver. */
|
|
134
|
+
export function createGetClient(options: createGetClient.Options = {}): createGetClient.ReturnType {
|
|
135
|
+
const { defaultChainId: defaultChainId_option = defaultChainId, rpc } = options
|
|
136
|
+
const clients = new Map<string, getClient.ReturnType>()
|
|
137
|
+
|
|
138
|
+
return (chainId = defaultChainId_option, principal = null) => {
|
|
139
|
+
const { basicAuth, url } = resolve(rpc, { chainId, principal })
|
|
140
|
+
const cacheKey = JSON.stringify([url, basicAuth, chainId])
|
|
141
|
+
const existing = clients.get(cacheKey)
|
|
142
|
+
if (existing) return existing
|
|
143
|
+
|
|
144
|
+
const client = getClient({
|
|
145
|
+
chainId,
|
|
146
|
+
rpc: { basicAuth, url: () => url },
|
|
147
|
+
})
|
|
148
|
+
clients.set(cacheKey, client)
|
|
149
|
+
return client
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export declare namespace createGetClient {
|
|
154
|
+
/** Options for building a memoized Tempo client resolver. */
|
|
155
|
+
type Options = {
|
|
156
|
+
/** Tempo chain id used when a caller omits one. */
|
|
157
|
+
defaultChainId?: ChainId | undefined
|
|
158
|
+
/** Tempo RPC options applied to every constructed client. */
|
|
159
|
+
rpc?: getClient.Rpc | undefined
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Memoized Tempo client resolver. */
|
|
163
|
+
type ReturnType = (chainId?: ChainId, principal?: Auth.Principal | null) => getClient.ReturnType
|
|
164
|
+
}
|
|
165
|
+
|
|
133
166
|
export declare namespace getClient {
|
|
134
167
|
/** Tempo viem client with public and Tempo action helpers. */
|
|
135
168
|
type ReturnType = core_Client<
|