tapimo 0.1.0 → 0.3.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 +57 -16
- package/dist/ApiKey.d.ts +4 -1
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +6 -2
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +98 -3
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +150 -1
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +7917 -2315
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +141 -329
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +20 -4
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +23 -4
- package/dist/Scope.js.map +1 -1
- package/dist/Webhooks.d.ts +2 -2
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +2 -2
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +203 -120
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +111 -6
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +67 -0
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/scopes.d.ts +12 -1
- package/dist/admin/apps/scopes.d.ts.map +1 -1
- package/dist/admin/apps/scopes.js +3 -0
- package/dist/admin/apps/scopes.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +116 -116
- package/dist/admin/apps/verified-tokens.js +1 -1
- package/dist/admin/apps/verified-tokens.js.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.js +13 -13
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts +151 -0
- package/dist/analytics/Analytics.d.ts.map +1 -0
- package/dist/analytics/Analytics.js +212 -0
- package/dist/analytics/Analytics.js.map +1 -0
- package/dist/analytics/tables/requestEvents.d.ts +215 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -0
- package/dist/analytics/tables/requestEvents.js +264 -0
- package/dist/analytics/tables/requestEvents.js.map +1 -0
- package/dist/apps/data/App.d.ts +19576 -0
- package/dist/apps/data/App.d.ts.map +1 -0
- package/dist/apps/data/App.js +272 -0
- package/dist/apps/data/App.js.map +1 -0
- package/dist/apps/data/index.d.ts +3 -0
- package/dist/apps/data/index.d.ts.map +1 -0
- package/dist/apps/data/index.js +3 -0
- package/dist/apps/data/index.js.map +1 -0
- package/dist/apps/{activities.d.ts → data/routes/activities.d.ts} +32 -32
- package/dist/apps/{activities.d.ts.map → data/routes/activities.d.ts.map} +1 -1
- package/dist/apps/{activities.js → data/routes/activities.js} +13 -13
- package/dist/apps/data/routes/activities.js.map +1 -0
- package/dist/apps/{addresses.d.ts → data/routes/addresses.d.ts} +22 -22
- package/dist/apps/{addresses.d.ts.map → data/routes/addresses.d.ts.map} +1 -1
- package/dist/apps/{addresses.js → data/routes/addresses.js} +5 -5
- package/dist/apps/data/routes/addresses.js.map +1 -0
- package/dist/apps/{balances.d.ts → data/routes/balances.d.ts} +4 -4
- package/dist/apps/data/routes/balances.d.ts.map +1 -0
- package/dist/apps/{balances.js → data/routes/balances.js} +42 -11
- package/dist/apps/data/routes/balances.js.map +1 -0
- package/dist/apps/{blocks.d.ts → data/routes/blocks.d.ts} +47 -47
- package/dist/apps/data/routes/blocks.d.ts.map +1 -0
- package/dist/apps/{blocks.js → data/routes/blocks.js} +13 -13
- package/dist/apps/data/routes/blocks.js.map +1 -0
- package/dist/apps/{coingecko.d.ts → data/routes/coingecko.d.ts} +8 -8
- package/dist/apps/data/routes/coingecko.d.ts.map +1 -0
- package/dist/apps/{coingecko.js → data/routes/coingecko.js} +13 -13
- package/dist/apps/data/routes/coingecko.js.map +1 -0
- package/dist/apps/{exchanges.d.ts → data/routes/exchanges.d.ts} +108 -108
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -0
- package/dist/apps/{exchanges.js → data/routes/exchanges.js} +19 -19
- package/dist/apps/data/routes/exchanges.js.map +1 -0
- package/dist/apps/{fee-amm.d.ts → data/routes/fee-amm.d.ts} +39 -39
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -0
- package/dist/apps/{fee-amm.js → data/routes/fee-amm.js} +17 -17
- package/dist/apps/data/routes/fee-amm.js.map +1 -0
- package/dist/apps/data/routes/funding.d.ts +765 -0
- package/dist/apps/data/routes/funding.d.ts.map +1 -0
- package/dist/apps/data/routes/funding.js +383 -0
- package/dist/apps/data/routes/funding.js.map +1 -0
- package/dist/apps/{indexer.d.ts → data/routes/indexer.d.ts} +4 -4
- package/dist/apps/data/routes/indexer.d.ts.map +1 -0
- package/dist/apps/{indexer.js → data/routes/indexer.js} +13 -9
- package/dist/apps/data/routes/indexer.js.map +1 -0
- package/dist/apps/{receipts.d.ts → data/routes/receipts.d.ts} +49 -49
- package/dist/apps/data/routes/receipts.d.ts.map +1 -0
- package/dist/apps/{receipts.js → data/routes/receipts.js} +14 -20
- package/dist/apps/data/routes/receipts.js.map +1 -0
- package/dist/apps/{rpc.d.ts → data/routes/rpc.d.ts} +33 -40
- package/dist/apps/data/routes/rpc.d.ts.map +1 -0
- package/dist/apps/{rpc.js → data/routes/rpc.js} +35 -7
- package/dist/apps/data/routes/rpc.js.map +1 -0
- package/dist/apps/{tokenlist.d.ts → data/routes/tokenlist.d.ts} +40 -40
- package/dist/apps/data/routes/tokenlist.d.ts.map +1 -0
- package/dist/apps/{tokenlist.js → data/routes/tokenlist.js} +8 -8
- package/dist/apps/data/routes/tokenlist.js.map +1 -0
- package/dist/apps/{tokens.d.ts → data/routes/tokens.d.ts} +468 -468
- package/dist/apps/data/routes/tokens.d.ts.map +1 -0
- package/dist/apps/{tokens.js → data/routes/tokens.js} +19 -19
- package/dist/apps/data/routes/tokens.js.map +1 -0
- package/dist/apps/{transactions.d.ts → data/routes/transactions.d.ts} +304 -304
- package/dist/apps/data/routes/transactions.d.ts.map +1 -0
- package/dist/apps/{transactions.js → data/routes/transactions.js} +13 -13
- package/dist/apps/data/routes/transactions.js.map +1 -0
- package/dist/apps/{transfers.d.ts → data/routes/transfers.d.ts} +62 -62
- package/dist/apps/data/routes/transfers.d.ts.map +1 -0
- package/dist/apps/{transfers.js → data/routes/transfers.js} +13 -13
- package/dist/apps/data/routes/transfers.js.map +1 -0
- package/dist/apps/{verified-tokens.d.ts → data/routes/verified-tokens.d.ts} +6 -6
- package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -0
- package/dist/apps/{verified-tokens.js → data/routes/verified-tokens.js} +9 -9
- package/dist/apps/data/routes/verified-tokens.js.map +1 -0
- package/dist/apps/{webhooks.d.ts → data/routes/webhooks.d.ts} +17 -17
- package/dist/apps/{webhooks.d.ts.map → data/routes/webhooks.d.ts.map} +1 -1
- package/dist/apps/{webhooks.js → data/routes/webhooks.js} +38 -34
- package/dist/apps/data/routes/webhooks.js.map +1 -0
- package/dist/apps/docs/App.d.ts +29 -0
- package/dist/apps/docs/App.d.ts.map +1 -0
- package/dist/apps/docs/App.js +54 -0
- package/dist/apps/docs/App.js.map +1 -0
- package/dist/{internal/OpenApi.fonts.d.ts → apps/docs/fonts.d.ts} +1 -1
- package/dist/apps/docs/fonts.d.ts.map +1 -0
- package/dist/{internal/OpenApi.fonts.js → apps/docs/fonts.js} +1 -1
- package/dist/apps/docs/fonts.js.map +1 -0
- package/dist/apps/docs/index.d.ts +2 -0
- package/dist/apps/docs/index.d.ts.map +1 -0
- package/dist/apps/docs/index.js +2 -0
- package/dist/apps/docs/index.js.map +1 -0
- package/dist/{internal/OpenApi.logo.d.ts → apps/docs/logo.d.ts} +1 -1
- package/dist/apps/docs/logo.d.ts.map +1 -0
- package/dist/{internal/OpenApi.logo.js → apps/docs/logo.js} +1 -1
- package/dist/apps/docs/logo.js.map +1 -0
- package/dist/apps/docs/reference.d.ts +21 -0
- package/dist/apps/docs/reference.d.ts.map +1 -0
- package/dist/apps/docs/reference.js +112 -0
- package/dist/apps/docs/reference.js.map +1 -0
- package/dist/apps/index.d.ts +5 -0
- package/dist/apps/index.d.ts.map +1 -0
- package/dist/apps/index.js +5 -0
- package/dist/apps/index.js.map +1 -0
- package/dist/apps/mcp.d.ts +76 -0
- package/dist/apps/mcp.d.ts.map +1 -0
- package/dist/apps/mcp.js +188 -0
- package/dist/apps/mcp.js.map +1 -0
- package/dist/apps/metadata.d.ts +7 -0
- package/dist/apps/metadata.d.ts.map +1 -0
- package/dist/apps/metadata.js +15 -0
- package/dist/apps/metadata.js.map +1 -0
- package/dist/apps/platform/App.d.ts +5262 -0
- package/dist/apps/platform/App.d.ts.map +1 -0
- package/dist/apps/platform/App.js +84 -0
- package/dist/apps/platform/App.js.map +1 -0
- package/dist/apps/platform/Billing.d.ts +279 -0
- package/dist/apps/platform/Billing.d.ts.map +1 -0
- package/dist/apps/platform/Billing.js +477 -0
- package/dist/apps/platform/Billing.js.map +1 -0
- package/dist/apps/platform/index.d.ts +3 -0
- package/dist/apps/platform/index.d.ts.map +1 -0
- package/dist/apps/platform/index.js +3 -0
- package/dist/apps/platform/index.js.map +1 -0
- package/dist/apps/platform/routes/api-keys.d.ts +973 -0
- package/dist/apps/platform/routes/api-keys.d.ts.map +1 -0
- package/dist/apps/platform/routes/api-keys.js +430 -0
- package/dist/apps/platform/routes/api-keys.js.map +1 -0
- package/dist/apps/platform/routes/billing.d.ts +1520 -0
- package/dist/apps/platform/routes/billing.d.ts.map +1 -0
- package/dist/apps/platform/routes/billing.js +795 -0
- package/dist/apps/platform/routes/billing.js.map +1 -0
- package/dist/apps/platform/routes/invitations.d.ts +851 -0
- package/dist/apps/platform/routes/invitations.d.ts.map +1 -0
- package/dist/apps/platform/routes/invitations.js +471 -0
- package/dist/apps/platform/routes/invitations.js.map +1 -0
- package/dist/apps/platform/routes/me.d.ts +95 -0
- package/dist/apps/platform/routes/me.d.ts.map +1 -0
- package/dist/apps/platform/routes/me.js +81 -0
- package/dist/apps/platform/routes/me.js.map +1 -0
- package/dist/apps/platform/routes/members.d.ts +554 -0
- package/dist/apps/platform/routes/members.d.ts.map +1 -0
- package/dist/apps/platform/routes/members.js +251 -0
- package/dist/apps/platform/routes/members.js.map +1 -0
- package/dist/apps/platform/routes/orgs.d.ts +596 -0
- package/dist/apps/platform/routes/orgs.d.ts.map +1 -0
- package/dist/apps/platform/routes/orgs.js +276 -0
- package/dist/apps/platform/routes/orgs.js.map +1 -0
- package/dist/apps/platform/routes/projects.d.ts +740 -0
- package/dist/apps/platform/routes/projects.d.ts.map +1 -0
- package/dist/apps/platform/routes/projects.js +286 -0
- package/dist/apps/platform/routes/projects.js.map +1 -0
- package/dist/apps/platform/routes/scopes.d.ts +107 -0
- package/dist/apps/platform/routes/scopes.d.ts.map +1 -0
- package/dist/apps/platform/routes/scopes.js +66 -0
- package/dist/apps/platform/routes/scopes.js.map +1 -0
- package/dist/apps/platform/routes/usage.d.ts +588 -0
- package/dist/apps/platform/routes/usage.d.ts.map +1 -0
- package/dist/apps/platform/routes/usage.js +391 -0
- package/dist/apps/platform/routes/usage.js.map +1 -0
- package/dist/apps/relay/App.d.ts +44 -0
- package/dist/apps/relay/App.d.ts.map +1 -0
- package/dist/apps/relay/App.js +211 -0
- package/dist/apps/relay/App.js.map +1 -0
- package/dist/apps/relay/Sponsorships.d.ts +107 -0
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -0
- package/dist/apps/relay/Sponsorships.js +194 -0
- package/dist/apps/relay/Sponsorships.js.map +1 -0
- package/dist/apps/relay/index.d.ts +3 -0
- package/dist/apps/relay/index.d.ts.map +1 -0
- package/dist/apps/relay/index.js +3 -0
- package/dist/apps/relay/index.js.map +1 -0
- package/dist/cli/Cli.d.ts +9 -2
- package/dist/cli/Cli.d.ts.map +1 -1
- package/dist/cli/Cli.js +12 -4
- package/dist/cli/Cli.js.map +1 -1
- package/dist/cli/commands/admin.d.ts +5 -1
- package/dist/cli/commands/admin.d.ts.map +1 -1
- package/dist/cli/commands/admin.js +82 -3
- package/dist/cli/commands/admin.js.map +1 -1
- package/dist/db/Db.d.ts +17 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +254 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +159 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +187 -2
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/billingSettings.d.ts +55 -0
- package/dist/db/tables/billingSettings.d.ts.map +1 -0
- package/dist/db/tables/billingSettings.js +70 -0
- package/dist/db/tables/billingSettings.js.map +1 -0
- package/dist/db/tables/invitations.d.ts +84 -0
- package/dist/db/tables/invitations.d.ts.map +1 -0
- package/dist/db/tables/invitations.js +165 -0
- package/dist/db/tables/invitations.js.map +1 -0
- package/dist/db/tables/memberships.d.ts +108 -0
- package/dist/db/tables/memberships.d.ts.map +1 -0
- package/dist/db/tables/memberships.js +153 -0
- package/dist/db/tables/memberships.js.map +1 -0
- package/dist/db/tables/organizations.d.ts +48 -0
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +97 -2
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/projects.d.ts +65 -0
- package/dist/db/tables/projects.d.ts.map +1 -0
- package/dist/db/tables/projects.js +75 -0
- package/dist/db/tables/projects.js.map +1 -0
- package/dist/db/tables/requestUsage.d.ts +121 -0
- package/dist/db/tables/requestUsage.d.ts.map +1 -0
- package/dist/db/tables/requestUsage.js +150 -0
- package/dist/db/tables/requestUsage.js.map +1 -0
- package/dist/db/tables/sponsoredTransactions.d.ts +239 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -0
- package/dist/db/tables/sponsoredTransactions.js +314 -0
- package/dist/db/tables/sponsoredTransactions.js.map +1 -0
- package/dist/db/tables/stripeCustomers.d.ts +81 -0
- package/dist/db/tables/stripeCustomers.d.ts.map +1 -0
- package/dist/db/tables/stripeCustomers.js +120 -0
- package/dist/db/tables/stripeCustomers.js.map +1 -0
- package/dist/db/tables/users.d.ts +48 -0
- package/dist/db/tables/users.d.ts.map +1 -0
- package/dist/db/tables/users.js +65 -0
- package/dist/db/tables/users.js.map +1 -0
- package/dist/handlers/internal/executionError.d.ts.map +1 -1
- package/dist/handlers/internal/executionError.js +2 -0
- package/dist/handlers/internal/executionError.js.map +1 -1
- package/dist/handlers/internal/multisig.d.ts +2 -6
- package/dist/handlers/internal/multisig.d.ts.map +1 -1
- package/dist/handlers/internal/multisig.js +11 -36
- package/dist/handlers/internal/multisig.js.map +1 -1
- package/dist/handlers/internal/sponsorship.d.ts +35 -2
- package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
- package/dist/handlers/internal/sponsorship.js +53 -14
- package/dist/handlers/internal/sponsorship.js.map +1 -1
- package/dist/handlers/internal/utils.d.ts +10 -3
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +14 -6
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/handlers/relay.d.ts +6 -2
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +16 -2
- package/dist/handlers/relay.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/Auth.d.ts +222 -6
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +625 -74
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +4 -1
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts +10 -0
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +39 -8
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/Fees.d.ts +27 -0
- package/dist/internal/Fees.d.ts.map +1 -0
- package/dist/internal/Fees.js +48 -0
- package/dist/internal/Fees.js.map +1 -0
- package/dist/internal/FundingRoutes.d.ts +183 -0
- package/dist/internal/FundingRoutes.d.ts.map +1 -0
- package/dist/internal/FundingRoutes.js +490 -0
- package/dist/internal/FundingRoutes.js.map +1 -0
- package/dist/internal/Id.d.ts +15 -0
- package/dist/internal/Id.d.ts.map +1 -0
- package/dist/internal/Id.js +22 -0
- package/dist/internal/Id.js.map +1 -0
- package/dist/internal/Log.d.ts +9 -3
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +7 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +10 -20
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +8 -58
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/RateLimit.d.ts +25 -0
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +51 -0
- package/dist/internal/RateLimit.js.map +1 -1
- package/dist/internal/Response.d.ts +1 -1
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Schema.d.ts +8 -0
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +7 -0
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Store.d.ts +7 -1
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +16 -2
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Viem.d.ts +84 -0
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Webhooks.d.ts +1 -1
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +3 -3
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +33 -6
- package/src/ApiKey.ts +10 -2
- package/src/ApiKeys.test.ts +155 -1
- package/src/ApiKeys.ts +203 -1
- package/src/App.test.ts +64 -75741
- package/src/App.ts +218 -420
- package/src/Client.test-d.ts +657 -15
- package/src/Scope.ts +26 -4
- package/src/Webhooks.ts +2 -2
- package/src/admin/apps/api-keys.test.ts +51 -0
- package/src/admin/apps/api-keys.ts +84 -0
- package/src/admin/apps/scopes.test.ts +11 -1
- package/src/admin/apps/scopes.ts +3 -0
- package/src/admin/apps/verified-tokens.ts +1 -1
- package/src/admin/ui/src/components/Page.tsx +2 -3
- package/src/admin/ui/src/routes/__root.tsx +2 -2
- package/src/admin/ui/src/routes/api-keys.tsx +2 -2
- package/src/admin/ui.generated.ts +13 -13
- package/src/analytics/Analytics.test.ts +527 -0
- package/src/analytics/Analytics.ts +318 -0
- package/src/analytics/tables/requestEvents.ts +523 -0
- package/src/apps/composition.test.ts +66 -0
- package/src/apps/data/App.test.ts +72 -0
- package/src/apps/data/App.ts +330 -0
- package/src/apps/data/index.ts +2 -0
- package/src/apps/{activities.test.ts → data/routes/activities.test.ts} +3 -3
- package/src/apps/{activities.ts → data/routes/activities.ts} +15 -15
- package/src/apps/{addresses.ts → data/routes/addresses.ts} +6 -6
- package/src/apps/{balances.test.ts → data/routes/balances.test.ts} +2 -2
- package/src/apps/{balances.ts → data/routes/balances.ts} +46 -12
- package/src/apps/{blocks.test.ts → data/routes/blocks.test.ts} +3 -3
- package/src/apps/{blocks.ts → data/routes/blocks.ts} +14 -14
- package/src/apps/{coingecko.test.ts → data/routes/coingecko.test.ts} +2 -2
- package/src/apps/{coingecko.ts → data/routes/coingecko.ts} +14 -14
- package/src/apps/{exchanges.test.ts → data/routes/exchanges.test.ts} +1 -1
- package/src/apps/{exchanges.ts → data/routes/exchanges.ts} +20 -20
- package/src/apps/{fee-amm.test.ts → data/routes/fee-amm.test.ts} +3 -3
- package/src/apps/{fee-amm.ts → data/routes/fee-amm.ts} +18 -18
- package/src/apps/data/routes/funding.test.ts +214 -0
- package/src/apps/data/routes/funding.ts +584 -0
- package/src/apps/{indexer.test.ts → data/routes/indexer.test.ts} +26 -5
- package/src/apps/{indexer.ts → data/routes/indexer.ts} +13 -10
- package/src/apps/{receipts.test.ts → data/routes/receipts.test.ts} +3 -3
- package/src/apps/{receipts.ts → data/routes/receipts.ts} +15 -22
- package/src/apps/{rpc.test.ts → data/routes/rpc.test.ts} +122 -7
- package/src/apps/{rpc.ts → data/routes/rpc.ts} +38 -8
- package/src/apps/{tokenlist.test.ts → data/routes/tokenlist.test.ts} +3 -3
- package/src/apps/{tokenlist.ts → data/routes/tokenlist.ts} +9 -9
- package/src/apps/{tokens.test.ts → data/routes/tokens.test.ts} +2 -2
- package/src/apps/{tokens.ts → data/routes/tokens.ts} +20 -20
- package/src/apps/{transactions.test.ts → data/routes/transactions.test.ts} +3 -3
- package/src/apps/{transactions.ts → data/routes/transactions.ts} +15 -15
- package/src/apps/{transfers.test.ts → data/routes/transfers.test.ts} +2 -2
- package/src/apps/{transfers.ts → data/routes/transfers.ts} +15 -15
- package/src/apps/{verified-tokens.test.ts → data/routes/verified-tokens.test.ts} +3 -3
- package/src/apps/{verified-tokens.ts → data/routes/verified-tokens.ts} +10 -10
- package/src/apps/{webhooks.test.ts → data/routes/webhooks.test.ts} +7 -7
- package/src/apps/{webhooks.ts → data/routes/webhooks.ts} +50 -43
- package/src/apps/docs/App.ts +65 -0
- package/src/apps/docs/index.ts +1 -0
- package/src/apps/docs/reference.ts +132 -0
- package/src/apps/index.ts +4 -0
- package/src/apps/mcp.test.ts +206 -0
- package/src/apps/mcp.ts +250 -0
- package/src/apps/metadata.ts +23 -0
- package/src/apps/platform/App.ts +169 -0
- package/src/apps/platform/Billing.test.ts +530 -0
- package/src/apps/platform/Billing.ts +682 -0
- package/src/apps/platform/index.ts +2 -0
- package/src/apps/platform/routes/api-keys.test.ts +493 -0
- package/src/apps/platform/routes/api-keys.ts +543 -0
- package/src/apps/platform/routes/billing.test.ts +1100 -0
- package/src/apps/platform/routes/billing.ts +966 -0
- package/src/apps/platform/routes/invitations.test.ts +409 -0
- package/src/apps/platform/routes/invitations.ts +587 -0
- package/src/apps/platform/routes/me.test.ts +351 -0
- package/src/apps/platform/routes/me.ts +106 -0
- package/src/apps/platform/routes/members.test.ts +195 -0
- package/src/apps/platform/routes/members.ts +313 -0
- package/src/apps/platform/routes/orgs.test.ts +313 -0
- package/src/apps/platform/routes/orgs.ts +365 -0
- package/src/apps/platform/routes/projects.test.ts +181 -0
- package/src/apps/platform/routes/projects.ts +367 -0
- package/src/apps/platform/routes/scopes.test.ts +29 -0
- package/src/apps/platform/routes/scopes.ts +85 -0
- package/src/apps/platform/routes/usage.test.ts +422 -0
- package/src/apps/platform/routes/usage.ts +527 -0
- package/src/apps/relay/App.test.ts +933 -0
- package/src/apps/relay/App.ts +236 -0
- package/src/apps/relay/Sponsorships.test.ts +375 -0
- package/src/apps/relay/Sponsorships.ts +306 -0
- package/src/apps/relay/index.ts +2 -0
- package/src/cli/Cli.test.ts +25 -2
- package/src/cli/Cli.ts +18 -3
- package/src/cli/commands/admin.test.ts +83 -0
- package/src/cli/commands/admin.ts +91 -3
- package/src/db/Db.ts +296 -0
- package/src/db/Schema.ts +241 -2
- package/src/db/tables/billingSettings.test.ts +87 -0
- package/src/db/tables/billingSettings.ts +108 -0
- package/src/db/tables/invitations.ts +198 -0
- package/src/db/tables/memberships.ts +208 -0
- package/src/db/tables/organizations.test.ts +38 -2
- package/src/db/tables/organizations.ts +117 -2
- package/src/db/tables/projects.ts +107 -0
- package/src/db/tables/requestUsage.ts +231 -0
- package/src/db/tables/sponsoredTransactions.test.ts +325 -0
- package/src/db/tables/sponsoredTransactions.ts +464 -0
- package/src/db/tables/stripeCustomers.test.ts +109 -0
- package/src/db/tables/stripeCustomers.ts +162 -0
- package/src/db/tables/users.ts +85 -0
- package/src/handlers/internal/executionError.ts +2 -0
- package/src/handlers/internal/multisig.test.ts +84 -10
- package/src/handlers/internal/multisig.ts +15 -50
- package/src/handlers/internal/sponsorship.ts +106 -20
- package/src/handlers/internal/utils.ts +19 -7
- package/src/handlers/{internal/relay.localnet.test.ts → relay.test.ts} +2 -2
- package/src/handlers/relay.ts +23 -5
- package/src/index.ts +1 -0
- package/src/internal/Auth.test.ts +491 -25
- package/src/internal/Auth.ts +839 -84
- package/src/internal/Cache.ts +5 -1
- package/src/internal/Cursor.test.ts +3 -2
- package/src/internal/EdgeCache.test.ts +27 -4
- package/src/internal/EdgeCache.ts +47 -9
- package/src/internal/Fees.test.ts +32 -0
- package/src/internal/Fees.ts +51 -0
- package/src/internal/FundingRoutes.ts +583 -0
- package/src/internal/Id.test.ts +17 -0
- package/src/internal/Id.ts +24 -0
- package/src/internal/Log.test.ts +2 -1
- package/src/internal/Log.ts +16 -3
- package/src/internal/MetricSink.ts +1 -1
- package/src/internal/OpenApi.ts +12 -60
- package/src/internal/RateLimit.test.ts +84 -0
- package/src/internal/RateLimit.ts +70 -0
- package/src/internal/Response.ts +1 -1
- package/src/internal/Schema.ts +8 -0
- package/src/internal/Store.test.ts +52 -0
- package/src/internal/Store.ts +24 -5
- package/src/internal/Tidx.local.test.ts +1 -1
- package/src/internal/VerifiedTokens.test.ts +1 -1
- package/src/internal/WebhookDestination.test.ts +1 -1
- package/src/internal/Webhooks.test.ts +7 -7
- package/src/internal/Webhooks.ts +4 -4
- package/dist/apps/activities.js.map +0 -1
- package/dist/apps/addresses.js.map +0 -1
- package/dist/apps/balances.d.ts.map +0 -1
- package/dist/apps/balances.js.map +0 -1
- package/dist/apps/blocks.d.ts.map +0 -1
- package/dist/apps/blocks.js.map +0 -1
- package/dist/apps/coingecko.d.ts.map +0 -1
- package/dist/apps/coingecko.js.map +0 -1
- package/dist/apps/exchanges.d.ts.map +0 -1
- package/dist/apps/exchanges.js.map +0 -1
- package/dist/apps/fee-amm.d.ts.map +0 -1
- package/dist/apps/fee-amm.js.map +0 -1
- package/dist/apps/indexer.d.ts.map +0 -1
- package/dist/apps/indexer.js.map +0 -1
- package/dist/apps/receipts.d.ts.map +0 -1
- package/dist/apps/receipts.js.map +0 -1
- package/dist/apps/rpc.d.ts.map +0 -1
- package/dist/apps/rpc.js.map +0 -1
- package/dist/apps/tokenlist.d.ts.map +0 -1
- package/dist/apps/tokenlist.js.map +0 -1
- package/dist/apps/tokens.d.ts.map +0 -1
- package/dist/apps/tokens.js.map +0 -1
- package/dist/apps/transactions.d.ts.map +0 -1
- package/dist/apps/transactions.js.map +0 -1
- package/dist/apps/transfers.d.ts.map +0 -1
- package/dist/apps/transfers.js.map +0 -1
- package/dist/apps/verified-tokens.d.ts.map +0 -1
- package/dist/apps/verified-tokens.js.map +0 -1
- package/dist/apps/webhooks.js.map +0 -1
- package/dist/internal/OpenApi.fonts.d.ts.map +0 -1
- package/dist/internal/OpenApi.fonts.js.map +0 -1
- package/dist/internal/OpenApi.logo.d.ts.map +0 -1
- package/dist/internal/OpenApi.logo.js.map +0 -1
- package/src/handlers/internal/multisig.localnet.test.ts +0 -146
- /package/src/{internal/OpenApi.fonts.ts → apps/docs/fonts.ts} +0 -0
- /package/src/{internal/OpenApi.logo.ts → apps/docs/logo.ts} +0 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import type { Hex } from 'ox'
|
|
2
|
+
import { TxEnvelopeTempo } from 'ox/tempo'
|
|
3
|
+
import {
|
|
4
|
+
type Address,
|
|
5
|
+
type Client,
|
|
6
|
+
type EIP1193RequestFn,
|
|
7
|
+
type TransactionReceipt,
|
|
8
|
+
TransactionReceiptNotFoundError,
|
|
9
|
+
} from 'viem'
|
|
10
|
+
import { getTransactionReceipt } from 'viem/actions'
|
|
11
|
+
|
|
12
|
+
import * as Db from '../../db/Db.js'
|
|
13
|
+
import * as Fees from '../../internal/Fees.js'
|
|
14
|
+
import * as SponsoredTransactions from '../../db/tables/sponsoredTransactions.js'
|
|
15
|
+
import * as Tidx from '../../internal/Tidx.js'
|
|
16
|
+
import * as Viem from '../../internal/Viem.js'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Runs one finalization pass over pending sponsored transactions: rows with a
|
|
20
|
+
* receipt finalize with the actual fee (`gasUsed × effectiveGasPrice`, in
|
|
21
|
+
* fee-token base units); rows still unmined past the pending TTL fail, as do
|
|
22
|
+
* hash-less fill intents the TTL outlives. Rows whose receipt lookup errors
|
|
23
|
+
* persist past the error TTL fail so they cannot monopolize every batch.
|
|
24
|
+
*
|
|
25
|
+
* @param db - The database holding `sponsored_transactions`.
|
|
26
|
+
* @param options - Finalization options.
|
|
27
|
+
* @returns Counters for the pass.
|
|
28
|
+
*/
|
|
29
|
+
export async function finalize(db: Db.Db, options: finalize.Options): Promise<finalize.Result> {
|
|
30
|
+
const {
|
|
31
|
+
batchSize = 100,
|
|
32
|
+
getClient,
|
|
33
|
+
now = () => new Date(),
|
|
34
|
+
pendingTtlMs = 3_600_000,
|
|
35
|
+
receiptErrorTtlMs = 86_400_000,
|
|
36
|
+
} = options
|
|
37
|
+
|
|
38
|
+
const rows = await SponsoredTransactions.listPending(db, { limit: batchSize })
|
|
39
|
+
const result = { failed: 0, finalized: 0, pending: 0 }
|
|
40
|
+
|
|
41
|
+
for (const row of rows) {
|
|
42
|
+
// Fill intents carry no hash until reconciliation matches them on-chain;
|
|
43
|
+
// here only the TTL can settle them.
|
|
44
|
+
if (row.transactionHash === null) {
|
|
45
|
+
if (Date.parse(row.createdAt) + pendingTtlMs <= now().getTime()) {
|
|
46
|
+
await SponsoredTransactions.fail(db, row.id, now().toISOString())
|
|
47
|
+
result.failed++
|
|
48
|
+
} else result.pending++
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let receipt: TransactionReceipt | null
|
|
53
|
+
try {
|
|
54
|
+
receipt = await getTransactionReceipt(getClient(row.chainId), {
|
|
55
|
+
hash: row.transactionHash as Hex.Hex,
|
|
56
|
+
})
|
|
57
|
+
} catch (error) {
|
|
58
|
+
// Unmined transactions surface as a typed not-found; let the TTL decide.
|
|
59
|
+
if (error instanceof TransactionReceiptNotFoundError) receipt = null
|
|
60
|
+
else {
|
|
61
|
+
if (Date.parse(row.createdAt) + receiptErrorTtlMs <= now().getTime()) {
|
|
62
|
+
await SponsoredTransactions.fail(db, row.id, now().toISOString())
|
|
63
|
+
result.failed++
|
|
64
|
+
} else result.pending++
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (receipt) {
|
|
70
|
+
// A reverted transaction still finalizes: the fee payer paid its fees.
|
|
71
|
+
const feeAmount = Fees.fromGas(receipt.gasUsed, receipt.effectiveGasPrice)
|
|
72
|
+
await SponsoredTransactions.finalize(db, row.id, {
|
|
73
|
+
feeAmount: feeAmount.toString(),
|
|
74
|
+
finalizedAt: now().toISOString(),
|
|
75
|
+
})
|
|
76
|
+
result.finalized++
|
|
77
|
+
} else if (Date.parse(row.createdAt) + pendingTtlMs <= now().getTime()) {
|
|
78
|
+
await SponsoredTransactions.fail(db, row.id, now().toISOString())
|
|
79
|
+
result.failed++
|
|
80
|
+
} else result.pending++
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export declare namespace finalize {
|
|
87
|
+
/** Options for {@link finalize}. */
|
|
88
|
+
type Options = {
|
|
89
|
+
/** Maximum pending rows processed per pass. @default 100 */
|
|
90
|
+
batchSize?: number | undefined
|
|
91
|
+
/** Client resolver keyed by the row's chain id. */
|
|
92
|
+
getClient: (chainId: number) => Client
|
|
93
|
+
/** Clock; injectable for tests. */
|
|
94
|
+
now?: (() => Date) | undefined
|
|
95
|
+
/** Age after which an unmined sponsorship fails. @default 1 hour */
|
|
96
|
+
pendingTtlMs?: number | undefined
|
|
97
|
+
/** Age after which repeated receipt lookup errors fail a row. @default 24 hours */
|
|
98
|
+
receiptErrorTtlMs?: number | undefined
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Counters returned by one finalization pass. */
|
|
102
|
+
type Result = {
|
|
103
|
+
/** Rows marked failed (unmined past the pending TTL). */
|
|
104
|
+
failed: number
|
|
105
|
+
/** Rows finalized with an actual fee. */
|
|
106
|
+
finalized: number
|
|
107
|
+
/** Rows left pending (unmined, or receipt lookup errored within the error TTL). */
|
|
108
|
+
pending: number
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Runs one reconciliation pass over pending fill intents (rows with no
|
|
114
|
+
* transaction hash): fetches the fee payer's recent on-chain transactions
|
|
115
|
+
* from TIDX, recomputes each candidate's fee-payer sign payload, and fills
|
|
116
|
+
* matching intents' hashes so the receipt pass can finalize them. Query or
|
|
117
|
+
* candidate errors leave intents for the next pass.
|
|
118
|
+
*
|
|
119
|
+
* @param db - The database holding `sponsored_transactions`.
|
|
120
|
+
* @param options - Reconciliation options.
|
|
121
|
+
* @returns Counters for the pass.
|
|
122
|
+
*/
|
|
123
|
+
export async function reconcile(db: Db.Db, options: reconcile.Options): Promise<reconcile.Result> {
|
|
124
|
+
const {
|
|
125
|
+
batchSize = 100,
|
|
126
|
+
candidateCap = 500,
|
|
127
|
+
failedIntentTtlMs = 86_400_000,
|
|
128
|
+
feePayer,
|
|
129
|
+
getClient,
|
|
130
|
+
getTidx,
|
|
131
|
+
skewMs = 120_000,
|
|
132
|
+
} = options
|
|
133
|
+
|
|
134
|
+
const intents = await SponsoredTransactions.listIntents(db, {
|
|
135
|
+
failedSince: new Date(Date.now() - failedIntentTtlMs).toISOString(),
|
|
136
|
+
limit: batchSize,
|
|
137
|
+
})
|
|
138
|
+
const result = { matched: 0, scanned: 0 }
|
|
139
|
+
if (intents.length === 0) return result
|
|
140
|
+
|
|
141
|
+
const chains = new Map<number, SponsoredTransactions.Record[]>()
|
|
142
|
+
for (const intent of intents) chains.set(intent.chainId, [...(chains.get(intent.chainId) ?? []), intent]) // prettier-ignore
|
|
143
|
+
|
|
144
|
+
for (const [chainId, rows] of chains) {
|
|
145
|
+
const bySignPayload = new Map(rows.map((row) => [row.signPayload, row]))
|
|
146
|
+
// The intent set bounds the scan window: no cursor state to persist.
|
|
147
|
+
const since = new Date(
|
|
148
|
+
Math.min(...rows.map((row) => Date.parse(row.createdAt))) - skewMs,
|
|
149
|
+
).toISOString()
|
|
150
|
+
|
|
151
|
+
let candidates: readonly globalThis.Record<string, unknown>[]
|
|
152
|
+
try {
|
|
153
|
+
// Dynamic filter values; the tidx client's query type wants literals.
|
|
154
|
+
const fetched = await getTidx(chainId).fetch({
|
|
155
|
+
chainId,
|
|
156
|
+
query:
|
|
157
|
+
`SELECT hash, "from" FROM txs WHERE fee_payer = '${feePayer.toLowerCase()}' AND block_timestamp >= '${since}' ORDER BY block_timestamp ASC LIMIT ${candidateCap}` as string,
|
|
158
|
+
})
|
|
159
|
+
candidates = fetched.rows
|
|
160
|
+
} catch {
|
|
161
|
+
// Indexer outage must not fail intents; retry on the next pass.
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (const candidate of candidates) {
|
|
166
|
+
if (bySignPayload.size === 0) break
|
|
167
|
+
const hash = candidate['hash'] as Hex.Hex | undefined
|
|
168
|
+
const sender = candidate['from'] as Address | undefined
|
|
169
|
+
if (!hash || !sender) continue
|
|
170
|
+
result.scanned++
|
|
171
|
+
try {
|
|
172
|
+
const serialized = await getRawTransaction(getClient(chainId), hash)
|
|
173
|
+
if (!serialized?.startsWith(TxEnvelopeTempo.serializedType)) continue
|
|
174
|
+
const signPayload = TxEnvelopeTempo.getFeePayerSignPayload(
|
|
175
|
+
TxEnvelopeTempo.deserialize(serialized as TxEnvelopeTempo.Serialized),
|
|
176
|
+
{ sender },
|
|
177
|
+
)
|
|
178
|
+
const intent = bySignPayload.get(signPayload)
|
|
179
|
+
if (!intent) continue
|
|
180
|
+
await SponsoredTransactions.assignTransactionHash(db, intent.id, hash)
|
|
181
|
+
bySignPayload.delete(signPayload)
|
|
182
|
+
result.matched++
|
|
183
|
+
} catch {
|
|
184
|
+
// Unresolvable candidate (lookup error, malformed envelope): skip it.
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return result
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export declare namespace reconcile {
|
|
193
|
+
/** Options for {@link reconcile}. */
|
|
194
|
+
type Options = {
|
|
195
|
+
/** Maximum intents considered per pass. @default 100 */
|
|
196
|
+
batchSize?: number | undefined
|
|
197
|
+
/** Maximum on-chain candidates fetched per chain per pass. @default 500 */
|
|
198
|
+
candidateCap?: number | undefined
|
|
199
|
+
/** How long failed intents remain reconciliation candidates. @default 24 hours */
|
|
200
|
+
failedIntentTtlMs?: number | undefined
|
|
201
|
+
/** Fee payer address whose on-chain transactions are candidates. */
|
|
202
|
+
feePayer: Address
|
|
203
|
+
/** Client resolver keyed by the intent's chain id. */
|
|
204
|
+
getClient: (chainId: number) => Client
|
|
205
|
+
/** TIDX client resolver keyed by the intent's chain id. */
|
|
206
|
+
getTidx: (chainId: number) => Tidx.Client
|
|
207
|
+
/** Lookback slack before the oldest intent's creation. @default 2 minutes */
|
|
208
|
+
skewMs?: number | undefined
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Counters returned by one reconciliation pass. */
|
|
212
|
+
type Result = {
|
|
213
|
+
/** Intents matched to an on-chain transaction. */
|
|
214
|
+
matched: number
|
|
215
|
+
/** On-chain candidates inspected. */
|
|
216
|
+
scanned: number
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Fetches a mined transaction's canonical envelope bytes.
|
|
222
|
+
* `eth_getRawTransactionByHash` is a node extension absent from viem's typed
|
|
223
|
+
* RPC schema, hence the request-fn narrowing.
|
|
224
|
+
*/
|
|
225
|
+
function getRawTransaction(client: Client, hash: Hex.Hex) {
|
|
226
|
+
type Request = EIP1193RequestFn<
|
|
227
|
+
[
|
|
228
|
+
{
|
|
229
|
+
Method: 'eth_getRawTransactionByHash'
|
|
230
|
+
Parameters: readonly [Hex.Hex]
|
|
231
|
+
ReturnType: Hex.Hex | null
|
|
232
|
+
},
|
|
233
|
+
]
|
|
234
|
+
>
|
|
235
|
+
return (client.request as Request)({ method: 'eth_getRawTransactionByHash', params: [hash] })
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Builds a scheduled sponsorship finalizer bound to a database and RPC config.
|
|
240
|
+
* A host runtime drives {@link createFinalizer.Finalizer.tick} on a timer (a
|
|
241
|
+
* Cloudflare `scheduled` cron handler, a self-host `setInterval`, …); each
|
|
242
|
+
* tick reconciles fill intents (when `feePayer` + `tidx` are configured) and
|
|
243
|
+
* runs one {@link finalize} pass, with memoized per-chain clients.
|
|
244
|
+
*/
|
|
245
|
+
export function createFinalizer(options: createFinalizer.Options): createFinalizer.Finalizer {
|
|
246
|
+
const clients = new Map<number, Viem.getClient.ReturnType>()
|
|
247
|
+
const getClient = (chainId: number) => {
|
|
248
|
+
let client = clients.get(chainId)
|
|
249
|
+
if (!client) {
|
|
250
|
+
client = Viem.getClient({ chainId: chainId as Viem.ChainId, rpc: options.rpc })
|
|
251
|
+
clients.set(chainId, client)
|
|
252
|
+
}
|
|
253
|
+
return client
|
|
254
|
+
}
|
|
255
|
+
const getTidx = options.tidx
|
|
256
|
+
? Tidx.createGetClient({ defaultChainId: options.defaultChainId, tidx: options.tidx })
|
|
257
|
+
: undefined
|
|
258
|
+
const feePayer = options.feePayer
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
async tick() {
|
|
262
|
+
// Resolve per tick so Workers factories build a fresh Hyperdrive-pooled
|
|
263
|
+
// connection each run.
|
|
264
|
+
const db = Db.get(options.db)
|
|
265
|
+
// Reconcile first so freshly matched intents finalize in the same tick.
|
|
266
|
+
const reconciled =
|
|
267
|
+
feePayer && getTidx
|
|
268
|
+
? await reconcile(db, {
|
|
269
|
+
batchSize: options.batchSize,
|
|
270
|
+
feePayer,
|
|
271
|
+
getClient,
|
|
272
|
+
getTidx: (chainId) => getTidx(chainId as Viem.ChainId),
|
|
273
|
+
})
|
|
274
|
+
: { matched: 0, scanned: 0 }
|
|
275
|
+
const finalized = await finalize(db, {
|
|
276
|
+
batchSize: options.batchSize,
|
|
277
|
+
getClient,
|
|
278
|
+
now: options.now,
|
|
279
|
+
pendingTtlMs: options.pendingTtlMs,
|
|
280
|
+
})
|
|
281
|
+
return { ...finalized, ...reconciled }
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export declare namespace createFinalizer {
|
|
287
|
+
/** Options for {@link createFinalizer}. */
|
|
288
|
+
type Options = Pick<finalize.Options, 'batchSize' | 'now' | 'pendingTtlMs'> & {
|
|
289
|
+
/** Database holding sponsorship rows, or a factory resolved per tick (Workers/Hyperdrive). */
|
|
290
|
+
db: Db.Source
|
|
291
|
+
/** Default chain id for the TIDX client resolver. */
|
|
292
|
+
defaultChainId?: Viem.ChainId | undefined
|
|
293
|
+
/** Fee payer address whose on-chain transactions reconcile fill intents; omit to skip reconciliation. */
|
|
294
|
+
feePayer?: Address | undefined
|
|
295
|
+
/** RPC options for the receipt-lookup clients. */
|
|
296
|
+
rpc?: Viem.getClient.Rpc | undefined
|
|
297
|
+
/** TIDX query client options for intent reconciliation; omit to skip reconciliation. */
|
|
298
|
+
tidx?: Tidx.getClient.Tidx | undefined
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** A scheduled sponsorship finalizer. */
|
|
302
|
+
type Finalizer = {
|
|
303
|
+
/** Runs one reconcile + finalize pass. */
|
|
304
|
+
tick(): Promise<finalize.Result & reconcile.Result>
|
|
305
|
+
}
|
|
306
|
+
}
|
package/src/cli/Cli.test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Cli as incur_Cli, z } from 'incur'
|
|
1
2
|
import { Cli } from 'tapimo'
|
|
2
3
|
|
|
3
4
|
import * as TestApp from '../../test/App.js'
|
|
@@ -10,7 +11,7 @@ describe('from', () => {
|
|
|
10
11
|
const fetch = mockHostedApi()
|
|
11
12
|
|
|
12
13
|
try {
|
|
13
|
-
const cli = Cli.from(apiUrl, { version: '1.2.3' })
|
|
14
|
+
const cli = Cli.from(apiUrl, { docs: false, version: '1.2.3' })
|
|
14
15
|
await serve(cli, ['--help'])
|
|
15
16
|
|
|
16
17
|
expect(cli.name).toMatchInlineSnapshot(`"tapimo"`)
|
|
@@ -28,7 +29,7 @@ describe('from', () => {
|
|
|
28
29
|
const fetch = mockHostedApi(TestApp.create({ db }))
|
|
29
30
|
|
|
30
31
|
try {
|
|
31
|
-
const cli = Cli.from(apiUrl)
|
|
32
|
+
const cli = Cli.from(apiUrl, { docs: false })
|
|
32
33
|
// `/v1/tokens?verified=true` now serves the curated verified list through
|
|
33
34
|
// the standard listing endpoint, so the CLI surfaces the filter as a
|
|
34
35
|
// `--verified` flag on the `v1 tokens get` command instead of routing
|
|
@@ -52,6 +53,28 @@ describe('from', () => {
|
|
|
52
53
|
fetch.mockRestore()
|
|
53
54
|
}
|
|
54
55
|
})
|
|
56
|
+
|
|
57
|
+
test('mounts the docs MCP source as a command group', async () => {
|
|
58
|
+
const fetch = mockHostedApi()
|
|
59
|
+
|
|
60
|
+
// Stub remote docs MCP server: an in-process incur CLI serving `/mcp`.
|
|
61
|
+
const remote = incur_Cli.create('docs-remote', { version: '1.0.0' }).command('search', {
|
|
62
|
+
description: 'Search docs',
|
|
63
|
+
options: z.object({ query: z.string().describe('Search query') }),
|
|
64
|
+
run: (context) => ({ hits: [context.options.query] }),
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const cli = Cli.from(apiUrl, {
|
|
69
|
+
docs: { fetch: (request) => remote.fetch(request), url: 'http://docs.local/mcp' },
|
|
70
|
+
})
|
|
71
|
+
const output = await serve(cli, ['docs', 'search', '--query', 'fees', '--format', 'json'])
|
|
72
|
+
|
|
73
|
+
expect(JSON.parse(output)).toEqual({ hits: ['fees'] })
|
|
74
|
+
} finally {
|
|
75
|
+
fetch.mockRestore()
|
|
76
|
+
}
|
|
77
|
+
})
|
|
55
78
|
})
|
|
56
79
|
|
|
57
80
|
function mockHostedApi(app = TestApp.create()) {
|
package/src/cli/Cli.ts
CHANGED
|
@@ -1,29 +1,42 @@
|
|
|
1
1
|
import { Cli as incur_Cli, Fetch, type Openapi } from 'incur'
|
|
2
2
|
|
|
3
|
+
import type { mcp } from '../apps/mcp.js'
|
|
3
4
|
import * as Admin from './commands/admin.js'
|
|
4
5
|
|
|
6
|
+
/** Tool patterns hidden from MCP clients: super admin, partner-shaped gecko mirrors, browser session flows. */
|
|
7
|
+
const excludedTools = ['admin_*', 'gecko_*', 'v1_auth_*']
|
|
8
|
+
|
|
9
|
+
/** Usage guidance surfaced to MCP clients on initialize (`<cli> --mcp`). */
|
|
10
|
+
const instructions =
|
|
11
|
+
'Tools mirror the hosted Tempo API. Authenticated tools accept an `authorization` input (`Bearer <api key>`). List endpoints paginate via `cursor`/`nextCursor`. `docs_*` tools search the Tempo documentation.'
|
|
12
|
+
|
|
5
13
|
/**
|
|
6
|
-
* Creates an incur CLI backed by a hosted Tempo API, plus the
|
|
7
|
-
* commands (`<cli> admin …`).
|
|
14
|
+
* Creates an incur CLI backed by a hosted Tempo API, plus the super admin
|
|
15
|
+
* commands (`<cli> admin …`) and the remote Tempo docs tools (`<cli> docs …`).
|
|
8
16
|
*/
|
|
9
17
|
export function from(url: string | URL, options: from.Options = {}) {
|
|
10
18
|
const {
|
|
11
19
|
description = 'Tempo API CLI',
|
|
20
|
+
docs = 'https://mcp.tempo.xyz/mcp',
|
|
12
21
|
name = 'tapimo',
|
|
13
22
|
openapi = 'openapi.json',
|
|
14
23
|
request,
|
|
15
24
|
version = '0.0.0',
|
|
16
25
|
} = options
|
|
17
26
|
|
|
18
|
-
|
|
27
|
+
const cli = incur_Cli
|
|
19
28
|
.create(name, {
|
|
20
29
|
description,
|
|
21
30
|
fetch: Fetch.fromRequest(url, request),
|
|
31
|
+
mcp: { instructions, tools: { exclude: excludedTools } },
|
|
22
32
|
openapi,
|
|
23
33
|
openapiConfig: options.openapiConfig ?? { mode: 'namespace' },
|
|
24
34
|
version,
|
|
25
35
|
})
|
|
26
36
|
.command(Admin.admin)
|
|
37
|
+
if (docs !== false)
|
|
38
|
+
cli.command('docs', { description: 'Search the Tempo documentation.', mcp: docs })
|
|
39
|
+
return cli
|
|
27
40
|
}
|
|
28
41
|
|
|
29
42
|
export declare namespace from {
|
|
@@ -31,6 +44,8 @@ export declare namespace from {
|
|
|
31
44
|
type Options = {
|
|
32
45
|
/** CLI description. */
|
|
33
46
|
description?: string | undefined
|
|
47
|
+
/** Remote docs MCP source mounted as the `docs` command group, or `false` to omit it. @default 'https://mcp.tempo.xyz/mcp' */
|
|
48
|
+
docs?: mcp.Source | false | undefined
|
|
34
49
|
/** CLI name. */
|
|
35
50
|
name?: string | undefined
|
|
36
51
|
/** OpenAPI document source. Relative paths resolve from the API URL. */
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { nanoid } from 'nanoid'
|
|
2
2
|
|
|
3
3
|
import * as TestCli from '../../../test/cli.js'
|
|
4
|
+
import * as Analytics from '../../analytics/Analytics.js'
|
|
5
|
+
|
|
6
|
+
afterEach(() => vi.unstubAllGlobals())
|
|
4
7
|
|
|
5
8
|
describe('admin', () => {
|
|
6
9
|
describe('migrate', () => {
|
|
@@ -67,5 +70,85 @@ describe('admin', () => {
|
|
|
67
70
|
expect(code).toBe(1)
|
|
68
71
|
expect(envelope.error.code).toBe('migrate_failed')
|
|
69
72
|
})
|
|
73
|
+
|
|
74
|
+
test('behavior: applies ClickHouse analytics migrations when configured', async () => {
|
|
75
|
+
const fetch = vi
|
|
76
|
+
.fn<typeof globalThis.fetch>()
|
|
77
|
+
.mockResolvedValue(new Response('', { status: 200 }))
|
|
78
|
+
vi.stubGlobal('fetch', fetch)
|
|
79
|
+
|
|
80
|
+
const { code, envelope } = await TestCli.run(
|
|
81
|
+
['admin', 'migrate', '--db-schema', `t_${nanoid()}`],
|
|
82
|
+
{
|
|
83
|
+
CLICKHOUSE_DATABASE: 'tempo_api',
|
|
84
|
+
CLICKHOUSE_MIGRATE_PASSWORD: 'ddl-secret',
|
|
85
|
+
CLICKHOUSE_MIGRATE_USER: 'ddl',
|
|
86
|
+
CLICKHOUSE_URL: 'https://clickhouse.test',
|
|
87
|
+
},
|
|
88
|
+
)
|
|
89
|
+
expect(code).toBe(0)
|
|
90
|
+
expect(envelope).toEqual({ data: { analytics: true, migrated: true }, ok: true })
|
|
91
|
+
const url = new URL(String(fetch.mock.calls[0]![0]))
|
|
92
|
+
expect(url.searchParams.get('database')).toBe('tempo_api')
|
|
93
|
+
const bodies = fetch.mock.calls.map((call) => String(call[1]?.body))
|
|
94
|
+
for (const migration of Analytics.migrations) expect(bodies).toContain(migration.sql)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test('behavior: skips analytics migrations when ClickHouse env is unset or empty', async () => {
|
|
98
|
+
const fetch = vi.fn<typeof globalThis.fetch>()
|
|
99
|
+
vi.stubGlobal('fetch', fetch)
|
|
100
|
+
|
|
101
|
+
const { code, envelope } = await TestCli.run(
|
|
102
|
+
['admin', 'migrate', '--db-schema', `t_${nanoid()}`],
|
|
103
|
+
{
|
|
104
|
+
CLICKHOUSE_DATABASE: '',
|
|
105
|
+
CLICKHOUSE_MIGRATE_PASSWORD: '',
|
|
106
|
+
CLICKHOUSE_MIGRATE_USER: '',
|
|
107
|
+
CLICKHOUSE_URL: '',
|
|
108
|
+
},
|
|
109
|
+
)
|
|
110
|
+
expect(code).toBe(0)
|
|
111
|
+
expect(envelope).toEqual({ data: { migrated: true }, ok: true })
|
|
112
|
+
expect(fetch).not.toHaveBeenCalled()
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
test('error: partial ClickHouse config exits 1', async () => {
|
|
116
|
+
const { code, envelope } = await TestCli.run(['admin', 'migrate'], {
|
|
117
|
+
CLICKHOUSE_MIGRATE_PASSWORD: 'ddl-secret',
|
|
118
|
+
})
|
|
119
|
+
expect(code).toBe(1)
|
|
120
|
+
expect(envelope).toEqual({
|
|
121
|
+
error: {
|
|
122
|
+
code: 'missing_clickhouse_config',
|
|
123
|
+
message:
|
|
124
|
+
'ClickHouse analytics migration is partially configured; set CLICKHOUSE_DATABASE, CLICKHOUSE_MIGRATE_USER, CLICKHOUSE_URL.',
|
|
125
|
+
},
|
|
126
|
+
ok: false,
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test('error: a ClickHouse migration failure exits 1', async () => {
|
|
131
|
+
vi.stubGlobal(
|
|
132
|
+
'fetch',
|
|
133
|
+
vi.fn<typeof globalThis.fetch>().mockResolvedValue(new Response('denied', { status: 403 })),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
const { code, envelope } = await TestCli.run([
|
|
137
|
+
'admin',
|
|
138
|
+
'migrate',
|
|
139
|
+
'--clickhouse-database',
|
|
140
|
+
'tempo_api',
|
|
141
|
+
'--clickhouse-migrate-password',
|
|
142
|
+
'ddl-secret',
|
|
143
|
+
'--clickhouse-migrate-user',
|
|
144
|
+
'ddl',
|
|
145
|
+
'--clickhouse-url',
|
|
146
|
+
'https://clickhouse.test',
|
|
147
|
+
'--db-schema',
|
|
148
|
+
`t_${nanoid()}`,
|
|
149
|
+
])
|
|
150
|
+
expect(code).toBe(1)
|
|
151
|
+
expect(envelope.error.code).toBe('migrate_failed')
|
|
152
|
+
})
|
|
70
153
|
})
|
|
71
154
|
})
|
|
@@ -1,21 +1,53 @@
|
|
|
1
1
|
import { Cli as incur_Cli, z } from 'incur'
|
|
2
2
|
|
|
3
|
+
import * as Analytics from '../../analytics/Analytics.js'
|
|
3
4
|
import * as Db from '../../db/Db.js'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Applies pending Postgres migrations, connecting directly via
|
|
7
8
|
* `--database-url` or `DATABASE_URL` (never through Hyperdrive — the migrate
|
|
8
9
|
* advisory lock needs session semantics); `--db-schema` scopes the session.
|
|
10
|
+
* When ClickHouse migrate credentials are configured, also applies analytics
|
|
11
|
+
* schema migrations ({@link Analytics.migrations}) over the HTTP interface.
|
|
9
12
|
*/
|
|
10
13
|
const migrate = incur_Cli.create('migrate', {
|
|
11
14
|
description: 'Apply pending database migrations.',
|
|
12
15
|
env: z.object({
|
|
16
|
+
CLICKHOUSE_DATABASE: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('ClickHouse database for analytics migrations.'),
|
|
20
|
+
CLICKHOUSE_MIGRATE_PASSWORD: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Password for the DDL-capable ClickHouse user.'),
|
|
24
|
+
CLICKHOUSE_MIGRATE_USER: z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('DDL-capable ClickHouse user for analytics migrations.'),
|
|
28
|
+
CLICKHOUSE_URL: z.string().optional().describe('ClickHouse HTTPS endpoint.'),
|
|
13
29
|
DATABASE_URL: z
|
|
14
30
|
.string()
|
|
15
31
|
.optional()
|
|
16
32
|
.describe('Postgres connection string. Used when --database-url is omitted.'),
|
|
17
33
|
}),
|
|
18
34
|
options: z.object({
|
|
35
|
+
clickhouseDatabase: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('ClickHouse database. Overrides CLICKHOUSE_DATABASE.'),
|
|
39
|
+
clickhouseMigratePassword: z
|
|
40
|
+
.string()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe('ClickHouse DDL password. Overrides CLICKHOUSE_MIGRATE_PASSWORD.'),
|
|
43
|
+
clickhouseMigrateUser: z
|
|
44
|
+
.string()
|
|
45
|
+
.optional()
|
|
46
|
+
.describe('ClickHouse DDL user. Overrides CLICKHOUSE_MIGRATE_USER.'),
|
|
47
|
+
clickhouseUrl: z
|
|
48
|
+
.string()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe('ClickHouse HTTPS endpoint. Overrides CLICKHOUSE_URL.'),
|
|
19
51
|
databaseUrl: z
|
|
20
52
|
.string()
|
|
21
53
|
.optional()
|
|
@@ -29,13 +61,25 @@ const migrate = incur_Cli.create('migrate', {
|
|
|
29
61
|
code: 'missing_database_url',
|
|
30
62
|
message: 'Set --database-url or DATABASE_URL to the Postgres connection string.',
|
|
31
63
|
})
|
|
64
|
+
|
|
65
|
+
const analytics = clickhouseConfig({
|
|
66
|
+
database: c.options.clickhouseDatabase ?? c.env.CLICKHOUSE_DATABASE,
|
|
67
|
+
password: c.options.clickhouseMigratePassword ?? c.env.CLICKHOUSE_MIGRATE_PASSWORD,
|
|
68
|
+
url: c.options.clickhouseUrl ?? c.env.CLICKHOUSE_URL,
|
|
69
|
+
user: c.options.clickhouseMigrateUser ?? c.env.CLICKHOUSE_MIGRATE_USER,
|
|
70
|
+
})
|
|
71
|
+
if (analytics?.missing)
|
|
72
|
+
return c.error({
|
|
73
|
+
code: 'missing_clickhouse_config',
|
|
74
|
+
message: `ClickHouse analytics migration is partially configured; set ${analytics.missing.join(', ')}.`,
|
|
75
|
+
})
|
|
76
|
+
|
|
32
77
|
const db = Db.postgres({
|
|
33
78
|
connectionString,
|
|
34
79
|
...(c.options.dbSchema ? { schema: c.options.dbSchema } : {}),
|
|
35
80
|
})
|
|
36
81
|
try {
|
|
37
82
|
await db.migrate()
|
|
38
|
-
return { migrated: true }
|
|
39
83
|
} catch (error) {
|
|
40
84
|
/* v8 ignore next */
|
|
41
85
|
const message = error instanceof Error ? error.message : 'Migration failed.'
|
|
@@ -46,15 +90,59 @@ const migrate = incur_Cli.create('migrate', {
|
|
|
46
90
|
} finally {
|
|
47
91
|
await db.close()
|
|
48
92
|
}
|
|
93
|
+
if (!analytics) return { migrated: true }
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
await Analytics.clickhouse(analytics.options).migrate()
|
|
97
|
+
} catch (error) {
|
|
98
|
+
/* v8 ignore next */
|
|
99
|
+
const message = error instanceof Error ? error.message : 'Migration failed.'
|
|
100
|
+
return c.error({
|
|
101
|
+
code: 'migrate_failed',
|
|
102
|
+
message,
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
return { analytics: true, migrated: true }
|
|
49
106
|
},
|
|
50
107
|
})
|
|
51
108
|
|
|
52
109
|
/**
|
|
53
|
-
*
|
|
110
|
+
* Super admin commands that run against a deployment's infrastructure rather
|
|
54
111
|
* than the hosted API (database migrations, …).
|
|
55
112
|
*/
|
|
56
113
|
export const admin = incur_Cli
|
|
57
114
|
.create('admin', {
|
|
58
|
-
description: '
|
|
115
|
+
description: 'Super admin commands for a Tempo API deployment.',
|
|
59
116
|
})
|
|
60
117
|
.command(migrate)
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Resolves ClickHouse migrate config. Credentials gate the migration (absent
|
|
121
|
+
* → skip); empty values count as unset since CI renders missing secrets as
|
|
122
|
+
* empty strings. Partial config returns the missing variable names instead.
|
|
123
|
+
*/
|
|
124
|
+
function clickhouseConfig(input: {
|
|
125
|
+
database?: string | undefined
|
|
126
|
+
password?: string | undefined
|
|
127
|
+
url?: string | undefined
|
|
128
|
+
user?: string | undefined
|
|
129
|
+
}):
|
|
130
|
+
| { missing: readonly string[]; options?: undefined }
|
|
131
|
+
| { missing?: undefined; options: Analytics.clickhouse.Options }
|
|
132
|
+
| undefined {
|
|
133
|
+
const database = input.database || undefined
|
|
134
|
+
const password = input.password || undefined
|
|
135
|
+
const url = input.url || undefined
|
|
136
|
+
const user = input.user || undefined
|
|
137
|
+
if (password === undefined && user === undefined) return undefined
|
|
138
|
+
if (database === undefined || password === undefined || url === undefined || user === undefined)
|
|
139
|
+
return {
|
|
140
|
+
missing: [
|
|
141
|
+
...(database === undefined ? ['CLICKHOUSE_DATABASE'] : []),
|
|
142
|
+
...(password === undefined ? ['CLICKHOUSE_MIGRATE_PASSWORD'] : []),
|
|
143
|
+
...(user === undefined ? ['CLICKHOUSE_MIGRATE_USER'] : []),
|
|
144
|
+
...(url === undefined ? ['CLICKHOUSE_URL'] : []),
|
|
145
|
+
],
|
|
146
|
+
}
|
|
147
|
+
return { options: { database, password, url, user } }
|
|
148
|
+
}
|