tapimo 0.6.0 → 0.7.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 +8641 -8263
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +9 -1
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +4 -0
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +5 -0
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +112 -11
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +2 -1
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/early-access.d.ts +2 -2
- package/dist/admin/apps/early-access.d.ts.map +1 -1
- package/dist/admin/apps/early-access.js +5 -5
- package/dist/admin/apps/early-access.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +124 -1
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +97 -6
- package/dist/admin/apps/organizations.js.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +47 -39
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +20 -0
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +18 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +36 -7
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/data/App.d.ts +8050 -8019
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.js +2 -15
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +1 -1
- package/dist/apps/data/FxOracle.d.ts.map +1 -1
- package/dist/apps/data/FxOracle.js +1 -1
- package/dist/apps/data/FxOracle.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +27 -27
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +21 -1
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +58 -58
- package/dist/apps/data/routes/blocks.d.ts +39 -39
- package/dist/apps/data/routes/coingecko.d.ts +176 -176
- package/dist/apps/data/routes/exchanges.d.ts +669 -669
- package/dist/apps/data/routes/fee-amm.d.ts +157 -143
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +76 -91
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/funding.d.ts +72 -34
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +34 -26
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +30 -30
- package/dist/apps/data/routes/receipts.d.ts +8 -8
- package/dist/apps/data/routes/rpc.d.ts +31 -31
- package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
- package/dist/apps/data/routes/tokenlist.js +12 -3
- package/dist/apps/data/routes/tokenlist.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +4 -4
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +5 -1
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +6 -6
- package/dist/apps/data/routes/transfers.d.ts +101 -90
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +226 -141
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +2 -2
- package/dist/apps/data/routes/valuation.js +3 -3
- package/dist/apps/data/routes/valuation.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
- package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/verified-tokens.js +34 -9
- package/dist/apps/data/routes/verified-tokens.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +2 -2
- package/dist/apps/data/routes/webhooks.js +14 -6
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +1 -0
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +1 -0
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +460 -523
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +7 -23
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +20 -8
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +106 -151
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +28 -28
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +48 -34
- package/dist/apps/management/routes/faucet.d.ts.map +1 -1
- package/dist/apps/management/routes/faucet.js +33 -18
- package/dist/apps/management/routes/faucet.js.map +1 -1
- package/dist/apps/management/routes/invitations.d.ts +131 -131
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +0 -3
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/me.d.ts +6 -8
- package/dist/apps/management/routes/me.d.ts.map +1 -1
- package/dist/apps/management/routes/me.js +0 -4
- package/dist/apps/management/routes/me.js.map +1 -1
- package/dist/apps/management/routes/members.d.ts +73 -73
- package/dist/apps/management/routes/orgs.d.ts +94 -94
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +5 -0
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts +72 -72
- package/dist/apps/management/routes/verified-token-requests.d.ts +94 -94
- package/dist/apps/management/routes/webhooks.d.ts +1 -1
- package/dist/apps/mpp/App.d.ts +363 -0
- package/dist/apps/mpp/App.d.ts.map +1 -0
- package/dist/apps/mpp/App.js +72 -0
- package/dist/apps/mpp/App.js.map +1 -0
- package/dist/apps/mpp/Mpp.d.ts +178 -0
- package/dist/apps/mpp/Mpp.d.ts.map +1 -0
- package/dist/apps/mpp/Mpp.js +183 -0
- package/dist/apps/mpp/Mpp.js.map +1 -0
- package/dist/apps/mpp/index.d.ts +3 -0
- package/dist/apps/mpp/index.d.ts.map +1 -0
- package/dist/apps/mpp/index.js +3 -0
- package/dist/apps/mpp/index.js.map +1 -0
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +57 -10
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.js +1 -1
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/db/Db.d.ts +2 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +27 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +12 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +11 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/enabledBillingSources.d.ts +73 -0
- package/dist/db/tables/enabledBillingSources.d.ts.map +1 -0
- package/dist/db/tables/enabledBillingSources.js +69 -0
- package/dist/db/tables/enabledBillingSources.js.map +1 -0
- package/dist/db/tables/invitations.d.ts +1 -12
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/invitations.js +3 -23
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +5 -2
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +32 -2
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +13 -3
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/handlers/internal/utils.d.ts +1 -16
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +17 -6
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +37 -5
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +0 -32
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +3 -51
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts +1 -1
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +3 -2
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +78 -32
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +45 -8
- package/dist/internal/FundingQuotes.js.map +1 -1
- package/dist/internal/Log.d.ts +18 -4
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +50 -3
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +15 -0
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/Response.d.ts +2 -2
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Response.js +12 -4
- package/dist/internal/Response.js.map +1 -1
- package/dist/internal/Schema.d.ts +2 -2
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +4 -2
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Viem.d.ts +1 -1
- package/package.json +7 -2
- package/src/App.test.ts +9 -4
- package/src/App.ts +14 -2
- package/src/Client.test-d.ts +109 -28
- package/src/Scope.ts +5 -0
- package/src/admin/App.test.ts +4 -0
- package/src/admin/apps/early-access.ts +6 -5
- package/src/admin/apps/organizations.test.ts +86 -2
- package/src/admin/apps/organizations.ts +155 -31
- package/src/admin/apps/scopes.test.ts +5 -0
- package/src/admin/ui/src/lib/organizations.test.ts +81 -1
- package/src/admin/ui/src/lib/organizations.ts +92 -0
- package/src/admin/ui/src/routes/api-keys.tsx +1 -1
- package/src/admin/ui/src/routes/early-access.tsx +8 -3
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +103 -0
- package/src/admin/ui.generated.ts +49 -39
- package/src/analytics/Analytics.test.ts +83 -0
- package/src/analytics/Analytics.ts +20 -0
- package/src/analytics/tables/requestEvents.ts +60 -7
- package/src/apps/composition.test.ts +11 -2
- package/src/apps/data/App.test.ts +14 -2
- package/src/apps/data/FundingQuoteProviders.test.ts +0 -5
- package/src/apps/data/FundingQuoteProviders.ts +2 -29
- package/src/apps/data/FxOracle.test.ts +2 -2
- package/src/apps/data/FxOracle.ts +2 -2
- package/src/apps/data/routes/activities.test.ts +6 -2
- package/src/apps/data/routes/activities.ts +39 -1
- package/src/apps/data/routes/balances.test.ts +6 -2
- package/src/apps/data/routes/exchanges.test.ts +7 -3
- package/src/apps/data/routes/fee-amm.test.ts +47 -23
- package/src/apps/data/routes/fee-amm.ts +98 -119
- package/src/apps/data/routes/funding.test.ts +29 -8
- package/src/apps/data/routes/funding.ts +42 -48
- package/src/apps/data/routes/receipts.test.ts +6 -2
- package/src/apps/data/routes/tokenlist.test.ts +15 -0
- package/src/apps/data/routes/tokenlist.ts +18 -5
- package/src/apps/data/routes/tokens.ts +5 -1
- package/src/apps/data/routes/transfers.test.ts +203 -35
- package/src/apps/data/routes/transfers.ts +294 -172
- package/src/apps/data/routes/valuation.test.ts +18 -3
- package/src/apps/data/routes/valuation.ts +4 -4
- package/src/apps/data/routes/verified-tokens.test.ts +51 -0
- package/src/apps/data/routes/verified-tokens.ts +52 -15
- package/src/apps/data/routes/webhooks.test.ts +56 -0
- package/src/apps/data/routes/webhooks.ts +17 -8
- package/src/apps/index.ts +1 -0
- package/src/apps/management/routes/api-keys.test.ts +2 -75
- package/src/apps/management/routes/api-keys.ts +30 -7
- package/src/apps/management/routes/billing.test.ts +106 -85
- package/src/apps/management/routes/billing.ts +32 -21
- package/src/apps/management/routes/faucet.test.ts +11 -3
- package/src/apps/management/routes/faucet.ts +46 -30
- package/src/apps/management/routes/invitations.test.ts +0 -172
- package/src/apps/management/routes/invitations.ts +0 -3
- package/src/apps/management/routes/me.test.ts +3 -145
- package/src/apps/management/routes/me.ts +0 -6
- package/src/apps/management/routes/orgs.test.ts +45 -2
- package/src/apps/management/routes/orgs.ts +6 -0
- package/src/apps/management/routes/scopes.test.ts +1 -0
- package/src/apps/mpp/App.ts +86 -0
- package/src/apps/mpp/Mpp.test.ts +193 -0
- package/src/apps/mpp/Mpp.ts +353 -0
- package/src/apps/mpp/index.ts +2 -0
- package/src/apps/mpp/internal/Adapter.ts +11 -0
- package/src/apps/mpp/internal/Error.ts +9 -0
- package/src/apps/mpp/internal/Idempotency.ts +7 -0
- package/src/apps/mpp/internal/Screening.ts +10 -0
- package/src/apps/relay/App.test.ts +90 -8
- package/src/apps/relay/App.ts +62 -10
- package/src/apps/relay/Sponsorships.test.ts +2 -0
- package/src/apps/relay/Sponsorships.ts +1 -1
- package/src/db/Db.test.ts +2 -2
- package/src/db/Db.ts +30 -0
- package/src/db/Schema.ts +15 -0
- package/src/db/tables/enabledBillingSources.test.ts +303 -0
- package/src/db/tables/enabledBillingSources.ts +118 -0
- package/src/db/tables/invitations.ts +4 -26
- package/src/db/tables/organizations.test.ts +191 -0
- package/src/db/tables/organizations.ts +44 -3
- package/src/db/tables/sponsoredTransactions.test.ts +41 -2
- package/src/db/tables/sponsoredTransactions.ts +15 -3
- package/src/handlers/internal/utils.ts +22 -6
- package/src/handlers/relay.errors.test.ts +153 -0
- package/src/handlers/relay.ts +42 -7
- package/src/internal/Auth.test.ts +3 -3
- package/src/internal/Auth.ts +3 -63
- package/src/internal/EdgeCache.test.ts +18 -5
- package/src/internal/EdgeCache.ts +4 -2
- package/src/internal/FundingQuotes.test.ts +18 -5
- package/src/internal/FundingQuotes.ts +46 -11
- package/src/internal/Log.test.ts +91 -0
- package/src/internal/Log.ts +69 -5
- package/src/internal/MetricSink.test.ts +55 -0
- package/src/internal/MetricSink.ts +14 -0
- package/src/internal/Response.test.ts +28 -0
- package/src/internal/Response.ts +12 -4
- package/src/internal/Schema.test.ts +13 -0
- package/src/internal/Schema.ts +14 -7
package/src/internal/Auth.ts
CHANGED
|
@@ -16,8 +16,6 @@ import * as ApiKey from '../ApiKey.js'
|
|
|
16
16
|
import * as ApiKeys from '../ApiKeys.js'
|
|
17
17
|
import * as Db from '../db/Db.js'
|
|
18
18
|
import type * as Store from './Store.js'
|
|
19
|
-
import * as EarlyAccess from '../db/tables/earlyAccess.js'
|
|
20
|
-
import * as Invitations from '../db/tables/invitations.js'
|
|
21
19
|
import * as Memberships from '../db/tables/memberships.js'
|
|
22
20
|
import * as Metadata from '../apps/metadata.js'
|
|
23
21
|
import * as OpenApi from './OpenApi.js'
|
|
@@ -32,6 +30,7 @@ import * as Viem from './Viem.js'
|
|
|
32
30
|
|
|
33
31
|
const policySymbol = Symbol('tempo-api.auth.policy')
|
|
34
32
|
const mppManagementSymbol = Symbol('tempo-api.auth.mpp-management')
|
|
33
|
+
const defaultApiKeyRateLimit = { perMinute: 10_000 } satisfies RateLimit.Limit
|
|
35
34
|
const defaultMppRateLimit = { perMinute: 100 } satisfies RateLimit.Limit
|
|
36
35
|
|
|
37
36
|
/** Auth context consumed by Tempo API handlers. */
|
|
@@ -159,8 +158,6 @@ export type PolicyOverride = {
|
|
|
159
158
|
| undefined
|
|
160
159
|
/** Session lane: `true` allows signed-in wallet sessions, `false` disables. */
|
|
161
160
|
session?: boolean | undefined
|
|
162
|
-
/** Temporary early-access gate: `true` rejects sessions without early access ({@link tmp_earlyAccess}). TODO: remove after GA. */
|
|
163
|
-
tmp_earlyAccess?: boolean | undefined
|
|
164
161
|
}
|
|
165
162
|
|
|
166
163
|
/** Authenticated or anonymous caller. */
|
|
@@ -229,8 +226,6 @@ export type Variables = {
|
|
|
229
226
|
principal?: Principal | undefined
|
|
230
227
|
/** Project resolved by {@link ensureProject} for the current request. */
|
|
231
228
|
project?: Projects.Record | undefined
|
|
232
|
-
/** Temporary early-access gate toggle; unset or false grants everyone early access. TODO: remove after GA. */
|
|
233
|
-
tmp_earlyAccess?: boolean | undefined
|
|
234
229
|
}
|
|
235
230
|
|
|
236
231
|
/** Reads the authenticated principal from a Hono context. */
|
|
@@ -385,42 +380,6 @@ export function ensureProjectError(c: hono_Context) {
|
|
|
385
380
|
})
|
|
386
381
|
}
|
|
387
382
|
|
|
388
|
-
/** Whether the caller can grant early access, independent of the temporary route gate. TODO: remove after GA. */
|
|
389
|
-
export async function tmp_earlyAccessGrant(c: hono_Context): Promise<boolean> {
|
|
390
|
-
const principal = getPrincipal(c)
|
|
391
|
-
// Trust chain: `management:write` keys are only mintable by early-access owners.
|
|
392
|
-
if (principal?.type === 'api_key' || principal?.type === 'super_admin') return true
|
|
393
|
-
if (principal?.type !== 'session' || !principal.email) return false
|
|
394
|
-
const email = principal.email.trim().toLowerCase()
|
|
395
|
-
const db = Db.get(contextDb(c))
|
|
396
|
-
if (await EarlyAccess.matches(db, email)) return true
|
|
397
|
-
return Invitations.hasEarlyAccessGrant(db, email)
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/** Whether the caller has effective early access, including a dormant temporary gate. TODO: remove after GA. */
|
|
401
|
-
export async function tmp_earlyAccess(c: hono_Context): Promise<boolean> {
|
|
402
|
-
const enabled = (c.get as (key: string) => unknown)('tmp_earlyAccess') as boolean | undefined
|
|
403
|
-
if (!enabled) return true
|
|
404
|
-
return tmp_earlyAccessGrant(c)
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Always false at runtime, but typed as `boolean` so handlers can include a
|
|
409
|
-
* never-reached early-access-error branch in Hono's inferred response union
|
|
410
|
-
* (the `tmp_earlyAccess` policy flag produces this `403` before the handler
|
|
411
|
-
* runs). TODO: remove after GA.
|
|
412
|
-
*/
|
|
413
|
-
export const tmp_narrowEarlyAccess = false as boolean
|
|
414
|
-
|
|
415
|
-
/** Typed early-access error response for Hono client inference; also the live gate rejection. TODO: remove after GA. */
|
|
416
|
-
export function tmp_ensureEarlyAccessError(c: hono_Context) {
|
|
417
|
-
return Response.error(c, {
|
|
418
|
-
code: 'early_access_required',
|
|
419
|
-
message: 'Requires early access. Ask a teammate with access to invite you by email, or contact Tempo.', // prettier-ignore
|
|
420
|
-
status: 403,
|
|
421
|
-
})
|
|
422
|
-
}
|
|
423
|
-
|
|
424
383
|
/** Reads the caller's membership resolved by the organization or project guard; `undefined` for API keys and `super_admin`. */
|
|
425
384
|
export function membership<environment extends Environment>(
|
|
426
385
|
c: hono_Context<environment>,
|
|
@@ -629,9 +588,6 @@ export function middleware<
|
|
|
629
588
|
if (management && (!auth.mpp || !endpointPolicy.mpp)) return next()
|
|
630
589
|
|
|
631
590
|
c.set('auth', auth)
|
|
632
|
-
// Consumed by `tmp_earlyAccess`; absent (or false) leaves the gate dormant.
|
|
633
|
-
// TODO: remove after GA.
|
|
634
|
-
c.set('tmp_earlyAccess', options.tmp_earlyAccess)
|
|
635
591
|
return require<environment>(endpointPolicy)(c, next)
|
|
636
592
|
})
|
|
637
593
|
}
|
|
@@ -687,12 +643,6 @@ export declare namespace middleware {
|
|
|
687
643
|
* checks — before the key lookup runs. Omit to disable the entry entirely.
|
|
688
644
|
*/
|
|
689
645
|
superAdmin?: { secret: string } | undefined
|
|
690
|
-
/**
|
|
691
|
-
* Temporary invite-only gate for routes flagged via {@link policy}.
|
|
692
|
-
* Allowlist entries live in the `early_access` table (admin dash); unset
|
|
693
|
-
* grants everyone early access. TODO: remove after GA.
|
|
694
|
-
*/
|
|
695
|
-
tmp_earlyAccess?: boolean | undefined
|
|
696
646
|
}
|
|
697
647
|
|
|
698
648
|
/** Resolve-cache tuning for API-key resolution. */
|
|
@@ -1196,7 +1146,6 @@ function resolvePolicy(
|
|
|
1196
1146
|
let mpp = base.mpp
|
|
1197
1147
|
let public_ = base.public
|
|
1198
1148
|
let session = base.session
|
|
1199
|
-
let tmp_earlyAccess = base.tmp_earlyAccess
|
|
1200
1149
|
|
|
1201
1150
|
for (const override of overrides) {
|
|
1202
1151
|
if (override === false) return undefined
|
|
@@ -1205,7 +1154,6 @@ function resolvePolicy(
|
|
|
1205
1154
|
mpp = resolveMppLane(mpp, override.mpp, defaults.mpp)
|
|
1206
1155
|
public_ = resolvePublicLane(public_, override.public, defaults.public)
|
|
1207
1156
|
session = resolveSessionLane(session, override.session, defaults.session)
|
|
1208
|
-
tmp_earlyAccess = override.tmp_earlyAccess ?? tmp_earlyAccess
|
|
1209
1157
|
}
|
|
1210
1158
|
|
|
1211
1159
|
// The OpenAPI summary/description rides along as the payment-challenge
|
|
@@ -1221,7 +1169,6 @@ function resolvePolicy(
|
|
|
1221
1169
|
...(mpp ? { mpp } : {}),
|
|
1222
1170
|
...(public_ ? { public: public_ } : {}),
|
|
1223
1171
|
...(session ? { session } : {}),
|
|
1224
|
-
...(tmp_earlyAccess ? { tmp_earlyAccess } : {}),
|
|
1225
1172
|
}
|
|
1226
1173
|
}
|
|
1227
1174
|
|
|
@@ -1444,12 +1391,6 @@ export function require<environment extends Environment = Environment>(
|
|
|
1444
1391
|
)
|
|
1445
1392
|
return Response.unsupportedChainId(c, chainId, supportedChainIds)
|
|
1446
1393
|
const proceed = async () => {
|
|
1447
|
-
// Runs after principal resolution, so api_key and super_admin pass by
|
|
1448
|
-
// type; only gated sessions are rejected. TODO: remove after GA.
|
|
1449
|
-
if (policy.tmp_earlyAccess && !(await tmp_earlyAccess(c))) {
|
|
1450
|
-
c.res = tmp_ensureEarlyAccessError(c)
|
|
1451
|
-
return
|
|
1452
|
-
}
|
|
1453
1394
|
await next()
|
|
1454
1395
|
// Query credential responses must not enter shared caches.
|
|
1455
1396
|
const cacheControl = c.res.headers.get('Cache-Control')?.toLowerCase()
|
|
@@ -1685,8 +1626,6 @@ export declare namespace require {
|
|
|
1685
1626
|
| undefined
|
|
1686
1627
|
/** Session access policy: `true` allows signed-in wallet sessions. */
|
|
1687
1628
|
session?: boolean | undefined
|
|
1688
|
-
/** Temporary early-access gate for this route; see {@link tmp_earlyAccess}. TODO: remove after GA. */
|
|
1689
|
-
tmp_earlyAccess?: boolean | undefined
|
|
1690
1629
|
}
|
|
1691
1630
|
}
|
|
1692
1631
|
|
|
@@ -1782,7 +1721,8 @@ function resolveApiKeyLimit(options: resolveApiKeyLimit.Options): RateLimit.Limi
|
|
|
1782
1721
|
policy?.rateLimit ?? // 2. route override (protective cap)
|
|
1783
1722
|
apiKey.rateLimits?.[Scope.wildcard] ?? // 3. per-key default
|
|
1784
1723
|
auth.apiKey?.rateLimits?.[scope] ?? // 4. config per-scope
|
|
1785
|
-
auth.apiKey?.rateLimits?.[Scope.wildcard] ??
|
|
1724
|
+
auth.apiKey?.rateLimits?.[Scope.wildcard] ?? // 5. config default
|
|
1725
|
+
defaultApiKeyRateLimit // 6. hardcoded fallback
|
|
1786
1726
|
)
|
|
1787
1727
|
}
|
|
1788
1728
|
|
|
@@ -219,7 +219,7 @@ describe('middleware', () => {
|
|
|
219
219
|
|
|
220
220
|
test('rechecks route eligibility before every cache lookup', async () => {
|
|
221
221
|
let eligible = true
|
|
222
|
-
const { app, downstreamCalls, store } = createApp({ eligibility: () => eligible })
|
|
222
|
+
const { app, downstreamCalls, store } = createApp({ eligibility: [() => eligible] })
|
|
223
223
|
|
|
224
224
|
await app.request('/cached')
|
|
225
225
|
eligible = false
|
|
@@ -229,6 +229,19 @@ describe('middleware', () => {
|
|
|
229
229
|
expect(store.gets).toBe(1)
|
|
230
230
|
expect(store.size).toBe(1)
|
|
231
231
|
})
|
|
232
|
+
|
|
233
|
+
test('requires every route eligibility predicate to permit caching', async () => {
|
|
234
|
+
const { app, downstreamCalls, store } = createApp({
|
|
235
|
+
eligibility: [() => true, () => false],
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
await app.request('/cached')
|
|
239
|
+
await app.request('/cached')
|
|
240
|
+
|
|
241
|
+
expect(downstreamCalls()).toBe(2)
|
|
242
|
+
expect(store.gets).toBe(0)
|
|
243
|
+
expect(store.size).toBe(0)
|
|
244
|
+
})
|
|
232
245
|
})
|
|
233
246
|
|
|
234
247
|
type Environment = { Variables: EdgeCache.Variables }
|
|
@@ -263,7 +276,7 @@ function memoryStore() {
|
|
|
263
276
|
|
|
264
277
|
function createApp(
|
|
265
278
|
options: {
|
|
266
|
-
eligibility?: ((c: Context<Environment>) => boolean) | undefined
|
|
279
|
+
eligibility?: readonly ((c: Context<Environment>) => boolean)[] | undefined
|
|
267
280
|
store?: Store.Store | undefined
|
|
268
281
|
} = {},
|
|
269
282
|
) {
|
|
@@ -282,9 +295,9 @@ function createApp(
|
|
|
282
295
|
const cacheable_marked = EdgeCache.markCacheable(
|
|
283
296
|
createMiddleware<Environment>(async (_c, next) => next()),
|
|
284
297
|
)
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
298
|
+
for (const predicate of options.eligibility ?? [])
|
|
299
|
+
EdgeCache.setEligibility(cacheable_marked, predicate)
|
|
300
|
+
const cacheable = cacheable_marked
|
|
288
301
|
app.get('/cached', cacheable, (c) => {
|
|
289
302
|
c.set('edgeCache', { maxAge: 30, staleWhileRevalidate: 300 })
|
|
290
303
|
c.header('Age', '123')
|
|
@@ -154,12 +154,14 @@ export function markCacheable<const handler extends (...args: never[]) => unknow
|
|
|
154
154
|
return Object.assign(handler, { [cacheableSymbol]: true })
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
/** Adds a request eligibility check
|
|
157
|
+
/** Adds a request eligibility check; every check must permit caching. */
|
|
158
158
|
export function setEligibility<const handler extends (...args: never[]) => unknown>(
|
|
159
159
|
handler: handler,
|
|
160
160
|
predicate: (c: Context) => boolean,
|
|
161
161
|
): handler {
|
|
162
|
-
|
|
162
|
+
const existing = eligibility.get(handler)
|
|
163
|
+
if (cacheableSymbol in handler)
|
|
164
|
+
eligibility.set(handler, existing ? (c) => existing(c) && predicate(c) : predicate)
|
|
163
165
|
return handler
|
|
164
166
|
}
|
|
165
167
|
|
|
@@ -40,16 +40,29 @@ describe('listQuotes', () => {
|
|
|
40
40
|
expect(seen?.candidate.id).toBe('base-usdc-tempo-usdce-relay')
|
|
41
41
|
expect(quotes).toHaveLength(1)
|
|
42
42
|
expect(quotes[0]).toMatchObject({
|
|
43
|
+
destinationAmount: {
|
|
44
|
+
baseUnits: '990000',
|
|
45
|
+
currency: 'USD',
|
|
46
|
+
decimals: 6,
|
|
47
|
+
formatted: '0.99',
|
|
48
|
+
},
|
|
49
|
+
destinationAmountMin: {
|
|
50
|
+
baseUnits: '980000',
|
|
51
|
+
currency: 'USD',
|
|
52
|
+
decimals: 6,
|
|
53
|
+
formatted: '0.98',
|
|
54
|
+
},
|
|
43
55
|
id: 'base-usdc-tempo-usdce-relay',
|
|
44
56
|
quality: {
|
|
45
57
|
liquiditySource: 'providerQuote',
|
|
46
58
|
tier: 'liquid',
|
|
47
59
|
},
|
|
48
|
-
quote: {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
60
|
+
quote: { sampledAt: '2026-01-01T00:00:00Z' },
|
|
61
|
+
sourceAmount: {
|
|
62
|
+
baseUnits: '1000000',
|
|
63
|
+
currency: 'USD',
|
|
64
|
+
decimals: 6,
|
|
65
|
+
formatted: '1',
|
|
53
66
|
},
|
|
54
67
|
})
|
|
55
68
|
expect(attempts.map(stableAttempt)).toEqual([{ outcome: 'available', provider: 'relay' }])
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as Value from './Value.js'
|
|
2
|
+
|
|
1
3
|
/** Tempo mainnet as a CAIP-2 chain reference. */
|
|
2
4
|
const destinationChain = {
|
|
3
5
|
addressFormat: 'evm',
|
|
@@ -27,6 +29,7 @@ const sourceChains = [
|
|
|
27
29
|
{
|
|
28
30
|
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
29
31
|
coingeckoId: 'usd-coin',
|
|
32
|
+
currency: 'USD',
|
|
30
33
|
decimals: 6,
|
|
31
34
|
name: 'USD Coin',
|
|
32
35
|
standard: 'ERC-20',
|
|
@@ -35,6 +38,7 @@ const sourceChains = [
|
|
|
35
38
|
{
|
|
36
39
|
address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
37
40
|
coingeckoId: 'tether',
|
|
41
|
+
currency: 'USD',
|
|
38
42
|
decimals: 6,
|
|
39
43
|
name: 'Tether USD',
|
|
40
44
|
standard: 'ERC-20',
|
|
@@ -43,6 +47,7 @@ const sourceChains = [
|
|
|
43
47
|
{
|
|
44
48
|
address: '0x6c3ea9036406852006290770bedfcaba0e23a0e8',
|
|
45
49
|
coingeckoId: 'paypal-usd',
|
|
50
|
+
currency: 'USD',
|
|
46
51
|
decimals: 6,
|
|
47
52
|
name: 'PayPal USD',
|
|
48
53
|
standard: 'ERC-20',
|
|
@@ -51,6 +56,7 @@ const sourceChains = [
|
|
|
51
56
|
{
|
|
52
57
|
address: '0x1abaea1f7c830bd89acc67ec4af516284b1bc33c',
|
|
53
58
|
coingeckoId: 'euro-coin',
|
|
59
|
+
currency: 'EUR',
|
|
54
60
|
decimals: 6,
|
|
55
61
|
name: 'Euro Coin',
|
|
56
62
|
standard: 'ERC-20',
|
|
@@ -59,6 +65,7 @@ const sourceChains = [
|
|
|
59
65
|
{
|
|
60
66
|
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
|
|
61
67
|
coingeckoId: 'dai',
|
|
68
|
+
currency: 'USD',
|
|
62
69
|
decimals: 18,
|
|
63
70
|
name: 'Dai Stablecoin',
|
|
64
71
|
standard: 'ERC-20',
|
|
@@ -83,6 +90,7 @@ const sourceChains = [
|
|
|
83
90
|
{
|
|
84
91
|
address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
|
|
85
92
|
coingeckoId: 'usd-coin',
|
|
93
|
+
currency: 'USD',
|
|
86
94
|
decimals: 6,
|
|
87
95
|
name: 'USD Coin',
|
|
88
96
|
standard: 'ERC-20',
|
|
@@ -91,6 +99,7 @@ const sourceChains = [
|
|
|
91
99
|
{
|
|
92
100
|
address: '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2',
|
|
93
101
|
coingeckoId: 'tether',
|
|
102
|
+
currency: 'USD',
|
|
94
103
|
decimals: 6,
|
|
95
104
|
name: 'Tether USD',
|
|
96
105
|
standard: 'ERC-20',
|
|
@@ -99,6 +108,7 @@ const sourceChains = [
|
|
|
99
108
|
{
|
|
100
109
|
address: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
|
|
101
110
|
coingeckoId: 'euro-coin',
|
|
111
|
+
currency: 'EUR',
|
|
102
112
|
decimals: 6,
|
|
103
113
|
name: 'Euro Coin',
|
|
104
114
|
standard: 'ERC-20',
|
|
@@ -122,6 +132,7 @@ const sourceChains = [
|
|
|
122
132
|
{
|
|
123
133
|
address: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d',
|
|
124
134
|
coingeckoId: 'usd-coin',
|
|
135
|
+
currency: 'USD',
|
|
125
136
|
decimals: 18,
|
|
126
137
|
name: 'Binance-Peg USD Coin',
|
|
127
138
|
standard: 'BEP-20',
|
|
@@ -130,6 +141,7 @@ const sourceChains = [
|
|
|
130
141
|
{
|
|
131
142
|
address: '0x55d398326f99059ff775485246999027b3197955',
|
|
132
143
|
coingeckoId: 'tether',
|
|
144
|
+
currency: 'USD',
|
|
133
145
|
decimals: 18,
|
|
134
146
|
name: 'Tether USD',
|
|
135
147
|
standard: 'BEP-20',
|
|
@@ -151,6 +163,7 @@ const sourceChains = [
|
|
|
151
163
|
{
|
|
152
164
|
address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
153
165
|
coingeckoId: 'usd-coin',
|
|
166
|
+
currency: 'USD',
|
|
154
167
|
decimals: 6,
|
|
155
168
|
name: 'USD Coin',
|
|
156
169
|
standard: 'SPL',
|
|
@@ -173,6 +186,7 @@ const sourceChains = [
|
|
|
173
186
|
{
|
|
174
187
|
address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
|
|
175
188
|
coingeckoId: 'tether',
|
|
189
|
+
currency: 'USD',
|
|
176
190
|
decimals: 6,
|
|
177
191
|
name: 'Tether USD',
|
|
178
192
|
standard: 'TRC-20',
|
|
@@ -186,6 +200,7 @@ const sourceChains = [
|
|
|
186
200
|
const destinationTokens = [
|
|
187
201
|
{
|
|
188
202
|
address: '0x20c0000000000000000000000000000000000000',
|
|
203
|
+
currency: 'USD',
|
|
189
204
|
decimals: 6,
|
|
190
205
|
name: 'pathUSD',
|
|
191
206
|
slug: 'pathusd',
|
|
@@ -194,6 +209,7 @@ const destinationTokens = [
|
|
|
194
209
|
},
|
|
195
210
|
{
|
|
196
211
|
address: '0x20c000000000000000000000b9537d11c60e8b50',
|
|
212
|
+
currency: 'USD',
|
|
197
213
|
decimals: 6,
|
|
198
214
|
name: 'Bridged USDC (Stargate)',
|
|
199
215
|
slug: 'usdce',
|
|
@@ -202,6 +218,7 @@ const destinationTokens = [
|
|
|
202
218
|
},
|
|
203
219
|
{
|
|
204
220
|
address: '0x20c0000000000000000000001621e21f71cf12fb',
|
|
221
|
+
currency: 'EUR',
|
|
205
222
|
decimals: 6,
|
|
206
223
|
name: 'Bridged EURC',
|
|
207
224
|
slug: 'eurce',
|
|
@@ -210,6 +227,7 @@ const destinationTokens = [
|
|
|
210
227
|
},
|
|
211
228
|
{
|
|
212
229
|
address: '0x20c00000000000000000000014f22ca97301eb73',
|
|
230
|
+
currency: 'USD',
|
|
213
231
|
decimals: 6,
|
|
214
232
|
name: 'USDT0',
|
|
215
233
|
slug: 'usdt0',
|
|
@@ -218,6 +236,7 @@ const destinationTokens = [
|
|
|
218
236
|
},
|
|
219
237
|
{
|
|
220
238
|
address: '0x20c0000000000000000000003554d28269e0f3c2',
|
|
239
|
+
currency: 'USD',
|
|
221
240
|
decimals: 6,
|
|
222
241
|
name: 'frxUSD',
|
|
223
242
|
slug: 'frxusd',
|
|
@@ -346,8 +365,6 @@ export type QuoteProbeResult = {
|
|
|
346
365
|
minimumOutputAmount?: string | undefined
|
|
347
366
|
/** Expected destination amount in base units. */
|
|
348
367
|
outputAmount?: string | undefined
|
|
349
|
-
/** Expected destination amount rendered with destination token decimals. */
|
|
350
|
-
outputAmountFormatted?: string | undefined
|
|
351
368
|
/** Timestamp for the live quote probe. */
|
|
352
369
|
sampledAt: string
|
|
353
370
|
/** Provider-specific quote status for the requested amount. */
|
|
@@ -659,6 +676,7 @@ function formatChain(chain: SourceChainInput) {
|
|
|
659
676
|
function formatDestinationToken(token: DestinationTokenInput) {
|
|
660
677
|
return {
|
|
661
678
|
address: token.address,
|
|
679
|
+
currency: token.currency,
|
|
662
680
|
decimals: token.decimals,
|
|
663
681
|
metadata: {},
|
|
664
682
|
name: token.name,
|
|
@@ -706,6 +724,7 @@ function formatQuoteCandidate(options: {
|
|
|
706
724
|
function formatSourceToken(chain: SourceChainInput, token: TokenInput) {
|
|
707
725
|
return {
|
|
708
726
|
address: token.address,
|
|
727
|
+
currency: token.currency,
|
|
709
728
|
decimals: token.decimals,
|
|
710
729
|
metadata: { coingeckoId: token.coingeckoId },
|
|
711
730
|
name: token.name,
|
|
@@ -741,7 +760,24 @@ type SuccessfulQuoteProbe = QuoteProbeResult & {
|
|
|
741
760
|
|
|
742
761
|
function formatFundingQuote(candidate: QuoteCandidate, quote: SuccessfulQuoteProbe) {
|
|
743
762
|
return {
|
|
744
|
-
|
|
763
|
+
destinationAmount: Value.tokenAmount({
|
|
764
|
+
baseUnits: quote.outputAmount,
|
|
765
|
+
currency: candidate.destinationToken.currency,
|
|
766
|
+
decimals: candidate.destinationToken.decimals,
|
|
767
|
+
}),
|
|
768
|
+
...(quote.minimumOutputAmount !== undefined
|
|
769
|
+
? {
|
|
770
|
+
destinationAmountMin: Value.tokenAmount({
|
|
771
|
+
baseUnits: quote.minimumOutputAmount,
|
|
772
|
+
currency: candidate.destinationToken.currency,
|
|
773
|
+
decimals: candidate.destinationToken.decimals,
|
|
774
|
+
}),
|
|
775
|
+
}
|
|
776
|
+
: {}),
|
|
777
|
+
destinationChain: candidate.destinationChain,
|
|
778
|
+
destinationToken: candidate.destinationToken,
|
|
779
|
+
id: candidate.id,
|
|
780
|
+
provider: candidate.provider,
|
|
745
781
|
quality: {
|
|
746
782
|
...(quote.quality?.estimatedSeconds !== undefined
|
|
747
783
|
? { estimatedSeconds: quote.quality.estimatedSeconds }
|
|
@@ -754,16 +790,15 @@ function formatFundingQuote(candidate: QuoteCandidate, quote: SuccessfulQuotePro
|
|
|
754
790
|
},
|
|
755
791
|
quote: {
|
|
756
792
|
...(quote.expiresAt !== undefined ? { expiresAt: quote.expiresAt } : {}),
|
|
757
|
-
inputAmount: candidate.sourceAmount.amount,
|
|
758
|
-
...(quote.minimumOutputAmount !== undefined
|
|
759
|
-
? { minimumOutputAmount: quote.minimumOutputAmount }
|
|
760
|
-
: {}),
|
|
761
|
-
outputAmount: quote.outputAmount,
|
|
762
|
-
outputAmountFormatted:
|
|
763
|
-
quote.outputAmountFormatted ??
|
|
764
|
-
decimalFromBaseUnits(quote.outputAmount, candidate.destinationToken.decimals),
|
|
765
793
|
sampledAt: quote.sampledAt,
|
|
766
794
|
},
|
|
795
|
+
sourceAmount: Value.tokenAmount({
|
|
796
|
+
baseUnits: candidate.sourceAmount.amount,
|
|
797
|
+
currency: candidate.sourceToken.currency,
|
|
798
|
+
decimals: candidate.sourceToken.decimals,
|
|
799
|
+
}),
|
|
800
|
+
sourceChain: candidate.sourceChain,
|
|
801
|
+
sourceToken: candidate.sourceToken,
|
|
767
802
|
} as const
|
|
768
803
|
}
|
|
769
804
|
|
package/src/internal/Log.test.ts
CHANGED
|
@@ -138,6 +138,97 @@ describe('middleware', () => {
|
|
|
138
138
|
`)
|
|
139
139
|
})
|
|
140
140
|
|
|
141
|
+
test('records a JSON-RPC error returned with HTTP 200', async () => {
|
|
142
|
+
const entries: Log.Entry[] = []
|
|
143
|
+
const api = app({ emit: (entry) => void entries.push(entry) })
|
|
144
|
+
api.post('/rpc/sponsor', (c) => {
|
|
145
|
+
const body = {
|
|
146
|
+
error: {
|
|
147
|
+
code: -32602,
|
|
148
|
+
data: { code: 'billing_required', retryable: false },
|
|
149
|
+
message: 'Sponsorship requires an active billing source.',
|
|
150
|
+
},
|
|
151
|
+
id: 1,
|
|
152
|
+
jsonrpc: '2.0',
|
|
153
|
+
}
|
|
154
|
+
c.set('rpcResponse', Log.rpcErrors(body))
|
|
155
|
+
return c.json(body)
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const response = await api.request('/rpc/sponsor', { method: 'POST' })
|
|
159
|
+
|
|
160
|
+
expect(response.status).toBe(200)
|
|
161
|
+
expect(stable(entries[0]!)).toMatchInlineSnapshot(`
|
|
162
|
+
{
|
|
163
|
+
"level": "warn",
|
|
164
|
+
"method": "POST",
|
|
165
|
+
"path": "/rpc/sponsor",
|
|
166
|
+
"route": "/rpc/sponsor",
|
|
167
|
+
"rpc": {
|
|
168
|
+
"code": -32602,
|
|
169
|
+
"dataCode": "billing_required",
|
|
170
|
+
"errors": 1,
|
|
171
|
+
},
|
|
172
|
+
"status": 200,
|
|
173
|
+
}
|
|
174
|
+
`)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
test('logs JSON-RPC server errors at error level', async () => {
|
|
178
|
+
const entries: Log.Entry[] = []
|
|
179
|
+
const api = app({ emit: (entry) => void entries.push(entry) })
|
|
180
|
+
api.post('/rpc/sponsor', (c) => {
|
|
181
|
+
const body = {
|
|
182
|
+
error: {
|
|
183
|
+
code: -32603,
|
|
184
|
+
data: { code: 'internal_error' },
|
|
185
|
+
message: 'Internal error',
|
|
186
|
+
},
|
|
187
|
+
id: 1,
|
|
188
|
+
jsonrpc: '2.0',
|
|
189
|
+
}
|
|
190
|
+
c.set('rpcResponse', Log.rpcErrors(body))
|
|
191
|
+
return c.json(body)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
await api.request('/rpc/sponsor', { method: 'POST' })
|
|
195
|
+
|
|
196
|
+
expect(entries[0]?.level).toBe('error')
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
test('counts batch JSON-RPC errors without retaining mixed codes', async () => {
|
|
200
|
+
const entries: Log.Entry[] = []
|
|
201
|
+
const api = app({ emit: (entry) => void entries.push(entry) })
|
|
202
|
+
api.post('/rpc/relay', (c) => {
|
|
203
|
+
const body = [
|
|
204
|
+
{ id: 1, jsonrpc: '2.0', result: '0x1' },
|
|
205
|
+
{ error: { code: -32602, message: 'Invalid params.' }, id: 2, jsonrpc: '2.0' },
|
|
206
|
+
{
|
|
207
|
+
error: { code: -32603, data: { code: 'Internal Error' }, message: 'Internal error.' },
|
|
208
|
+
id: 3,
|
|
209
|
+
jsonrpc: '2.0',
|
|
210
|
+
},
|
|
211
|
+
]
|
|
212
|
+
c.set('rpcResponse', Log.rpcErrors(body))
|
|
213
|
+
return c.json(body)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
await api.request('/rpc/relay', { method: 'POST' })
|
|
217
|
+
|
|
218
|
+
expect(stable(entries[0]!)).toMatchInlineSnapshot(`
|
|
219
|
+
{
|
|
220
|
+
"level": "warn",
|
|
221
|
+
"method": "POST",
|
|
222
|
+
"path": "/rpc/relay",
|
|
223
|
+
"route": "/rpc/relay",
|
|
224
|
+
"rpc": {
|
|
225
|
+
"errors": 2,
|
|
226
|
+
},
|
|
227
|
+
"status": 200,
|
|
228
|
+
}
|
|
229
|
+
`)
|
|
230
|
+
})
|
|
231
|
+
|
|
141
232
|
test('includes redacted provider failure details', async () => {
|
|
142
233
|
const entries: Log.Entry[] = []
|
|
143
234
|
const api = app({ emit: (entry) => void entries.push(entry) })
|