tapimo 0.15.0 → 0.18.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/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 +896 -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 +33 -33
- 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 +454 -1
- 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 +10 -4
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.js +24 -4
- package/dist/admin/apps/verified-tokens.js.map +1 -1
- 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 +99 -103
- 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 +5 -5
- 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/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 +1 -19
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +93 -56
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +10 -10
- package/dist/apps/data/routes/rpc.d.ts +30 -30
- package/dist/apps/data/routes/rpc.js +45 -11
- package/dist/apps/data/routes/rpc.js.map +1 -1
- 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 +12 -12
- package/dist/apps/data/routes/valuation.d.ts +30 -30
- package/dist/apps/data/routes/verified-tokens.d.ts +5 -5
- package/dist/apps/data/routes/webhooks.d.ts +1 -1
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +18 -11
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +3 -3
- package/dist/apps/management/App.d.ts +3043 -2198
- 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 +16 -4
- 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 +24 -24
- package/dist/apps/management/routes/invite-links.d.ts +66 -66
- package/dist/apps/management/routes/members.d.ts +16 -16
- package/dist/apps/management/routes/orgs.d.ts +20 -20
- 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 +76 -76
- package/dist/apps/management/routes/usage.d.ts +8 -8
- package/dist/apps/management/routes/verified-token-requests.d.ts +42 -42
- package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.js +7 -9
- package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
- package/dist/apps/management/routes/webhooks.d.ts +119 -119
- package/dist/apps/mcp.d.ts.map +1 -1
- package/dist/apps/mcp.js +16 -3
- package/dist/apps/mcp.js.map +1 -1
- 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/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 +90 -0
- 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 +187 -135
- 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 +418 -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/db/tables/verifiedTokenRequests.d.ts +21 -4
- package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -1
- package/dist/db/tables/verifiedTokenRequests.js +65 -44
- package/dist/db/tables/verifiedTokenRequests.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 +73 -6
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +212 -85
- 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 +4 -1
- package/dist/internal/routes/providers/relay.d.ts.map +1 -1
- package/dist/internal/routes/providers/relay.js +353 -42
- 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/apps/verified-tokens.test.ts +32 -0
- package/src/admin/apps/verified-tokens.ts +30 -4
- 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/lib/verified-tokens.ts +24 -9
- package/src/admin/ui/src/routeTree.gen.ts +21 -0
- package/src/admin/ui/src/routes/__root.tsx +1 -1
- 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 +35 -4
- 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 +65 -20
- package/src/admin/ui.generated.ts +99 -104
- 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/App.test.ts +26 -0
- 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 +153 -2
- package/src/apps/data/routes/fee-amm.ts +132 -62
- package/src/apps/data/routes/receipts.test.ts +21 -18
- package/src/apps/data/routes/rpc.test.ts +34 -2
- package/src/apps/data/routes/rpc.ts +47 -10
- 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.scan.test.ts +29 -0
- package/src/apps/data/routes/webhooks.test.ts +18 -3
- package/src/apps/data/routes/webhooks.ts +27 -13
- 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/management/routes/verified-token-requests.test.ts +16 -2
- package/src/apps/management/routes/verified-token-requests.ts +7 -10
- package/src/apps/mcp.test.ts +108 -25
- package/src/apps/mcp.ts +15 -3
- 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 +507 -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 +133 -0
- 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/db/tables/verifiedTokenRequests.test.ts +39 -20
- package/src/db/tables/verifiedTokenRequests.ts +80 -44
- 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 +383 -8
- package/src/internal/Auth.ts +272 -99
- 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 +1299 -18
- package/src/internal/routes/providers/relay.ts +424 -39
- 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
|
@@ -7,6 +7,7 @@ import * as ApiKey from '../../../ApiKey.js'
|
|
|
7
7
|
import * as ApiKeys from '../../../ApiKeys.js'
|
|
8
8
|
import type * as App from '../../../App.js'
|
|
9
9
|
import * as Db from '../../../db/Db.js'
|
|
10
|
+
import * as RoutesPolicies from '../../../db/tables/routesPolicies.js'
|
|
10
11
|
import * as Auth from '../../../internal/Auth.js'
|
|
11
12
|
import * as Billing from '../Billing.js'
|
|
12
13
|
import * as OpenApi from '../../../internal/OpenApi.js'
|
|
@@ -84,7 +85,7 @@ export namespace schema {
|
|
|
84
85
|
.array(z.string().check(z.minLength(1)))
|
|
85
86
|
.check(
|
|
86
87
|
z.describe(
|
|
87
|
-
"Granted scopes. '*'
|
|
88
|
+
"Granted scopes. '*' requires the super admin; a CLI can derive Routes writes from a provisioned project key.",
|
|
88
89
|
),
|
|
89
90
|
z.meta({ examples: [['data:read']] }),
|
|
90
91
|
),
|
|
@@ -205,6 +206,14 @@ export namespace schema {
|
|
|
205
206
|
z.describe('Unique scopes to grant.'),
|
|
206
207
|
z.meta({ examples: [['data:read']] }),
|
|
207
208
|
),
|
|
209
|
+
sourceKeyId: z.optional(
|
|
210
|
+
z
|
|
211
|
+
.string()
|
|
212
|
+
.check(
|
|
213
|
+
z.describe('Approved project key to derive a scoped CLI credential from.'),
|
|
214
|
+
z.meta({ examples: ['key_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
|
|
215
|
+
),
|
|
216
|
+
),
|
|
208
217
|
})
|
|
209
218
|
.check(z.describe('Fields for minting an API key.')),
|
|
210
219
|
'CreateApiKeyRequest',
|
|
@@ -384,6 +393,7 @@ export function apiKeys(options: apiKeys.Options = {}) {
|
|
|
384
393
|
if (!kv) return notEnabled(c)
|
|
385
394
|
const createdBy = mintedBy(c)
|
|
386
395
|
if (!createdBy) return ManagementError.sessionRequired(c)
|
|
396
|
+
const principal = Auth.getPrincipal(c)
|
|
387
397
|
|
|
388
398
|
const body = c.req.valid('json')
|
|
389
399
|
|
|
@@ -395,7 +405,23 @@ export function apiKeys(options: apiKeys.Options = {}) {
|
|
|
395
405
|
})
|
|
396
406
|
|
|
397
407
|
// Session issuers are limited to the finite self-serve catalog, so uniqueness bounds the vector without a new policy cap.
|
|
398
|
-
|
|
408
|
+
const source =
|
|
409
|
+
body.sourceKeyId && principal?.type === 'session' && principal.cli
|
|
410
|
+
? await ApiKeys.get(kv.store, body.sourceKeyId, { scopeCatalog: c.get('scopeCatalog') })
|
|
411
|
+
: undefined
|
|
412
|
+
if (
|
|
413
|
+
body.sourceKeyId &&
|
|
414
|
+
(!source ||
|
|
415
|
+
source.orgId !== Auth.org(c).id ||
|
|
416
|
+
source.projectId !== Auth.project(c).id ||
|
|
417
|
+
source.environment !== body.environment)
|
|
418
|
+
)
|
|
419
|
+
return Response.error(c, {
|
|
420
|
+
code: 'scope_not_issuable',
|
|
421
|
+
message: 'Select an approved API key from this project and environment.',
|
|
422
|
+
status: 403,
|
|
423
|
+
})
|
|
424
|
+
if (!canIssue(c, body.scopes, source ?? undefined))
|
|
399
425
|
return Response.error(c, {
|
|
400
426
|
code: 'scope_not_issuable',
|
|
401
427
|
message: 'The requested scopes are not issuable.',
|
|
@@ -416,14 +442,27 @@ export function apiKeys(options: apiKeys.Options = {}) {
|
|
|
416
442
|
{
|
|
417
443
|
createdBy,
|
|
418
444
|
environment: body.environment,
|
|
419
|
-
...(
|
|
445
|
+
...(principal?.type === 'session' && principal.cli
|
|
446
|
+
? { expiresAt: principal.cli.expiresAt }
|
|
447
|
+
: {}),
|
|
448
|
+
...(!source && body.allowedIps !== undefined ? { allowedIps: body.allowedIps } : {}),
|
|
420
449
|
...(billingActive === undefined ? {} : { billingActive }),
|
|
421
450
|
...(body.name === undefined ? {} : { name: body.name }),
|
|
422
451
|
orgId,
|
|
423
452
|
projectId: Auth.project(c).id,
|
|
424
453
|
scopes: body.scopes,
|
|
425
454
|
},
|
|
426
|
-
{
|
|
455
|
+
{
|
|
456
|
+
...(source
|
|
457
|
+
? {
|
|
458
|
+
policySourceApiKeyId: source.id,
|
|
459
|
+
sourceScopes: body.scopes.filter(
|
|
460
|
+
(scope) => !Scope.selfServeFrom(c.get('scopeCatalog')).includes(scope),
|
|
461
|
+
),
|
|
462
|
+
}
|
|
463
|
+
: {}),
|
|
464
|
+
scopeCatalog: c.get('scopeCatalog'),
|
|
465
|
+
},
|
|
427
466
|
)
|
|
428
467
|
return c.json(
|
|
429
468
|
Response.validated(schema.createApiKey.Response, { ...serializeKey(record), token }),
|
|
@@ -432,6 +471,12 @@ export function apiKeys(options: apiKeys.Options = {}) {
|
|
|
432
471
|
} catch (cause) {
|
|
433
472
|
if (cause instanceof ApiKeys.OwnerDeletedError) return Auth.ensureProjectError(c)
|
|
434
473
|
if (cause instanceof ApiKeys.LiveKeyLimitError) return keyLimitReached(c)
|
|
474
|
+
if (cause instanceof RoutesPolicies.InvalidScopeError)
|
|
475
|
+
return Response.error(c, {
|
|
476
|
+
code: 'scope_not_issuable',
|
|
477
|
+
message: 'The approved source key is no longer available.',
|
|
478
|
+
status: 403,
|
|
479
|
+
})
|
|
435
480
|
return Response.upstream(c, cause)
|
|
436
481
|
}
|
|
437
482
|
},
|
|
@@ -637,6 +682,7 @@ export function apiKeys(options: apiKeys.Options = {}) {
|
|
|
637
682
|
})
|
|
638
683
|
return await rotate(c, kv.store, source, createdBy)
|
|
639
684
|
} catch (cause) {
|
|
685
|
+
if (cause instanceof RoutesPolicies.InvalidScopeError) return keyNotFound(c)
|
|
640
686
|
if (cause instanceof ApiKeys.OwnerDeletedError) return Auth.ensureOrgError(c)
|
|
641
687
|
if (cause instanceof ApiKeys.LiveKeyLimitError) return keyLimitReached(c)
|
|
642
688
|
return Response.upstream(c, cause)
|
|
@@ -848,6 +894,7 @@ export function apiKeys(options: apiKeys.Options = {}) {
|
|
|
848
894
|
})
|
|
849
895
|
return await rotate(c, kv.store, source, createdBy)
|
|
850
896
|
} catch (cause) {
|
|
897
|
+
if (cause instanceof RoutesPolicies.InvalidScopeError) return keyNotFound(c)
|
|
851
898
|
if (cause instanceof ApiKeys.OwnerDeletedError) return Auth.ensureProjectError(c)
|
|
852
899
|
if (cause instanceof ApiKeys.LiveKeyLimitError) return keyLimitReached(c)
|
|
853
900
|
return Response.upstream(c, cause)
|
|
@@ -967,14 +1014,27 @@ function mintedBy(c: Context<App.Environment>) {
|
|
|
967
1014
|
}
|
|
968
1015
|
|
|
969
1016
|
/** Checks whether the caller may grant every requested scope. */
|
|
970
|
-
function canIssue(
|
|
1017
|
+
function canIssue(
|
|
1018
|
+
c: Context<App.Environment>,
|
|
1019
|
+
scopes: readonly Scope.Id[],
|
|
1020
|
+
source?: ApiKeys.Record,
|
|
1021
|
+
) {
|
|
971
1022
|
const principal = Auth.getPrincipal(c)
|
|
972
1023
|
if (principal?.type === 'super_admin') return true
|
|
973
1024
|
if (principal?.type === 'session') {
|
|
974
1025
|
const selfServe = Scope.selfServeFrom(c.get('scopeCatalog'))
|
|
975
1026
|
return (
|
|
976
|
-
scopes.every(
|
|
977
|
-
|
|
1027
|
+
scopes.every(
|
|
1028
|
+
(scope) =>
|
|
1029
|
+
selfServe.includes(scope) ||
|
|
1030
|
+
(principal.cli &&
|
|
1031
|
+
source &&
|
|
1032
|
+
scope === 'routes:write' &&
|
|
1033
|
+
(source.scopes.includes(scope) || source.scopes.includes(Scope.wildcard))),
|
|
1034
|
+
) &&
|
|
1035
|
+
(!principal.cli || scopes.every((scope) => principal.cli!.scopes.includes(scope))) &&
|
|
1036
|
+
((!scopes.includes('management:write') && !scopes.includes('routes:write')) ||
|
|
1037
|
+
Auth.membership(c)?.role === 'owner')
|
|
978
1038
|
)
|
|
979
1039
|
}
|
|
980
1040
|
return false
|
|
@@ -986,8 +1046,11 @@ function canRotate(c: Context<App.Environment>, scopes: readonly Scope.Id[]) {
|
|
|
986
1046
|
if (principal?.type === 'super_admin') return true
|
|
987
1047
|
if (principal?.type !== 'session') return false
|
|
988
1048
|
return (
|
|
989
|
-
(!scopes.
|
|
990
|
-
|
|
1049
|
+
(!principal.cli || scopes.every((scope) => principal.cli!.scopes.includes(scope))) &&
|
|
1050
|
+
((!scopes.includes('management:write') &&
|
|
1051
|
+
!scopes.includes('routes:write') &&
|
|
1052
|
+
!scopes.includes(Scope.wildcard)) ||
|
|
1053
|
+
Auth.membership(c)?.role === 'owner')
|
|
991
1054
|
)
|
|
992
1055
|
}
|
|
993
1056
|
|
|
@@ -998,6 +1061,8 @@ async function rotate(
|
|
|
998
1061
|
source: ApiKeys.Record,
|
|
999
1062
|
createdBy: string,
|
|
1000
1063
|
) {
|
|
1064
|
+
const principal = Auth.getPrincipal(c)
|
|
1065
|
+
const expiresAt = principal?.type === 'session' ? principal.cli?.expiresAt : undefined
|
|
1001
1066
|
const billingActive =
|
|
1002
1067
|
source.environment === 'sandbox'
|
|
1003
1068
|
? await Billing.active(Db.get(c.get('db')), source.orgId, 'sandbox')
|
|
@@ -1013,11 +1078,20 @@ async function rotate(
|
|
|
1013
1078
|
...(source.projectId === undefined ? {} : { projectId: source.projectId }),
|
|
1014
1079
|
scopes: [...new Set(source.scopes)],
|
|
1015
1080
|
...(billingActive === undefined ? {} : { billingActive }),
|
|
1016
|
-
...(
|
|
1081
|
+
...(expiresAt || source.expiresAt
|
|
1082
|
+
? {
|
|
1083
|
+
expiresAt: [expiresAt, source.expiresAt]
|
|
1084
|
+
.filter(Boolean)
|
|
1085
|
+
.sort((a, b) => Date.parse(a!) - Date.parse(b!))[0]!,
|
|
1086
|
+
}
|
|
1087
|
+
: {}),
|
|
1017
1088
|
...(source.name === undefined ? {} : { name: source.name }),
|
|
1018
1089
|
...(source.rateLimits === undefined ? {} : { rateLimits: source.rateLimits }),
|
|
1019
1090
|
},
|
|
1020
|
-
{
|
|
1091
|
+
{
|
|
1092
|
+
policySourceApiKeyId: source.id,
|
|
1093
|
+
scopeCatalog: c.get('scopeCatalog'),
|
|
1094
|
+
},
|
|
1021
1095
|
)
|
|
1022
1096
|
return c.json(
|
|
1023
1097
|
Response.validated(schema.rotateApiKey.Response, { ...serializeKey(record), token }),
|
|
@@ -1636,16 +1636,18 @@ describe.runIf(TestStripe.secretKey)('stripe sandbox (metering)', () => {
|
|
|
1636
1636
|
const finalize = async (input: { feeAmount: string; orgId: string; seed: string }) => {
|
|
1637
1637
|
const row = await SponsoredTransactions.upsert(db, { ...meterable(input.orgId), signPayload: `0x${input.seed.repeat(32)}` }) // prettier-ignore
|
|
1638
1638
|
await SponsoredTransactions.finalize(db, row.id, { feeAmount: input.feeAmount, finalizedAt: new Date().toISOString() }) // prettier-ignore
|
|
1639
|
+
return row
|
|
1639
1640
|
}
|
|
1640
1641
|
await finalize({ feeAmount: '100000', orgId: 'org_1', seed: '41' })
|
|
1641
1642
|
await finalize({ feeAmount: '250000', orgId: 'org_1', seed: '42' })
|
|
1642
|
-
// A
|
|
1643
|
-
await finalize({ feeAmount: '900000', orgId: 'org_ghost', seed: '43' })
|
|
1643
|
+
// A missing customer's liability stays unreported for retry; a pending row waits.
|
|
1644
|
+
const ghost = await finalize({ feeAmount: '900000', orgId: 'org_ghost', seed: '43' })
|
|
1644
1645
|
await SponsoredTransactions.upsert(db, { ...meterable('org_1'), signPayload: `0x${'44'.repeat(32)}` }) // prettier-ignore
|
|
1645
1646
|
|
|
1646
1647
|
const reporter = core_Billing.createReporter({ db, stripe })
|
|
1647
|
-
expect(await reporter.tick()).toStrictEqual({ failed:
|
|
1648
|
-
expect(await reporter.tick()).toStrictEqual({ failed:
|
|
1648
|
+
expect(await reporter.tick()).toStrictEqual({ failed: 1, reported: 2, skipped: 0 })
|
|
1649
|
+
expect(await reporter.tick()).toStrictEqual({ failed: 1, reported: 0, skipped: 0 })
|
|
1650
|
+
expect((await SponsoredTransactions.get(db, ghost.id))?.meterReportedAt).toBeNull()
|
|
1649
1651
|
})
|
|
1650
1652
|
|
|
1651
1653
|
test('the metered invoice preview matches reported spend', { timeout: 240_000 }, async () => {
|
|
@@ -1689,6 +1691,68 @@ describe.runIf(TestStripe.secretKey)('stripe sandbox (metering)', () => {
|
|
|
1689
1691
|
expect(line?.amount).toBe(35)
|
|
1690
1692
|
})
|
|
1691
1693
|
|
|
1694
|
+
test.each(['request-first', 'sponsorship-first'] as const)(
|
|
1695
|
+
'request backlog reaches the invoice when the %s reporter provisions meters',
|
|
1696
|
+
{ timeout: 240_000 },
|
|
1697
|
+
async (ordering) => {
|
|
1698
|
+
const db = TestApp.database()
|
|
1699
|
+
const stripe = TestStripe.client()
|
|
1700
|
+
const orgId = `org_${nanoid(10)}`
|
|
1701
|
+
const customer = await stripe.customers.create({
|
|
1702
|
+
metadata: { orgId },
|
|
1703
|
+
name: `Test Org ${nanoid(10)}`,
|
|
1704
|
+
})
|
|
1705
|
+
TestStripe.track(customer.id)
|
|
1706
|
+
await StripeCustomers.create(db, { orgId, stripeCustomerId: customer.id })
|
|
1707
|
+
const bucket = new Date(Date.now() - 2 * 60 * 60 * 1_000)
|
|
1708
|
+
bucket.setUTCMinutes(0, 0, 0)
|
|
1709
|
+
const bucketStart = bucket.toISOString()
|
|
1710
|
+
const reportRequests = () =>
|
|
1711
|
+
core_Billing
|
|
1712
|
+
.createRequestUsageReporter({
|
|
1713
|
+
db,
|
|
1714
|
+
readCounts: async () => [{ bucketStart, count: 100, orgId }],
|
|
1715
|
+
stripe,
|
|
1716
|
+
})
|
|
1717
|
+
.tick()
|
|
1718
|
+
const reportSponsorship = async () => {
|
|
1719
|
+
const seed = ordering === 'request-first' ? '61' : '62'
|
|
1720
|
+
const row = await SponsoredTransactions.upsert(db, {
|
|
1721
|
+
...meterable(orgId),
|
|
1722
|
+
signPayload: `0x${seed.repeat(32)}`,
|
|
1723
|
+
})
|
|
1724
|
+
await SponsoredTransactions.finalize(db, row.id, {
|
|
1725
|
+
feeAmount: '100000',
|
|
1726
|
+
finalizedAt: new Date().toISOString(),
|
|
1727
|
+
})
|
|
1728
|
+
return core_Billing.createReporter({ db, stripe }).tick()
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
if (ordering === 'request-first') {
|
|
1732
|
+
expect(await reportRequests()).toStrictEqual({ failed: 0, reported: 1, skipped: 0 })
|
|
1733
|
+
expect(await reportSponsorship()).toStrictEqual({ failed: 0, reported: 1, skipped: 0 })
|
|
1734
|
+
} else {
|
|
1735
|
+
expect(await reportSponsorship()).toStrictEqual({ failed: 0, reported: 1, skipped: 0 })
|
|
1736
|
+
expect(await reportRequests()).toStrictEqual({ failed: 0, reported: 1, skipped: 0 })
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
const { priceId } = await core_Billing.ensureFixtures(stripe, 'apiRequests')
|
|
1740
|
+
const [subscription] = (
|
|
1741
|
+
await stripe.subscriptions.list({ customer: customer.id, limit: 1, price: priceId })
|
|
1742
|
+
).data
|
|
1743
|
+
let line: { amount: number; quantity: number | null } | undefined
|
|
1744
|
+
await until(async () => {
|
|
1745
|
+
const preview = await stripe.invoices.createPreview({
|
|
1746
|
+
customer: customer.id,
|
|
1747
|
+
subscription: subscription!.id,
|
|
1748
|
+
})
|
|
1749
|
+
line = preview.lines.data.find((item) => item.pricing?.price_details?.price === priceId)
|
|
1750
|
+
return line?.quantity === 100
|
|
1751
|
+
}, 180_000)
|
|
1752
|
+
expect(line).toMatchObject({ amount: 1, quantity: 100 })
|
|
1753
|
+
},
|
|
1754
|
+
)
|
|
1755
|
+
|
|
1692
1756
|
test.each(['past_due', 'canceled'] as const)(
|
|
1693
1757
|
'a failed metered invoice blocks a %s subscription until payment',
|
|
1694
1758
|
{ timeout: 600_000 },
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { testClient } from 'hono/testing'
|
|
2
|
+
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
|
|
3
|
+
|
|
4
|
+
import * as TestApp from '../../../../test/App.js'
|
|
5
|
+
import * as CliAuth from '../../../internal/CliAuth.js'
|
|
6
|
+
|
|
7
|
+
/** Origin pinned for SIWE domain binding; Hono test requests use this host. */
|
|
8
|
+
const origin = 'http://localhost'
|
|
9
|
+
|
|
10
|
+
// RFC 7636 appendix B test vector.
|
|
11
|
+
const codeVerifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'
|
|
12
|
+
const codeChallenge = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM'
|
|
13
|
+
|
|
14
|
+
function createApp(options: { consoleUrl?: string | undefined } = {}) {
|
|
15
|
+
const app = TestApp.create({ ...options, session: { wallet: { origin } } })
|
|
16
|
+
return { app, client: testClient(app) }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function as(cookie: string) {
|
|
20
|
+
return { headers: { cookie } } as const
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function bearer(token: string) {
|
|
24
|
+
return { headers: { authorization: `Bearer ${token}` } } as const
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Signs in a fresh scripted account through SIWE, returning its console cookie and user id. */
|
|
28
|
+
async function session({ app, client }: ReturnType<typeof createApp>) {
|
|
29
|
+
const { cookie } = await TestApp.signIn(app, privateKeyToAccount(generatePrivateKey()))
|
|
30
|
+
if (!cookie) throw new Error('Sign-in did not establish a session')
|
|
31
|
+
const me = await client.v1.me.$get(undefined, as(cookie))
|
|
32
|
+
if (me.status !== 200) throw new Error(`Failed to resolve session user: ${me.status}`)
|
|
33
|
+
return { cookie, userId: (await me.json()).id }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function start({ client }: ReturnType<typeof createApp>) {
|
|
37
|
+
const response = await client.v1.cli.authorizations.$post({
|
|
38
|
+
json: { codeChallenge, device: 'build-box', name: 'tempo api 0.1.0' },
|
|
39
|
+
})
|
|
40
|
+
if (response.status !== 200) throw new Error(`Failed to start sign-in: ${response.status}`)
|
|
41
|
+
return response.json()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function exchange({ client }: ReturnType<typeof createApp>, code: string) {
|
|
45
|
+
return client.v1.cli.authorizations[':code{[A-Za-z -]+}'].token.$post({
|
|
46
|
+
json: { codeVerifier },
|
|
47
|
+
param: { code },
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Runs the whole sign-in flow and returns the CLI token plus the approving user. */
|
|
52
|
+
async function signInCli(context: ReturnType<typeof createApp>) {
|
|
53
|
+
const user = await session(context)
|
|
54
|
+
const { code } = await start(context)
|
|
55
|
+
const approve = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].approve.$post(
|
|
56
|
+
{ json: {}, param: { code } },
|
|
57
|
+
as(user.cookie),
|
|
58
|
+
)
|
|
59
|
+
expect(approve.status).toBe(200)
|
|
60
|
+
const response = await exchange(context, code)
|
|
61
|
+
const body = await response.json()
|
|
62
|
+
if (!('status' in body) || body.status !== 'approved') throw new Error('Sign-in was not approved')
|
|
63
|
+
return { token: body.token, user }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
describe('POST /v1/cli/authorizations', () => {
|
|
67
|
+
test('starts a sign-in with a console verification URL', async () => {
|
|
68
|
+
const response = await createApp().client.v1.cli.authorizations.$post({
|
|
69
|
+
json: { codeChallenge },
|
|
70
|
+
})
|
|
71
|
+
if (response.status !== 200) throw new Error(`Failed to start sign-in: ${response.status}`)
|
|
72
|
+
const { code, expiresAt, ...body } = await response.json()
|
|
73
|
+
expect(code).toMatch(/^[BCDFGHJKLMNPQRSTVWXZ]{4}-[BCDFGHJKLMNPQRSTVWXZ]{4}$/)
|
|
74
|
+
expect(Date.parse(expiresAt)).toBeGreaterThan(Date.now())
|
|
75
|
+
expect(body).toEqual({
|
|
76
|
+
interval: CliAuth.pollInterval,
|
|
77
|
+
verificationUrl: `https://console.tempo.xyz/cli?code=${code}`,
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('links to the configured console', async () => {
|
|
82
|
+
const response = await createApp({
|
|
83
|
+
consoleUrl: 'https://console.example.test/',
|
|
84
|
+
}).client.v1.cli.authorizations.$post({ json: { codeChallenge } })
|
|
85
|
+
if (response.status !== 200) throw new Error(`Failed to start sign-in: ${response.status}`)
|
|
86
|
+
const { code, verificationUrl } = await response.json()
|
|
87
|
+
expect(verificationUrl).toBe(`https://console.example.test/cli?code=${code}`)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('rejects a malformed code challenge', async () => {
|
|
91
|
+
const response = await createApp().client.v1.cli.authorizations.$post({
|
|
92
|
+
json: { codeChallenge: 'too-short' },
|
|
93
|
+
})
|
|
94
|
+
expect(response.status).toBe(400)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test('stays out of the OpenAPI document', async () => {
|
|
98
|
+
const spec = await (await createApp().app.request('/openapi.json')).json()
|
|
99
|
+
expect(Object.keys(spec.paths).filter((path) => path.startsWith('/v1/cli'))).toEqual([])
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
describe('GET /v1/cli/authorizations/:code', () => {
|
|
104
|
+
test('shows the pending request to a console session', async () => {
|
|
105
|
+
const context = createApp()
|
|
106
|
+
const { cookie } = await session(context)
|
|
107
|
+
const { code } = await start(context)
|
|
108
|
+
const response = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].$get(
|
|
109
|
+
// Codes are case- and separator-insensitive, as users may retype them.
|
|
110
|
+
{ param: { code: code.toLowerCase().replace('-', '') } },
|
|
111
|
+
as(cookie),
|
|
112
|
+
)
|
|
113
|
+
if (response.status !== 200) throw new Error(`Failed to read sign-in: ${response.status}`)
|
|
114
|
+
const { createdAt, expiresAt, ...body } = await response.json()
|
|
115
|
+
expect(Date.parse(expiresAt) - Date.parse(createdAt)).toBe(CliAuth.authorizationTtl)
|
|
116
|
+
expect(body).toEqual({
|
|
117
|
+
client: { device: 'build-box', name: 'tempo api 0.1.0' },
|
|
118
|
+
code,
|
|
119
|
+
scopes: CliAuth.defaultScopes,
|
|
120
|
+
status: 'pending',
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test('requires a session', async () => {
|
|
125
|
+
const context = createApp()
|
|
126
|
+
const { code } = await start(context)
|
|
127
|
+
const response = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].$get({
|
|
128
|
+
param: { code },
|
|
129
|
+
})
|
|
130
|
+
expect(response.status).toBe(401)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
test('reports unknown and malformed codes as not found', async () => {
|
|
134
|
+
const context = createApp()
|
|
135
|
+
const { cookie } = await session(context)
|
|
136
|
+
for (const code of ['BCDF-GHJK', 'ABCD-EFGH']) {
|
|
137
|
+
const response = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].$get(
|
|
138
|
+
{ param: { code } },
|
|
139
|
+
as(cookie),
|
|
140
|
+
)
|
|
141
|
+
expect(response.status).toBe(404)
|
|
142
|
+
expect(await response.json()).toMatchObject({
|
|
143
|
+
error: { code: 'cli_authorization_not_found' },
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
describe('POST /v1/cli/authorizations/:code/token', () => {
|
|
150
|
+
test('reports pending until a console session approves', async () => {
|
|
151
|
+
const context = createApp()
|
|
152
|
+
const { code } = await start(context)
|
|
153
|
+
const response = await exchange(context, code)
|
|
154
|
+
expect(response.status).toBe(200)
|
|
155
|
+
expect(response.headers.get('cache-control')).toBe('no-store')
|
|
156
|
+
expect(await response.json()).toEqual({ status: 'pending' })
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test('issues a single-use CLI session token that acts as the approving user', async () => {
|
|
160
|
+
const context = createApp()
|
|
161
|
+
const { token, user } = await signInCli(context)
|
|
162
|
+
expect(CliAuth.isToken(token)).toBe(true)
|
|
163
|
+
|
|
164
|
+
const me = await context.client.v1.me.$get(undefined, bearer(token))
|
|
165
|
+
expect(me.status).toBe(200)
|
|
166
|
+
if (me.status !== 200) throw new Error('unreachable')
|
|
167
|
+
expect((await me.json()).id).toBe(user.userId)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('reports denial once, then forgets the code', async () => {
|
|
171
|
+
const context = createApp()
|
|
172
|
+
const { cookie } = await session(context)
|
|
173
|
+
const { code } = await start(context)
|
|
174
|
+
const deny = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].deny.$post(
|
|
175
|
+
{ param: { code } },
|
|
176
|
+
as(cookie),
|
|
177
|
+
)
|
|
178
|
+
expect(deny.status).toBe(200)
|
|
179
|
+
expect(await deny.json()).toEqual({ code, status: 'denied' })
|
|
180
|
+
expect(await (await exchange(context, code)).json()).toEqual({ status: 'denied' })
|
|
181
|
+
expect((await exchange(context, code)).status).toBe(404)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
test('hides the code from callers without the verifier', async () => {
|
|
185
|
+
const context = createApp()
|
|
186
|
+
const { cookie } = await session(context)
|
|
187
|
+
const { code } = await start(context)
|
|
188
|
+
await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].approve.$post(
|
|
189
|
+
{ json: {}, param: { code } },
|
|
190
|
+
as(cookie),
|
|
191
|
+
)
|
|
192
|
+
const response = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].token.$post({
|
|
193
|
+
json: { codeVerifier: 'x'.repeat(43) },
|
|
194
|
+
param: { code },
|
|
195
|
+
})
|
|
196
|
+
expect(response.status).toBe(404)
|
|
197
|
+
// The verifier holder can still redeem.
|
|
198
|
+
expect((await (await exchange(context, code)).json()) as unknown).toMatchObject({
|
|
199
|
+
status: 'approved',
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
describe('POST /v1/cli/authorizations/:code/approve', () => {
|
|
205
|
+
test.each([
|
|
206
|
+
{ body: undefined, contentType: undefined },
|
|
207
|
+
{ body: undefined, contentType: 'application/json' },
|
|
208
|
+
{ body: '', contentType: 'application/json' },
|
|
209
|
+
{ body: '{}', contentType: 'application/json' },
|
|
210
|
+
])(
|
|
211
|
+
'uses default scopes for a legacy approval $body $contentType',
|
|
212
|
+
async ({ body, contentType }) => {
|
|
213
|
+
const context = createApp()
|
|
214
|
+
const user = await session(context)
|
|
215
|
+
const { code } = await start(context)
|
|
216
|
+
const response = await context.app.request(`/v1/cli/authorizations/${code}/approve`, {
|
|
217
|
+
...(body === undefined ? {} : { body }),
|
|
218
|
+
headers: {
|
|
219
|
+
...(contentType === undefined ? {} : { 'content-type': contentType }),
|
|
220
|
+
cookie: user.cookie,
|
|
221
|
+
},
|
|
222
|
+
method: 'POST',
|
|
223
|
+
})
|
|
224
|
+
expect(response.status).toBe(200)
|
|
225
|
+
expect(await (await exchange(context, code)).json()).toMatchObject({
|
|
226
|
+
scopes: CliAuth.defaultScopes,
|
|
227
|
+
status: 'approved',
|
|
228
|
+
})
|
|
229
|
+
},
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
test.each(['{', 'null', '{"scopes":null}'])(
|
|
233
|
+
'still rejects invalid nonempty JSON %j',
|
|
234
|
+
async (body) => {
|
|
235
|
+
const context = createApp()
|
|
236
|
+
const user = await session(context)
|
|
237
|
+
const { code } = await start(context)
|
|
238
|
+
const response = await context.app.request(`/v1/cli/authorizations/${code}/approve`, {
|
|
239
|
+
body,
|
|
240
|
+
headers: { 'content-type': 'application/json', cookie: user.cookie },
|
|
241
|
+
method: 'POST',
|
|
242
|
+
})
|
|
243
|
+
expect(response.status).toBe(400)
|
|
244
|
+
expect(await (await exchange(context, code)).json()).toEqual({ status: 'pending' })
|
|
245
|
+
},
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
test('persists selected API scopes through token exchange', async () => {
|
|
249
|
+
const context = createApp()
|
|
250
|
+
const user = await session(context)
|
|
251
|
+
const { code } = await start(context)
|
|
252
|
+
const response = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].approve.$post(
|
|
253
|
+
{ json: { scopes: ['routes:read'] }, param: { code } },
|
|
254
|
+
as(user.cookie),
|
|
255
|
+
)
|
|
256
|
+
expect(response.status).toBe(200)
|
|
257
|
+
const token = await exchange(context, code)
|
|
258
|
+
expect(await token.json()).toMatchObject({ scopes: ['routes:read'], status: 'approved' })
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
test.each([
|
|
262
|
+
{ scopes: ['*'] },
|
|
263
|
+
{ scopes: ['unknown:write'] },
|
|
264
|
+
{ scopes: ['routes:read', 'routes:read'] },
|
|
265
|
+
])('rejects unsupported or duplicated scopes $scopes', async ({ scopes }) => {
|
|
266
|
+
const context = createApp()
|
|
267
|
+
const user = await session(context)
|
|
268
|
+
const { code } = await start(context)
|
|
269
|
+
const response = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].approve.$post(
|
|
270
|
+
{ json: { scopes }, param: { code } },
|
|
271
|
+
as(user.cookie),
|
|
272
|
+
)
|
|
273
|
+
expect(response.status).toBe(400)
|
|
274
|
+
expect(await response.json()).toMatchObject({ error: { code: 'body_invalid' } })
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
test('conflicts once another user decided the request', async () => {
|
|
278
|
+
const context = createApp()
|
|
279
|
+
const first = await session(context)
|
|
280
|
+
const second = await session(context)
|
|
281
|
+
const { code } = await start(context)
|
|
282
|
+
const approve = context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].approve
|
|
283
|
+
expect((await approve.$post({ json: {}, param: { code } }, as(first.cookie))).status).toBe(200)
|
|
284
|
+
// Repeating the approval is a no-op for the same user.
|
|
285
|
+
expect((await approve.$post({ json: {}, param: { code } }, as(first.cookie))).status).toBe(200)
|
|
286
|
+
const conflict = await approve.$post({ json: {}, param: { code } }, as(second.cookie))
|
|
287
|
+
expect(conflict.status).toBe(409)
|
|
288
|
+
expect(await conflict.json()).toMatchObject({ error: { code: 'cli_authorization_decided' } })
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
test('refuses CLI sessions so a CLI token cannot mint more CLI sessions', async () => {
|
|
292
|
+
const context = createApp()
|
|
293
|
+
const { token } = await signInCli(context)
|
|
294
|
+
const { code } = await start(context)
|
|
295
|
+
const response = await context.client.v1.cli.authorizations[':code{[A-Za-z -]+}'].approve.$post(
|
|
296
|
+
{ json: {}, param: { code } },
|
|
297
|
+
bearer(token),
|
|
298
|
+
)
|
|
299
|
+
expect(response.status).toBe(403)
|
|
300
|
+
expect(await response.json()).toMatchObject({
|
|
301
|
+
error: { code: 'forbidden', message: 'Approve CLI sign-ins from the console' },
|
|
302
|
+
})
|
|
303
|
+
})
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
describe('CLI session tokens', () => {
|
|
307
|
+
test('manage organizations, projects, and API keys', async () => {
|
|
308
|
+
const context = createApp()
|
|
309
|
+
const { token } = await signInCli(context)
|
|
310
|
+
const org = await context.client.v1.orgs.$post({ json: { name: 'Acme' } }, bearer(token))
|
|
311
|
+
expect(org.status).toBe(200)
|
|
312
|
+
if (org.status !== 200) throw new Error('unreachable')
|
|
313
|
+
const { id: orgId } = await org.json()
|
|
314
|
+
|
|
315
|
+
const project = await context.client.v1.orgs[':orgId{org_[A-Za-z0-9_-]+}'].projects.$post(
|
|
316
|
+
{ json: { name: 'Checkout' }, param: { orgId } },
|
|
317
|
+
bearer(token),
|
|
318
|
+
)
|
|
319
|
+
expect(project.status).toBe(200)
|
|
320
|
+
if (project.status !== 200) throw new Error('unreachable')
|
|
321
|
+
const { id: projectId } = await project.json()
|
|
322
|
+
|
|
323
|
+
const key = await context.client.v1.orgs[':orgId{org_[A-Za-z0-9_-]+}'].projects[
|
|
324
|
+
':projectId{prj_[A-Za-z0-9_-]+}'
|
|
325
|
+
]['api-keys'].$post(
|
|
326
|
+
{ json: { name: 'CLI', scopes: ['data:read'] }, param: { orgId, projectId } },
|
|
327
|
+
bearer(token),
|
|
328
|
+
)
|
|
329
|
+
expect(key.status).toBe(200)
|
|
330
|
+
if (key.status !== 200) throw new Error('unreachable')
|
|
331
|
+
const { createdAt, id, token: apiKey, tokenLast4, ...record } = await key.json()
|
|
332
|
+
expect(apiKey).toMatch(/^tempo:sk:[a-f0-9]{48}$/)
|
|
333
|
+
expect(id).toMatch(/^key_/)
|
|
334
|
+
expect(tokenLast4).toBe(apiKey.slice(-4))
|
|
335
|
+
expect(Date.parse(createdAt)).not.toBeNaN()
|
|
336
|
+
expect(record).toMatchObject({ environment: 'production', name: 'CLI', scopes: ['data:read'] })
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
test('are refused on routes without a session lane', async () => {
|
|
340
|
+
const context = createApp()
|
|
341
|
+
const { token } = await signInCli(context)
|
|
342
|
+
const response = await context.app.request('/v1/tokenlist', bearer(token))
|
|
343
|
+
expect(response.status).toBe(403)
|
|
344
|
+
expect(await response.json()).toMatchObject({
|
|
345
|
+
error: { code: 'forbidden', message: 'CLI sessions cannot call this route. Use an API key.' },
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
test('report unknown tokens as an invalid session', async () => {
|
|
350
|
+
const response = await createApp().client.v1.me.$get(undefined, bearer(CliAuth.generateToken()))
|
|
351
|
+
expect(response.status).toBe(401)
|
|
352
|
+
expect(await response.json()).toMatchObject({
|
|
353
|
+
error: {
|
|
354
|
+
code: 'session_invalid',
|
|
355
|
+
message: 'CLI session is invalid or expired. Sign in again.',
|
|
356
|
+
},
|
|
357
|
+
})
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
test('are revoked by logout', async () => {
|
|
361
|
+
const context = createApp()
|
|
362
|
+
const { token } = await signInCli(context)
|
|
363
|
+
const logout = await context.app.request('/v1/auth/logout', {
|
|
364
|
+
...bearer(token),
|
|
365
|
+
method: 'POST',
|
|
366
|
+
})
|
|
367
|
+
expect(logout.status).toBe(204)
|
|
368
|
+
expect((await context.client.v1.me.$get(undefined, bearer(token))).status).toBe(401)
|
|
369
|
+
})
|
|
370
|
+
})
|