tapimo 0.0.2 → 0.2.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 +38 -16
- package/dist/ApiKey.d.ts +14 -11
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +11 -12
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +207 -0
- package/dist/ApiKeys.d.ts.map +1 -0
- package/dist/ApiKeys.js +282 -0
- package/dist/ApiKeys.js.map +1 -0
- package/dist/App.d.ts +6771 -3819
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +145 -317
- package/dist/App.js.map +1 -1
- package/dist/Handler.d.ts +86 -0
- package/dist/Handler.d.ts.map +1 -0
- package/dist/Handler.js +83 -0
- package/dist/Handler.js.map +1 -0
- package/dist/Scope.d.ts +14 -4
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +16 -4
- package/dist/Scope.js.map +1 -1
- package/dist/Webhooks.d.ts +5 -7
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +11 -4
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/Access.d.ts +1 -3
- package/dist/admin/Access.d.ts.map +1 -1
- package/dist/admin/Access.js +1 -3
- package/dist/admin/Access.js.map +1 -1
- package/dist/admin/App.d.ts +167 -205
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +2 -4
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +105 -5
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +75 -9
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/scopes.d.ts +6 -0
- package/dist/admin/apps/scopes.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +35 -149
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.js +18 -39
- 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 +1 -1
- package/dist/apps/data/App.d.ts +19176 -0
- package/dist/apps/data/App.d.ts.map +1 -0
- package/dist/apps/data/App.js +236 -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} +49 -49
- 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} +183 -183
- 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} +460 -460
- 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} +94 -94
- 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/{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} +6 -6
- package/dist/apps/data/routes/receipts.d.ts.map +1 -0
- package/dist/apps/{receipts.js → data/routes/receipts.js} +12 -12
- package/dist/apps/data/routes/receipts.js.map +1 -0
- package/dist/apps/{rpc.d.ts → data/routes/rpc.d.ts} +4 -4
- package/dist/apps/data/routes/rpc.d.ts.map +1 -0
- package/dist/apps/{rpc.js → data/routes/rpc.js} +6 -6
- package/dist/apps/data/routes/rpc.js.map +1 -0
- package/dist/apps/{tokenlist.d.ts → data/routes/tokenlist.d.ts} +4 -4
- 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} +11 -11
- 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} +288 -288
- 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} +35 -35
- 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} +42 -42
- 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} +66 -63
- package/dist/apps/{webhooks.d.ts.map → data/routes/webhooks.d.ts.map} +1 -1
- package/dist/apps/{webhooks.js → data/routes/webhooks.js} +67 -59
- package/dist/apps/data/routes/webhooks.js.map +1 -0
- package/dist/apps/docs/App.d.ts +27 -0
- package/dist/apps/docs/App.d.ts.map +1 -0
- package/dist/apps/docs/App.js +122 -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/index.d.ts +4 -0
- package/dist/apps/index.d.ts.map +1 -0
- package/dist/apps/index.js +4 -0
- package/dist/apps/index.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 +2985 -0
- package/dist/apps/platform/App.d.ts.map +1 -0
- package/dist/apps/platform/App.js +74 -0
- package/dist/apps/platform/App.js.map +1 -0
- package/dist/apps/platform/index.d.ts +2 -0
- package/dist/apps/platform/index.d.ts.map +1 -0
- package/dist/apps/platform/index.js +2 -0
- package/dist/apps/platform/index.js.map +1 -0
- package/dist/apps/platform/routes/api-keys.d.ts +681 -0
- package/dist/apps/platform/routes/api-keys.d.ts.map +1 -0
- package/dist/apps/platform/routes/api-keys.js +328 -0
- package/dist/apps/platform/routes/api-keys.js.map +1 -0
- package/dist/apps/platform/routes/invitations.d.ts +733 -0
- package/dist/apps/platform/routes/invitations.d.ts.map +1 -0
- package/dist/apps/platform/routes/invitations.js +413 -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 +582 -0
- package/dist/apps/platform/routes/orgs.d.ts.map +1 -0
- package/dist/apps/platform/routes/orgs.js +265 -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/relay/App.d.ts +41 -0
- package/dist/apps/relay/App.d.ts.map +1 -0
- package/dist/apps/relay/App.js +103 -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 +193 -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.d.ts → cli/Cli.d.ts} +13 -2
- package/dist/cli/Cli.d.ts.map +1 -0
- package/dist/cli/Cli.js +19 -0
- package/dist/cli/Cli.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +4 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands/admin.d.ts +15 -0
- package/dist/cli/commands/admin.d.ts.map +1 -0
- package/dist/cli/commands/admin.js +60 -0
- package/dist/cli/commands/admin.js.map +1 -0
- package/dist/cloudflare.d.ts +7 -0
- package/dist/cloudflare.d.ts.map +1 -1
- package/dist/cloudflare.js +9 -0
- package/dist/cloudflare.js.map +1 -1
- package/dist/db/Db.d.ts +113 -0
- package/dist/db/Db.d.ts.map +1 -0
- package/dist/db/Db.js +402 -0
- package/dist/db/Db.js.map +1 -0
- package/dist/db/Schema.d.ts +168 -0
- package/dist/db/Schema.d.ts.map +1 -0
- package/dist/db/Schema.js +229 -0
- package/dist/db/Schema.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 +123 -0
- package/dist/db/tables/organizations.d.ts.map +1 -0
- package/dist/db/tables/organizations.js +170 -0
- package/dist/db/tables/organizations.js.map +1 -0
- 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/sponsoredTransactions.d.ts +120 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -0
- package/dist/db/tables/sponsoredTransactions.js +161 -0
- package/dist/db/tables/sponsoredTransactions.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/db/tables/verifiedTokens.d.ts +53 -0
- package/dist/db/tables/verifiedTokens.d.ts.map +1 -0
- package/dist/db/tables/verifiedTokens.js +74 -0
- package/dist/db/tables/verifiedTokens.js.map +1 -0
- package/dist/db/tables/webhookDeliveries.d.ts +71 -0
- package/dist/db/tables/webhookDeliveries.d.ts.map +1 -0
- package/dist/db/tables/webhookDeliveries.js +119 -0
- package/dist/db/tables/webhookDeliveries.js.map +1 -0
- package/dist/db/tables/webhookSubscriptions.d.ts +158 -0
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -0
- package/dist/db/tables/webhookSubscriptions.js +272 -0
- package/dist/db/tables/webhookSubscriptions.js.map +1 -0
- package/dist/handlers/internal/executionError.d.ts +25 -0
- package/dist/handlers/internal/executionError.d.ts.map +1 -0
- package/dist/handlers/internal/executionError.js +186 -0
- package/dist/handlers/internal/executionError.js.map +1 -0
- package/dist/handlers/internal/multisig.d.ts +233 -0
- package/dist/handlers/internal/multisig.d.ts.map +1 -0
- package/dist/handlers/internal/multisig.js +542 -0
- package/dist/handlers/internal/multisig.js.map +1 -0
- package/dist/handlers/internal/requestListener.d.ts +124 -0
- package/dist/handlers/internal/requestListener.d.ts.map +1 -0
- package/dist/handlers/internal/requestListener.js +173 -0
- package/dist/handlers/internal/requestListener.js.map +1 -0
- package/dist/handlers/internal/sponsorship.d.ts +113 -0
- package/dist/handlers/internal/sponsorship.d.ts.map +1 -0
- package/dist/handlers/internal/sponsorship.js +128 -0
- package/dist/handlers/internal/sponsorship.js.map +1 -0
- package/dist/handlers/internal/types.d.ts +284 -0
- package/dist/handlers/internal/types.d.ts.map +1 -0
- package/dist/handlers/internal/types.js +2 -0
- package/dist/handlers/internal/types.js.map +1 -0
- package/dist/handlers/internal/utils.d.ts +34 -0
- package/dist/handlers/internal/utils.d.ts.map +1 -0
- package/dist/handlers/internal/utils.js +131 -0
- package/dist/handlers/internal/utils.js.map +1 -0
- package/dist/handlers/relay.d.ts +123 -0
- package/dist/handlers/relay.d.ts.map +1 -0
- package/dist/handlers/relay.js +1278 -0
- package/dist/handlers/relay.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/Auth.d.ts +224 -16
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +572 -33
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Log.d.ts +7 -3
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +4 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +0 -19
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +0 -57
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/RpcSchema.d.ts +10 -0
- package/dist/internal/RpcSchema.d.ts.map +1 -0
- package/dist/internal/RpcSchema.js +2 -0
- package/dist/internal/RpcSchema.js.map +1 -0
- package/dist/internal/Store.d.ts +49 -4
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +81 -5
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/VerifiedTokens.d.ts +15 -34
- package/dist/internal/VerifiedTokens.d.ts.map +1 -1
- package/dist/internal/VerifiedTokens.js +115 -159
- package/dist/internal/VerifiedTokens.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 +50 -36
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +92 -205
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +37 -6
- package/src/ApiKey.test.ts +3 -3
- package/src/ApiKey.ts +11 -12
- package/src/ApiKeys.test.ts +278 -0
- package/src/ApiKeys.ts +358 -0
- package/src/App.test-d.ts +1 -1
- package/src/App.test.ts +40508 -19083
- package/src/App.ts +239 -416
- package/src/Client.test-d.ts +307 -16
- package/src/Handler.ts +154 -0
- package/src/Scope.ts +17 -4
- package/src/Webhooks.test.ts +8 -7
- package/src/Webhooks.ts +13 -7
- package/src/admin/Access.ts +1 -3
- package/src/admin/App.ts +19 -24
- package/src/admin/apps/api-keys.test.ts +70 -18
- package/src/admin/apps/api-keys.ts +92 -9
- package/src/admin/apps/scopes.test.ts +8 -0
- package/src/admin/apps/verified-tokens.test.ts +3 -30
- package/src/admin/apps/verified-tokens.ts +18 -37
- package/src/admin/ui.generated.ts +1 -1
- package/src/apps/composition.test.ts +66 -0
- package/src/apps/data/App.ts +295 -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} +6 -5
- package/src/apps/{balances.ts → data/routes/balances.ts} +46 -12
- package/src/apps/{blocks.test.ts → data/routes/blocks.test.ts} +4 -4
- 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} +2 -2
- 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/{indexer.test.ts → data/routes/indexer.test.ts} +27 -6
- package/src/apps/{indexer.ts → data/routes/indexer.ts} +13 -10
- package/src/apps/{receipts.test.ts → data/routes/receipts.test.ts} +4 -4
- package/src/apps/{receipts.ts → data/routes/receipts.ts} +13 -13
- package/src/apps/{rpc.test.ts → data/routes/rpc.test.ts} +142 -13
- package/src/apps/{rpc.ts → data/routes/rpc.ts} +7 -7
- package/src/apps/{tokenlist.test.ts → data/routes/tokenlist.test.ts} +8 -10
- package/src/apps/{tokenlist.ts → data/routes/tokenlist.ts} +9 -9
- package/src/apps/{tokens.test.ts → data/routes/tokens.test.ts} +6 -5
- package/src/apps/{tokens.ts → data/routes/tokens.ts} +20 -20
- package/src/apps/{transactions.test.ts → data/routes/transactions.test.ts} +4 -4
- package/src/apps/{transactions.ts → data/routes/transactions.ts} +15 -15
- package/src/apps/{transfers.test.ts → data/routes/transfers.test.ts} +3 -3
- package/src/apps/{transfers.ts → data/routes/transfers.ts} +15 -15
- package/src/apps/{verified-tokens.test.ts → data/routes/verified-tokens.test.ts} +27 -15
- package/src/apps/{verified-tokens.ts → data/routes/verified-tokens.ts} +10 -10
- package/src/apps/{webhooks.test.ts → data/routes/webhooks.test.ts} +137 -150
- package/src/apps/{webhooks.ts → data/routes/webhooks.ts} +83 -81
- package/src/apps/docs/App.ts +136 -0
- package/src/apps/docs/index.ts +1 -0
- package/src/apps/index.ts +3 -0
- package/src/apps/metadata.ts +23 -0
- package/src/apps/platform/App.ts +130 -0
- package/src/apps/platform/index.ts +1 -0
- package/src/apps/platform/routes/api-keys.test.ts +330 -0
- package/src/apps/platform/routes/api-keys.ts +427 -0
- package/src/apps/platform/routes/invitations.test.ts +361 -0
- package/src/apps/platform/routes/invitations.ts +519 -0
- package/src/apps/platform/routes/me.test.ts +121 -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 +343 -0
- package/src/apps/platform/routes/projects.test.ts +181 -0
- package/src/apps/platform/routes/projects.ts +367 -0
- package/src/apps/relay/App.test.ts +484 -0
- package/src/apps/relay/App.ts +128 -0
- package/src/apps/relay/Sponsorships.test.ts +375 -0
- package/src/apps/relay/Sponsorships.ts +305 -0
- package/src/apps/relay/index.ts +2 -0
- package/src/{Cli.test.ts → cli/Cli.test.ts} +10 -9
- package/src/{Cli.ts → cli/Cli.ts} +16 -9
- package/src/cli/bin.ts +4 -0
- package/src/cli/commands/admin.test.ts +71 -0
- package/src/cli/commands/admin.ts +60 -0
- package/src/cloudflare.ts +10 -0
- package/src/db/Db.test.ts +84 -0
- package/src/db/Db.ts +542 -0
- package/src/db/Schema.ts +301 -0
- package/src/db/tables/invitations.ts +198 -0
- package/src/db/tables/memberships.ts +208 -0
- package/src/db/tables/organizations.test.ts +160 -0
- package/src/db/tables/organizations.ts +232 -0
- package/src/db/tables/projects.ts +107 -0
- package/src/db/tables/sponsoredTransactions.test.ts +218 -0
- package/src/db/tables/sponsoredTransactions.ts +236 -0
- package/src/db/tables/users.ts +85 -0
- package/src/db/tables/verifiedTokens.ts +111 -0
- package/src/db/tables/webhookDeliveries.ts +159 -0
- package/src/db/tables/webhookSubscriptions.ts +358 -0
- package/src/handlers/internal/executionError.ts +207 -0
- package/src/handlers/internal/multisig.test.ts +818 -0
- package/src/handlers/internal/multisig.ts +823 -0
- package/src/handlers/internal/requestListener.ts +273 -0
- package/src/handlers/internal/sponsorship.ts +245 -0
- package/src/handlers/internal/types.ts +378 -0
- package/src/handlers/internal/utils.ts +153 -0
- package/src/handlers/relay.test.ts +2035 -0
- package/src/handlers/relay.ts +1623 -0
- package/src/index.ts +4 -2
- package/src/internal/Auth.test.ts +337 -21
- package/src/internal/Auth.ts +783 -44
- package/src/internal/Cursor.test.ts +3 -2
- package/src/internal/Log.test.ts +1 -1
- package/src/internal/Log.ts +11 -3
- package/src/internal/MetricSink.ts +1 -1
- package/src/internal/OpenApi.ts +0 -59
- package/src/internal/RateLimit.test.ts +1 -1
- package/src/internal/RpcSchema.ts +10 -0
- package/src/internal/Store.test.ts +150 -10
- package/src/internal/Store.ts +136 -11
- package/src/internal/Tidx.local.test.ts +1 -1
- package/src/internal/VerifiedTokens.test.ts +99 -115
- package/src/internal/VerifiedTokens.ts +123 -175
- package/src/internal/WebhookDestination.test.ts +1 -1
- package/src/internal/Webhooks.test.ts +111 -111
- package/src/internal/Webhooks.ts +103 -221
- package/dist/ApiKeySource.d.ts +0 -166
- package/dist/ApiKeySource.d.ts.map +0 -1
- package/dist/ApiKeySource.js +0 -234
- package/dist/ApiKeySource.js.map +0 -1
- package/dist/Cli.d.ts.map +0 -1
- package/dist/Cli.js +0 -13
- package/dist/Cli.js.map +0 -1
- 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/seeds/31318/icons/0x20c0000000000000000000000000000000000000.svg +0 -1
- package/seeds/31318/icons/0x20c0000000000000000000000000000000000001.svg +0 -1
- package/seeds/31318/icons/0x20c0000000000000000000000000000000000002.svg +0 -1
- package/seeds/31318/icons/0x20c0000000000000000000000000000000000003.svg +0 -1
- package/seeds/31318/verified-tokens.json +0 -30
- package/seeds/4217/icons/0x20c0000000000000000000000000000000000000.svg +0 -25
- package/seeds/4217/icons/0x20c000000000000000000000048c8f36df1c9a4a.svg +0 -1
- package/seeds/4217/icons/0x20c0000000000000000000000520792dcccccccc.svg +0 -1
- package/seeds/4217/icons/0x20c0000000000000000000000a6da882d075a4c3.svg +0 -4
- package/seeds/4217/icons/0x20c000000000000000000000111111111e910f0f.svg +0 -30
- package/seeds/4217/icons/0x20c00000000000000000000014f22ca97301eb73.svg +0 -1
- package/seeds/4217/icons/0x20c0000000000000000000001621e21f71cf12fb.svg +0 -1
- package/seeds/4217/icons/0x20c0000000000000000000002f52d5cc21a3207b.svg +0 -1
- package/seeds/4217/icons/0x20c0000000000000000000003158081efd85bfc2.svg +0 -11
- package/seeds/4217/icons/0x20c0000000000000000000003554d28269e0f3c2.svg +0 -1
- package/seeds/4217/icons/0x20c000000000000000000000383a23bacb546ab9.svg +0 -1
- package/seeds/4217/icons/0x20c00000000000000000000042109aef2f8b28e1.png +0 -0
- package/seeds/4217/icons/0x20c0000000000000000000005c0bac7cef389a11.svg +0 -1
- package/seeds/4217/icons/0x20c0000000000000000000006fd9a167923ba194.png +0 -0
- package/seeds/4217/icons/0x20c0000000000000000000007f7ba549dd0251b9.svg +0 -1
- package/seeds/4217/icons/0x20c0000000000000000000008191667423f70e67.svg +0 -5
- package/seeds/4217/icons/0x20c0000000000000000000008ee4fcff88888888.svg +0 -1
- package/seeds/4217/icons/0x20c0000000000000000000009a4a4b17e0dc6651.svg +0 -1
- package/seeds/4217/icons/0x20c000000000000000000000ab02d39df30bd17e.svg +0 -1
- package/seeds/4217/icons/0x20c000000000000000000000ae247a1130450f09.svg +0 -1
- package/seeds/4217/icons/0x20c000000000000000000000aeed2ec36a54d0e5.svg +0 -1
- package/seeds/4217/icons/0x20c000000000000000000000b9537d11c60e8b50.svg +0 -1
- package/seeds/4217/icons/0x20c000000000000000000000bd95bfb69fbe6ce3.svg +0 -1
- package/seeds/4217/icons/0x20c000000000000000000000c412ec89d0c08be5.svg +0 -1
- package/seeds/4217/icons/0x20c000000000000000000000f047dd7018e50367.png +0 -0
- package/seeds/4217/verified-tokens.json +0 -177
- package/seeds/42431/icons/0x20c0000000000000000000000000000000000000.svg +0 -25
- package/seeds/42431/icons/0x20c0000000000000000000000000000000000001.svg +0 -1
- package/seeds/42431/icons/0x20c0000000000000000000000000000000000002.svg +0 -1
- package/seeds/42431/icons/0x20c0000000000000000000000000000000000003.svg +0 -1
- package/seeds/42431/icons/0x20c0000000000000000000009e8d7eb59b783726.svg +0 -1
- package/seeds/42431/icons/0x20c000000000000000000000d72572838bbee59c.svg +0 -1
- package/seeds/42431/verified-tokens.json +0 -44
- package/seeds/openrpc/README.md +0 -27
- package/seeds/openrpc/execution-apis.json +0 -8989
- package/src/ApiKeySource.test-d.ts +0 -11
- package/src/ApiKeySource.test.ts +0 -295
- package/src/ApiKeySource.ts +0 -303
- /package/src/{internal/OpenApi.fonts.ts → apps/docs/fonts.ts} +0 -0
- /package/src/{internal/OpenApi.logo.ts → apps/docs/logo.ts} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import * as Tidx from '
|
|
4
|
-
import * as Viem from '
|
|
5
|
-
import * as TestApp from '
|
|
6
|
-
import * as Mppx from '
|
|
7
|
-
import * as Runtime from '
|
|
8
|
-
import * as Tempo from '
|
|
1
|
+
import { type Db, Webhooks as Core } from 'tapimo'
|
|
2
|
+
|
|
3
|
+
import * as Tidx from '../../../internal/Tidx.js'
|
|
4
|
+
import * as Viem from '../../../internal/Viem.js'
|
|
5
|
+
import * as TestApp from '../../../../test/App.js'
|
|
6
|
+
import * as Mppx from '../../../../test/Mppx.js'
|
|
7
|
+
import * as Runtime from '../../../../test/runtime.js'
|
|
8
|
+
import * as Tempo from '../../../../test/Tempo.js'
|
|
9
9
|
import * as Webhooks from './webhooks.js'
|
|
10
10
|
|
|
11
11
|
/** API key with both webhook scopes, owned by `org_test`. */
|
|
@@ -14,7 +14,7 @@ const writer = {
|
|
|
14
14
|
orgId: 'org_test',
|
|
15
15
|
scopes: ['webhooks:read', 'webhooks:write'],
|
|
16
16
|
token: 'secret_writer',
|
|
17
|
-
} satisfies TestApp.
|
|
17
|
+
} satisfies TestApp.kvStore.Key
|
|
18
18
|
|
|
19
19
|
/** API key with read-only webhook scope, owned by `org_test`. */
|
|
20
20
|
const reader = {
|
|
@@ -22,7 +22,7 @@ const reader = {
|
|
|
22
22
|
orgId: 'org_test',
|
|
23
23
|
scopes: ['webhooks:read'],
|
|
24
24
|
token: 'secret_reader',
|
|
25
|
-
} satisfies TestApp.
|
|
25
|
+
} satisfies TestApp.kvStore.Key
|
|
26
26
|
|
|
27
27
|
/** API key in a different org, used to prove owner isolation. */
|
|
28
28
|
const other = {
|
|
@@ -30,13 +30,12 @@ const other = {
|
|
|
30
30
|
orgId: 'org_other',
|
|
31
31
|
scopes: ['webhooks:read', 'webhooks:write'],
|
|
32
32
|
token: 'secret_other',
|
|
33
|
-
} satisfies TestApp.
|
|
33
|
+
} satisfies TestApp.kvStore.Key
|
|
34
34
|
|
|
35
|
-
/** Creates a webhooks-enabled test client backed by an in-memory state
|
|
36
|
-
function client(keys: readonly TestApp.
|
|
35
|
+
/** Creates a webhooks-enabled test client backed by an in-memory state db. */
|
|
36
|
+
function client(keys: readonly TestApp.kvStore.Key[] = [writer, reader, other]) {
|
|
37
37
|
return TestApp.client({
|
|
38
|
-
auth: {
|
|
39
|
-
webhook: { store: Store.memory() },
|
|
38
|
+
auth: { keys },
|
|
40
39
|
})
|
|
41
40
|
}
|
|
42
41
|
|
|
@@ -52,7 +51,7 @@ const validBody = {
|
|
|
52
51
|
} as const
|
|
53
52
|
|
|
54
53
|
describe('feature gate', () => {
|
|
55
|
-
test('returns 404 when
|
|
54
|
+
test('returns 404 when webhooks are disabled', async () => {
|
|
56
55
|
// Routes stay mounted for a stable schema, but the resource is disabled.
|
|
57
56
|
// `event-types` requires `data:read`, so seed a key that holds it to reach
|
|
58
57
|
// the feature gate rather than tripping the scope check first.
|
|
@@ -61,8 +60,8 @@ describe('feature gate', () => {
|
|
|
61
60
|
orgId: 'org_test',
|
|
62
61
|
scopes: ['data:read'],
|
|
63
62
|
token: 'secret_data_reader',
|
|
64
|
-
} satisfies TestApp.
|
|
65
|
-
const disabled = TestApp.client({ auth: {
|
|
63
|
+
} satisfies TestApp.kvStore.Key
|
|
64
|
+
const disabled = TestApp.client({ auth: { keys: [dataReader] }, webhook: false })
|
|
66
65
|
const response = await disabled.v1.webhooks['event-types'].$get({}, as(dataReader))
|
|
67
66
|
|
|
68
67
|
expect(response.status).toMatchInlineSnapshot(`404`)
|
|
@@ -97,7 +96,7 @@ describe('access matrix', () => {
|
|
|
97
96
|
orgId: 'org_test',
|
|
98
97
|
scopes: ['data:read'],
|
|
99
98
|
token: 'secret_noscope',
|
|
100
|
-
} satisfies TestApp.
|
|
99
|
+
} satisfies TestApp.kvStore.Key
|
|
101
100
|
const response = await client([noScope]).v1.webhooks.$get({ query: {} }, as(noScope))
|
|
102
101
|
const body = (await response.json()) as { error?: { code?: string } }
|
|
103
102
|
|
|
@@ -142,7 +141,7 @@ describe('access matrix', () => {
|
|
|
142
141
|
orgId: 'org_test',
|
|
143
142
|
scopes: ['data:read'],
|
|
144
143
|
token: 'secret_data_reader',
|
|
145
|
-
} satisfies TestApp.
|
|
144
|
+
} satisfies TestApp.kvStore.Key
|
|
146
145
|
const response = await client([dataReader]).v1.webhooks['event-types'].$get({}, as(dataReader))
|
|
147
146
|
|
|
148
147
|
expect(response.status).toMatchInlineSnapshot(`200`)
|
|
@@ -272,8 +271,8 @@ describe('owner isolation', () => {
|
|
|
272
271
|
describe('subscription limits', () => {
|
|
273
272
|
test('rejects creation past the configured per-owner cap with 403 limit_exceeded', async () => {
|
|
274
273
|
const app = TestApp.client({
|
|
275
|
-
auth: {
|
|
276
|
-
webhook: { maxPerOwner: 2
|
|
274
|
+
auth: { keys: [writer, other] },
|
|
275
|
+
webhook: { maxPerOwner: 2 },
|
|
277
276
|
})
|
|
278
277
|
|
|
279
278
|
// Fill the writer's quota.
|
|
@@ -317,20 +316,20 @@ describe('delivery log', () => {
|
|
|
317
316
|
}
|
|
318
317
|
|
|
319
318
|
/** Seeds a subscription owned by `writer` plus `count` delivery rows. */
|
|
320
|
-
async function seed(
|
|
319
|
+
async function seed(db: Db.Db, count: number) {
|
|
321
320
|
const app = TestApp.client({
|
|
322
|
-
auth: {
|
|
323
|
-
|
|
321
|
+
auth: { keys: [writer, reader, other] },
|
|
322
|
+
db,
|
|
324
323
|
})
|
|
325
324
|
const created = await app.v1.webhooks.$post({ json: validBody }, as(writer))
|
|
326
325
|
const { id } = await TestApp.json(created, Webhooks.schema.createWebhook.Response)
|
|
327
|
-
for (let n = 1; n <= count; n++) await Core.recordDelivery(
|
|
326
|
+
for (let n = 1; n <= count; n++) await Core.recordDelivery(db, row(id, n))
|
|
328
327
|
return { app, id }
|
|
329
328
|
}
|
|
330
329
|
|
|
331
330
|
test('lists a subscription deliveries newest-first', async () => {
|
|
332
|
-
const
|
|
333
|
-
const { app, id } = await seed(
|
|
331
|
+
const db = TestApp.database()
|
|
332
|
+
const { app, id } = await seed(db, 3)
|
|
334
333
|
|
|
335
334
|
const response = await app.v1.webhooks[':id{wh_[A-Za-z0-9_-]+}'].deliveries.$get(
|
|
336
335
|
{ param: { id }, query: {} },
|
|
@@ -349,8 +348,8 @@ describe('delivery log', () => {
|
|
|
349
348
|
})
|
|
350
349
|
|
|
351
350
|
test('embeds the exact delivery total via include=totalCount', async () => {
|
|
352
|
-
const
|
|
353
|
-
const { app, id } = await seed(
|
|
351
|
+
const db = TestApp.database()
|
|
352
|
+
const { app, id } = await seed(db, 8)
|
|
354
353
|
|
|
355
354
|
const response = await app.v1.webhooks[':id{wh_[A-Za-z0-9_-]+}'].deliveries.$get(
|
|
356
355
|
{ param: { id }, query: { include: 'totalCount', limit: '5' } },
|
|
@@ -372,8 +371,8 @@ describe('delivery log', () => {
|
|
|
372
371
|
})
|
|
373
372
|
|
|
374
373
|
test('paginates with cursor and limit', async () => {
|
|
375
|
-
const
|
|
376
|
-
const { app, id } = await seed(
|
|
374
|
+
const db = TestApp.database()
|
|
375
|
+
const { app, id } = await seed(db, 6)
|
|
377
376
|
|
|
378
377
|
const first = await app.v1.webhooks[':id{wh_[A-Za-z0-9_-]+}'].deliveries.$get(
|
|
379
378
|
{ param: { id }, query: { limit: '5' } },
|
|
@@ -397,8 +396,8 @@ describe('delivery log', () => {
|
|
|
397
396
|
})
|
|
398
397
|
|
|
399
398
|
test('serves a positional page via `page` (deterministic in-memory slice)', async () => {
|
|
400
|
-
const
|
|
401
|
-
const { app, id } = await seed(
|
|
399
|
+
const db = TestApp.database()
|
|
400
|
+
const { app, id } = await seed(db, 6)
|
|
402
401
|
|
|
403
402
|
const response = await app.v1.webhooks[':id{wh_[A-Za-z0-9_-]+}'].deliveries.$get(
|
|
404
403
|
{ param: { id }, query: { limit: '5', page: '2' } },
|
|
@@ -411,8 +410,8 @@ describe('delivery log', () => {
|
|
|
411
410
|
})
|
|
412
411
|
|
|
413
412
|
test('rejects `page` combined with `cursor`', async () => {
|
|
414
|
-
const
|
|
415
|
-
const { app, id } = await seed(
|
|
413
|
+
const db = TestApp.database()
|
|
414
|
+
const { app, id } = await seed(db, 6)
|
|
416
415
|
|
|
417
416
|
const first = await app.v1.webhooks[':id{wh_[A-Za-z0-9_-]+}'].deliveries.$get(
|
|
418
417
|
{ param: { id }, query: { limit: '5' } },
|
|
@@ -428,8 +427,8 @@ describe('delivery log', () => {
|
|
|
428
427
|
})
|
|
429
428
|
|
|
430
429
|
test('a read-only key can list deliveries', async () => {
|
|
431
|
-
const
|
|
432
|
-
const { app, id } = await seed(
|
|
430
|
+
const db = TestApp.database()
|
|
431
|
+
const { app, id } = await seed(db, 1)
|
|
433
432
|
|
|
434
433
|
const response = await app.v1.webhooks[':id{wh_[A-Za-z0-9_-]+}'].deliveries.$get(
|
|
435
434
|
{ param: { id }, query: {} },
|
|
@@ -439,8 +438,8 @@ describe('delivery log', () => {
|
|
|
439
438
|
})
|
|
440
439
|
|
|
441
440
|
test('a different org cannot read another org deliveries', async () => {
|
|
442
|
-
const
|
|
443
|
-
const { app, id } = await seed(
|
|
441
|
+
const db = TestApp.database()
|
|
442
|
+
const { app, id } = await seed(db, 1)
|
|
444
443
|
|
|
445
444
|
const response = await app.v1.webhooks[':id{wh_[A-Za-z0-9_-]+}'].deliveries.$get(
|
|
446
445
|
{ param: { id }, query: {} },
|
|
@@ -491,8 +490,7 @@ describe('SSRF protection', () => {
|
|
|
491
490
|
describe('subscription context', () => {
|
|
492
491
|
test('round-trips context through create and read', async () => {
|
|
493
492
|
const app = TestApp.client({
|
|
494
|
-
auth: {
|
|
495
|
-
webhook: { store: Store.memory() },
|
|
493
|
+
auth: { keys: [writer] },
|
|
496
494
|
})
|
|
497
495
|
const context = {
|
|
498
496
|
description: 'Notify #ops when a large USDC transfer settles.',
|
|
@@ -523,8 +521,7 @@ describe('subscription context', () => {
|
|
|
523
521
|
|
|
524
522
|
test('clears context with an explicit null patch', async () => {
|
|
525
523
|
const app = TestApp.client({
|
|
526
|
-
auth: {
|
|
527
|
-
webhook: { store: Store.memory() },
|
|
524
|
+
auth: { keys: [writer] },
|
|
528
525
|
})
|
|
529
526
|
const created = await app.v1.webhooks.$post(
|
|
530
527
|
{
|
|
@@ -548,8 +545,7 @@ describe('subscription context', () => {
|
|
|
548
545
|
|
|
549
546
|
test('rejects metadata that exceeds the entry limit', async () => {
|
|
550
547
|
const app = TestApp.client({
|
|
551
|
-
auth: {
|
|
552
|
-
webhook: { store: Store.memory() },
|
|
548
|
+
auth: { keys: [writer] },
|
|
553
549
|
})
|
|
554
550
|
const metadata = Object.fromEntries(Array.from({ length: 21 }, (_, i) => [`key${i}`, 'value']))
|
|
555
551
|
const created = await app.v1.webhooks.$post(
|
|
@@ -569,8 +565,7 @@ describe('subscription context', () => {
|
|
|
569
565
|
describe('slack destination', () => {
|
|
570
566
|
test('creates a subscription with a slack incoming-webhook URL', async () => {
|
|
571
567
|
const app = TestApp.client({
|
|
572
|
-
auth: {
|
|
573
|
-
webhook: { store: Store.memory() },
|
|
568
|
+
auth: { keys: [writer] },
|
|
574
569
|
})
|
|
575
570
|
const created = await app.v1.webhooks.$post(
|
|
576
571
|
{
|
|
@@ -596,8 +591,7 @@ describe('slack destination', () => {
|
|
|
596
591
|
|
|
597
592
|
test('rejects a slack destination whose host is not hooks.slack.com', async () => {
|
|
598
593
|
const app = TestApp.client({
|
|
599
|
-
auth: {
|
|
600
|
-
webhook: { store: Store.memory() },
|
|
594
|
+
auth: { keys: [writer] },
|
|
601
595
|
})
|
|
602
596
|
const response = await app.v1.webhooks.$post(
|
|
603
597
|
{
|
|
@@ -618,8 +612,7 @@ describe('slack destination', () => {
|
|
|
618
612
|
describe('betterstack destination', () => {
|
|
619
613
|
test('creates a subscription with a Better Stack source', async () => {
|
|
620
614
|
const app = TestApp.client({
|
|
621
|
-
auth: {
|
|
622
|
-
webhook: { store: Store.memory() },
|
|
615
|
+
auth: { keys: [writer] },
|
|
623
616
|
})
|
|
624
617
|
const created = await app.v1.webhooks.$post(
|
|
625
618
|
{
|
|
@@ -647,8 +640,7 @@ describe('betterstack destination', () => {
|
|
|
647
640
|
|
|
648
641
|
test('rejects a Better Stack destination whose host is not betterstackdata.com', async () => {
|
|
649
642
|
const app = TestApp.client({
|
|
650
|
-
auth: {
|
|
651
|
-
webhook: { store: Store.memory() },
|
|
643
|
+
auth: { keys: [writer] },
|
|
652
644
|
})
|
|
653
645
|
const response = await app.v1.webhooks.$post(
|
|
654
646
|
{
|
|
@@ -678,8 +670,7 @@ describe('ping', () => {
|
|
|
678
670
|
/** Seeds a webhooks-enabled client with a subscription owned by `writer`. */
|
|
679
671
|
async function seed() {
|
|
680
672
|
const app = TestApp.client({
|
|
681
|
-
auth: {
|
|
682
|
-
webhook: { store: Store.memory() },
|
|
673
|
+
auth: { keys: [writer, reader, other] },
|
|
683
674
|
})
|
|
684
675
|
const created = await app.v1.webhooks.$post({ json: validBody }, as(writer))
|
|
685
676
|
const { id } = await TestApp.json(created, Webhooks.schema.createWebhook.Response)
|
|
@@ -775,14 +766,14 @@ describe('retry delivery', () => {
|
|
|
775
766
|
|
|
776
767
|
/** Seeds a webhooks client with a subscription plus one logged delivery to replay. */
|
|
777
768
|
async function seed() {
|
|
778
|
-
const
|
|
769
|
+
const db = TestApp.database()
|
|
779
770
|
const app = TestApp.client({
|
|
780
|
-
auth: {
|
|
781
|
-
|
|
771
|
+
auth: { keys: [writer, reader, other] },
|
|
772
|
+
db,
|
|
782
773
|
})
|
|
783
774
|
const created = await app.v1.webhooks.$post({ json: validBody }, as(writer))
|
|
784
775
|
const { id } = await TestApp.json(created, Webhooks.schema.createWebhook.Response)
|
|
785
|
-
await Core.recordDelivery(
|
|
776
|
+
await Core.recordDelivery(db, {
|
|
786
777
|
attempt: 1,
|
|
787
778
|
createdAt: new Date(1_700_000_000_000).toISOString(),
|
|
788
779
|
envelope: {
|
|
@@ -799,11 +790,11 @@ describe('retry delivery', () => {
|
|
|
799
790
|
status: 'failed',
|
|
800
791
|
subscriptionId: id,
|
|
801
792
|
})
|
|
802
|
-
return { app, id,
|
|
793
|
+
return { app, id, db }
|
|
803
794
|
}
|
|
804
795
|
|
|
805
796
|
test('replays the stored envelope and records a new attempt', async () => {
|
|
806
|
-
const { app, id,
|
|
797
|
+
const { app, id, db } = await seed()
|
|
807
798
|
vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response(null, { status: 200 }))
|
|
808
799
|
|
|
809
800
|
const response = await app.v1.webhooks[':id{wh_[A-Za-z0-9_-]+}'].deliveries[
|
|
@@ -815,7 +806,7 @@ describe('retry delivery', () => {
|
|
|
815
806
|
expect(body.eventId).toMatchInlineSnapshot(`"evt_seed"`)
|
|
816
807
|
|
|
817
808
|
// A new attempt was appended alongside the seeded row.
|
|
818
|
-
expect(await Core.listDeliveries(
|
|
809
|
+
expect(await Core.listDeliveries(db, id)).toHaveLength(2)
|
|
819
810
|
})
|
|
820
811
|
|
|
821
812
|
test('a failed replay reports the error', async () => {
|
|
@@ -867,7 +858,7 @@ describe('retry delivery', () => {
|
|
|
867
858
|
|
|
868
859
|
describe('OpenAPI visibility', () => {
|
|
869
860
|
test('hides webhook routes when the feature is disabled', async () => {
|
|
870
|
-
const app = TestApp.create({ auth: {
|
|
861
|
+
const app = TestApp.create({ auth: { keys: [writer] }, webhook: false })
|
|
871
862
|
const body = (await (await app.request('/openapi.json')).json()) as { paths: object }
|
|
872
863
|
|
|
873
864
|
// OpenAPI paths include App.create's mounted `/v1` prefix; the webhook
|
|
@@ -877,8 +868,7 @@ describe('OpenAPI visibility', () => {
|
|
|
877
868
|
|
|
878
869
|
test('documents webhook routes when the feature is enabled', async () => {
|
|
879
870
|
const app = TestApp.create({
|
|
880
|
-
auth: {
|
|
881
|
-
webhook: { store: Store.memory() },
|
|
871
|
+
auth: { keys: [writer] },
|
|
882
872
|
})
|
|
883
873
|
const body = (await (await app.request('/openapi.json')).json()) as { paths: object }
|
|
884
874
|
const paths = Object.keys(body.paths)
|
|
@@ -898,7 +888,7 @@ describe('OpenAPI visibility', () => {
|
|
|
898
888
|
})
|
|
899
889
|
|
|
900
890
|
test('omits the outbound `webhooks` section when the feature is disabled', async () => {
|
|
901
|
-
const app = TestApp.create({ auth: {
|
|
891
|
+
const app = TestApp.create({ auth: { keys: [writer] }, webhook: false })
|
|
902
892
|
const body = (await (await app.request('/openapi.json')).json()) as { webhooks?: object }
|
|
903
893
|
|
|
904
894
|
expect(body.webhooks).toMatchInlineSnapshot(`undefined`)
|
|
@@ -906,8 +896,7 @@ describe('OpenAPI visibility', () => {
|
|
|
906
896
|
|
|
907
897
|
test('documents the outbound delivery envelope under OAS `webhooks` when enabled', async () => {
|
|
908
898
|
const app = TestApp.create({
|
|
909
|
-
auth: {
|
|
910
|
-
webhook: { store: Store.memory() },
|
|
899
|
+
auth: { keys: [writer] },
|
|
911
900
|
})
|
|
912
901
|
const body = (await (await app.request('/openapi.json')).json()) as {
|
|
913
902
|
webhooks?: {
|
|
@@ -946,8 +935,7 @@ describe('OpenAPI visibility', () => {
|
|
|
946
935
|
|
|
947
936
|
test('documents per-event-type filters on the create body', async () => {
|
|
948
937
|
const app = TestApp.create({
|
|
949
|
-
auth: {
|
|
950
|
-
webhook: { store: Store.memory() },
|
|
938
|
+
auth: { keys: [writer] },
|
|
951
939
|
})
|
|
952
940
|
const body = (await (await app.request('/openapi.json')).json()) as {
|
|
953
941
|
paths: {
|
|
@@ -1050,7 +1038,7 @@ describe('OpenAPI visibility', () => {
|
|
|
1050
1038
|
describe('envelope schema', () => {
|
|
1051
1039
|
/** A `transfer` subscription used to build representative envelopes. */
|
|
1052
1040
|
async function transferSubscription() {
|
|
1053
|
-
const
|
|
1041
|
+
const db = TestApp.database()
|
|
1054
1042
|
return Core.buildEnvelope({
|
|
1055
1043
|
blockNumber: 100,
|
|
1056
1044
|
createdAt: new Date('2026-01-01T00:00:00.000Z'),
|
|
@@ -1064,7 +1052,7 @@ describe('envelope schema', () => {
|
|
|
1064
1052
|
transactionHash: '0x33333333333333333333333333333333333333333333333333333333333333aa',
|
|
1065
1053
|
},
|
|
1066
1054
|
logIndex: 0,
|
|
1067
|
-
subscription: await Core.createSubscription(
|
|
1055
|
+
subscription: await Core.createSubscription(db, {
|
|
1068
1056
|
chainId: 42431,
|
|
1069
1057
|
eventType: 'token:transfer',
|
|
1070
1058
|
owner: { orgId: 'org_test', type: 'api_key' },
|
|
@@ -1080,8 +1068,8 @@ describe('envelope schema', () => {
|
|
|
1080
1068
|
})
|
|
1081
1069
|
|
|
1082
1070
|
test('round-trips a ping envelope', async () => {
|
|
1083
|
-
const
|
|
1084
|
-
const subscription = await Core.createSubscription(
|
|
1071
|
+
const db = TestApp.database()
|
|
1072
|
+
const subscription = await Core.createSubscription(db, {
|
|
1085
1073
|
chainId: 42431,
|
|
1086
1074
|
eventType: 'token:transfer',
|
|
1087
1075
|
owner: { orgId: 'org_test', type: 'api_key' },
|
|
@@ -1110,7 +1098,7 @@ describe('envelope schema', () => {
|
|
|
1110
1098
|
describe('MPP access (disabled for now — API-key-only)', () => {
|
|
1111
1099
|
test('rejects an MPP payer with 401, offering no payment challenge', async () => {
|
|
1112
1100
|
const app = TestApp.create({
|
|
1113
|
-
auth: {
|
|
1101
|
+
auth: { keys: [] },
|
|
1114
1102
|
mpp: {
|
|
1115
1103
|
charge: {
|
|
1116
1104
|
chainId: Tempo.chain.id,
|
|
@@ -1121,7 +1109,6 @@ describe('MPP access (disabled for now — API-key-only)', () => {
|
|
|
1121
1109
|
},
|
|
1122
1110
|
secretKey: 'secret_test_key_0123456789abcdef',
|
|
1123
1111
|
},
|
|
1124
|
-
webhook: { store: Store.memory() },
|
|
1125
1112
|
})
|
|
1126
1113
|
|
|
1127
1114
|
// The paid lane is disabled on webhook routes, so no `402` challenge is
|
|
@@ -1182,8 +1169,8 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1182
1169
|
// followed by its fee payment. Filtering on it makes the scan deterministic.
|
|
1183
1170
|
const windowSender = '0xe7687128b0a808c2831ff94d4f7b2fb35c65af38'
|
|
1184
1171
|
|
|
1185
|
-
async function createTransferSubscription(
|
|
1186
|
-
return Core.createSubscription(
|
|
1172
|
+
async function createTransferSubscription(db: Db.Db) {
|
|
1173
|
+
return Core.createSubscription(db, {
|
|
1187
1174
|
chainId: 42431,
|
|
1188
1175
|
eventType: 'token:transfer',
|
|
1189
1176
|
filters: { sender: windowSender },
|
|
@@ -1193,12 +1180,12 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1193
1180
|
}
|
|
1194
1181
|
|
|
1195
1182
|
test('dispatches a signed envelope per row and advances the cursor', async () => {
|
|
1196
|
-
const
|
|
1197
|
-
const subscription = await createTransferSubscription(
|
|
1183
|
+
const db = TestApp.database()
|
|
1184
|
+
const subscription = await createTransferSubscription(db)
|
|
1198
1185
|
// Anchor the subscription just below the pinned window so the poller scans
|
|
1199
1186
|
// it this tick (a brand-new subscription anchors at head and skips its first
|
|
1200
1187
|
// tick).
|
|
1201
|
-
await Core.setCursor(
|
|
1188
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1202
1189
|
|
|
1203
1190
|
const dispatched: Webhooks.poll.Dispatchable[] = []
|
|
1204
1191
|
const result = await Webhooks.poll({
|
|
@@ -1210,7 +1197,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1210
1197
|
eventTypes: ['token:transfer'],
|
|
1211
1198
|
headBlockNumber: windowHead,
|
|
1212
1199
|
client,
|
|
1213
|
-
|
|
1200
|
+
db,
|
|
1214
1201
|
tidx: realTidx,
|
|
1215
1202
|
})
|
|
1216
1203
|
|
|
@@ -1245,7 +1232,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1245
1232
|
`)
|
|
1246
1233
|
|
|
1247
1234
|
// Cursor advanced to the last dispatched row `(1000002, 1)`.
|
|
1248
|
-
expect(decodeCursor(await Core.getCursor(
|
|
1235
|
+
expect(decodeCursor(await Core.getCursor(db, subscription.id))).toMatchInlineSnapshot(`
|
|
1249
1236
|
[
|
|
1250
1237
|
1000002,
|
|
1251
1238
|
1,
|
|
@@ -1254,9 +1241,9 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1254
1241
|
})
|
|
1255
1242
|
|
|
1256
1243
|
test('pauses the cursor at the last success when dispatch fails', async () => {
|
|
1257
|
-
const
|
|
1258
|
-
const subscription = await createTransferSubscription(
|
|
1259
|
-
await Core.setCursor(
|
|
1244
|
+
const db = TestApp.database()
|
|
1245
|
+
const subscription = await createTransferSubscription(db)
|
|
1246
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1260
1247
|
|
|
1261
1248
|
let calls = 0
|
|
1262
1249
|
const result = await Webhooks.poll({
|
|
@@ -1266,7 +1253,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1266
1253
|
eventTypes: ['token:transfer'],
|
|
1267
1254
|
headBlockNumber: windowHead,
|
|
1268
1255
|
client,
|
|
1269
|
-
|
|
1256
|
+
db,
|
|
1270
1257
|
tidx: realTidx,
|
|
1271
1258
|
})
|
|
1272
1259
|
|
|
@@ -1275,7 +1262,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1275
1262
|
|
|
1276
1263
|
// Cursor stops at the first (successful) row `(1000002, 0)`, so the failed
|
|
1277
1264
|
// one re-runs on the next tick (at-least-once).
|
|
1278
|
-
expect(decodeCursor(await Core.getCursor(
|
|
1265
|
+
expect(decodeCursor(await Core.getCursor(db, subscription.id))).toMatchInlineSnapshot(`
|
|
1279
1266
|
[
|
|
1280
1267
|
1000002,
|
|
1281
1268
|
0,
|
|
@@ -1284,9 +1271,9 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1284
1271
|
})
|
|
1285
1272
|
|
|
1286
1273
|
test('does not advance the cursor when the first row fails', async () => {
|
|
1287
|
-
const
|
|
1288
|
-
const subscription = await createTransferSubscription(
|
|
1289
|
-
await Core.setCursor(
|
|
1274
|
+
const db = TestApp.database()
|
|
1275
|
+
const subscription = await createTransferSubscription(db)
|
|
1276
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1290
1277
|
|
|
1291
1278
|
const result = await Webhooks.poll({
|
|
1292
1279
|
chainId: 42431,
|
|
@@ -1294,7 +1281,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1294
1281
|
eventTypes: ['token:transfer'],
|
|
1295
1282
|
headBlockNumber: windowHead,
|
|
1296
1283
|
client,
|
|
1297
|
-
|
|
1284
|
+
db,
|
|
1298
1285
|
tidx: realTidx,
|
|
1299
1286
|
})
|
|
1300
1287
|
|
|
@@ -1302,7 +1289,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1302
1289
|
expect(result.failed).toMatchInlineSnapshot(`1`)
|
|
1303
1290
|
// Nothing accepted → cursor untouched at the window anchor, so the row
|
|
1304
1291
|
// retries next tick.
|
|
1305
|
-
expect(decodeCursor(await Core.getCursor(
|
|
1292
|
+
expect(decodeCursor(await Core.getCursor(db, subscription.id))).toMatchInlineSnapshot(`
|
|
1306
1293
|
[
|
|
1307
1294
|
999999,
|
|
1308
1295
|
2147483647,
|
|
@@ -1311,8 +1298,8 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1311
1298
|
})
|
|
1312
1299
|
|
|
1313
1300
|
test('anchors a first-seen subscription at the confirmed head without backfilling', async () => {
|
|
1314
|
-
const
|
|
1315
|
-
const subscription = await createTransferSubscription(
|
|
1301
|
+
const db = TestApp.database()
|
|
1302
|
+
const subscription = await createTransferSubscription(db)
|
|
1316
1303
|
|
|
1317
1304
|
const dispatched: Webhooks.poll.Dispatchable[] = []
|
|
1318
1305
|
const result = await Webhooks.poll({
|
|
@@ -1324,7 +1311,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1324
1311
|
eventTypes: ['token:transfer'],
|
|
1325
1312
|
headBlockNumber: windowHead,
|
|
1326
1313
|
client,
|
|
1327
|
-
|
|
1314
|
+
db,
|
|
1328
1315
|
// Rows exist in history, but a brand-new subscription must not replay them.
|
|
1329
1316
|
tidx: realTidx,
|
|
1330
1317
|
})
|
|
@@ -1333,7 +1320,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1333
1320
|
// the head of the confirmed window (`windowHead - confirmations` = 1000002).
|
|
1334
1321
|
expect(result.scanned).toMatchInlineSnapshot(`0`)
|
|
1335
1322
|
expect(dispatched).toHaveLength(0)
|
|
1336
|
-
expect(decodeCursor(await Core.getCursor(
|
|
1323
|
+
expect(decodeCursor(await Core.getCursor(db, subscription.id))).toMatchInlineSnapshot(`
|
|
1337
1324
|
[
|
|
1338
1325
|
1000002,
|
|
1339
1326
|
2147483647,
|
|
@@ -1342,12 +1329,12 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1342
1329
|
})
|
|
1343
1330
|
|
|
1344
1331
|
test('advances to the end of the confirmed window on an empty scan', async () => {
|
|
1345
|
-
const
|
|
1346
|
-
const subscription = await createTransferSubscription(
|
|
1332
|
+
const db = TestApp.database()
|
|
1333
|
+
const subscription = await createTransferSubscription(db)
|
|
1347
1334
|
// Anchor just past the window's only matching block (1000002) and confirm up
|
|
1348
1335
|
// to block 1000004 — a range `windowSender` has no transfers in, so the scan
|
|
1349
1336
|
// is genuinely empty.
|
|
1350
|
-
await Core.setCursor(
|
|
1337
|
+
await Core.setCursor(db, subscription.id, encodeCursor([windowTo, endOfBlockIndex]))
|
|
1351
1338
|
|
|
1352
1339
|
const result = await Webhooks.poll({
|
|
1353
1340
|
chainId: 42431,
|
|
@@ -1355,7 +1342,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1355
1342
|
eventTypes: ['token:transfer'],
|
|
1356
1343
|
headBlockNumber: windowTo + 4,
|
|
1357
1344
|
client,
|
|
1358
|
-
|
|
1345
|
+
db,
|
|
1359
1346
|
tidx: realTidx,
|
|
1360
1347
|
})
|
|
1361
1348
|
|
|
@@ -1363,7 +1350,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1363
1350
|
|
|
1364
1351
|
// No rows, clean scan: cursor jumps past the end of the confirmed window
|
|
1365
1352
|
// (`headBlockNumber - confirmations` = block 1000004) so it is not rescanned.
|
|
1366
|
-
expect(decodeCursor(await Core.getCursor(
|
|
1353
|
+
expect(decodeCursor(await Core.getCursor(db, subscription.id))).toMatchInlineSnapshot(`
|
|
1367
1354
|
[
|
|
1368
1355
|
1000004,
|
|
1369
1356
|
2147483647,
|
|
@@ -1381,15 +1368,15 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1381
1368
|
const windowSenderTopic = `0x${'0'.repeat(24)}${windowSender.slice(2)}`
|
|
1382
1369
|
|
|
1383
1370
|
test('log:emitted decodes args from a signature-matched event view', async () => {
|
|
1384
|
-
const
|
|
1385
|
-
const subscription = await Core.createSubscription(
|
|
1371
|
+
const db = TestApp.database()
|
|
1372
|
+
const subscription = await Core.createSubscription(db, {
|
|
1386
1373
|
chainId: 42431,
|
|
1387
1374
|
eventType: 'log:emitted',
|
|
1388
1375
|
filters: { signature: transferSignature, args: { from: windowSender } },
|
|
1389
1376
|
owner: { orgId: 'org_test', type: 'api_key' },
|
|
1390
1377
|
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
1391
1378
|
})
|
|
1392
|
-
await Core.setCursor(
|
|
1379
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1393
1380
|
|
|
1394
1381
|
const dispatched: Webhooks.poll.Dispatchable[] = []
|
|
1395
1382
|
const result = await Webhooks.poll({
|
|
@@ -1401,7 +1388,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1401
1388
|
eventTypes: ['log:emitted'],
|
|
1402
1389
|
headBlockNumber: windowHead,
|
|
1403
1390
|
client,
|
|
1404
|
-
|
|
1391
|
+
db,
|
|
1405
1392
|
tidx: realTidx,
|
|
1406
1393
|
})
|
|
1407
1394
|
|
|
@@ -1435,15 +1422,15 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1435
1422
|
})
|
|
1436
1423
|
|
|
1437
1424
|
test('log:emitted scans raw logs by topic when no signature is given', async () => {
|
|
1438
|
-
const
|
|
1439
|
-
const subscription = await Core.createSubscription(
|
|
1425
|
+
const db = TestApp.database()
|
|
1426
|
+
const subscription = await Core.createSubscription(db, {
|
|
1440
1427
|
chainId: 42431,
|
|
1441
1428
|
eventType: 'log:emitted',
|
|
1442
1429
|
filters: { topic0: transferSelector, topic1: windowSenderTopic },
|
|
1443
1430
|
owner: { orgId: 'org_test', type: 'api_key' },
|
|
1444
1431
|
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
1445
1432
|
})
|
|
1446
|
-
await Core.setCursor(
|
|
1433
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1447
1434
|
|
|
1448
1435
|
const dispatched: Webhooks.poll.Dispatchable[] = []
|
|
1449
1436
|
const result = await Webhooks.poll({
|
|
@@ -1455,7 +1442,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1455
1442
|
eventTypes: ['log:emitted'],
|
|
1456
1443
|
headBlockNumber: windowHead,
|
|
1457
1444
|
client,
|
|
1458
|
-
|
|
1445
|
+
db,
|
|
1459
1446
|
tidx: realTidx,
|
|
1460
1447
|
})
|
|
1461
1448
|
|
|
@@ -1479,8 +1466,8 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1479
1466
|
})
|
|
1480
1467
|
|
|
1481
1468
|
test('block:created scans new blocks and resolves transaction counts', async () => {
|
|
1482
|
-
const
|
|
1483
|
-
const subscription = await Core.createSubscription(
|
|
1469
|
+
const db = TestApp.database()
|
|
1470
|
+
const subscription = await Core.createSubscription(db, {
|
|
1484
1471
|
chainId: 42431,
|
|
1485
1472
|
eventType: 'block:created',
|
|
1486
1473
|
// Pin to a single block so the heartbeat feed is deterministic.
|
|
@@ -1488,7 +1475,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1488
1475
|
owner: { orgId: 'org_test', type: 'api_key' },
|
|
1489
1476
|
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
1490
1477
|
})
|
|
1491
|
-
await Core.setCursor(
|
|
1478
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1492
1479
|
|
|
1493
1480
|
const dispatched: Webhooks.poll.Dispatchable[] = []
|
|
1494
1481
|
const result = await Webhooks.poll({
|
|
@@ -1500,7 +1487,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1500
1487
|
eventTypes: ['block:created'],
|
|
1501
1488
|
headBlockNumber: windowHead,
|
|
1502
1489
|
client,
|
|
1503
|
-
|
|
1490
|
+
db,
|
|
1504
1491
|
tidx: realTidx,
|
|
1505
1492
|
})
|
|
1506
1493
|
|
|
@@ -1519,7 +1506,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1519
1506
|
`)
|
|
1520
1507
|
// The window scanner advances to the end of the fully-scanned block so the
|
|
1521
1508
|
// next tick resumes at the following block.
|
|
1522
|
-
expect(decodeCursor(await Core.getCursor(
|
|
1509
|
+
expect(decodeCursor(await Core.getCursor(db, subscription.id))).toMatchInlineSnapshot(`
|
|
1523
1510
|
[
|
|
1524
1511
|
1000002,
|
|
1525
1512
|
2147483647,
|
|
@@ -1528,8 +1515,8 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1528
1515
|
})
|
|
1529
1516
|
|
|
1530
1517
|
test('transaction:included filters on txs columns and inner calls', async () => {
|
|
1531
|
-
const
|
|
1532
|
-
const subscription = await Core.createSubscription(
|
|
1518
|
+
const db = TestApp.database()
|
|
1519
|
+
const subscription = await Core.createSubscription(db, {
|
|
1533
1520
|
chainId: 42431,
|
|
1534
1521
|
eventType: 'transaction:included',
|
|
1535
1522
|
// `from` + an `input` selector (ERC20 `transfer` = 0xa9059cbb) pins the
|
|
@@ -1538,7 +1525,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1538
1525
|
owner: { orgId: 'org_test', type: 'api_key' },
|
|
1539
1526
|
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
1540
1527
|
})
|
|
1541
|
-
await Core.setCursor(
|
|
1528
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1542
1529
|
|
|
1543
1530
|
const dispatched: Webhooks.poll.Dispatchable[] = []
|
|
1544
1531
|
const result = await Webhooks.poll({
|
|
@@ -1550,7 +1537,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1550
1537
|
eventTypes: ['transaction:included'],
|
|
1551
1538
|
headBlockNumber: windowHead,
|
|
1552
1539
|
client,
|
|
1553
|
-
|
|
1540
|
+
db,
|
|
1554
1541
|
tidx: realTidx,
|
|
1555
1542
|
})
|
|
1556
1543
|
|
|
@@ -1563,15 +1550,15 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1563
1550
|
})
|
|
1564
1551
|
|
|
1565
1552
|
test('transaction:included routes a status filter through receipts', async () => {
|
|
1566
|
-
const
|
|
1567
|
-
const subscription = await Core.createSubscription(
|
|
1553
|
+
const db = TestApp.database()
|
|
1554
|
+
const subscription = await Core.createSubscription(db, {
|
|
1568
1555
|
chainId: 42431,
|
|
1569
1556
|
eventType: 'transaction:included',
|
|
1570
1557
|
filters: { from: windowSender, status: 'success' },
|
|
1571
1558
|
owner: { orgId: 'org_test', type: 'api_key' },
|
|
1572
1559
|
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
1573
1560
|
})
|
|
1574
|
-
await Core.setCursor(
|
|
1561
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1575
1562
|
|
|
1576
1563
|
const result = await Webhooks.poll({
|
|
1577
1564
|
chainId: 42431,
|
|
@@ -1579,7 +1566,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1579
1566
|
eventTypes: ['transaction:included'],
|
|
1580
1567
|
headBlockNumber: windowHead,
|
|
1581
1568
|
client,
|
|
1582
|
-
|
|
1569
|
+
db,
|
|
1583
1570
|
tidx: realTidx,
|
|
1584
1571
|
})
|
|
1585
1572
|
|
|
@@ -1588,8 +1575,8 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1588
1575
|
})
|
|
1589
1576
|
|
|
1590
1577
|
test('transaction:included embeds the receipt when includeReceipt is set', async () => {
|
|
1591
|
-
const
|
|
1592
|
-
const subscription = await Core.createSubscription(
|
|
1578
|
+
const db = TestApp.database()
|
|
1579
|
+
const subscription = await Core.createSubscription(db, {
|
|
1593
1580
|
chainId: 42431,
|
|
1594
1581
|
eventType: 'transaction:included',
|
|
1595
1582
|
// No receipt-touching filter — `includeReceipt` alone must trigger the
|
|
@@ -1598,7 +1585,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1598
1585
|
owner: { orgId: 'org_test', type: 'api_key' },
|
|
1599
1586
|
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
1600
1587
|
})
|
|
1601
|
-
await Core.setCursor(
|
|
1588
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1602
1589
|
|
|
1603
1590
|
const dispatched: Webhooks.poll.Dispatchable[] = []
|
|
1604
1591
|
const result = await Webhooks.poll({
|
|
@@ -1610,7 +1597,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1610
1597
|
eventTypes: ['transaction:included'],
|
|
1611
1598
|
headBlockNumber: windowHead,
|
|
1612
1599
|
client,
|
|
1613
|
-
|
|
1600
|
+
db,
|
|
1614
1601
|
tidx: realTidx,
|
|
1615
1602
|
})
|
|
1616
1603
|
|
|
@@ -1634,9 +1621,9 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1634
1621
|
})
|
|
1635
1622
|
|
|
1636
1623
|
test('delivers a verifiable signed envelope and records success', async () => {
|
|
1637
|
-
const
|
|
1638
|
-
const subscription = await createTransferSubscription(
|
|
1639
|
-
await Core.setCursor(
|
|
1624
|
+
const db = TestApp.database()
|
|
1625
|
+
const subscription = await createTransferSubscription(db)
|
|
1626
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1640
1627
|
|
|
1641
1628
|
// Real TIDX queries also go through `globalThis.fetch`, so the mock passes
|
|
1642
1629
|
// non-webhook requests through to the real network and only captures the
|
|
@@ -1663,7 +1650,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1663
1650
|
eventTypes: ['token:transfer'],
|
|
1664
1651
|
headBlockNumber: windowHead,
|
|
1665
1652
|
client,
|
|
1666
|
-
|
|
1653
|
+
db,
|
|
1667
1654
|
tidx: realTidx,
|
|
1668
1655
|
})
|
|
1669
1656
|
|
|
@@ -1687,16 +1674,16 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1687
1674
|
expect((envelope.data as { blockNumber: number }).blockNumber).toBe(windowTo)
|
|
1688
1675
|
|
|
1689
1676
|
// Success resets the failure counter, stamps lastDeliveryAt, stays active.
|
|
1690
|
-
const after = await Core.getSubscription(
|
|
1677
|
+
const after = await Core.getSubscription(db, subscription.owner, subscription.id)
|
|
1691
1678
|
expect(after?.status).toBe('active')
|
|
1692
1679
|
expect(after?.failureCount).toBe(0)
|
|
1693
1680
|
expect(after?.lastDeliveryAt).toBeDefined()
|
|
1694
1681
|
})
|
|
1695
1682
|
|
|
1696
1683
|
test('pauses on a failed delivery and re-delivers on the next tick', async () => {
|
|
1697
|
-
const
|
|
1698
|
-
const subscription = await createTransferSubscription(
|
|
1699
|
-
await Core.setCursor(
|
|
1684
|
+
const db = TestApp.database()
|
|
1685
|
+
const subscription = await createTransferSubscription(db)
|
|
1686
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1700
1687
|
|
|
1701
1688
|
const realFetch = globalThis.fetch.bind(globalThis)
|
|
1702
1689
|
let attempts = 0
|
|
@@ -1715,7 +1702,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1715
1702
|
eventTypes: ['token:transfer'],
|
|
1716
1703
|
headBlockNumber: windowHead,
|
|
1717
1704
|
client,
|
|
1718
|
-
|
|
1705
|
+
db,
|
|
1719
1706
|
tidx: realTidx,
|
|
1720
1707
|
})
|
|
1721
1708
|
|
|
@@ -1723,7 +1710,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1723
1710
|
expect(first.failed).toBe(1)
|
|
1724
1711
|
expect(first.dispatched).toBe(0)
|
|
1725
1712
|
// Cursor paused at the prior position so the row re-delivers next tick.
|
|
1726
|
-
expect(decodeCursor(await Core.getCursor(
|
|
1713
|
+
expect(decodeCursor(await Core.getCursor(db, subscription.id))).toEqual([
|
|
1727
1714
|
windowFrom - 1,
|
|
1728
1715
|
endOfBlockIndex,
|
|
1729
1716
|
])
|
|
@@ -1732,13 +1719,13 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1732
1719
|
expect(second.dispatched).toBe(1)
|
|
1733
1720
|
expect(attempts).toBe(2)
|
|
1734
1721
|
// Now advanced past the redelivered row (the first row in block 1000002).
|
|
1735
|
-
expect(decodeCursor(await Core.getCursor(
|
|
1722
|
+
expect(decodeCursor(await Core.getCursor(db, subscription.id))).toEqual([windowTo, 0])
|
|
1736
1723
|
})
|
|
1737
1724
|
|
|
1738
1725
|
test('auto-disables a subscription after sustained failures', async () => {
|
|
1739
|
-
const
|
|
1740
|
-
const subscription = await createTransferSubscription(
|
|
1741
|
-
await Core.setCursor(
|
|
1726
|
+
const db = TestApp.database()
|
|
1727
|
+
const subscription = await createTransferSubscription(db)
|
|
1728
|
+
await Core.setCursor(db, subscription.id, windowCursor)
|
|
1742
1729
|
|
|
1743
1730
|
// Real TIDX queries pass through; only the webhook delivery fails (500).
|
|
1744
1731
|
const realFetch = globalThis.fetch.bind(globalThis)
|
|
@@ -1756,7 +1743,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1756
1743
|
eventTypes: ['token:transfer'],
|
|
1757
1744
|
headBlockNumber: windowHead,
|
|
1758
1745
|
client,
|
|
1759
|
-
|
|
1746
|
+
db,
|
|
1760
1747
|
tidx: realTidx,
|
|
1761
1748
|
})
|
|
1762
1749
|
|
|
@@ -1764,7 +1751,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1764
1751
|
// subscription auto-disables and drops out of the poller's active index.
|
|
1765
1752
|
for (let i = 0; i < Core.maxFailures; i++) await tick()
|
|
1766
1753
|
|
|
1767
|
-
const disabled = await Core.getSubscription(
|
|
1754
|
+
const disabled = await Core.getSubscription(db, subscription.owner, subscription.id)
|
|
1768
1755
|
expect(disabled?.status).toBe('disabled')
|
|
1769
1756
|
expect(disabled?.failureCount).toBe(Core.maxFailures)
|
|
1770
1757
|
|
|
@@ -1781,10 +1768,10 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1781
1768
|
// proves the route-issued secret and id line up with what is delivered/logged.
|
|
1782
1769
|
describe('end-to-end (routes + poller)', () => {
|
|
1783
1770
|
test('create → poll → signed delivery → deliveries route records success', async () => {
|
|
1784
|
-
const
|
|
1771
|
+
const db = TestApp.database()
|
|
1785
1772
|
const app = TestApp.client({
|
|
1786
|
-
auth: {
|
|
1787
|
-
|
|
1773
|
+
auth: { keys: [writer] },
|
|
1774
|
+
db,
|
|
1788
1775
|
})
|
|
1789
1776
|
|
|
1790
1777
|
// 1. Create through the route; capture the one-time signing secret + id.
|
|
@@ -1799,7 +1786,7 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1799
1786
|
// Anchor the cursor just below the window so the poller scans this tick (a
|
|
1800
1787
|
// brand-new subscription anchors at the confirmed head and skips its first
|
|
1801
1788
|
// tick).
|
|
1802
|
-
await Core.setCursor(
|
|
1789
|
+
await Core.setCursor(db, id, windowCursor)
|
|
1803
1790
|
|
|
1804
1791
|
// 2. A local delivery sink that captures the request and acks 200, injected
|
|
1805
1792
|
// via `deliverAndRecord`'s `fetch` option (the SSRF guard blocks loopback,
|
|
@@ -1821,11 +1808,11 @@ describe.skipIf(Runtime.get().mode === 'localnet')('poll', () => {
|
|
|
1821
1808
|
batchSize: 1,
|
|
1822
1809
|
chainId: 42431,
|
|
1823
1810
|
dispatch: ({ envelope, subscription }) =>
|
|
1824
|
-
Core.deliverAndRecord(
|
|
1811
|
+
Core.deliverAndRecord(db, subscription, envelope, { fetch }),
|
|
1825
1812
|
eventTypes: ['token:transfer'],
|
|
1826
1813
|
headBlockNumber: windowHead,
|
|
1827
1814
|
client,
|
|
1828
|
-
|
|
1815
|
+
db,
|
|
1829
1816
|
tidx: realTidx,
|
|
1830
1817
|
})
|
|
1831
1818
|
expect(result.dispatched).toBe(1)
|