tapimo 0.15.1 → 0.18.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/README.md +137 -0
- package/dist/ApiKey.d.ts +1 -0
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +4 -2
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +37 -11
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +163 -10
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +13085 -11974
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +46 -15
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +1 -1
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +1 -1
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +893 -191
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +5 -1
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +70 -70
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +8 -3
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/earn-vaults.d.ts +66 -27
- package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
- package/dist/admin/apps/earn-vaults.js +36 -7
- package/dist/admin/apps/earn-vaults.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +25 -25
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +5 -4
- package/dist/admin/apps/organizations.js.map +1 -1
- package/dist/admin/apps/route-policies.d.ts +632 -0
- package/dist/admin/apps/route-policies.d.ts.map +1 -0
- package/dist/admin/apps/route-policies.js +257 -0
- package/dist/admin/apps/route-policies.js.map +1 -0
- package/dist/admin/apps/routes-support.js +39 -3
- package/dist/admin/apps/routes-support.js.map +1 -1
- package/dist/admin/apps/routes.d.ts +529 -76
- package/dist/admin/apps/routes.d.ts.map +1 -1
- package/dist/admin/apps/routes.js +82 -1
- package/dist/admin/apps/routes.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +157 -157
- package/dist/admin/index.d.ts +0 -1
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +0 -1
- package/dist/admin/index.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 +205 -201
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +65 -1
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +1 -1
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +58 -59
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/data/App.d.ts +2709 -2670
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +357 -357
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +50 -0
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +248 -248
- package/dist/apps/data/routes/balances.d.ts +22 -22
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +5 -7
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +125 -125
- package/dist/apps/data/routes/coingecko.d.ts +54 -54
- package/dist/apps/data/routes/earn.d.ts +103 -12
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +456 -220
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +267 -97
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +109 -127
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +83 -54
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +43 -43
- package/dist/apps/data/routes/receipts.d.ts +235 -235
- package/dist/apps/data/routes/rpc.d.ts +30 -30
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +11 -6
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +2 -0
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +30 -22
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +77 -77
- package/dist/apps/data/routes/valuation.d.ts +32 -32
- package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +1 -1
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +31 -31
- package/dist/apps/management/App.d.ts +2909 -2064
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +2 -0
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/Billing.d.ts +2 -4
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +65 -26
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +257 -245
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +70 -11
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +84 -84
- package/dist/apps/management/routes/cli.d.ts +912 -0
- package/dist/apps/management/routes/cli.d.ts.map +1 -0
- package/dist/apps/management/routes/cli.js +416 -0
- package/dist/apps/management/routes/cli.js.map +1 -0
- package/dist/apps/management/routes/faucet.d.ts +8 -8
- package/dist/apps/management/routes/invitations.d.ts +138 -138
- package/dist/apps/management/routes/invite-links.d.ts +172 -172
- package/dist/apps/management/routes/members.d.ts +16 -16
- package/dist/apps/management/routes/orgs.d.ts +104 -104
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +8 -2
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +125 -125
- package/dist/apps/management/routes/usage.d.ts +8 -8
- package/dist/apps/management/routes/verified-token-requests.d.ts +86 -86
- package/dist/apps/management/routes/webhooks.d.ts +485 -485
- package/dist/apps/mpp/App.d.ts +44 -44
- package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Policy.js +4 -2
- package/dist/apps/mpp/internal/Policy.js.map +1 -1
- package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Sponsorship.js +6 -4
- package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
- package/dist/apps/relay/App.d.ts +8 -0
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +16 -4
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.d.ts +4 -6
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +71 -60
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/apps/routes/Access.d.ts +53 -0
- package/dist/apps/routes/Access.d.ts.map +1 -1
- package/dist/apps/routes/Access.js +121 -0
- package/dist/apps/routes/Access.js.map +1 -1
- package/dist/apps/routes/App.d.ts +397 -158
- package/dist/apps/routes/App.d.ts.map +1 -1
- package/dist/apps/routes/App.js.map +1 -1
- package/dist/apps/routes/routes/chains.d.ts +25 -25
- package/dist/apps/routes/routes/deposit-addresses.d.ts +169 -61
- package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -1
- package/dist/apps/routes/routes/deposit-addresses.js +217 -32
- package/dist/apps/routes/routes/deposit-addresses.js.map +1 -1
- package/dist/apps/routes/routes/quotes.d.ts +171 -81
- package/dist/apps/routes/routes/quotes.d.ts.map +1 -1
- package/dist/apps/routes/routes/quotes.js +101 -27
- package/dist/apps/routes/routes/quotes.js.map +1 -1
- package/dist/apps/routes/routes/transfers.d.ts +532 -480
- package/dist/apps/routes/routes/transfers.d.ts.map +1 -1
- package/dist/apps/routes/routes/transfers.js +182 -37
- package/dist/apps/routes/routes/transfers.js.map +1 -1
- package/dist/cli/ApiKeys.d.ts +120 -0
- package/dist/cli/ApiKeys.d.ts.map +1 -0
- package/dist/cli/ApiKeys.js +138 -0
- package/dist/cli/ApiKeys.js.map +1 -0
- package/dist/cli/Cli.d.ts +92 -34
- package/dist/cli/Cli.d.ts.map +1 -1
- package/dist/cli/Cli.js +188 -11
- package/dist/cli/Cli.js.map +1 -1
- package/dist/cli/Credentials.d.ts +95 -0
- package/dist/cli/Credentials.d.ts.map +1 -0
- package/dist/cli/Credentials.js +110 -0
- package/dist/cli/Credentials.js.map +1 -0
- package/dist/cli/Spec.d.ts +59 -0
- package/dist/cli/Spec.d.ts.map +1 -0
- package/dist/cli/Spec.js +77 -0
- package/dist/cli/Spec.js.map +1 -0
- package/dist/cli/bin.js +5 -1
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/admin.d.ts +5 -5
- package/dist/cli/commands/admin.d.ts.map +1 -1
- package/dist/cli/commands/auth.d.ts +73 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +204 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/keys.d.ts +17 -0
- package/dist/cli/commands/keys.d.ts.map +1 -0
- package/dist/cli/commands/keys.js +109 -0
- package/dist/cli/commands/keys.js.map +1 -0
- package/dist/cloudflare.d.ts +27 -2
- package/dist/cloudflare.d.ts.map +1 -1
- package/dist/cloudflare.js +144 -17
- package/dist/cloudflare.js.map +1 -1
- package/dist/db/Db.d.ts +23 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +413 -1
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +44 -1
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +56 -3
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/apiKeyAdmissions.d.ts +28 -2
- package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -1
- package/dist/db/tables/apiKeyAdmissions.js +65 -9
- package/dist/db/tables/apiKeyAdmissions.js.map +1 -1
- package/dist/db/tables/apiKeyOwnerTombstones.d.ts +2 -0
- package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -1
- package/dist/db/tables/apiKeyOwnerTombstones.js +2 -2
- package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -1
- package/dist/db/tables/authAccounts.d.ts.map +1 -1
- package/dist/db/tables/authAccounts.js +1 -0
- package/dist/db/tables/authAccounts.js.map +1 -1
- package/dist/db/tables/earnVaults.d.ts +5 -1
- package/dist/db/tables/earnVaults.d.ts.map +1 -1
- package/dist/db/tables/earnVaults.js +12 -1
- package/dist/db/tables/earnVaults.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +4 -2
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +8 -34
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/requestUsage.d.ts +5 -1
- package/dist/db/tables/requestUsage.d.ts.map +1 -1
- package/dist/db/tables/requestUsage.js +10 -2
- package/dist/db/tables/requestUsage.js.map +1 -1
- package/dist/db/tables/rewardEligibilityAssociations.d.ts +13 -0
- package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -1
- package/dist/db/tables/rewardEligibilityAssociations.js +11 -0
- package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -1
- package/dist/db/tables/rewardRuns.d.ts.map +1 -1
- package/dist/db/tables/rewardRuns.js +4 -0
- package/dist/db/tables/rewardRuns.js.map +1 -1
- package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -1
- package/dist/db/tables/rewardTransactionAttempts.js +2 -0
- package/dist/db/tables/rewardTransactionAttempts.js.map +1 -1
- package/dist/db/tables/routesDepositAddresses.d.ts +29 -0
- package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -1
- package/dist/db/tables/routesDepositAddresses.js +84 -31
- package/dist/db/tables/routesDepositAddresses.js.map +1 -1
- package/dist/db/tables/routesDeposits.d.ts.map +1 -1
- package/dist/db/tables/routesDeposits.js +31 -21
- package/dist/db/tables/routesDeposits.js.map +1 -1
- package/dist/db/tables/routesIdempotency.d.ts.map +1 -1
- package/dist/db/tables/routesIdempotency.js +2 -0
- package/dist/db/tables/routesIdempotency.js.map +1 -1
- package/dist/db/tables/routesPolicies.d.ts +58 -0
- package/dist/db/tables/routesPolicies.d.ts.map +1 -0
- package/dist/db/tables/routesPolicies.js +198 -0
- package/dist/db/tables/routesPolicies.js.map +1 -0
- package/dist/db/tables/routesTransferSubsidies.d.ts +22 -0
- package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -1
- package/dist/db/tables/routesTransferSubsidies.js +41 -0
- package/dist/db/tables/routesTransferSubsidies.js.map +1 -1
- package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -1
- package/dist/db/tables/routesTransferSubsidyNonces.js +12 -4
- package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -1
- package/dist/db/tables/routesTransfers.d.ts +26 -1
- package/dist/db/tables/routesTransfers.d.ts.map +1 -1
- package/dist/db/tables/routesTransfers.js +36 -6
- package/dist/db/tables/routesTransfers.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +45 -13
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +144 -33
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/users.d.ts +2 -0
- package/dist/db/tables/users.d.ts.map +1 -1
- package/dist/db/tables/users.js +11 -0
- package/dist/db/tables/users.js.map +1 -1
- package/dist/handlers/internal/multisig.d.ts +1 -1
- package/dist/handlers/internal/multisig.d.ts.map +1 -1
- package/dist/handlers/internal/multisig.js +3 -2
- package/dist/handlers/internal/multisig.js.map +1 -1
- package/dist/handlers/relay.d.ts +2 -0
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +34 -15
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +57 -6
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +182 -78
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/BetterAuth.d.ts +22 -0
- package/dist/internal/BetterAuth.d.ts.map +1 -1
- package/dist/internal/BetterAuth.js +17 -14
- package/dist/internal/BetterAuth.js.map +1 -1
- package/dist/internal/Cache.d.ts +5 -0
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +3 -1
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/CliAuth.d.ts +243 -0
- package/dist/internal/CliAuth.d.ts.map +1 -0
- package/dist/internal/CliAuth.js +249 -0
- package/dist/internal/CliAuth.js.map +1 -0
- package/dist/internal/EarnSharePrices.d.ts +1 -1
- package/dist/internal/EarnSharePrices.d.ts.map +1 -1
- package/dist/internal/EarnSharePrices.js +7 -3
- package/dist/internal/EarnSharePrices.js.map +1 -1
- package/dist/internal/EarnVaults.d.ts +47 -0
- package/dist/internal/EarnVaults.d.ts.map +1 -1
- package/dist/internal/EarnVaults.js +188 -4
- package/dist/internal/EarnVaults.js.map +1 -1
- package/dist/internal/EarnWithdrawals.d.ts +73 -0
- package/dist/internal/EarnWithdrawals.d.ts.map +1 -0
- package/dist/internal/EarnWithdrawals.js +189 -0
- package/dist/internal/EarnWithdrawals.js.map +1 -0
- package/dist/internal/ExecutionContext.d.ts +21 -0
- package/dist/internal/ExecutionContext.d.ts.map +1 -0
- package/dist/internal/ExecutionContext.js +16 -0
- package/dist/internal/ExecutionContext.js.map +1 -0
- package/dist/internal/Log.d.ts +7 -3
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +163 -130
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +26 -1
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/RateLimit.d.ts +67 -0
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +174 -27
- package/dist/internal/RateLimit.js.map +1 -1
- package/dist/internal/Store.d.ts +6 -0
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +4 -5
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Timing.d.ts +6 -0
- package/dist/internal/Timing.d.ts.map +1 -1
- package/dist/internal/Timing.js +21 -1
- package/dist/internal/Timing.js.map +1 -1
- package/dist/internal/Tron.d.ts +124 -0
- package/dist/internal/Tron.d.ts.map +1 -0
- package/dist/internal/Tron.js +202 -0
- package/dist/internal/Tron.js.map +1 -0
- package/dist/internal/Viem.d.ts +4 -0
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +25 -6
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/rewards/Read.d.ts +2 -2
- package/dist/internal/rewards/Read.d.ts.map +1 -1
- package/dist/internal/rewards/Read.js +11 -2
- package/dist/internal/rewards/Read.js.map +1 -1
- package/dist/internal/routes/Action.d.ts +27 -0
- package/dist/internal/routes/Action.d.ts.map +1 -1
- package/dist/internal/routes/Action.js +49 -1
- package/dist/internal/routes/Action.js.map +1 -1
- package/dist/internal/routes/Chain.d.ts +2 -0
- package/dist/internal/routes/Chain.d.ts.map +1 -1
- package/dist/internal/routes/Chain.js +4 -0
- package/dist/internal/routes/Chain.js.map +1 -1
- package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
- package/dist/internal/routes/DepositAddress.js +5 -0
- package/dist/internal/routes/DepositAddress.js.map +1 -1
- package/dist/internal/routes/Evidence.d.ts.map +1 -1
- package/dist/internal/routes/Evidence.js +6 -2
- package/dist/internal/routes/Evidence.js.map +1 -1
- package/dist/internal/routes/EvmTransferSettlement.d.ts +17 -0
- package/dist/internal/routes/EvmTransferSettlement.d.ts.map +1 -0
- package/dist/internal/routes/EvmTransferSettlement.js +196 -0
- package/dist/internal/routes/EvmTransferSettlement.js.map +1 -0
- package/dist/internal/routes/Policy.d.ts +161 -0
- package/dist/internal/routes/Policy.d.ts.map +1 -0
- package/dist/internal/routes/Policy.js +249 -0
- package/dist/internal/routes/Policy.js.map +1 -0
- package/dist/internal/routes/Provider.d.ts +66 -3
- package/dist/internal/routes/Provider.d.ts.map +1 -1
- package/dist/internal/routes/Provider.js +106 -27
- package/dist/internal/routes/Provider.js.map +1 -1
- package/dist/internal/routes/Quota.d.ts +57 -0
- package/dist/internal/routes/Quota.d.ts.map +1 -0
- package/dist/internal/routes/Quota.js +144 -0
- package/dist/internal/routes/Quota.js.map +1 -0
- package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
- package/dist/internal/routes/Reconciliation.js +163 -47
- package/dist/internal/routes/Reconciliation.js.map +1 -1
- package/dist/internal/routes/SolanaTransferSettlement.d.ts +12 -0
- package/dist/internal/routes/SolanaTransferSettlement.d.ts.map +1 -0
- package/dist/internal/routes/SolanaTransferSettlement.js +220 -0
- package/dist/internal/routes/SolanaTransferSettlement.js.map +1 -0
- package/dist/internal/routes/SolanaTransferSubsidy.d.ts +172 -0
- package/dist/internal/routes/SolanaTransferSubsidy.d.ts.map +1 -0
- package/dist/internal/routes/SolanaTransferSubsidy.js +564 -0
- package/dist/internal/routes/SolanaTransferSubsidy.js.map +1 -0
- package/dist/internal/routes/Subsidy.d.ts +2 -2
- package/dist/internal/routes/Subsidy.d.ts.map +1 -1
- package/dist/internal/routes/Subsidy.js +2 -2
- package/dist/internal/routes/Subsidy.js.map +1 -1
- package/dist/internal/routes/Transfer.d.ts +229 -1
- package/dist/internal/routes/Transfer.d.ts.map +1 -1
- package/dist/internal/routes/Transfer.js +644 -7
- package/dist/internal/routes/Transfer.js.map +1 -1
- package/dist/internal/routes/TransferReconciliation.d.ts +6 -0
- package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -1
- package/dist/internal/routes/TransferReconciliation.js +83 -159
- package/dist/internal/routes/TransferReconciliation.js.map +1 -1
- package/dist/internal/routes/TransferSettlement.d.ts +45 -0
- package/dist/internal/routes/TransferSettlement.d.ts.map +1 -0
- package/dist/internal/routes/TransferSettlement.js +2 -0
- package/dist/internal/routes/TransferSettlement.js.map +1 -0
- package/dist/internal/routes/TransferSubsidy.d.ts +23 -8
- package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -1
- package/dist/internal/routes/TransferSubsidy.js +64 -5
- package/dist/internal/routes/TransferSubsidy.js.map +1 -1
- package/dist/internal/routes/TronTransferSettlement.d.ts +12 -0
- package/dist/internal/routes/TronTransferSettlement.d.ts.map +1 -0
- package/dist/internal/routes/TronTransferSettlement.js +201 -0
- package/dist/internal/routes/TronTransferSettlement.js.map +1 -0
- package/dist/internal/routes/TronTransferSubsidy.d.ts +174 -0
- package/dist/internal/routes/TronTransferSubsidy.d.ts.map +1 -0
- package/dist/internal/routes/TronTransferSubsidy.js +439 -0
- package/dist/internal/routes/TronTransferSubsidy.js.map +1 -0
- package/dist/internal/routes/index.d.ts +3 -0
- package/dist/internal/routes/index.d.ts.map +1 -1
- package/dist/internal/routes/index.js +3 -0
- package/dist/internal/routes/index.js.map +1 -1
- package/dist/internal/routes/providers/across.d.ts +3 -0
- package/dist/internal/routes/providers/across.d.ts.map +1 -1
- package/dist/internal/routes/providers/across.js +11 -0
- package/dist/internal/routes/providers/across.js.map +1 -1
- package/dist/internal/routes/providers/legacyMesh.d.ts +29 -0
- package/dist/internal/routes/providers/legacyMesh.d.ts.map +1 -0
- package/dist/internal/routes/providers/legacyMesh.js +474 -0
- package/dist/internal/routes/providers/legacyMesh.js.map +1 -0
- package/dist/internal/routes/providers/legacyMeshDelivery.d.ts +59 -0
- package/dist/internal/routes/providers/legacyMeshDelivery.d.ts.map +1 -0
- package/dist/internal/routes/providers/legacyMeshDelivery.js +229 -0
- package/dist/internal/routes/providers/legacyMeshDelivery.js.map +1 -0
- package/dist/internal/routes/providers/legacyMeshOutbound.d.ts +19 -0
- package/dist/internal/routes/providers/legacyMeshOutbound.d.ts.map +1 -0
- package/dist/internal/routes/providers/legacyMeshOutbound.js +457 -0
- package/dist/internal/routes/providers/legacyMeshOutbound.js.map +1 -0
- package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts +123 -0
- package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts.map +1 -0
- package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js +333 -0
- package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js.map +1 -0
- package/dist/internal/routes/providers/propAmm.d.ts +70 -0
- package/dist/internal/routes/providers/propAmm.d.ts.map +1 -0
- package/dist/internal/routes/providers/propAmm.js +524 -0
- package/dist/internal/routes/providers/propAmm.js.map +1 -0
- package/dist/internal/routes/providers/relay.d.ts +3 -0
- package/dist/internal/routes/providers/relay.d.ts.map +1 -1
- package/dist/internal/routes/providers/relay.js +352 -41
- package/dist/internal/routes/providers/relay.js.map +1 -1
- package/dist/internal/routes/providers/rhino.d.ts +3 -0
- package/dist/internal/routes/providers/rhino.d.ts.map +1 -1
- package/dist/internal/routes/providers/rhino.js +11 -0
- package/dist/internal/routes/providers/rhino.js.map +1 -1
- package/dist/internal/routes/providers/squid.d.ts +3 -0
- package/dist/internal/routes/providers/squid.d.ts.map +1 -1
- package/dist/internal/routes/providers/squid.js +19 -0
- package/dist/internal/routes/providers/squid.js.map +1 -1
- package/dist/internal/routes/providers/stargate.d.ts.map +1 -1
- package/dist/internal/routes/providers/stargate.js +22 -9
- package/dist/internal/routes/providers/stargate.js.map +1 -1
- package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -1
- package/dist/internal/routes/providers/symbiosis.js +13 -17
- package/dist/internal/routes/providers/symbiosis.js.map +1 -1
- package/dist/providers/index.d.ts +14 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +6 -0
- package/dist/providers/index.js.map +1 -1
- package/package.json +16 -6
- package/src/ApiKey.ts +7 -3
- package/src/ApiKeys.test.ts +652 -8
- package/src/ApiKeys.ts +191 -11
- package/src/App.test.ts +405 -18
- package/src/App.ts +51 -15
- package/src/Client.test-d.ts +157 -10
- package/src/Client.test.ts +4 -4
- package/src/Scope.ts +1 -2
- package/src/admin/App.ts +11 -5
- package/src/admin/apps/api-keys.test.ts +98 -2
- package/src/admin/apps/api-keys.ts +21 -12
- package/src/admin/apps/earn-vaults.test.ts +76 -7
- package/src/admin/apps/earn-vaults.ts +47 -8
- package/src/admin/apps/organizations.test.ts +147 -31
- package/src/admin/apps/organizations.ts +5 -4
- package/src/admin/apps/route-policies.test.ts +220 -0
- package/src/admin/apps/route-policies.ts +322 -0
- package/src/admin/apps/routes-support.test.ts +107 -2
- package/src/admin/apps/routes-support.ts +43 -3
- package/src/admin/apps/routes.test.ts +150 -0
- package/src/admin/apps/routes.ts +97 -1
- package/src/admin/apps/scopes.test.ts +1 -1
- package/src/admin/index.ts +0 -1
- package/src/admin/ui/plugin.ts +2 -1
- package/src/admin/ui/src/components/Dialog.tsx +1 -1
- package/src/admin/ui/src/components/EarnVaultForm.tsx +45 -0
- package/src/admin/ui/src/components/RoutePicker.tsx +79 -0
- package/src/admin/ui/src/lib/earn-vaults.ts +1 -1
- package/src/admin/ui/src/lib/route-policies.test.ts +452 -0
- package/src/admin/ui/src/lib/route-policies.ts +232 -0
- package/src/admin/ui/src/lib/routes.ts +34 -0
- package/src/admin/ui/src/routeTree.gen.ts +21 -0
- package/src/admin/ui/src/routes/api-keys.tsx +21 -2
- package/src/admin/ui/src/routes/early-access.tsx +1 -0
- package/src/admin/ui/src/routes/earn.vaults.tsx +1 -0
- package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +22 -0
- package/src/admin/ui/src/routes/earn.vaults_.new.tsx +10 -0
- package/src/admin/ui/src/routes/organizations.tsx +1 -0
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +18 -3
- package/src/admin/ui/src/routes/route-policies.tsx +678 -0
- package/src/admin/ui/src/routes/routes.tsx +85 -2
- package/src/admin/ui/src/routes/routes_.support.tsx +6 -22
- package/src/admin/ui/src/routes/subsidies.tsx +1 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +1 -0
- package/src/admin/ui.generated.ts +258 -202
- package/src/analytics/Analytics.test.ts +4 -50
- package/src/analytics/Analytics.ts +65 -1
- package/src/analytics/tables/requestEvents.test.ts +402 -1
- package/src/analytics/tables/requestEvents.ts +62 -93
- package/src/apps/data/routes/activities.test.ts +315 -14
- package/src/apps/data/routes/activities.ts +60 -0
- package/src/apps/data/routes/balances.ts +5 -7
- package/src/apps/data/routes/earn.bench.ts +18 -0
- package/src/apps/data/routes/earn.local.test.ts +507 -0
- package/src/apps/data/routes/earn.test.ts +405 -127
- package/src/apps/data/routes/earn.ts +660 -270
- package/src/apps/data/routes/exchanges.bench.ts +3 -1
- package/src/apps/data/routes/exchanges.test.ts +166 -2
- package/src/apps/data/routes/exchanges.ts +308 -101
- package/src/apps/data/routes/fee-amm.test.ts +134 -2
- package/src/apps/data/routes/fee-amm.ts +122 -60
- package/src/apps/data/routes/receipts.test.ts +21 -18
- package/src/apps/data/routes/rpc.test.ts +2 -2
- package/src/apps/data/routes/tokens.provenance.test.ts +157 -0
- package/src/apps/data/routes/tokens.test.ts +4 -4
- package/src/apps/data/routes/tokens.ts +11 -6
- package/src/apps/data/routes/transactions.test.ts +29 -0
- package/src/apps/data/routes/transactions.ts +33 -22
- package/src/apps/data/routes/webhooks.test.ts +12 -3
- package/src/apps/data/routes/webhooks.ts +2 -1
- package/src/apps/management/App.ts +4 -0
- package/src/apps/management/Billing.test.ts +253 -27
- package/src/apps/management/Billing.ts +83 -29
- package/src/apps/management/routes/api-keys.test.ts +1 -1
- package/src/apps/management/routes/api-keys.ts +85 -11
- package/src/apps/management/routes/billing.test.ts +68 -4
- package/src/apps/management/routes/cli.test.ts +370 -0
- package/src/apps/management/routes/cli.ts +533 -0
- package/src/apps/management/routes/me.test.ts +14 -4
- package/src/apps/management/routes/orgs.test.ts +108 -4
- package/src/apps/management/routes/orgs.ts +7 -2
- package/src/apps/management/routes/usage.test.ts +2 -2
- package/src/apps/mpp/internal/Policy.test.ts +51 -4
- package/src/apps/mpp/internal/Policy.ts +6 -2
- package/src/apps/mpp/internal/Sponsorship.test.ts +29 -0
- package/src/apps/mpp/internal/Sponsorship.ts +6 -4
- package/src/apps/relay/App.test.ts +85 -1
- package/src/apps/relay/App.ts +28 -4
- package/src/apps/relay/Sponsorships.test.ts +97 -1
- package/src/apps/relay/Sponsorships.ts +77 -66
- package/src/apps/routes/Access.test.ts +319 -0
- package/src/apps/routes/Access.ts +147 -0
- package/src/apps/routes/App.ts +10 -0
- package/src/apps/routes/routes/chains.test.ts +3 -2
- package/src/apps/routes/routes/deposit-addresses.test.ts +978 -34
- package/src/apps/routes/routes/deposit-addresses.ts +243 -32
- package/src/apps/routes/routes/propAmm.local.test.ts +951 -0
- package/src/apps/routes/routes/quotes.test.ts +81 -8
- package/src/apps/routes/routes/quotes.ts +109 -27
- package/src/apps/routes/routes/transfers.test.ts +252 -15
- package/src/apps/routes/routes/transfers.ts +212 -33
- package/src/cli/ApiKeys.test.ts +265 -0
- package/src/cli/ApiKeys.ts +189 -0
- package/src/cli/Cli.test.ts +188 -0
- package/src/cli/Cli.ts +280 -12
- package/src/cli/Credentials.test.ts +122 -0
- package/src/cli/Credentials.ts +144 -0
- package/src/cli/Spec.test.ts +133 -0
- package/src/cli/Spec.ts +132 -0
- package/src/cli/bin.test.ts +49 -0
- package/src/cli/bin.ts +5 -1
- package/src/cli/commands/auth.test.ts +138 -0
- package/src/cli/commands/auth.ts +254 -0
- package/src/cli/commands/keys.test.ts +68 -0
- package/src/cli/commands/keys.ts +125 -0
- package/src/cloudflare.ts +184 -36
- package/src/db/Db.test.ts +877 -0
- package/src/db/Db.ts +498 -1
- package/src/db/Schema.ts +75 -4
- package/src/db/tables/apiKeyAdmissions.test.ts +57 -0
- package/src/db/tables/apiKeyAdmissions.ts +101 -11
- package/src/db/tables/apiKeyOwnerTombstones.ts +2 -2
- package/src/db/tables/authAccounts.test.ts +30 -0
- package/src/db/tables/authAccounts.ts +1 -0
- package/src/db/tables/earnVaults.test.ts +34 -0
- package/src/db/tables/earnVaults.ts +17 -2
- package/src/db/tables/organizations.test.ts +148 -84
- package/src/db/tables/organizations.ts +11 -43
- package/src/db/tables/requestUsage.ts +13 -2
- package/src/db/tables/rewardCampaigns.test.ts +163 -0
- package/src/db/tables/rewardEligibilityAssociations.test.ts +14 -0
- package/src/db/tables/rewardEligibilityAssociations.ts +24 -0
- package/src/db/tables/rewardRuns.ts +4 -0
- package/src/db/tables/rewardTransactionAttempts.ts +2 -0
- package/src/db/tables/routesDepositAddresses.test.ts +263 -0
- package/src/db/tables/routesDepositAddresses.ts +118 -34
- package/src/db/tables/routesDeposits.test.ts +66 -5
- package/src/db/tables/routesDeposits.ts +47 -26
- package/src/db/tables/routesIdempotency.test.ts +80 -0
- package/src/db/tables/routesIdempotency.ts +2 -0
- package/src/db/tables/routesPolicies.test.ts +143 -0
- package/src/db/tables/routesPolicies.ts +251 -0
- package/src/db/tables/routesTransferSubsidies.ts +64 -0
- package/src/db/tables/routesTransferSubsidyNonces.ts +16 -4
- package/src/db/tables/routesTransfers.test.ts +183 -2
- package/src/db/tables/routesTransfers.ts +65 -6
- package/src/db/tables/sponsoredTransactions.test.ts +351 -76
- package/src/db/tables/sponsoredTransactions.ts +182 -38
- package/src/db/tables/users.test.ts +51 -0
- package/src/db/tables/users.ts +12 -0
- package/src/handlers/internal/multisig.store.test.ts +120 -0
- package/src/handlers/internal/multisig.test.ts +389 -0
- package/src/handlers/internal/multisig.ts +13 -10
- package/src/handlers/relay.test.ts +259 -83
- package/src/handlers/relay.ts +36 -17
- package/src/internal/Auth.test.ts +291 -8
- package/src/internal/Auth.ts +227 -96
- package/src/internal/BetterAuth.test.ts +58 -22
- package/src/internal/BetterAuth.ts +23 -17
- package/src/internal/Cache.ts +3 -1
- package/src/internal/CliAuth.test.ts +279 -0
- package/src/internal/CliAuth.ts +319 -0
- package/src/internal/EarnSharePrices.test.ts +25 -0
- package/src/internal/EarnSharePrices.ts +9 -2
- package/src/internal/EarnVaults.test.ts +67 -0
- package/src/internal/EarnVaults.ts +299 -4
- package/src/internal/EarnWithdrawals.test.ts +315 -0
- package/src/internal/EarnWithdrawals.ts +266 -0
- package/src/internal/ExecutionContext.ts +31 -0
- package/src/internal/Log.test.ts +210 -0
- package/src/internal/Log.ts +180 -142
- package/src/internal/MetricSink.test.ts +190 -15
- package/src/internal/MetricSink.ts +27 -1
- package/src/internal/RateLimit.test.ts +144 -8
- package/src/internal/RateLimit.ts +254 -26
- package/src/internal/Store.ts +4 -5
- package/src/internal/Timing.test.ts +32 -0
- package/src/internal/Timing.ts +20 -1
- package/src/internal/Tron.test-d.ts +22 -0
- package/src/internal/Tron.test.ts +94 -0
- package/src/internal/Tron.ts +289 -0
- package/src/internal/Viem.rpc.test.ts +76 -0
- package/src/internal/Viem.ts +29 -6
- package/src/internal/rewards/Read.test.ts +109 -0
- package/src/internal/rewards/Read.ts +13 -4
- package/src/internal/routes/Action.test.ts +70 -0
- package/src/internal/routes/Action.ts +76 -1
- package/src/internal/routes/Chain.test.ts +18 -0
- package/src/internal/routes/Chain.ts +5 -0
- package/src/internal/routes/DepositAddress.ts +5 -0
- package/src/internal/routes/Evidence.test.ts +64 -0
- package/src/internal/routes/Evidence.ts +11 -3
- package/src/internal/routes/EvmTransferSettlement.ts +213 -0
- package/src/internal/routes/Policy.test.ts +316 -0
- package/src/internal/routes/Policy.ts +399 -0
- package/src/internal/routes/Provider.test.ts +103 -2
- package/src/internal/routes/Provider.ts +149 -27
- package/src/internal/routes/Quota.test.ts +149 -0
- package/src/internal/routes/Quota.ts +226 -0
- package/src/internal/routes/Reconciliation.local.test.ts +285 -0
- package/src/internal/routes/Reconciliation.test.ts +371 -13
- package/src/internal/routes/Reconciliation.ts +193 -42
- package/src/internal/routes/SolanaTransferSettlement.ts +232 -0
- package/src/internal/routes/SolanaTransferSubsidy.test.ts +471 -0
- package/src/internal/routes/SolanaTransferSubsidy.ts +760 -0
- package/src/internal/routes/SourceObservation.test.ts +221 -0
- package/src/internal/routes/Subsidy.local.test.ts +46 -0
- package/src/internal/routes/Subsidy.ts +4 -2
- package/src/internal/routes/Transfer.solana.test.ts +389 -0
- package/src/internal/routes/Transfer.test.ts +130 -1
- package/src/internal/routes/Transfer.tron.test.ts +172 -0
- package/src/internal/routes/Transfer.ts +866 -8
- package/src/internal/routes/TransferReconciliation.test.ts +26 -4
- package/src/internal/routes/TransferReconciliation.ts +91 -166
- package/src/internal/routes/TransferSettlement.ts +48 -0
- package/src/internal/routes/TransferSubsidy.local.test.ts +143 -0
- package/src/internal/routes/TransferSubsidy.test.ts +34 -4
- package/src/internal/routes/TransferSubsidy.ts +87 -12
- package/src/internal/routes/TronTransferSettlement.ts +212 -0
- package/src/internal/routes/TronTransferSubsidy.test.ts +109 -0
- package/src/internal/routes/TronTransferSubsidy.ts +619 -0
- package/src/internal/routes/index.test.ts +3 -0
- package/src/internal/routes/index.ts +3 -0
- package/src/internal/routes/providers/across.ts +13 -0
- package/src/internal/routes/providers/index.test.ts +141 -0
- package/src/internal/routes/providers/legacyMesh.test.ts +484 -0
- package/src/internal/routes/providers/legacyMesh.ts +633 -0
- package/src/internal/routes/providers/legacyMeshDelivery.test.ts +306 -0
- package/src/internal/routes/providers/legacyMeshDelivery.ts +320 -0
- package/src/internal/routes/providers/legacyMeshOutbound.test.ts +401 -0
- package/src/internal/routes/providers/legacyMeshOutbound.ts +566 -0
- package/src/internal/routes/providers/legacyMeshOutboundDelivery.ts +473 -0
- package/src/internal/routes/providers/propAmm.ts +640 -0
- package/src/internal/routes/providers/relay.test.ts +1263 -41
- package/src/internal/routes/providers/relay.ts +423 -38
- package/src/internal/routes/providers/rhino.ts +14 -1
- package/src/internal/routes/providers/squid.ts +21 -0
- package/src/internal/routes/providers/stargate.test.ts +105 -1
- package/src/internal/routes/providers/stargate.ts +22 -9
- package/src/internal/routes/providers/symbiosis.ts +13 -47
- package/src/providers/index.test.ts +2 -0
- package/src/providers/index.ts +18 -0
- package/dist/admin/Access.d.ts +0 -39
- package/dist/admin/Access.d.ts.map +0 -1
- package/dist/admin/Access.js +0 -73
- package/dist/admin/Access.js.map +0 -1
- package/src/admin/Access.test.ts +0 -130
- package/src/admin/Access.ts +0 -85
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { Address } from 'ox'
|
|
2
2
|
import * as z from 'zod/mini'
|
|
3
3
|
|
|
4
|
+
import * as Store from '../../Store.js'
|
|
4
5
|
import * as RoutesChain from '../Chain.js'
|
|
5
6
|
import * as RoutesProvider from '../Provider.js'
|
|
7
|
+
import * as ProviderQuota from '../Quota.js'
|
|
6
8
|
|
|
7
9
|
const defaultBaseUrl = 'https://v2.api.squidrouter.com/v2'
|
|
8
10
|
const defaultFetch: RoutesProvider.Fetch = (input, init) => globalThis.fetch(input, init)
|
|
11
|
+
// Squid documents 10 req/s across all endpoints for one integrator ID:
|
|
12
|
+
// https://docs.squidrouter.com/api-and-sdk-integration/api/rate-limiting
|
|
13
|
+
const rateLimit = 10
|
|
14
|
+
const rateLimitWindowMs = 1_000
|
|
15
|
+
const quotaStoreKey = 'routes:squid:integrator'
|
|
9
16
|
|
|
10
17
|
namespace schema {
|
|
11
18
|
const IntegerString = z.string().check(z.regex(/^\d+$/))
|
|
@@ -45,6 +52,7 @@ export function squid(options: squid.Options) {
|
|
|
45
52
|
endpoint.pathname = `${endpoint.pathname.replace(/\/+$/, '')}/route`
|
|
46
53
|
const fetch = options.fetch ?? defaultFetch
|
|
47
54
|
const now = options.now ?? (() => new Date())
|
|
55
|
+
const rateLimitStore = options.rateLimitStore ?? Store.memory()
|
|
48
56
|
|
|
49
57
|
return RoutesProvider.from({
|
|
50
58
|
id: 'squid',
|
|
@@ -53,6 +61,12 @@ export function squid(options: squid.Options) {
|
|
|
53
61
|
const destinationChainId = RoutesChain.eip155Id(route.destination.chain)
|
|
54
62
|
const sourceChainId = RoutesChain.eip155Id(route.source.chain)
|
|
55
63
|
try {
|
|
64
|
+
await ProviderQuota.consume(rateLimitStore, {
|
|
65
|
+
key: quotaStoreKey,
|
|
66
|
+
limit: rateLimit,
|
|
67
|
+
now: now(),
|
|
68
|
+
windowMs: rateLimitWindowMs,
|
|
69
|
+
})
|
|
56
70
|
const quote = await RoutesProvider.requestJson(endpoint, {
|
|
57
71
|
body: {
|
|
58
72
|
fromAddress: options.userAddress,
|
|
@@ -97,6 +111,11 @@ export function squid(options: squid.Options) {
|
|
|
97
111
|
status: 'available',
|
|
98
112
|
}
|
|
99
113
|
} catch (cause) {
|
|
114
|
+
await ProviderQuota.blockOnRateLimit(rateLimitStore, cause, {
|
|
115
|
+
key: quotaStoreKey,
|
|
116
|
+
now: now(),
|
|
117
|
+
windowMs: rateLimitWindowMs,
|
|
118
|
+
})
|
|
100
119
|
const unavailable =
|
|
101
120
|
RoutesProvider.unavailable(cause, [
|
|
102
121
|
'NO_ROUTE',
|
|
@@ -127,6 +146,8 @@ export declare namespace squid {
|
|
|
127
146
|
integratorId: string
|
|
128
147
|
/** Clock override for deterministic tests. */
|
|
129
148
|
now?: (() => Date) | undefined
|
|
149
|
+
/** Atomic store used to enforce the integrator-wide quota. */
|
|
150
|
+
rateLimitStore?: Store.Store | undefined
|
|
130
151
|
/** Quote wallet address used as the Squid sender and recipient. */
|
|
131
152
|
userAddress: string
|
|
132
153
|
}
|
|
@@ -3,12 +3,17 @@ import { base } from 'viem/chains'
|
|
|
3
3
|
import { tempoMainnet } from 'viem/tempo/chains'
|
|
4
4
|
|
|
5
5
|
import * as Anvil from '../../../../test/Anvil.js'
|
|
6
|
+
import * as TestApp from '../../../../test/App.js'
|
|
7
|
+
import * as Containers from '../../../../test/containers.js'
|
|
6
8
|
import * as TestRoutes from '../../../../test/Routes.js'
|
|
9
|
+
import * as RoutesTransfers from '../../../db/tables/routesTransfers.js'
|
|
7
10
|
|
|
8
11
|
import type * as Action from '../Action.js'
|
|
9
12
|
import type * as Catalog from '../Catalog.js'
|
|
10
13
|
import * as RoutesChain from '../Chain.js'
|
|
11
14
|
import * as RoutesProvider from '../Provider.js'
|
|
15
|
+
import * as Policy from '../Policy.js'
|
|
16
|
+
import * as Transfer from '../Transfer.js'
|
|
12
17
|
import * as Stargate from './stargate.js'
|
|
13
18
|
|
|
14
19
|
const amount = 1_000_000n
|
|
@@ -43,6 +48,105 @@ type RpcRequest = {
|
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
describe('stargate', () => {
|
|
51
|
+
test('retains pinned financial identity through real source reorg verification and later billing', async () => {
|
|
52
|
+
const db = TestApp.database()
|
|
53
|
+
const node = await Containers.tempo({ chainId: 8453 })
|
|
54
|
+
const endpoint = node.endpoints.default
|
|
55
|
+
const sourceChain = RoutesChain.from({
|
|
56
|
+
id: 'eip155:8453',
|
|
57
|
+
name: 'Base',
|
|
58
|
+
slug: 'base',
|
|
59
|
+
rpcUrls: [`http://${endpoint.host}:${endpoint.port}`],
|
|
60
|
+
})
|
|
61
|
+
const destinationChain = TestRoutes.snapshot.chainsByKey.get('eip155:4217')!
|
|
62
|
+
try {
|
|
63
|
+
for (const subsidyPayer of ['tempo', 'enterprise'] as const) {
|
|
64
|
+
const routePolicy = {
|
|
65
|
+
maxAmount: '0.04',
|
|
66
|
+
scope: { environment: 'production', orgId: `org_reorg_${subsidyPayer}` } as const,
|
|
67
|
+
subsidyPayer,
|
|
68
|
+
versions: [1],
|
|
69
|
+
}
|
|
70
|
+
const routePolicyKey = Policy.commitmentKey(routePolicy)
|
|
71
|
+
const providerState = {
|
|
72
|
+
destinationBlockNumber: '0',
|
|
73
|
+
routeConfiguration: { poolAddress: pool },
|
|
74
|
+
routePolicy,
|
|
75
|
+
routePolicyKey,
|
|
76
|
+
// Cached evidence from a block absent from the local canonical chain.
|
|
77
|
+
stargate: {
|
|
78
|
+
guid,
|
|
79
|
+
sourceBlock: { hash: `0x${'aa'.repeat(32)}`, number: '0' },
|
|
80
|
+
sourceEid: 30_184,
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
const record = await Transfer.create(db, {
|
|
84
|
+
apiKeyId: `key_reorg_${subsidyPayer}`,
|
|
85
|
+
environment: 'production',
|
|
86
|
+
orgId: routePolicy.scope.orgId,
|
|
87
|
+
providerState,
|
|
88
|
+
snapshot: TestRoutes.transferSnapshot({
|
|
89
|
+
provider: { id: 'stargate', name: 'Stargate' },
|
|
90
|
+
subsidize: true,
|
|
91
|
+
}),
|
|
92
|
+
})
|
|
93
|
+
const registered = await Transfer.registerSourceTransactions(db, {
|
|
94
|
+
chainId: sourceChain.id,
|
|
95
|
+
id: record.id,
|
|
96
|
+
providerState,
|
|
97
|
+
transactionHashes: [sourceTransactionHash],
|
|
98
|
+
})
|
|
99
|
+
expect(registered.type).toBe('registered')
|
|
100
|
+
const evidence = await Stargate.stargate().verifySourceTransaction!(
|
|
101
|
+
{
|
|
102
|
+
destinationChain,
|
|
103
|
+
providerState,
|
|
104
|
+
sourceChain,
|
|
105
|
+
transactionHash: sourceTransactionHash,
|
|
106
|
+
transfer: record.snapshot,
|
|
107
|
+
},
|
|
108
|
+
new AbortController().signal,
|
|
109
|
+
)
|
|
110
|
+
expect(evidence.type).toBe('reorged')
|
|
111
|
+
if (evidence.type !== 'reorged') throw new Error('Expected canonical source reorg.')
|
|
112
|
+
const reopened = await Transfer.reopenSourceTransaction(db, {
|
|
113
|
+
chainId: sourceChain.id,
|
|
114
|
+
id: record.id,
|
|
115
|
+
providerState: evidence.providerState,
|
|
116
|
+
transactionHash: sourceTransactionHash,
|
|
117
|
+
})
|
|
118
|
+
if (reopened.type !== 'reopened') throw new Error('Expected reopened transfer.')
|
|
119
|
+
expect(reopened.record.providerState).not.toHaveProperty('stargate')
|
|
120
|
+
expect(reopened.record.snapshot.sourceTransactionHashes).toBeUndefined()
|
|
121
|
+
expect.soft(reopened.record.providerState).toMatchObject({ routePolicy, routePolicyKey })
|
|
122
|
+
const replacement = await Transfer.registerSourceTransactions(db, {
|
|
123
|
+
chainId: sourceChain.id,
|
|
124
|
+
id: record.id,
|
|
125
|
+
providerState: reopened.record.providerState!,
|
|
126
|
+
transactionHashes: [`0x${'ab'.repeat(32)}`],
|
|
127
|
+
})
|
|
128
|
+
if (replacement.type !== 'registered') throw new Error('Expected replacement evidence.')
|
|
129
|
+
const completed = await Transfer.transition(db, {
|
|
130
|
+
expectedVersion: replacement.record.version,
|
|
131
|
+
id: record.id,
|
|
132
|
+
status: 'completed',
|
|
133
|
+
subsidyAmount: { baseUnits: '10000', currency: 'USD', decimals: 6, formatted: '0.01' },
|
|
134
|
+
subsidyTransactionHash: `0x${'cd'.repeat(32)}`,
|
|
135
|
+
})
|
|
136
|
+
expect(completed.type).toBe('applied')
|
|
137
|
+
const billable = (await RoutesTransfers.listUnreportedSubsidies(db)).some(
|
|
138
|
+
(row) => row.id === record.id,
|
|
139
|
+
)
|
|
140
|
+
expect.soft(billable).toBe(subsidyPayer === 'enterprise')
|
|
141
|
+
expect
|
|
142
|
+
.soft(await RoutesTransfers.hasUnreportedSubsidies(db, record.orgId))
|
|
143
|
+
.toBe(subsidyPayer === 'enterprise')
|
|
144
|
+
}
|
|
145
|
+
} finally {
|
|
146
|
+
await node.stop()
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
46
150
|
test('creates a credential-free quote and transfer provider', () => {
|
|
47
151
|
expect(Stargate.stargate()).toMatchObject({
|
|
48
152
|
getQuote: expect.any(Function),
|
|
@@ -601,7 +705,7 @@ describe.skipIf(!Anvil.available)('source and destination evidence', () => {
|
|
|
601
705
|
sourceTokenAddress: destinationToken,
|
|
602
706
|
}),
|
|
603
707
|
).resolves.toEqual({ transactionHash, type: 'verified' })
|
|
604
|
-
expect(blockTag).toBe('
|
|
708
|
+
expect(blockTag).toBe('safe')
|
|
605
709
|
})
|
|
606
710
|
})
|
|
607
711
|
|
|
@@ -62,7 +62,7 @@ const send = AbiFunction.from(
|
|
|
62
62
|
const endpointNativeToken = AbiFunction.from('function nativeToken() view returns (address)')
|
|
63
63
|
const wrap = AbiFunction.from('function wrap(address token, address to, uint256 amount)')
|
|
64
64
|
const quoteTtlMs = 60_000
|
|
65
|
-
const maximumLogBlockRange =
|
|
65
|
+
const maximumLogBlockRange = 2_000n
|
|
66
66
|
const transferEvent = AbiEvent.from(
|
|
67
67
|
'event Transfer(address indexed from, address indexed to, uint256 value)',
|
|
68
68
|
)
|
|
@@ -225,7 +225,10 @@ export function stargate(options: stargate.Options = {}) {
|
|
|
225
225
|
fetch,
|
|
226
226
|
signal,
|
|
227
227
|
urls: resolveRpcUrls(candidate.route.destination.chain),
|
|
228
|
-
}).getBlock({
|
|
228
|
+
}).getBlock({
|
|
229
|
+
blockTag: Chain.settlementBlockTag(candidate.route.destination.chain),
|
|
230
|
+
includeTransactions: false,
|
|
231
|
+
}),
|
|
229
232
|
])
|
|
230
233
|
if (!isValidQuote({ amount: candidate.sourceAmount.amount, feeDetails, limit, receipt }))
|
|
231
234
|
throw new RoutesProvider.ProviderUnavailableError()
|
|
@@ -345,6 +348,7 @@ export function stargate(options: stargate.Options = {}) {
|
|
|
345
348
|
}
|
|
346
349
|
},
|
|
347
350
|
validateTransferAction({ action, candidate, destinationAmountMin, recipient, sender }) {
|
|
351
|
+
if (action.type !== 'evm:calls') throw new RoutesProvider.ProviderPayloadError()
|
|
348
352
|
return validateAction({
|
|
349
353
|
action,
|
|
350
354
|
configuration: candidate.configuration,
|
|
@@ -661,8 +665,11 @@ export async function verifySourceTransaction(
|
|
|
661
665
|
!Hex.isEqual(block.hash, receipt.blockHash)
|
|
662
666
|
) {
|
|
663
667
|
if (!options.sourceBlock) return { type: 'pending' }
|
|
664
|
-
const
|
|
665
|
-
|
|
668
|
+
const head = await rpc.getBlock({
|
|
669
|
+
blockTag: Chain.settlementBlockTag(options.sourceChain),
|
|
670
|
+
includeTransactions: false,
|
|
671
|
+
})
|
|
672
|
+
if (head.number < options.sourceBlock.number) return { type: 'pending' }
|
|
666
673
|
const canonical = await rpc
|
|
667
674
|
.getBlock({ blockNumber: options.sourceBlock.number, includeTransactions: false })
|
|
668
675
|
.catch((cause) => {
|
|
@@ -896,8 +903,11 @@ export async function verifyDestinationDelivery(
|
|
|
896
903
|
signal: options.signal,
|
|
897
904
|
urls: options.rpcUrls ?? options.destinationChain.rpcUrls,
|
|
898
905
|
})
|
|
899
|
-
// Tempo
|
|
900
|
-
const blockTag =
|
|
906
|
+
// Tempo completes at inclusion; other destinations use their chain's settlement threshold.
|
|
907
|
+
const blockTag =
|
|
908
|
+
options.destinationChain.id === 'eip155:4217'
|
|
909
|
+
? 'latest'
|
|
910
|
+
: Chain.settlementBlockTag(options.destinationChain)
|
|
901
911
|
const [chainId, head] = await Promise.all([
|
|
902
912
|
rpc.getChainId(),
|
|
903
913
|
rpc.getBlock({ blockTag, includeTransactions: false }),
|
|
@@ -1018,16 +1028,19 @@ async function blockNumberBefore(options: blockNumberBefore.Options) {
|
|
|
1018
1028
|
signal: options.signal,
|
|
1019
1029
|
urls: options.rpcUrls ?? options.chain.rpcUrls,
|
|
1020
1030
|
})
|
|
1021
|
-
const [chainId,
|
|
1031
|
+
const [chainId, head] = await Promise.all([
|
|
1022
1032
|
rpc.getChainId(),
|
|
1023
|
-
rpc.getBlock({
|
|
1033
|
+
rpc.getBlock({
|
|
1034
|
+
blockTag: Chain.settlementBlockTag(options.chain),
|
|
1035
|
+
includeTransactions: false,
|
|
1036
|
+
}),
|
|
1024
1037
|
])
|
|
1025
1038
|
if (chainId !== Number(Chain.eip155Id(options.chain)))
|
|
1026
1039
|
throw new RoutesProvider.ProviderConfigurationError()
|
|
1027
1040
|
|
|
1028
1041
|
const target = BigInt(Math.floor(timestamp / 1_000) - 1)
|
|
1029
1042
|
let lower = 0n
|
|
1030
|
-
let upper =
|
|
1043
|
+
let upper = head.number
|
|
1031
1044
|
while (lower < upper) {
|
|
1032
1045
|
const middle = (lower + upper + 1n) / 2n
|
|
1033
1046
|
const block = await rpc.getBlock({ blockNumber: middle, includeTransactions: false })
|
|
@@ -4,6 +4,7 @@ import * as z from 'zod/mini'
|
|
|
4
4
|
import * as Store from '../../Store.js'
|
|
5
5
|
import * as RoutesChain from '../Chain.js'
|
|
6
6
|
import * as RoutesProvider from '../Provider.js'
|
|
7
|
+
import * as ProviderQuota from '../Quota.js'
|
|
7
8
|
import type * as RoutesToken from '../Token.js'
|
|
8
9
|
|
|
9
10
|
const defaultBaseUrl = 'https://api.symbiosis.finance/crosschain'
|
|
@@ -17,22 +18,6 @@ const quotaStoreKey = 'routes:symbiosis:quote'
|
|
|
17
18
|
const tronChainId = 728_126_428
|
|
18
19
|
const tronUsdtAddress = '0xa614f803b6fd780986a42c78ec9c7f77e6ded13c'
|
|
19
20
|
|
|
20
|
-
type TenantQuota = {
|
|
21
|
-
/** Requests accepted for this tenant in the active window. */
|
|
22
|
-
count: number
|
|
23
|
-
/** Stable non-secret tenant identity. */
|
|
24
|
-
key: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
type Quota = {
|
|
28
|
-
/** Fixed-window number. */
|
|
29
|
-
bucket: number
|
|
30
|
-
/** Requests accepted globally in the active window. */
|
|
31
|
-
count: number
|
|
32
|
-
/** Per-tenant counters for accepted requests. */
|
|
33
|
-
tenants: readonly TenantQuota[]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
21
|
namespace schema {
|
|
37
22
|
const IntegerString = z.string().check(z.regex(/^\d+$/))
|
|
38
23
|
|
|
@@ -84,7 +69,13 @@ export function symbiosis(options: symbiosis.Options) {
|
|
|
84
69
|
const sourceChainId = chainId(route.source.chain)
|
|
85
70
|
const sourceTokenAddress = tokenAddress(route.source)
|
|
86
71
|
try {
|
|
87
|
-
await
|
|
72
|
+
await ProviderQuota.consume(rateLimitStore, {
|
|
73
|
+
key: quotaStoreKey,
|
|
74
|
+
limit: rateLimit,
|
|
75
|
+
now: now(),
|
|
76
|
+
tenant: { key: quotaKey ?? 'public:anonymous', limit: tenantRateLimit },
|
|
77
|
+
windowMs: rateLimitWindowMs,
|
|
78
|
+
})
|
|
88
79
|
const quote = await RoutesProvider.requestJson(endpoint, {
|
|
89
80
|
body: {
|
|
90
81
|
from: options.userAddress,
|
|
@@ -159,6 +150,11 @@ export function symbiosis(options: symbiosis.Options) {
|
|
|
159
150
|
status: 'available',
|
|
160
151
|
}
|
|
161
152
|
} catch (cause) {
|
|
153
|
+
await ProviderQuota.blockOnRateLimit(rateLimitStore, cause, {
|
|
154
|
+
key: quotaStoreKey,
|
|
155
|
+
now: now(),
|
|
156
|
+
windowMs: rateLimitWindowMs,
|
|
157
|
+
})
|
|
162
158
|
const unavailable =
|
|
163
159
|
RoutesProvider.unavailable(cause, [
|
|
164
160
|
'AMOUNT_TOO_LOW',
|
|
@@ -195,36 +191,6 @@ export declare namespace symbiosis {
|
|
|
195
191
|
}
|
|
196
192
|
}
|
|
197
193
|
|
|
198
|
-
async function consumeQuota(store: Store.Store, options: consumeQuota.Options) {
|
|
199
|
-
const time = options.now.getTime()
|
|
200
|
-
const bucket = Math.floor(time / rateLimitWindowMs)
|
|
201
|
-
await Store.update(store, quotaStoreKey, (current) => {
|
|
202
|
-
const stored = current === null ? undefined : (JSON.parse(current) as Quota)
|
|
203
|
-
const activeBucket = Math.max(bucket, stored?.bucket ?? bucket)
|
|
204
|
-
const quota: Quota =
|
|
205
|
-
stored?.bucket === activeBucket ? stored : { bucket: activeBucket, count: 0, tenants: [] }
|
|
206
|
-
const tenant = quota.tenants.find((entry) => entry.key === options.quotaKey)
|
|
207
|
-
if ((tenant?.count ?? 0) >= tenantRateLimit || quota.count >= rateLimit)
|
|
208
|
-
throw new RoutesProvider.ProviderRateLimitError()
|
|
209
|
-
const tenants = tenant
|
|
210
|
-
? quota.tenants.map((entry) =>
|
|
211
|
-
entry.key === options.quotaKey ? { count: entry.count + 1, key: entry.key } : entry,
|
|
212
|
-
)
|
|
213
|
-
: [...quota.tenants, { count: 1, key: options.quotaKey }]
|
|
214
|
-
return JSON.stringify({ bucket: activeBucket, count: quota.count + 1, tenants })
|
|
215
|
-
})
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
declare namespace consumeQuota {
|
|
219
|
-
/** Tenant identity and wall clock for one quota decision. */
|
|
220
|
-
type Options = {
|
|
221
|
-
/** Current quota time. */
|
|
222
|
-
now: Date
|
|
223
|
-
/** Stable non-secret tenant identity. */
|
|
224
|
-
quotaKey: string
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
194
|
function amountUnavailable(cause: unknown) {
|
|
229
195
|
if (!(cause instanceof RoutesProvider.ProviderResponseError) || cause.status !== 400)
|
|
230
196
|
return undefined
|
package/src/providers/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as Uniswap from '../internal/exchange/providers/uniswap.js'
|
|
2
2
|
import * as Across from '../internal/routes/providers/across.js'
|
|
3
|
+
import * as LegacyMesh from '../internal/routes/providers/legacyMesh.js'
|
|
4
|
+
import * as PropAmm from '../internal/routes/providers/propAmm.js'
|
|
3
5
|
import * as Relay from '../internal/routes/providers/relay.js'
|
|
4
6
|
import * as Rhino from '../internal/routes/providers/rhino.js'
|
|
5
7
|
import * as Squid from '../internal/routes/providers/squid.js'
|
|
@@ -14,6 +16,22 @@ export declare namespace across {
|
|
|
14
16
|
type Options = Across.across.Options
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
/** Creates a Tron to Tempo USDT0 Legacy Mesh route provider. */
|
|
20
|
+
export const legacyMesh = LegacyMesh.legacyMesh
|
|
21
|
+
|
|
22
|
+
export declare namespace legacyMesh {
|
|
23
|
+
/** Legacy Mesh provider configuration. */
|
|
24
|
+
type Options = LegacyMesh.legacyMesh.Options
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Creates a same-chain PropAMM quote and transfer preparation provider. */
|
|
28
|
+
export const propAmm = PropAmm.propAmm
|
|
29
|
+
|
|
30
|
+
export declare namespace propAmm {
|
|
31
|
+
/** PropAMM provider configuration. */
|
|
32
|
+
type Options = PropAmm.propAmm.Options
|
|
33
|
+
}
|
|
34
|
+
|
|
17
35
|
/** Creates a Relay route provider. */
|
|
18
36
|
export const relay = Relay.relay
|
|
19
37
|
|
package/dist/admin/Access.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The default {@link App.create.Options.identify} hook: verifies a Cloudflare
|
|
3
|
-
* Access JWT in-worker, so a request sent directly to the worker URL (bypassing
|
|
4
|
-
* the edge gate) still can't reach the admin routes (defense in depth).
|
|
5
|
-
*
|
|
6
|
-
* The only admin module that imports `jose`, keeping that dependency out of the
|
|
7
|
-
* IdP-agnostic core. Self-hosters not on Access supply their own `identify`.
|
|
8
|
-
*/
|
|
9
|
-
import type * as App from './App.js';
|
|
10
|
-
/**
|
|
11
|
-
* Builds an {@link App.create.Options.identify} hook that verifies the Cloudflare
|
|
12
|
-
* Access JWT against the team-domain JWKS (fetched lazily, cached by `jose`). Any
|
|
13
|
-
* verification failure resolves to `null` (deny) rather than throwing.
|
|
14
|
-
*
|
|
15
|
-
* Verifies the signature and issuer (the team domain). The audience (`aud`) is
|
|
16
|
-
* not checked, so any token minted for any app in the team's org is accepted —
|
|
17
|
-
* fine when everyone with org access is trusted.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* import { App, Access } from 'tapimo/admin'
|
|
22
|
-
*
|
|
23
|
-
* App.create({
|
|
24
|
-
* // ...
|
|
25
|
-
* identify: Access.cloudflareAccess({
|
|
26
|
-
* teamDomain: 'https://tempo.cloudflareaccess.com',
|
|
27
|
-
* }),
|
|
28
|
-
* })
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export declare function cloudflareAccess(options: cloudflareAccess.Options): (request: Request) => Promise<App.Identity | null>;
|
|
32
|
-
export declare namespace cloudflareAccess {
|
|
33
|
-
/** Options for {@link cloudflareAccess}. */
|
|
34
|
-
type Options = {
|
|
35
|
-
/** Team domain (e.g. `https://<team>.cloudflareaccess.com`); the token issuer and JWKS host. */
|
|
36
|
-
teamDomain: string;
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
//# sourceMappingURL=Access.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Access.d.ts","sourceRoot":"","sources":["../../src/admin/Access.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAA;AAOpC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,CAAC,OAAO,GAChC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,CAmBpD;AAED,MAAM,CAAC,OAAO,WAAW,gBAAgB,CAAC;IACxC,4CAA4C;IAC5C,KAAK,OAAO,GAAG;QACb,gGAAgG;QAChG,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;CACF"}
|
package/dist/admin/Access.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The default {@link App.create.Options.identify} hook: verifies a Cloudflare
|
|
3
|
-
* Access JWT in-worker, so a request sent directly to the worker URL (bypassing
|
|
4
|
-
* the edge gate) still can't reach the admin routes (defense in depth).
|
|
5
|
-
*
|
|
6
|
-
* The only admin module that imports `jose`, keeping that dependency out of the
|
|
7
|
-
* IdP-agnostic core. Self-hosters not on Access supply their own `identify`.
|
|
8
|
-
*/
|
|
9
|
-
import * as jose from 'jose';
|
|
10
|
-
/** Header Cloudflare Access sets with the signed identity assertion (a JWT). */
|
|
11
|
-
const headerName = 'cf-access-jwt-assertion';
|
|
12
|
-
/** Cookie Cloudflare Access sets as a fallback carrier for the same JWT. */
|
|
13
|
-
const cookieName = 'CF_Authorization';
|
|
14
|
-
/**
|
|
15
|
-
* Builds an {@link App.create.Options.identify} hook that verifies the Cloudflare
|
|
16
|
-
* Access JWT against the team-domain JWKS (fetched lazily, cached by `jose`). Any
|
|
17
|
-
* verification failure resolves to `null` (deny) rather than throwing.
|
|
18
|
-
*
|
|
19
|
-
* Verifies the signature and issuer (the team domain). The audience (`aud`) is
|
|
20
|
-
* not checked, so any token minted for any app in the team's org is accepted —
|
|
21
|
-
* fine when everyone with org access is trusted.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```ts
|
|
25
|
-
* import { App, Access } from 'tapimo/admin'
|
|
26
|
-
*
|
|
27
|
-
* App.create({
|
|
28
|
-
* // ...
|
|
29
|
-
* identify: Access.cloudflareAccess({
|
|
30
|
-
* teamDomain: 'https://tempo.cloudflareaccess.com',
|
|
31
|
-
* }),
|
|
32
|
-
* })
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export function cloudflareAccess(options) {
|
|
36
|
-
const { teamDomain } = options;
|
|
37
|
-
// Created once and reused: `jose` caches keys and refetches on unknown `kid`.
|
|
38
|
-
const issuer = teamDomain.replace(/\/+$/, '');
|
|
39
|
-
const jwks = jose.createRemoteJWKSet(new URL(`${issuer}/cdn-cgi/access/certs`));
|
|
40
|
-
return async (request) => {
|
|
41
|
-
const token = readToken(request);
|
|
42
|
-
if (!token)
|
|
43
|
-
return null;
|
|
44
|
-
try {
|
|
45
|
-
const { payload } = await jose.jwtVerify(token, jwks, { issuer });
|
|
46
|
-
const email = payload['email'];
|
|
47
|
-
return typeof email === 'string' && email ? { email } : null;
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
// Any verification failure is a denial, not an error to surface.
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Extracts the Access JWT: the `Cf-Access-Jwt-Assertion` header, falling back to
|
|
57
|
-
* the `CF_Authorization` cookie. Returns `undefined` when neither is present.
|
|
58
|
-
*/
|
|
59
|
-
function readToken(request) {
|
|
60
|
-
const header = request.headers.get(headerName);
|
|
61
|
-
if (header)
|
|
62
|
-
return header;
|
|
63
|
-
const cookie = request.headers.get('cookie');
|
|
64
|
-
if (!cookie)
|
|
65
|
-
return undefined;
|
|
66
|
-
for (const part of cookie.split(';')) {
|
|
67
|
-
const [name, ...rest] = part.trim().split('=');
|
|
68
|
-
if (name === cookieName && rest.length)
|
|
69
|
-
return rest.join('=');
|
|
70
|
-
}
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
//# sourceMappingURL=Access.js.map
|
package/dist/admin/Access.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Access.js","sourceRoot":"","sources":["../../src/admin/Access.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAI5B,gFAAgF;AAChF,MAAM,UAAU,GAAG,yBAAyB,CAAA;AAC5C,4EAA4E;AAC5E,MAAM,UAAU,GAAG,kBAAkB,CAAA;AAErC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAiC;IAEjC,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAA;IAE9B,8EAA8E;IAC9E,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,GAAG,MAAM,uBAAuB,CAAC,CAAC,CAAA;IAE/E,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;QAChC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,IAAI,CAAC;YACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;YACjE,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;YAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;YACjE,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAUD;;;GAGG;AACH,SAAS,SAAS,CAAC,OAAgB;IACjC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IAC9C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAA;IACzB,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC5C,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAA;IAC7B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC9C,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
|
package/src/admin/Access.test.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import * as jose from 'jose'
|
|
2
|
-
|
|
3
|
-
import * as Access from './Access.js'
|
|
4
|
-
|
|
5
|
-
const teamDomain = 'https://tempo.cloudflareaccess.com'
|
|
6
|
-
const certsUrl = `${teamDomain}/cdn-cgi/access/certs`
|
|
7
|
-
const kid = 'test-key-1'
|
|
8
|
-
|
|
9
|
-
/** Generates an ES256 keypair and the JWKS the team domain would serve. */
|
|
10
|
-
async function makeKeys() {
|
|
11
|
-
const { privateKey, publicKey } = await jose.generateKeyPair('ES256', { extractable: true })
|
|
12
|
-
const jwk = { ...(await jose.exportJWK(publicKey)), kid }
|
|
13
|
-
return { jwks: { keys: [jwk] }, privateKey }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Signs an Access-style JWT with the given claims/overrides. */
|
|
17
|
-
async function sign(
|
|
18
|
-
privateKey: jose.CryptoKey,
|
|
19
|
-
options: {
|
|
20
|
-
audience?: string | undefined
|
|
21
|
-
email?: string | undefined
|
|
22
|
-
expirationTime?: string | number | undefined
|
|
23
|
-
issuer?: string | undefined
|
|
24
|
-
} = {},
|
|
25
|
-
) {
|
|
26
|
-
const payload = options.email === undefined ? {} : { email: options.email }
|
|
27
|
-
return new jose.SignJWT(payload)
|
|
28
|
-
.setProtectedHeader({ alg: 'ES256', kid })
|
|
29
|
-
.setIssuer(options.issuer ?? teamDomain)
|
|
30
|
-
.setAudience(options.audience ?? 'test-access-aud-tag')
|
|
31
|
-
.setIssuedAt()
|
|
32
|
-
.setExpirationTime(options.expirationTime ?? '1h')
|
|
33
|
-
.sign(privateKey)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
describe('cloudflareAccess', () => {
|
|
37
|
-
let privateKey: jose.CryptoKey
|
|
38
|
-
let jwks: { keys: readonly unknown[] }
|
|
39
|
-
|
|
40
|
-
beforeEach(async () => {
|
|
41
|
-
;({ jwks, privateKey } = await makeKeys())
|
|
42
|
-
// Serve the public JWKS from the team-domain certs URL.
|
|
43
|
-
vi.stubGlobal(
|
|
44
|
-
'fetch',
|
|
45
|
-
vi.fn(async (input: string | URL | Request) => {
|
|
46
|
-
const url =
|
|
47
|
-
typeof input === 'string' ? input : input instanceof URL ? input.href : input.url
|
|
48
|
-
if (url === certsUrl) return new Response(JSON.stringify(jwks))
|
|
49
|
-
throw new Error(`unexpected fetch: ${url}`)
|
|
50
|
-
}),
|
|
51
|
-
)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
afterEach(() => {
|
|
55
|
-
vi.unstubAllGlobals()
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('valid JWT in header → identity', async () => {
|
|
59
|
-
const identify = Access.cloudflareAccess({ teamDomain })
|
|
60
|
-
const token = await sign(privateKey, { email: 'admin@tempo.xyz' })
|
|
61
|
-
const request = new Request('https://admin.tempo.xyz/api-keys', {
|
|
62
|
-
headers: { 'cf-access-jwt-assertion': token },
|
|
63
|
-
})
|
|
64
|
-
expect(await identify(request)).toEqual({ email: 'admin@tempo.xyz' })
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('valid JWT in CF_Authorization cookie → identity', async () => {
|
|
68
|
-
const identify = Access.cloudflareAccess({ teamDomain })
|
|
69
|
-
const token = await sign(privateKey, { email: 'admin@tempo.xyz' })
|
|
70
|
-
const request = new Request('https://admin.tempo.xyz/api-keys', {
|
|
71
|
-
headers: { cookie: `foo=bar; CF_Authorization=${token}` },
|
|
72
|
-
})
|
|
73
|
-
expect(await identify(request)).toEqual({ email: 'admin@tempo.xyz' })
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('missing assertion → null', async () => {
|
|
77
|
-
const identify = Access.cloudflareAccess({ teamDomain })
|
|
78
|
-
const request = new Request('https://admin.tempo.xyz/api-keys')
|
|
79
|
-
expect(await identify(request)).toBeNull()
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('any audience accepted (issuer still enforced)', async () => {
|
|
83
|
-
const identify = Access.cloudflareAccess({ teamDomain })
|
|
84
|
-
const token = await sign(privateKey, { audience: 'some-other-aud', email: 'admin@tempo.xyz' })
|
|
85
|
-
const request = new Request('https://admin.tempo.xyz/api-keys', {
|
|
86
|
-
headers: { 'cf-access-jwt-assertion': token },
|
|
87
|
-
})
|
|
88
|
-
expect(await identify(request)).toEqual({ email: 'admin@tempo.xyz' })
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
test('wrong issuer → null', async () => {
|
|
92
|
-
const identify = Access.cloudflareAccess({ teamDomain })
|
|
93
|
-
const token = await sign(privateKey, {
|
|
94
|
-
email: 'admin@tempo.xyz',
|
|
95
|
-
issuer: 'https://evil.cloudflareaccess.com',
|
|
96
|
-
})
|
|
97
|
-
const request = new Request('https://admin.tempo.xyz/api-keys', {
|
|
98
|
-
headers: { 'cf-access-jwt-assertion': token },
|
|
99
|
-
})
|
|
100
|
-
expect(await identify(request)).toBeNull()
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
test('expired JWT → null', async () => {
|
|
104
|
-
const identify = Access.cloudflareAccess({ teamDomain })
|
|
105
|
-
const token = await sign(privateKey, { email: 'admin@tempo.xyz', expirationTime: '-1h' })
|
|
106
|
-
const request = new Request('https://admin.tempo.xyz/api-keys', {
|
|
107
|
-
headers: { 'cf-access-jwt-assertion': token },
|
|
108
|
-
})
|
|
109
|
-
expect(await identify(request)).toBeNull()
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
test('valid signature but no email claim → null', async () => {
|
|
113
|
-
const identify = Access.cloudflareAccess({ teamDomain })
|
|
114
|
-
const token = await sign(privateKey)
|
|
115
|
-
const request = new Request('https://admin.tempo.xyz/api-keys', {
|
|
116
|
-
headers: { 'cf-access-jwt-assertion': token },
|
|
117
|
-
})
|
|
118
|
-
expect(await identify(request)).toBeNull()
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
test('signature from an unknown key → null', async () => {
|
|
122
|
-
const identify = Access.cloudflareAccess({ teamDomain })
|
|
123
|
-
const other = await makeKeys()
|
|
124
|
-
const token = await sign(other.privateKey, { email: 'admin@tempo.xyz' })
|
|
125
|
-
const request = new Request('https://admin.tempo.xyz/api-keys', {
|
|
126
|
-
headers: { 'cf-access-jwt-assertion': token },
|
|
127
|
-
})
|
|
128
|
-
expect(await identify(request)).toBeNull()
|
|
129
|
-
})
|
|
130
|
-
})
|