tapimo 0.5.3 → 0.7.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.
- package/dist/App.d.ts +15830 -7220
- 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 +1011 -412
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +4 -0
- package/dist/admin/App.js.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 +148 -0
- package/dist/admin/apps/early-access.d.ts.map +1 -0
- package/dist/admin/apps/early-access.js +133 -0
- package/dist/admin/apps/early-access.js.map +1 -0
- 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/apps/verified-tokens.d.ts +526 -1
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.js +214 -1
- package/dist/admin/apps/verified-tokens.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 +95 -75
- 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 +6260 -4924
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +11 -6
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.js +194 -16
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +71 -0
- package/dist/apps/data/FxOracle.d.ts.map +1 -0
- package/dist/apps/data/FxOracle.js +97 -0
- package/dist/apps/data/FxOracle.js.map +1 -0
- package/dist/apps/data/index.d.ts +1 -0
- package/dist/apps/data/index.d.ts.map +1 -1
- package/dist/apps/data/index.js +1 -0
- package/dist/apps/data/index.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +3599 -1382
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +250 -88
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +872 -251
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/addresses.js +11 -9
- package/dist/apps/data/routes/addresses.js.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +77 -26
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +88 -45
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +39 -39
- package/dist/apps/data/routes/coingecko.d.ts +54 -54
- package/dist/apps/data/routes/exchanges.d.ts +856 -105
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +518 -76
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +81 -67
- 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 +80 -36
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +65 -31
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +392 -315
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +152 -77
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +167 -174
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +15 -13
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +277 -536
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +96 -77
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +157 -81
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +272 -130
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +307 -0
- package/dist/apps/data/routes/valuation.d.ts.map +1 -0
- package/dist/apps/data/routes/valuation.js +292 -0
- package/dist/apps/data/routes/valuation.js.map +1 -0
- 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 +7 -5
- package/dist/apps/data/routes/verified-tokens.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +103 -123
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +124 -25
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +2 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +2 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +8554 -1692
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +12 -1
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +7 -0
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +17 -3
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +157 -162
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +31 -23
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +232 -0
- package/dist/apps/management/routes/faucet.d.ts.map +1 -0
- package/dist/apps/management/routes/faucet.js +154 -0
- package/dist/apps/management/routes/faucet.js.map +1 -0
- package/dist/apps/management/routes/invitations.d.ts +60 -60
- package/dist/apps/management/routes/invite-links.d.ts +49 -20
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
- package/dist/apps/management/routes/invite-links.js +26 -1
- package/dist/apps/management/routes/invite-links.js.map +1 -1
- package/dist/apps/management/routes/me.d.ts +6 -6
- package/dist/apps/management/routes/members.d.ts +6 -6
- package/dist/apps/management/routes/orgs.d.ts +42 -42
- 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/projects.d.ts +44 -44
- package/dist/apps/management/routes/usage.d.ts +3 -0
- package/dist/apps/management/routes/usage.d.ts.map +1 -1
- package/dist/apps/management/routes/usage.js +4 -0
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
- package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
- package/dist/apps/management/routes/verified-token-requests.js +271 -0
- package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
- package/dist/apps/management/routes/webhooks.d.ts +6977 -0
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
- package/dist/apps/management/routes/webhooks.js +573 -0
- package/dist/apps/management/routes/webhooks.js.map +1 -0
- 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 +56 -9
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/db/Db.d.ts +6 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +110 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +53 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +56 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/earlyAccess.d.ts +50 -0
- package/dist/db/tables/earlyAccess.d.ts.map +1 -0
- package/dist/db/tables/earlyAccess.js +63 -0
- package/dist/db/tables/earlyAccess.js.map +1 -0
- 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.map +1 -1
- package/dist/db/tables/invitations.js +3 -0
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/inviteLinks.d.ts +10 -2
- package/dist/db/tables/inviteLinks.d.ts.map +1 -1
- package/dist/db/tables/inviteLinks.js +10 -1
- package/dist/db/tables/inviteLinks.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 +13 -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 +2 -0
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
- package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
- package/dist/db/tables/verifiedTokenRequests.js +120 -0
- package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
- package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +16 -0
- package/dist/db/tables/webhookSubscriptions.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 +11 -2
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +14 -47
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +147 -47
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +119 -33
- package/dist/internal/FundingQuotes.js.map +1 -1
- package/dist/internal/Log.d.ts +37 -5
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +52 -3
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +24 -0
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +2 -2
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +3 -0
- package/dist/internal/OpenApi.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 +14 -5
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +23 -5
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Value.d.ts +18 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js +11 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/VerifiedTokens.d.ts.map +1 -1
- package/dist/internal/VerifiedTokens.js +10 -1
- package/dist/internal/VerifiedTokens.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +24 -3
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +34 -8
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +7 -2
- package/src/App.test.ts +9 -4
- package/src/App.ts +23 -3
- package/src/Client.test-d.ts +733 -20
- package/src/Scope.ts +5 -0
- package/src/admin/App.test.ts +4 -0
- package/src/admin/App.ts +4 -0
- package/src/admin/apps/early-access.test.ts +125 -0
- package/src/admin/apps/early-access.ts +176 -0
- 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/apps/verified-tokens.test.ts +201 -0
- package/src/admin/apps/verified-tokens.ts +532 -286
- package/src/admin/ui/plugin.ts +2 -1
- package/src/admin/ui/src/lib/early-access.ts +63 -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/lib/verified-tokens.ts +79 -0
- package/src/admin/ui/src/routeTree.gen.ts +33 -2
- package/src/admin/ui/src/routes/__root.tsx +2 -1
- package/src/admin/ui/src/routes/api-keys.tsx +1 -1
- package/src/admin/ui/src/routes/early-access.tsx +162 -0
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +103 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
- package/src/admin/ui.generated.ts +95 -94
- 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 +1 -1
- package/src/apps/data/App.ts +22 -14
- package/src/apps/data/FundingQuoteProviders.test.ts +297 -4
- package/src/apps/data/FundingQuoteProviders.ts +255 -29
- package/src/apps/data/FxOracle.test.ts +118 -0
- package/src/apps/data/FxOracle.ts +153 -0
- package/src/apps/data/index.ts +1 -0
- package/src/apps/data/routes/activities.test.ts +177 -3
- package/src/apps/data/routes/activities.ts +441 -132
- package/src/apps/data/routes/addresses.ts +19 -9
- package/src/apps/data/routes/balances.test.ts +148 -11
- package/src/apps/data/routes/balances.ts +140 -51
- package/src/apps/data/routes/exchanges.test.ts +544 -9
- package/src/apps/data/routes/exchanges.ts +690 -103
- 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 +113 -8
- package/src/apps/data/routes/funding.ts +77 -51
- package/src/apps/data/routes/receipts.test.ts +129 -23
- package/src/apps/data/routes/receipts.ts +205 -100
- package/src/apps/data/routes/tokens.test.ts +43 -0
- package/src/apps/data/routes/tokens.ts +28 -13
- package/src/apps/data/routes/transactions.test.ts +72 -19
- package/src/apps/data/routes/transactions.ts +162 -92
- package/src/apps/data/routes/transfers.test.ts +341 -31
- package/src/apps/data/routes/transfers.ts +358 -158
- package/src/apps/data/routes/valuation.test.ts +437 -0
- package/src/apps/data/routes/valuation.ts +423 -0
- package/src/apps/data/routes/verified-tokens.ts +14 -2
- package/src/apps/data/routes/webhooks.test.ts +56 -8
- package/src/apps/data/routes/webhooks.ts +144 -27
- package/src/apps/index.ts +2 -1
- package/src/apps/management/App.ts +13 -0
- package/src/apps/management/routes/api-keys.test.ts +14 -0
- package/src/apps/management/routes/api-keys.ts +27 -3
- package/src/apps/management/routes/billing.test.ts +152 -20
- package/src/apps/management/routes/billing.ts +34 -18
- package/src/apps/management/routes/faucet.test.ts +87 -0
- package/src/apps/management/routes/faucet.ts +201 -0
- package/src/apps/management/routes/invite-links.test.ts +117 -0
- package/src/apps/management/routes/invite-links.ts +43 -1
- package/src/apps/management/routes/me.test.ts +9 -99
- 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/management/routes/usage.test.ts +6 -0
- package/src/apps/management/routes/usage.ts +7 -0
- package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
- package/src/apps/management/routes/verified-token-requests.ts +397 -0
- package/src/apps/management/routes/webhooks.test.ts +426 -0
- package/src/apps/management/routes/webhooks.ts +672 -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 +88 -6
- package/src/apps/relay/App.ts +61 -9
- package/src/db/Db.test.ts +19 -0
- package/src/db/Db.ts +125 -0
- package/src/db/Schema.ts +68 -0
- package/src/db/tables/earlyAccess.ts +86 -0
- package/src/db/tables/enabledBillingSources.test.ts +303 -0
- package/src/db/tables/enabledBillingSources.ts +118 -0
- package/src/db/tables/invitations.ts +3 -0
- package/src/db/tables/inviteLinks.ts +22 -3
- package/src/db/tables/organizations.test.ts +103 -0
- package/src/db/tables/organizations.ts +18 -2
- package/src/db/tables/sponsoredTransactions.ts +4 -0
- package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
- package/src/db/tables/verifiedTokenRequests.ts +182 -0
- package/src/db/tables/webhookSubscriptions.ts +31 -0
- 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 +15 -47
- package/src/internal/FundingQuotes.test.ts +161 -6
- package/src/internal/FundingQuotes.ts +141 -39
- package/src/internal/Log.test-d.ts +21 -0
- package/src/internal/Log.test.ts +141 -0
- package/src/internal/Log.ts +93 -6
- package/src/internal/MetricSink.test.ts +215 -0
- package/src/internal/MetricSink.ts +24 -0
- package/src/internal/OpenApi.ts +3 -0
- package/src/internal/Response.test.ts +28 -0
- package/src/internal/Response.ts +12 -4
- package/src/internal/Schema.ts +50 -5
- package/src/internal/Value.test.ts +20 -0
- package/src/internal/Value.ts +24 -1
- package/src/internal/VerifiedTokens.ts +9 -1
- package/src/internal/Webhooks.test.ts +140 -0
- package/src/internal/Webhooks.ts +53 -9
package/src/internal/Log.ts
CHANGED
|
@@ -4,16 +4,21 @@ import type { RequestIdVariables } from 'hono/request-id'
|
|
|
4
4
|
import * as ApiKey from '../ApiKey.js'
|
|
5
5
|
import type * as Auth from './Auth.js'
|
|
6
6
|
import type * as EdgeCache from './EdgeCache.js'
|
|
7
|
+
import type * as FundingQuotes from './FundingQuotes.js'
|
|
7
8
|
import type * as Timing from './Timing.js'
|
|
8
9
|
|
|
9
10
|
/** Hono variables read by the request logger and written by other layers. */
|
|
10
11
|
export type Variables = {
|
|
11
12
|
/** Stable error code recorded by `Response.error` for the request log entry. */
|
|
12
13
|
errorCode?: string | undefined
|
|
14
|
+
/** Bounded outcomes for funding providers attempted by the request. */
|
|
15
|
+
fundingProviderAttempts?: Entry['fundingProviderAttempts'] | undefined
|
|
13
16
|
/** Redacted provider failure details recorded by an upstream adapter. */
|
|
14
17
|
providerFailure?: Entry['provider'] | undefined
|
|
15
18
|
/** Redacted provider failures when multiple upstream adapters fail. */
|
|
16
19
|
providerFailures?: Entry['providerFailures'] | undefined
|
|
20
|
+
/** Bounded JSON-RPC failure metadata recorded by a composed RPC handler. */
|
|
21
|
+
rpcResponse?: Entry['rpc'] | undefined
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
/** Hono environment shape used by the request logger. */
|
|
@@ -35,7 +40,7 @@ export type ProviderFailure = {
|
|
|
35
40
|
/** Stable provider error code, when one is safe to retain. */
|
|
36
41
|
code?: string | undefined
|
|
37
42
|
/** Failure boundary that rejected the provider request. */
|
|
38
|
-
failure: 'http' | 'network' | 'payload' | 'timeout' | 'unknown'
|
|
43
|
+
failure: 'http' | 'network' | 'payload' | 'rate_limit' | 'timeout' | 'unknown'
|
|
39
44
|
/** Provider identifier. */
|
|
40
45
|
id: string
|
|
41
46
|
/** Provider operation identifier. */
|
|
@@ -44,6 +49,20 @@ export type ProviderFailure = {
|
|
|
44
49
|
status?: number | undefined
|
|
45
50
|
}
|
|
46
51
|
|
|
52
|
+
/** Bounded operational result for one funding quote provider attempt. */
|
|
53
|
+
export type FundingProviderAttempt = {
|
|
54
|
+
/** Wall-clock duration of the provider attempt in milliseconds. */
|
|
55
|
+
durationMs: number
|
|
56
|
+
/** Failure class, present only when the provider attempt failed. */
|
|
57
|
+
failure?: ProviderFailure['failure'] | undefined
|
|
58
|
+
/** Provider identifier. */
|
|
59
|
+
id: FundingQuotes.ProviderId
|
|
60
|
+
/** Stable upstream operation identifier. */
|
|
61
|
+
operation: string
|
|
62
|
+
/** Provider attempt outcome. */
|
|
63
|
+
outcome: 'available' | 'failed' | 'thin' | 'unavailable'
|
|
64
|
+
}
|
|
65
|
+
|
|
47
66
|
/** One canonical request log entry. */
|
|
48
67
|
export type Entry = {
|
|
49
68
|
/** `'hit'` when the edge response cache served the request without reaching the origin handlers. */
|
|
@@ -52,7 +71,9 @@ export type Entry = {
|
|
|
52
71
|
duration: number
|
|
53
72
|
/** Stable error code when the response is a JSON error envelope (e.g. `not_found`, `api_key_invalid`). */
|
|
54
73
|
errorCode?: string | undefined
|
|
55
|
-
/**
|
|
74
|
+
/** Bounded funding provider attempts made while serving the request. */
|
|
75
|
+
fundingProviderAttempts?: readonly FundingProviderAttempt[] | undefined
|
|
76
|
+
/** Log level: 5xx `error`; 4xx or JSON-RPC failure `warn`; otherwise `info`. */
|
|
56
77
|
level: Level
|
|
57
78
|
/** Request method. */
|
|
58
79
|
method: string
|
|
@@ -102,7 +123,16 @@ export type Entry = {
|
|
|
102
123
|
requestId: string
|
|
103
124
|
/** Matched handler path (bounded cardinality), e.g. `/v1/tokens/:address`; `/*` when a middleware (e.g. an edge-cache hit) short-circuited routing. */
|
|
104
125
|
route: string
|
|
105
|
-
/**
|
|
126
|
+
/** JSON-RPC failures returned in an otherwise successful HTTP response. */
|
|
127
|
+
rpc?: {
|
|
128
|
+
/** Numeric JSON-RPC error code when every failed response shares one code. */
|
|
129
|
+
code?: number | undefined
|
|
130
|
+
/** Stable application error code from `error.data.code`, when shared by every failed response. */
|
|
131
|
+
dataCode?: string | undefined
|
|
132
|
+
/** Number of failed responses in the single or batch JSON-RPC response. */
|
|
133
|
+
errors: number
|
|
134
|
+
}
|
|
135
|
+
/** HTTP response status code. JSON-RPC failures retain their protocol-native `200`. */
|
|
106
136
|
status: number
|
|
107
137
|
/** Upstream operation durations in milliseconds, from the request's Server-Timing metrics (e.g. RPC and TIDX calls). */
|
|
108
138
|
timings?: Record<string, number> | undefined
|
|
@@ -119,8 +149,9 @@ export type Emit = (entry: Entry) => Promise<void> | void
|
|
|
119
149
|
*
|
|
120
150
|
* The entry derives everything from state other layers already produce —
|
|
121
151
|
* `requestId`, the auth principal, `RateLimit-*` headers, Server-Timing
|
|
122
|
-
* metrics, the `errorCode` recorded by `Response.error`,
|
|
123
|
-
* hit marker
|
|
152
|
+
* metrics, the `errorCode` recorded by `Response.error`, JSON-RPC response
|
|
153
|
+
* errors, and the edge-cache hit marker, so handlers never log per-request
|
|
154
|
+
* lines themselves.
|
|
124
155
|
*/
|
|
125
156
|
export function middleware<environment extends Environment = Environment>(
|
|
126
157
|
options: middleware.Options = {},
|
|
@@ -140,8 +171,12 @@ export function middleware<environment extends Environment = Environment>(
|
|
|
140
171
|
// (the same pattern EdgeCache uses for its cross-layer reads).
|
|
141
172
|
const principal = c.get('principal' as never) as Auth.Principal | undefined
|
|
142
173
|
const errorCode = c.get('errorCode' as never) as string | undefined
|
|
174
|
+
const fundingProviderAttempts = c.get('fundingProviderAttempts' as never) as
|
|
175
|
+
| Entry['fundingProviderAttempts']
|
|
176
|
+
| undefined
|
|
143
177
|
const provider = c.get('providerFailure' as never) as Entry['provider']
|
|
144
178
|
const providerFailures = c.get('providerFailures' as never) as Entry['providerFailures']
|
|
179
|
+
const rpc = c.get('rpcResponse' as never) as Entry['rpc']
|
|
145
180
|
|
|
146
181
|
// The `request` total metric duplicates `duration` (measured here, one
|
|
147
182
|
// layer further out), so only operation timings are kept.
|
|
@@ -170,7 +205,13 @@ export function middleware<environment extends Environment = Environment>(
|
|
|
170
205
|
...(c.get('edgeCacheStatus' as never) === 'hit' ? { cache: 'hit' as const } : {}),
|
|
171
206
|
duration: round(duration),
|
|
172
207
|
...(errorCode === undefined ? {} : { errorCode }),
|
|
173
|
-
|
|
208
|
+
...(fundingProviderAttempts === undefined ? {} : { fundingProviderAttempts }),
|
|
209
|
+
level:
|
|
210
|
+
status >= 500 || rpcServerError(rpc?.code)
|
|
211
|
+
? 'error'
|
|
212
|
+
: status >= 400 || rpc
|
|
213
|
+
? 'warn'
|
|
214
|
+
: 'info',
|
|
174
215
|
method: c.req.method,
|
|
175
216
|
path: url.pathname,
|
|
176
217
|
...(principal?.payment === undefined ? {} : { payment: principal.payment.reason }),
|
|
@@ -197,6 +238,7 @@ export function middleware<environment extends Environment = Environment>(
|
|
|
197
238
|
...(rateLimit === undefined ? {} : { rateLimit }),
|
|
198
239
|
requestId: c.get('requestId' as never) as string,
|
|
199
240
|
route: c.req.routePath,
|
|
241
|
+
...(rpc === undefined ? {} : { rpc }),
|
|
200
242
|
status,
|
|
201
243
|
...(timings === undefined ? {} : { timings }),
|
|
202
244
|
})
|
|
@@ -215,6 +257,51 @@ export function middleware<environment extends Environment = Environment>(
|
|
|
215
257
|
}
|
|
216
258
|
}
|
|
217
259
|
|
|
260
|
+
const rpcDataCode = /^[a-z][a-z0-9_]{0,63}$/
|
|
261
|
+
|
|
262
|
+
/** Extracts bounded error metadata from an already-parsed JSON-RPC response. */
|
|
263
|
+
export function rpcErrors(body: unknown): Entry['rpc'] {
|
|
264
|
+
const values = Array.isArray(body) ? body : [body]
|
|
265
|
+
const errors = values.flatMap((value) => {
|
|
266
|
+
if (!value || typeof value !== 'object') return []
|
|
267
|
+
const record = value as Record<string, unknown>
|
|
268
|
+
if (record['jsonrpc'] !== '2.0' || !record['error'] || typeof record['error'] !== 'object')
|
|
269
|
+
return []
|
|
270
|
+
const error = record['error'] as Record<string, unknown>
|
|
271
|
+
if (
|
|
272
|
+
!Number.isInteger(error['code']) ||
|
|
273
|
+
Number(error['code']) < -2_147_483_648 ||
|
|
274
|
+
Number(error['code']) > 2_147_483_647
|
|
275
|
+
)
|
|
276
|
+
return []
|
|
277
|
+
const data = error['data']
|
|
278
|
+
const dataCode_value =
|
|
279
|
+
data && typeof data === 'object' ? (data as Record<string, unknown>)['code'] : undefined
|
|
280
|
+
const dataCode = typeof dataCode_value === 'string' ? dataCode_value : undefined
|
|
281
|
+
return [
|
|
282
|
+
{
|
|
283
|
+
code: error['code'] as number,
|
|
284
|
+
...(dataCode && rpcDataCode.test(dataCode) ? { dataCode } : {}),
|
|
285
|
+
},
|
|
286
|
+
]
|
|
287
|
+
})
|
|
288
|
+
if (errors.length === 0) return undefined
|
|
289
|
+
|
|
290
|
+
const codes = new Set(errors.map((error) => error.code))
|
|
291
|
+
const dataCodes = new Set(errors.map((error) => error.dataCode).filter(Boolean))
|
|
292
|
+
return {
|
|
293
|
+
...(codes.size === 1 ? { code: errors[0]!.code } : {}),
|
|
294
|
+
...(dataCodes.size === 1 && errors.every((error) => error.dataCode !== undefined)
|
|
295
|
+
? { dataCode: errors[0]!.dataCode }
|
|
296
|
+
: {}),
|
|
297
|
+
errors: Math.min(errors.length, 65_535),
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function rpcServerError(code: number | undefined) {
|
|
302
|
+
return code === -32603 || (code !== undefined && code >= -32099 && code <= -32000)
|
|
303
|
+
}
|
|
304
|
+
|
|
218
305
|
export declare namespace middleware {
|
|
219
306
|
/** Options for the request logger middleware. */
|
|
220
307
|
type Options = {
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import * as Metrics from '../Metrics.js'
|
|
2
|
+
import type * as Log from './Log.js'
|
|
3
|
+
import * as MetricSink from './MetricSink.js'
|
|
4
|
+
|
|
5
|
+
type MetricEvent = {
|
|
6
|
+
name: string
|
|
7
|
+
tags: Metrics.Tags | undefined
|
|
8
|
+
type: 'count' | 'gauge' | 'histogram'
|
|
9
|
+
value: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('requests', () => {
|
|
13
|
+
test('records JSON-RPC errors with bounded code tags', () => {
|
|
14
|
+
const events: MetricEvent[] = []
|
|
15
|
+
const metrics = Metrics.from({
|
|
16
|
+
count(name, value, tags) {
|
|
17
|
+
events.push({ name, tags, type: 'count', value })
|
|
18
|
+
},
|
|
19
|
+
flush() {},
|
|
20
|
+
gauge() {},
|
|
21
|
+
histogram() {},
|
|
22
|
+
})
|
|
23
|
+
const record = MetricSink.requests(metrics)
|
|
24
|
+
|
|
25
|
+
record({
|
|
26
|
+
duration: 10,
|
|
27
|
+
level: 'warn',
|
|
28
|
+
method: 'POST',
|
|
29
|
+
path: '/rpc/relay',
|
|
30
|
+
requestId: 'request_private',
|
|
31
|
+
route: '/rpc/relay',
|
|
32
|
+
rpc: { code: -32602, dataCode: 'billing_required', errors: 2 },
|
|
33
|
+
status: 200,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
expect(events).toMatchInlineSnapshot(`
|
|
37
|
+
[
|
|
38
|
+
{
|
|
39
|
+
"name": "http_response_count",
|
|
40
|
+
"tags": {
|
|
41
|
+
"cache": "miss",
|
|
42
|
+
"method": "POST",
|
|
43
|
+
"principal_environment": "none",
|
|
44
|
+
"principal_type": "unknown",
|
|
45
|
+
"route": "/rpc/relay",
|
|
46
|
+
"status": 200,
|
|
47
|
+
},
|
|
48
|
+
"type": "count",
|
|
49
|
+
"value": 1,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "rpc_response_error_count",
|
|
53
|
+
"tags": {
|
|
54
|
+
"cache": "miss",
|
|
55
|
+
"method": "POST",
|
|
56
|
+
"principal_environment": "none",
|
|
57
|
+
"principal_type": "unknown",
|
|
58
|
+
"route": "/rpc/relay",
|
|
59
|
+
"rpc_error_code": "-32602",
|
|
60
|
+
},
|
|
61
|
+
"type": "count",
|
|
62
|
+
"value": 2,
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
`)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('records bounded funding provider attempts without caller data', () => {
|
|
69
|
+
const events: MetricEvent[] = []
|
|
70
|
+
let flushes = 0
|
|
71
|
+
const metrics = Metrics.from({
|
|
72
|
+
count(name, value, tags) {
|
|
73
|
+
events.push({ name, tags, type: 'count', value })
|
|
74
|
+
},
|
|
75
|
+
flush() {
|
|
76
|
+
flushes += 1
|
|
77
|
+
},
|
|
78
|
+
gauge(name, value, tags) {
|
|
79
|
+
events.push({ name, tags, type: 'gauge', value })
|
|
80
|
+
},
|
|
81
|
+
histogram(name, value, tags) {
|
|
82
|
+
events.push({ name, tags, type: 'histogram', value })
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
const record = MetricSink.requests(metrics)
|
|
86
|
+
|
|
87
|
+
record({
|
|
88
|
+
duration: 100,
|
|
89
|
+
fundingProviderAttempts: [
|
|
90
|
+
{
|
|
91
|
+
durationMs: 10,
|
|
92
|
+
id: 'relay',
|
|
93
|
+
operation: 'quote/v2',
|
|
94
|
+
outcome: 'available',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
durationMs: 20,
|
|
98
|
+
id: 'rhino',
|
|
99
|
+
operation: 'quote/bridge-swap/public',
|
|
100
|
+
outcome: 'thin',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
durationMs: 30,
|
|
104
|
+
id: 'squid',
|
|
105
|
+
operation: 'v2/route',
|
|
106
|
+
outcome: 'unavailable',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
durationMs: 40,
|
|
110
|
+
failure: 'timeout',
|
|
111
|
+
id: 'across',
|
|
112
|
+
operation: 'swap/approval',
|
|
113
|
+
outcome: 'failed',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
level: 'info',
|
|
117
|
+
method: 'GET',
|
|
118
|
+
path: '/v1/funding/quotes',
|
|
119
|
+
principal: {
|
|
120
|
+
id: 'key_private',
|
|
121
|
+
orgId: 'org_private',
|
|
122
|
+
projectId: 'project_private',
|
|
123
|
+
type: 'api_key',
|
|
124
|
+
},
|
|
125
|
+
query: 'sourceAmount=secret',
|
|
126
|
+
requestId: 'request_private',
|
|
127
|
+
route: '/v1/funding/quotes',
|
|
128
|
+
status: 200,
|
|
129
|
+
} satisfies Log.Entry)
|
|
130
|
+
|
|
131
|
+
const funding = events.filter((event) => event.name.startsWith('funding_quote_provider_'))
|
|
132
|
+
expect(funding).toMatchInlineSnapshot(`
|
|
133
|
+
[
|
|
134
|
+
{
|
|
135
|
+
"name": "funding_quote_provider_attempt_count",
|
|
136
|
+
"tags": {
|
|
137
|
+
"outcome": "available",
|
|
138
|
+
"provider": "relay",
|
|
139
|
+
},
|
|
140
|
+
"type": "count",
|
|
141
|
+
"value": 1,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name": "funding_quote_provider_duration_ms",
|
|
145
|
+
"tags": {
|
|
146
|
+
"outcome": "available",
|
|
147
|
+
"provider": "relay",
|
|
148
|
+
},
|
|
149
|
+
"type": "histogram",
|
|
150
|
+
"value": 10,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"name": "funding_quote_provider_attempt_count",
|
|
154
|
+
"tags": {
|
|
155
|
+
"outcome": "thin",
|
|
156
|
+
"provider": "rhino",
|
|
157
|
+
},
|
|
158
|
+
"type": "count",
|
|
159
|
+
"value": 1,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"name": "funding_quote_provider_duration_ms",
|
|
163
|
+
"tags": {
|
|
164
|
+
"outcome": "thin",
|
|
165
|
+
"provider": "rhino",
|
|
166
|
+
},
|
|
167
|
+
"type": "histogram",
|
|
168
|
+
"value": 20,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"name": "funding_quote_provider_attempt_count",
|
|
172
|
+
"tags": {
|
|
173
|
+
"outcome": "unavailable",
|
|
174
|
+
"provider": "squid",
|
|
175
|
+
},
|
|
176
|
+
"type": "count",
|
|
177
|
+
"value": 1,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"name": "funding_quote_provider_duration_ms",
|
|
181
|
+
"tags": {
|
|
182
|
+
"outcome": "unavailable",
|
|
183
|
+
"provider": "squid",
|
|
184
|
+
},
|
|
185
|
+
"type": "histogram",
|
|
186
|
+
"value": 30,
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "funding_quote_provider_attempt_count",
|
|
190
|
+
"tags": {
|
|
191
|
+
"failure": "timeout",
|
|
192
|
+
"outcome": "failed",
|
|
193
|
+
"provider": "across",
|
|
194
|
+
},
|
|
195
|
+
"type": "count",
|
|
196
|
+
"value": 1,
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"name": "funding_quote_provider_duration_ms",
|
|
200
|
+
"tags": {
|
|
201
|
+
"failure": "timeout",
|
|
202
|
+
"outcome": "failed",
|
|
203
|
+
"provider": "across",
|
|
204
|
+
},
|
|
205
|
+
"type": "histogram",
|
|
206
|
+
"value": 40,
|
|
207
|
+
},
|
|
208
|
+
]
|
|
209
|
+
`)
|
|
210
|
+
expect(JSON.stringify(funding)).not.toMatch(
|
|
211
|
+
/key_private|org_private|project_private|request_private|secret/,
|
|
212
|
+
)
|
|
213
|
+
expect(flushes).toBe(1)
|
|
214
|
+
})
|
|
215
|
+
})
|
|
@@ -85,6 +85,12 @@ export function requests(backend: Metrics): RequestSink {
|
|
|
85
85
|
})
|
|
86
86
|
backend.histogram('http_response_duration_ms', entry.duration, tags)
|
|
87
87
|
|
|
88
|
+
if (entry.rpc)
|
|
89
|
+
backend.count('rpc_response_error_count', entry.rpc.errors, {
|
|
90
|
+
...tags,
|
|
91
|
+
rpc_error_code: rpcErrorCode(entry.rpc.code),
|
|
92
|
+
})
|
|
93
|
+
|
|
88
94
|
if (entry.status === 429 || entry.errorCode === 'rate_limit_exceeded')
|
|
89
95
|
backend.count('http_rate_limit_count', 1, {
|
|
90
96
|
...tags,
|
|
@@ -95,10 +101,28 @@ export function requests(backend: Metrics): RequestSink {
|
|
|
95
101
|
for (const [operation, duration] of Object.entries(entry.timings ?? {}))
|
|
96
102
|
backend.histogram('upstream_duration_ms', duration, { ...tags, operation })
|
|
97
103
|
|
|
104
|
+
for (const attempt of entry.fundingProviderAttempts ?? []) {
|
|
105
|
+
const tags_attempt = {
|
|
106
|
+
...(attempt.failure === undefined ? {} : { failure: attempt.failure }),
|
|
107
|
+
outcome: attempt.outcome,
|
|
108
|
+
provider: attempt.id,
|
|
109
|
+
}
|
|
110
|
+
backend.count('funding_quote_provider_attempt_count', 1, tags_attempt)
|
|
111
|
+
backend.histogram('funding_quote_provider_duration_ms', attempt.durationMs, tags_attempt)
|
|
112
|
+
}
|
|
113
|
+
|
|
98
114
|
backend.flush()
|
|
99
115
|
}
|
|
100
116
|
}
|
|
101
117
|
|
|
118
|
+
/** Maps arbitrary upstream JSON-RPC codes into bounded metric tags. */
|
|
119
|
+
function rpcErrorCode(code: number | undefined) {
|
|
120
|
+
if (code === undefined) return 'mixed'
|
|
121
|
+
if ([-32700, -32600, -32601, -32602, -32603].includes(code)) return String(code)
|
|
122
|
+
if (code >= -32099 && code <= -32000) return 'server'
|
|
123
|
+
return 'other'
|
|
124
|
+
}
|
|
125
|
+
|
|
102
126
|
function routeTags(entry: Log.Entry): RouteTags {
|
|
103
127
|
return {
|
|
104
128
|
cache: entry.cache ?? 'miss',
|
package/src/internal/OpenApi.ts
CHANGED
|
@@ -64,6 +64,7 @@ export const errorCodes = {
|
|
|
64
64
|
'address_invalid',
|
|
65
65
|
'token_invalid',
|
|
66
66
|
'symbol_invalid',
|
|
67
|
+
'quote_amount_out_of_range',
|
|
67
68
|
'pair_invalid',
|
|
68
69
|
'pair_id_invalid',
|
|
69
70
|
'transaction_invalid',
|
|
@@ -71,6 +72,7 @@ export const errorCodes = {
|
|
|
71
72
|
'block_invalid',
|
|
72
73
|
'chain_id_invalid',
|
|
73
74
|
'chain_id_unsupported',
|
|
75
|
+
'destination_transition_invalid',
|
|
74
76
|
'url_invalid',
|
|
75
77
|
'api_key_malformed',
|
|
76
78
|
],
|
|
@@ -85,6 +87,7 @@ export const errorCodes = {
|
|
|
85
87
|
'receipt_not_found',
|
|
86
88
|
'order_not_found',
|
|
87
89
|
'pair_not_found',
|
|
90
|
+
'quote_not_available',
|
|
88
91
|
'verified_token_not_found',
|
|
89
92
|
'webhook_not_found',
|
|
90
93
|
'delivery_not_found',
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Hono } from 'hono'
|
|
2
|
+
|
|
3
|
+
import * as Response from './Response.js'
|
|
4
|
+
|
|
5
|
+
describe('upstream', () => {
|
|
6
|
+
test('returns a stable message and preserves the cause on context', async () => {
|
|
7
|
+
const app = new Hono()
|
|
8
|
+
const cause = new Error('provider URL contains secret credentials')
|
|
9
|
+
let captured: Error | undefined
|
|
10
|
+
|
|
11
|
+
app.use(async (c, next) => {
|
|
12
|
+
await next()
|
|
13
|
+
captured = c.error
|
|
14
|
+
})
|
|
15
|
+
app.get('/', (c) => Response.upstream(c, cause))
|
|
16
|
+
|
|
17
|
+
const response = await app.request('/')
|
|
18
|
+
expect(await response.json()).toMatchInlineSnapshot(`
|
|
19
|
+
{
|
|
20
|
+
"error": {
|
|
21
|
+
"code": "upstream_error",
|
|
22
|
+
"message": "Upstream service could not complete the request",
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
`)
|
|
26
|
+
expect(captured).toBe(cause)
|
|
27
|
+
})
|
|
28
|
+
})
|
package/src/internal/Response.ts
CHANGED
|
@@ -39,12 +39,20 @@ export function unsupportedChainId(c: Context, chainId: number, supported: Itera
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* Maps an unexpected upstream failure to a 502 JSON error envelope.
|
|
43
|
-
*
|
|
42
|
+
* Maps an unexpected upstream failure to a stable 502 JSON error envelope.
|
|
43
|
+
* Preserves `Error` causes for reporting and rethrows non-`Error` causes.
|
|
44
44
|
*/
|
|
45
45
|
export function upstream(c: Context, cause: unknown) {
|
|
46
|
-
if (cause instanceof Error)
|
|
47
|
-
|
|
46
|
+
if (cause instanceof Error) {
|
|
47
|
+
// Preserve the original error for error-reporting middleware without
|
|
48
|
+
// exposing provider URLs, payloads, or credentials in the response.
|
|
49
|
+
c.error = cause
|
|
50
|
+
return error(c, {
|
|
51
|
+
code: 'upstream_error',
|
|
52
|
+
message: 'Upstream service could not complete the request',
|
|
53
|
+
status: 502,
|
|
54
|
+
})
|
|
55
|
+
}
|
|
48
56
|
throw cause
|
|
49
57
|
}
|
|
50
58
|
|
package/src/internal/Schema.ts
CHANGED
|
@@ -290,6 +290,35 @@ export const DecimalString = z
|
|
|
290
290
|
z.meta({ examples: ['1000000'] }),
|
|
291
291
|
)
|
|
292
292
|
|
|
293
|
+
/** A self-contained token quantity in base units and human-readable form. */
|
|
294
|
+
export const TokenAmount = describe(
|
|
295
|
+
z.object({
|
|
296
|
+
baseUnits: DecimalString.check(z.describe("The quantity in the token's smallest unit.")),
|
|
297
|
+
currency: z
|
|
298
|
+
.string()
|
|
299
|
+
.check(
|
|
300
|
+
z.describe('The monetary denomination of this quantity.'),
|
|
301
|
+
z.meta({ examples: ['USD'] }),
|
|
302
|
+
),
|
|
303
|
+
decimals: z
|
|
304
|
+
.number()
|
|
305
|
+
.check(
|
|
306
|
+
z.int(),
|
|
307
|
+
z.nonnegative(),
|
|
308
|
+
z.describe('Decimal places used to convert `baseUnits` into `formatted`.'),
|
|
309
|
+
z.meta({ examples: [6] }),
|
|
310
|
+
),
|
|
311
|
+
formatted: z
|
|
312
|
+
.string()
|
|
313
|
+
.check(
|
|
314
|
+
z.regex(/^\d+(\.\d+)?$/),
|
|
315
|
+
z.describe('The quantity rendered in whole token units.'),
|
|
316
|
+
z.meta({ examples: ['1'] }),
|
|
317
|
+
),
|
|
318
|
+
}),
|
|
319
|
+
'A token quantity with its denomination and decimal representation.',
|
|
320
|
+
)
|
|
321
|
+
|
|
293
322
|
/**
|
|
294
323
|
* Minimum page size accepted across list endpoints. Floored at 5 because the
|
|
295
324
|
* indexer rejects signature-decoded `Transfer` queries with `LIMIT < 5`
|
|
@@ -306,6 +335,22 @@ export const Limit = z
|
|
|
306
335
|
z.meta({ examples: [10] }),
|
|
307
336
|
)
|
|
308
337
|
|
|
338
|
+
/** Valuation denomination query parameter shared across valuation-bearing endpoints. */
|
|
339
|
+
export const Denomination = z
|
|
340
|
+
.optional(
|
|
341
|
+
z.pipe(
|
|
342
|
+
z.string().check(z.regex(/^[a-zA-Z]{3}$/)),
|
|
343
|
+
z.transform((value) => value.toUpperCase()),
|
|
344
|
+
),
|
|
345
|
+
)
|
|
346
|
+
.check(
|
|
347
|
+
z.describe(
|
|
348
|
+
'Currency to denominate values in (case-insensitive, e.g. `AUD`). ' +
|
|
349
|
+
'Must be priced by the configured FX oracle. Defaults to `USD`.',
|
|
350
|
+
),
|
|
351
|
+
z.meta({ examples: ['AUD'] }),
|
|
352
|
+
)
|
|
353
|
+
|
|
309
354
|
/** Opaque keyset-pagination cursor query parameter shared across list endpoints. */
|
|
310
355
|
export const Cursor = z
|
|
311
356
|
.optional(z.string())
|
|
@@ -464,17 +509,17 @@ export function timestampBound(noun: string, bound: 'from' | 'to') {
|
|
|
464
509
|
|
|
465
510
|
/**
|
|
466
511
|
* Builds the schema for a comma-separated opt-in query parameter (e.g.
|
|
467
|
-
* `?include=token,
|
|
512
|
+
* `?include=token,totalCount`), parsed into a validated array of the given enum's
|
|
468
513
|
* members. Absent or empty values yield `[]`. Centralizes the splitting,
|
|
469
514
|
* trimming, and OpenAPI array-enum metadata that every list endpoint otherwise
|
|
470
515
|
* repeats.
|
|
471
516
|
*
|
|
472
|
-
* A repeated parameter (`?include=token&include=
|
|
517
|
+
* A repeated parameter (`?include=token&include=totalCount`) arrives from the
|
|
473
518
|
* validator as a `string[]`, so the input accepts both forms and each entry is
|
|
474
|
-
* still comma-split
|
|
519
|
+
* still comma-split, so the two styles compose freely.
|
|
475
520
|
*
|
|
476
|
-
* Pass the endpoint's `Include` enum
|
|
477
|
-
*
|
|
521
|
+
* Pass the endpoint's local `Include` enum so its members drive the parsed type
|
|
522
|
+
* and documentation, plus the parameter description.
|
|
478
523
|
*/
|
|
479
524
|
export function includeQuery<const T extends Readonly<Record<string, string>>>(
|
|
480
525
|
member: z.ZodMiniEnum<T>,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as Value from './Value.js'
|
|
2
|
+
|
|
3
|
+
describe('tokenAmount', () => {
|
|
4
|
+
test('renders a self-contained token quantity', () => {
|
|
5
|
+
expect(
|
|
6
|
+
Value.tokenAmount({
|
|
7
|
+
baseUnits: '1234567',
|
|
8
|
+
currency: 'USD',
|
|
9
|
+
decimals: 6,
|
|
10
|
+
}),
|
|
11
|
+
).toMatchInlineSnapshot(`
|
|
12
|
+
{
|
|
13
|
+
"baseUnits": "1234567",
|
|
14
|
+
"currency": "USD",
|
|
15
|
+
"decimals": 6,
|
|
16
|
+
"formatted": "1.234567",
|
|
17
|
+
}
|
|
18
|
+
`)
|
|
19
|
+
})
|
|
20
|
+
})
|
package/src/internal/Value.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Hex } from 'ox'
|
|
1
|
+
import { Hex, Value as core_Value } from 'ox'
|
|
2
2
|
|
|
3
3
|
/** Coerce a TIDX numeric column (bigint / number / string) to a JS number. */
|
|
4
4
|
export function toNumber(value: unknown) {
|
|
@@ -39,6 +39,29 @@ export function toIntegerString(value: unknown) {
|
|
|
39
39
|
return undefined
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/** Builds a token amount from its base-unit quantity and immutable token metadata. */
|
|
43
|
+
export function tokenAmount(options: tokenAmount.Options) {
|
|
44
|
+
const baseUnits = options.baseUnits.toString()
|
|
45
|
+
return {
|
|
46
|
+
baseUnits,
|
|
47
|
+
currency: options.currency,
|
|
48
|
+
decimals: options.decimals,
|
|
49
|
+
formatted: core_Value.format(BigInt(baseUnits), options.decimals),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export declare namespace tokenAmount {
|
|
54
|
+
/** Inputs needed to render a self-contained token amount. */
|
|
55
|
+
type Options = {
|
|
56
|
+
/** Quantity in the token's smallest unit. */
|
|
57
|
+
baseUnits: bigint | string
|
|
58
|
+
/** Monetary denomination reported by the token. */
|
|
59
|
+
currency: string
|
|
60
|
+
/** Decimal places used by the token. */
|
|
61
|
+
decimals: number
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
/**
|
|
43
66
|
* Coerce a TIDX numeric column (bigint / number / decimal string) to a minimal
|
|
44
67
|
* `0x`-prefixed hex quantity (`0x0` for zero), matching the JSON-RPC wire
|
|
@@ -535,7 +535,15 @@ export async function snapshot(c: Context<App.Environment>, chainId: ChainId): P
|
|
|
535
535
|
|
|
536
536
|
// Soft-stale: serve immediately, refresh in the background. Never blocks.
|
|
537
537
|
if (cell) {
|
|
538
|
-
|
|
538
|
+
const inflight = refresh(c, Db.get(c.get('dbCached')), chainId, cell)
|
|
539
|
+
// Workers cancel post-response I/O unless kept alive via `waitUntil`;
|
|
540
|
+
// without it the refresh dies mid-query and publishes never propagate.
|
|
541
|
+
// Node has no execution context, and fire-and-forget survives there.
|
|
542
|
+
try {
|
|
543
|
+
c.executionCtx.waitUntil(inflight)
|
|
544
|
+
} catch {
|
|
545
|
+
void inflight
|
|
546
|
+
}
|
|
539
547
|
return cell.snapshot
|
|
540
548
|
}
|
|
541
549
|
|