tapimo 0.5.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.d.ts +15830 -7220
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +9 -1
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +4 -0
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +5 -0
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +1011 -412
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +4 -0
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +2 -1
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/early-access.d.ts +148 -0
- package/dist/admin/apps/early-access.d.ts.map +1 -0
- package/dist/admin/apps/early-access.js +133 -0
- package/dist/admin/apps/early-access.js.map +1 -0
- package/dist/admin/apps/organizations.d.ts +124 -1
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +97 -6
- package/dist/admin/apps/organizations.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +526 -1
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.js +214 -1
- package/dist/admin/apps/verified-tokens.js.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +95 -75
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +20 -0
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +18 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +36 -7
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/data/App.d.ts +6260 -4924
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +11 -6
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.js +194 -16
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +71 -0
- package/dist/apps/data/FxOracle.d.ts.map +1 -0
- package/dist/apps/data/FxOracle.js +97 -0
- package/dist/apps/data/FxOracle.js.map +1 -0
- package/dist/apps/data/index.d.ts +1 -0
- package/dist/apps/data/index.d.ts.map +1 -1
- package/dist/apps/data/index.js +1 -0
- package/dist/apps/data/index.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +3599 -1382
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +250 -88
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +872 -251
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/addresses.js +11 -9
- package/dist/apps/data/routes/addresses.js.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +77 -26
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +88 -45
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +39 -39
- package/dist/apps/data/routes/coingecko.d.ts +54 -54
- package/dist/apps/data/routes/exchanges.d.ts +856 -105
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +518 -76
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +81 -67
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +76 -91
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/funding.d.ts +80 -36
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +65 -31
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +392 -315
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +152 -77
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +167 -174
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +15 -13
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +277 -536
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +96 -77
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +157 -81
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +272 -130
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +307 -0
- package/dist/apps/data/routes/valuation.d.ts.map +1 -0
- package/dist/apps/data/routes/valuation.js +292 -0
- package/dist/apps/data/routes/valuation.js.map +1 -0
- package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
- package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/verified-tokens.js +7 -5
- package/dist/apps/data/routes/verified-tokens.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +103 -123
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +124 -25
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +2 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +2 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +8554 -1692
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +12 -1
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +7 -0
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +17 -3
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +157 -162
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +31 -23
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +232 -0
- package/dist/apps/management/routes/faucet.d.ts.map +1 -0
- package/dist/apps/management/routes/faucet.js +154 -0
- package/dist/apps/management/routes/faucet.js.map +1 -0
- package/dist/apps/management/routes/invitations.d.ts +60 -60
- package/dist/apps/management/routes/invite-links.d.ts +49 -20
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
- package/dist/apps/management/routes/invite-links.js +26 -1
- package/dist/apps/management/routes/invite-links.js.map +1 -1
- package/dist/apps/management/routes/me.d.ts +6 -6
- package/dist/apps/management/routes/members.d.ts +6 -6
- package/dist/apps/management/routes/orgs.d.ts +42 -42
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +5 -0
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +44 -44
- package/dist/apps/management/routes/usage.d.ts +3 -0
- package/dist/apps/management/routes/usage.d.ts.map +1 -1
- package/dist/apps/management/routes/usage.js +4 -0
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
- package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
- package/dist/apps/management/routes/verified-token-requests.js +271 -0
- package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
- package/dist/apps/management/routes/webhooks.d.ts +6977 -0
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
- package/dist/apps/management/routes/webhooks.js +573 -0
- package/dist/apps/management/routes/webhooks.js.map +1 -0
- package/dist/apps/mpp/App.d.ts +363 -0
- package/dist/apps/mpp/App.d.ts.map +1 -0
- package/dist/apps/mpp/App.js +72 -0
- package/dist/apps/mpp/App.js.map +1 -0
- package/dist/apps/mpp/Mpp.d.ts +178 -0
- package/dist/apps/mpp/Mpp.d.ts.map +1 -0
- package/dist/apps/mpp/Mpp.js +183 -0
- package/dist/apps/mpp/Mpp.js.map +1 -0
- package/dist/apps/mpp/index.d.ts +3 -0
- package/dist/apps/mpp/index.d.ts.map +1 -0
- package/dist/apps/mpp/index.js +3 -0
- package/dist/apps/mpp/index.js.map +1 -0
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +56 -9
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/db/Db.d.ts +6 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +110 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +53 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +56 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/earlyAccess.d.ts +50 -0
- package/dist/db/tables/earlyAccess.d.ts.map +1 -0
- package/dist/db/tables/earlyAccess.js +63 -0
- package/dist/db/tables/earlyAccess.js.map +1 -0
- package/dist/db/tables/enabledBillingSources.d.ts +73 -0
- package/dist/db/tables/enabledBillingSources.d.ts.map +1 -0
- package/dist/db/tables/enabledBillingSources.js +69 -0
- package/dist/db/tables/enabledBillingSources.js.map +1 -0
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/invitations.js +3 -0
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/inviteLinks.d.ts +10 -2
- package/dist/db/tables/inviteLinks.d.ts.map +1 -1
- package/dist/db/tables/inviteLinks.js +10 -1
- package/dist/db/tables/inviteLinks.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +5 -2
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +13 -2
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +2 -0
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
- package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
- package/dist/db/tables/verifiedTokenRequests.js +120 -0
- package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
- package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +16 -0
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/handlers/internal/utils.d.ts +1 -16
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +17 -6
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +37 -5
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +11 -2
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +14 -47
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +147 -47
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +119 -33
- package/dist/internal/FundingQuotes.js.map +1 -1
- package/dist/internal/Log.d.ts +37 -5
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +52 -3
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +24 -0
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +2 -2
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +3 -0
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/Response.d.ts +2 -2
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Response.js +12 -4
- package/dist/internal/Response.js.map +1 -1
- package/dist/internal/Schema.d.ts +14 -5
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +23 -5
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Value.d.ts +18 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js +11 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/VerifiedTokens.d.ts.map +1 -1
- package/dist/internal/VerifiedTokens.js +10 -1
- package/dist/internal/VerifiedTokens.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +24 -3
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +34 -8
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +7 -2
- package/src/App.test.ts +9 -4
- package/src/App.ts +23 -3
- package/src/Client.test-d.ts +733 -20
- package/src/Scope.ts +5 -0
- package/src/admin/App.test.ts +4 -0
- package/src/admin/App.ts +4 -0
- package/src/admin/apps/early-access.test.ts +125 -0
- package/src/admin/apps/early-access.ts +176 -0
- package/src/admin/apps/organizations.test.ts +86 -2
- package/src/admin/apps/organizations.ts +155 -31
- package/src/admin/apps/scopes.test.ts +5 -0
- package/src/admin/apps/verified-tokens.test.ts +201 -0
- package/src/admin/apps/verified-tokens.ts +532 -286
- package/src/admin/ui/plugin.ts +2 -1
- package/src/admin/ui/src/lib/early-access.ts +63 -0
- package/src/admin/ui/src/lib/organizations.test.ts +81 -1
- package/src/admin/ui/src/lib/organizations.ts +92 -0
- package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
- package/src/admin/ui/src/routeTree.gen.ts +33 -2
- package/src/admin/ui/src/routes/__root.tsx +2 -1
- package/src/admin/ui/src/routes/api-keys.tsx +1 -1
- package/src/admin/ui/src/routes/early-access.tsx +162 -0
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +103 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
- package/src/admin/ui.generated.ts +95 -94
- package/src/analytics/Analytics.test.ts +83 -0
- package/src/analytics/Analytics.ts +20 -0
- package/src/analytics/tables/requestEvents.ts +60 -7
- package/src/apps/composition.test.ts +11 -2
- package/src/apps/data/App.test.ts +1 -1
- package/src/apps/data/App.ts +22 -14
- package/src/apps/data/FundingQuoteProviders.test.ts +297 -4
- package/src/apps/data/FundingQuoteProviders.ts +255 -29
- package/src/apps/data/FxOracle.test.ts +118 -0
- package/src/apps/data/FxOracle.ts +153 -0
- package/src/apps/data/index.ts +1 -0
- package/src/apps/data/routes/activities.test.ts +177 -3
- package/src/apps/data/routes/activities.ts +441 -132
- package/src/apps/data/routes/addresses.ts +19 -9
- package/src/apps/data/routes/balances.test.ts +148 -11
- package/src/apps/data/routes/balances.ts +140 -51
- package/src/apps/data/routes/exchanges.test.ts +544 -9
- package/src/apps/data/routes/exchanges.ts +690 -103
- package/src/apps/data/routes/fee-amm.test.ts +47 -23
- package/src/apps/data/routes/fee-amm.ts +98 -119
- package/src/apps/data/routes/funding.test.ts +113 -8
- package/src/apps/data/routes/funding.ts +77 -51
- package/src/apps/data/routes/receipts.test.ts +129 -23
- package/src/apps/data/routes/receipts.ts +205 -100
- package/src/apps/data/routes/tokens.test.ts +43 -0
- package/src/apps/data/routes/tokens.ts +28 -13
- package/src/apps/data/routes/transactions.test.ts +72 -19
- package/src/apps/data/routes/transactions.ts +162 -92
- package/src/apps/data/routes/transfers.test.ts +341 -31
- package/src/apps/data/routes/transfers.ts +358 -158
- package/src/apps/data/routes/valuation.test.ts +437 -0
- package/src/apps/data/routes/valuation.ts +423 -0
- package/src/apps/data/routes/verified-tokens.ts +14 -2
- package/src/apps/data/routes/webhooks.test.ts +56 -8
- package/src/apps/data/routes/webhooks.ts +144 -27
- package/src/apps/index.ts +2 -1
- package/src/apps/management/App.ts +13 -0
- package/src/apps/management/routes/api-keys.test.ts +14 -0
- package/src/apps/management/routes/api-keys.ts +27 -3
- package/src/apps/management/routes/billing.test.ts +152 -20
- package/src/apps/management/routes/billing.ts +34 -18
- package/src/apps/management/routes/faucet.test.ts +87 -0
- package/src/apps/management/routes/faucet.ts +201 -0
- package/src/apps/management/routes/invite-links.test.ts +117 -0
- package/src/apps/management/routes/invite-links.ts +43 -1
- package/src/apps/management/routes/me.test.ts +9 -99
- package/src/apps/management/routes/orgs.test.ts +45 -2
- package/src/apps/management/routes/orgs.ts +6 -0
- package/src/apps/management/routes/scopes.test.ts +1 -0
- package/src/apps/management/routes/usage.test.ts +6 -0
- package/src/apps/management/routes/usage.ts +7 -0
- package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
- package/src/apps/management/routes/verified-token-requests.ts +397 -0
- package/src/apps/management/routes/webhooks.test.ts +426 -0
- package/src/apps/management/routes/webhooks.ts +672 -0
- package/src/apps/mpp/App.ts +86 -0
- package/src/apps/mpp/Mpp.test.ts +193 -0
- package/src/apps/mpp/Mpp.ts +353 -0
- package/src/apps/mpp/index.ts +2 -0
- package/src/apps/mpp/internal/Adapter.ts +11 -0
- package/src/apps/mpp/internal/Error.ts +9 -0
- package/src/apps/mpp/internal/Idempotency.ts +7 -0
- package/src/apps/mpp/internal/Screening.ts +10 -0
- package/src/apps/relay/App.test.ts +88 -6
- package/src/apps/relay/App.ts +61 -9
- package/src/db/Db.test.ts +19 -0
- package/src/db/Db.ts +125 -0
- package/src/db/Schema.ts +68 -0
- package/src/db/tables/earlyAccess.ts +86 -0
- package/src/db/tables/enabledBillingSources.test.ts +303 -0
- package/src/db/tables/enabledBillingSources.ts +118 -0
- package/src/db/tables/invitations.ts +3 -0
- package/src/db/tables/inviteLinks.ts +22 -3
- package/src/db/tables/organizations.test.ts +103 -0
- package/src/db/tables/organizations.ts +18 -2
- package/src/db/tables/sponsoredTransactions.ts +4 -0
- package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
- package/src/db/tables/verifiedTokenRequests.ts +182 -0
- package/src/db/tables/webhookSubscriptions.ts +31 -0
- package/src/handlers/internal/utils.ts +22 -6
- package/src/handlers/relay.errors.test.ts +153 -0
- package/src/handlers/relay.ts +42 -7
- package/src/internal/Auth.test.ts +3 -3
- package/src/internal/Auth.ts +15 -47
- package/src/internal/FundingQuotes.test.ts +161 -6
- package/src/internal/FundingQuotes.ts +141 -39
- package/src/internal/Log.test-d.ts +21 -0
- package/src/internal/Log.test.ts +141 -0
- package/src/internal/Log.ts +93 -6
- package/src/internal/MetricSink.test.ts +215 -0
- package/src/internal/MetricSink.ts +24 -0
- package/src/internal/OpenApi.ts +3 -0
- package/src/internal/Response.test.ts +28 -0
- package/src/internal/Response.ts +12 -4
- package/src/internal/Schema.ts +50 -5
- package/src/internal/Value.test.ts +20 -0
- package/src/internal/Value.ts +24 -1
- package/src/internal/VerifiedTokens.ts +9 -1
- package/src/internal/Webhooks.test.ts +140 -0
- package/src/internal/Webhooks.ts +53 -9
|
@@ -78,6 +78,45 @@ describe('createSubscription', () => {
|
|
|
78
78
|
)
|
|
79
79
|
})
|
|
80
80
|
|
|
81
|
+
test('counts paused subscriptions toward the live subscription cap', async () => {
|
|
82
|
+
const db = TestApp.database()
|
|
83
|
+
const created = await Webhooks.createSubscription(db, createInput(), { maxPerOwner: 1 })
|
|
84
|
+
await Webhooks.updateSubscription(db, apiKeyOwner, created.id, { status: 'paused' })
|
|
85
|
+
|
|
86
|
+
await expect(
|
|
87
|
+
Webhooks.createSubscription(db, createInput(), { maxPerOwner: 1 }),
|
|
88
|
+
).rejects.toBeInstanceOf(Webhooks.LimitExceededError)
|
|
89
|
+
await Webhooks.deleteSubscription(db, apiKeyOwner, created.id)
|
|
90
|
+
await expect(
|
|
91
|
+
Webhooks.createSubscription(db, createInput(), { maxPerOwner: 1 }),
|
|
92
|
+
).resolves.toMatchObject({ status: 'active' })
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test('enforces the per-owner cap across concurrent creates', async () => {
|
|
96
|
+
const getDb = TestApp.databaseFactory()
|
|
97
|
+
const results = await Promise.allSettled(
|
|
98
|
+
Array.from({ length: 8 }, () =>
|
|
99
|
+
Webhooks.createSubscription(getDb(), createInput(), { maxPerOwner: 3 }),
|
|
100
|
+
),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
expect(results.map((result) => result.status).sort()).toMatchInlineSnapshot(`
|
|
104
|
+
[
|
|
105
|
+
"fulfilled",
|
|
106
|
+
"fulfilled",
|
|
107
|
+
"fulfilled",
|
|
108
|
+
"rejected",
|
|
109
|
+
"rejected",
|
|
110
|
+
"rejected",
|
|
111
|
+
"rejected",
|
|
112
|
+
"rejected",
|
|
113
|
+
]
|
|
114
|
+
`)
|
|
115
|
+
for (const result of results)
|
|
116
|
+
if (result.status === 'rejected') expect(result.reason).toBeInstanceOf(Webhooks.LimitExceededError) // prettier-ignore
|
|
117
|
+
expect(await Webhooks.listSubscriptions(getDb(), apiKeyOwner)).toHaveLength(3)
|
|
118
|
+
})
|
|
119
|
+
|
|
81
120
|
test('rejects an undeliverable URL before persisting', async () => {
|
|
82
121
|
const db = TestApp.database()
|
|
83
122
|
await expect(
|
|
@@ -204,6 +243,27 @@ describe('updateSubscription', () => {
|
|
|
204
243
|
`[Webhooks.InvalidUrlError: Webhook URL rejected (protocol): http://10.0.0.1]`,
|
|
205
244
|
)
|
|
206
245
|
})
|
|
246
|
+
|
|
247
|
+
test('requires recreation before activating URL signing for a provider destination', async () => {
|
|
248
|
+
const db = TestApp.database()
|
|
249
|
+
const created = await Webhooks.createSubscription(
|
|
250
|
+
db,
|
|
251
|
+
createInput({
|
|
252
|
+
destination: {
|
|
253
|
+
type: 'slack',
|
|
254
|
+
url: 'https://hooks.slack.com/services/T000/B000/xxxx',
|
|
255
|
+
},
|
|
256
|
+
}),
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
await expect(
|
|
260
|
+
Webhooks.updateSubscription(db, apiKeyOwner, created.id, {
|
|
261
|
+
destination: { type: 'url', url: 'https://hooks.example.com/v2' },
|
|
262
|
+
}),
|
|
263
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
264
|
+
`[Webhooks.InvalidDestinationTransitionError: Create a new webhook to change a provider-managed destination to an HTTPS endpoint.]`,
|
|
265
|
+
)
|
|
266
|
+
})
|
|
207
267
|
})
|
|
208
268
|
|
|
209
269
|
describe('listActive', () => {
|
|
@@ -548,6 +608,86 @@ describe('delivery log', () => {
|
|
|
548
608
|
`)
|
|
549
609
|
})
|
|
550
610
|
|
|
611
|
+
test('deliverCurrentAndRecord skips paused and deleted queued subscriptions', async () => {
|
|
612
|
+
const db = TestApp.database()
|
|
613
|
+
const paused = await Webhooks.createSubscription(db, createInput())
|
|
614
|
+
const removed = await Webhooks.createSubscription(db, createInput())
|
|
615
|
+
const pausedEnvelope = Webhooks.buildEnvelope({
|
|
616
|
+
blockNumber: 1,
|
|
617
|
+
data: { amount: '1' },
|
|
618
|
+
logIndex: 0,
|
|
619
|
+
subscription: paused,
|
|
620
|
+
})
|
|
621
|
+
const removedEnvelope = Webhooks.buildEnvelope({
|
|
622
|
+
blockNumber: 1,
|
|
623
|
+
data: { amount: '1' },
|
|
624
|
+
logIndex: 1,
|
|
625
|
+
subscription: removed,
|
|
626
|
+
})
|
|
627
|
+
await Webhooks.updateSubscription(db, apiKeyOwner, paused.id, { status: 'paused' })
|
|
628
|
+
await Webhooks.deleteSubscription(db, apiKeyOwner, removed.id)
|
|
629
|
+
let requests = 0
|
|
630
|
+
const fetch = (async () => {
|
|
631
|
+
requests++
|
|
632
|
+
return new Response(null, { status: 200 })
|
|
633
|
+
}) satisfies typeof globalThis.fetch
|
|
634
|
+
|
|
635
|
+
await expect(
|
|
636
|
+
Webhooks.deliverCurrentAndRecord(db, paused, pausedEnvelope, { fetch }),
|
|
637
|
+
).resolves.toEqual({ status: 'skipped' })
|
|
638
|
+
await expect(
|
|
639
|
+
Webhooks.deliverCurrentAndRecord(db, removed, removedEnvelope, { fetch }),
|
|
640
|
+
).resolves.toEqual({ status: 'skipped' })
|
|
641
|
+
expect(requests).toBe(0)
|
|
642
|
+
})
|
|
643
|
+
|
|
644
|
+
test('deliverCurrentAndRecord uses the current destination and secret', async () => {
|
|
645
|
+
const db = TestApp.database()
|
|
646
|
+
const created = await Webhooks.createSubscription(db, createInput())
|
|
647
|
+
const envelope = Webhooks.buildEnvelope({
|
|
648
|
+
blockNumber: 1,
|
|
649
|
+
data: { amount: '1' },
|
|
650
|
+
logIndex: 0,
|
|
651
|
+
subscription: created,
|
|
652
|
+
})
|
|
653
|
+
const current = await Webhooks.updateSubscription(db, apiKeyOwner, created.id, {
|
|
654
|
+
destination: { type: 'url', url: 'https://hooks.example.com/current' },
|
|
655
|
+
})
|
|
656
|
+
const queued = { ...created, secret: `whsec_${'ff'.repeat(32)}` }
|
|
657
|
+
const captured: { body: string; signature: string | null; url: string } = {
|
|
658
|
+
body: '',
|
|
659
|
+
signature: null,
|
|
660
|
+
url: '',
|
|
661
|
+
}
|
|
662
|
+
const fetch = (async (input, init) => {
|
|
663
|
+
captured.body = typeof init?.body === 'string' ? init.body : ''
|
|
664
|
+
captured.signature = new Headers(init?.headers).get(Webhooks.signatureHeader)
|
|
665
|
+
captured.url = input instanceof Request ? input.url : input.toString()
|
|
666
|
+
return new Response(null, { status: 200 })
|
|
667
|
+
}) satisfies typeof globalThis.fetch
|
|
668
|
+
|
|
669
|
+
const delivery = await Webhooks.deliverCurrentAndRecord(db, queued, envelope, { fetch })
|
|
670
|
+
|
|
671
|
+
expect(delivery.status).toBe('delivered')
|
|
672
|
+
expect(captured.url).toBe('https://hooks.example.com/current')
|
|
673
|
+
expect(
|
|
674
|
+
Webhooks.verify({
|
|
675
|
+
body: captured.body,
|
|
676
|
+
secret: current!.secret,
|
|
677
|
+
signature: captured.signature ?? '',
|
|
678
|
+
tolerance: Number.POSITIVE_INFINITY,
|
|
679
|
+
}),
|
|
680
|
+
).toBe(true)
|
|
681
|
+
expect(
|
|
682
|
+
Webhooks.verify({
|
|
683
|
+
body: captured.body,
|
|
684
|
+
secret: queued.secret,
|
|
685
|
+
signature: captured.signature ?? '',
|
|
686
|
+
tolerance: Number.POSITIVE_INFINITY,
|
|
687
|
+
}),
|
|
688
|
+
).toBe(false)
|
|
689
|
+
})
|
|
690
|
+
|
|
551
691
|
test('deleteSubscription removes the delivery log', async () => {
|
|
552
692
|
const db = TestApp.database()
|
|
553
693
|
const created = await Webhooks.createSubscription(db, createInput())
|
package/src/internal/Webhooks.ts
CHANGED
|
@@ -161,8 +161,8 @@ export type Delivery = {
|
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
163
|
* Creates a subscription, validating its URL and (optionally) enforcing a
|
|
164
|
-
* per-owner cap, then persists it.
|
|
165
|
-
*
|
|
164
|
+
* per-owner cap, then persists it. Capped writes serialize per owner so
|
|
165
|
+
* concurrent requests cannot exceed the limit.
|
|
166
166
|
*/
|
|
167
167
|
export async function createSubscription(
|
|
168
168
|
db: Db.Db,
|
|
@@ -174,11 +174,6 @@ export async function createSubscription(
|
|
|
174
174
|
const now = (options.now ?? (() => new Date()))()
|
|
175
175
|
const iso = now.toISOString()
|
|
176
176
|
|
|
177
|
-
if (options.maxPerOwner !== undefined) {
|
|
178
|
-
const existing = await WebhookSubscriptions.count(db, input.owner, iso)
|
|
179
|
-
if (existing >= options.maxPerOwner) throw new LimitExceededError(options.maxPerOwner)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
177
|
const subscription: Subscription = {
|
|
183
178
|
chainId: input.chainId,
|
|
184
179
|
...(input.context === undefined ? {} : { context: input.context }),
|
|
@@ -197,14 +192,20 @@ export async function createSubscription(
|
|
|
197
192
|
: { expiresAt: new Date(now.getTime() + input.ttl).toISOString() }),
|
|
198
193
|
}
|
|
199
194
|
|
|
200
|
-
|
|
195
|
+
if (options.maxPerOwner !== undefined) {
|
|
196
|
+
const inserted = await WebhookSubscriptions.insertWithinLimit(db, subscription, {
|
|
197
|
+
maxPerOwner: options.maxPerOwner,
|
|
198
|
+
now: iso,
|
|
199
|
+
})
|
|
200
|
+
if (!inserted) throw new LimitExceededError(options.maxPerOwner)
|
|
201
|
+
} else await WebhookSubscriptions.insert(db, subscription)
|
|
201
202
|
return subscription
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
export declare namespace createSubscription {
|
|
205
206
|
/** Options for {@link createSubscription}. */
|
|
206
207
|
type Options = {
|
|
207
|
-
/** Reject creation once the owner has this many subscriptions. */
|
|
208
|
+
/** Reject creation once the owner has this many live subscriptions. */
|
|
208
209
|
maxPerOwner?: number | undefined
|
|
209
210
|
/** Clock used for timestamps (injectable for tests). */
|
|
210
211
|
now?: (() => Date) | undefined
|
|
@@ -268,6 +269,8 @@ export async function updateSubscription(
|
|
|
268
269
|
const current = await getSubscription(db, owner, id)
|
|
269
270
|
if (!current) return null
|
|
270
271
|
|
|
272
|
+
if (current.destination.type !== 'url' && patch.destination?.type === 'url')
|
|
273
|
+
throw new InvalidDestinationTransitionError()
|
|
271
274
|
if (patch.destination !== undefined) WebhookDestination.assertDestination(patch.destination)
|
|
272
275
|
|
|
273
276
|
const now = (options.now ?? (() => new Date()))()
|
|
@@ -550,6 +553,39 @@ export declare namespace deliverAndRecord {
|
|
|
550
553
|
}
|
|
551
554
|
}
|
|
552
555
|
|
|
556
|
+
/**
|
|
557
|
+
* Re-resolves an enqueued subscription before delivery. Missing or inactive
|
|
558
|
+
* subscriptions are skipped; delivery uses the current destination and secret.
|
|
559
|
+
*/
|
|
560
|
+
export async function deliverCurrentAndRecord(
|
|
561
|
+
db: Db.Db,
|
|
562
|
+
queued: Subscription,
|
|
563
|
+
envelope: Envelope,
|
|
564
|
+
options: deliverAndRecord.Options = {},
|
|
565
|
+
): Promise<deliverCurrentAndRecord.Result> {
|
|
566
|
+
const subscription = await getSubscription(db, queued.owner, queued.id)
|
|
567
|
+
if (!subscription || subscription.status !== 'active') return { status: 'skipped' }
|
|
568
|
+
return {
|
|
569
|
+
result: await deliverAndRecord(db, subscription, envelope, options),
|
|
570
|
+
status: 'delivered',
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
export declare namespace deliverCurrentAndRecord {
|
|
575
|
+
/** Authoritative delivery outcome, or a skipped stale queue message. */
|
|
576
|
+
type Result =
|
|
577
|
+
| {
|
|
578
|
+
/** Transport result from the current subscription state. */
|
|
579
|
+
result: WebhookDestination.Result
|
|
580
|
+
/** The current subscription was delivered. */
|
|
581
|
+
status: 'delivered'
|
|
582
|
+
}
|
|
583
|
+
| {
|
|
584
|
+
/** The queued subscription is absent or inactive. */
|
|
585
|
+
status: 'skipped'
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
553
589
|
/** Builds a delivery-log row from an attempt's envelope and classified result. */
|
|
554
590
|
function buildDelivery(
|
|
555
591
|
input: {
|
|
@@ -783,6 +819,14 @@ export class LimitExceededError extends Error {
|
|
|
783
819
|
}
|
|
784
820
|
}
|
|
785
821
|
|
|
822
|
+
/** Thrown when an update would activate URL signing with an unrecoverable secret. */
|
|
823
|
+
export class InvalidDestinationTransitionError extends Error {
|
|
824
|
+
constructor() {
|
|
825
|
+
super('Create a new webhook to change a provider-managed destination to an HTTPS endpoint.')
|
|
826
|
+
this.name = 'Webhooks.InvalidDestinationTransitionError'
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
786
830
|
/**
|
|
787
831
|
* Thrown when a subscription's `filters` fail to validate against the schema for
|
|
788
832
|
* its `eventType`. The detection path treats stored filters as **fail-closed**:
|