tapimo 0.5.2 → 0.6.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 +13987 -5755
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js.map +1 -1
- package/dist/admin/App.d.ts +910 -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/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/verified-tokens.d.ts +643 -118
- 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 +45 -33
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/apps/data/App.d.ts +3733 -2428
- 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 +193 -2
- 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 +3575 -1358
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +230 -88
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +963 -342
- 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 +108 -57
- 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/coingecko.d.ts +169 -169
- package/dist/apps/data/routes/exchanges.d.ts +952 -201
- 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 +24 -24
- package/dist/apps/data/routes/funding.d.ts +8 -2
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +32 -6
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +5 -5
- 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 +166 -173
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +14 -12
- 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 +82 -17
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +70 -13
- 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.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 +459 -479
- 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 +1 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +1 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +8606 -1681
- 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 +23 -0
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +5 -3
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +88 -48
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +10 -2
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +218 -0
- package/dist/apps/management/routes/faucet.d.ts.map +1 -0
- package/dist/apps/management/routes/faucet.js +139 -0
- package/dist/apps/management/routes/faucet.js.map +1 -0
- package/dist/apps/management/routes/invitations.d.ts +121 -121
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +3 -0
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +197 -168
- 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 +2 -0
- package/dist/apps/management/routes/me.d.ts.map +1 -1
- package/dist/apps/management/routes/me.js +4 -0
- package/dist/apps/management/routes/me.js.map +1 -1
- package/dist/apps/management/routes/members.d.ts +49 -49
- package/dist/apps/management/routes/orgs.d.ts +91 -91
- package/dist/apps/management/routes/projects.d.ts +115 -115
- package/dist/apps/management/routes/usage.d.ts +35 -32
- 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/mcp.d.ts +9 -2
- package/dist/apps/mcp.d.ts.map +1 -1
- package/dist/apps/mcp.js +9 -4
- package/dist/apps/mcp.js.map +1 -1
- package/dist/cli/Cli.d.ts.map +1 -1
- package/dist/cli/Cli.js +7 -2
- package/dist/cli/Cli.js.map +1 -1
- package/dist/db/Db.d.ts +4 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +83 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +41 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +45 -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/invitations.d.ts +12 -1
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/invitations.js +23 -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/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/internal/Auth.d.ts +43 -2
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +60 -45
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +69 -15
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +74 -25
- package/dist/internal/FundingQuotes.js.map +1 -1
- package/dist/internal/Log.d.ts +19 -1
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +2 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +9 -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/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/Viem.d.ts +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 +2 -2
- package/src/App.ts +9 -1
- package/src/Client.test-d.ts +638 -6
- package/src/admin/App.ts +4 -0
- package/src/admin/apps/early-access.test.ts +125 -0
- package/src/admin/apps/early-access.ts +175 -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/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/early-access.tsx +157 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
- package/src/admin/ui.generated.ts +48 -33
- package/src/apps/data/App.ts +22 -14
- package/src/apps/data/FundingQuoteProviders.test.ts +298 -0
- package/src/apps/data/FundingQuoteProviders.ts +257 -4
- 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 +173 -3
- package/src/apps/data/routes/activities.ts +403 -132
- package/src/apps/data/routes/addresses.ts +19 -9
- package/src/apps/data/routes/balances.test.ts +144 -11
- package/src/apps/data/routes/balances.ts +140 -51
- package/src/apps/data/routes/exchanges.test.ts +540 -9
- package/src/apps/data/routes/exchanges.ts +690 -103
- package/src/apps/data/routes/funding.test.ts +84 -0
- package/src/apps/data/routes/funding.ts +38 -6
- package/src/apps/data/routes/receipts.test.ts +125 -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 +27 -12
- 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 +146 -4
- package/src/apps/data/routes/transfers.ts +91 -13
- package/src/apps/data/routes/valuation.test.ts +422 -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 +1 -1
- package/src/apps/management/App.ts +13 -0
- package/src/apps/management/routes/api-keys.test.ts +87 -0
- package/src/apps/management/routes/api-keys.ts +4 -3
- package/src/apps/management/routes/billing.test.ts +112 -1
- package/src/apps/management/routes/billing.ts +7 -2
- package/src/apps/management/routes/faucet.test.ts +79 -0
- package/src/apps/management/routes/faucet.ts +185 -0
- package/src/apps/management/routes/invitations.test.ts +172 -0
- package/src/apps/management/routes/invitations.ts +3 -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 +140 -88
- package/src/apps/management/routes/me.ts +6 -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/mcp.test.ts +13 -0
- package/src/apps/mcp.ts +18 -5
- package/src/cli/Cli.test.ts +36 -0
- package/src/cli/Cli.ts +7 -2
- package/src/db/Db.test.ts +19 -0
- package/src/db/Db.ts +95 -0
- package/src/db/Schema.ts +53 -0
- package/src/db/tables/earlyAccess.ts +86 -0
- package/src/db/tables/invitations.ts +26 -1
- package/src/db/tables/inviteLinks.ts +22 -3
- 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/internal/Auth.ts +73 -45
- package/src/internal/FundingQuotes.test.ts +143 -1
- package/src/internal/FundingQuotes.ts +95 -28
- package/src/internal/Log.test-d.ts +21 -0
- package/src/internal/Log.test.ts +50 -0
- package/src/internal/Log.ts +24 -1
- package/src/internal/MetricSink.test.ts +160 -0
- package/src/internal/MetricSink.ts +10 -0
- package/src/internal/OpenApi.ts +3 -0
- 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
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
import { type Context, Hono } from 'hono'
|
|
2
|
+
import * as z from 'zod/mini'
|
|
3
|
+
|
|
4
|
+
import type * as App from '../../../App.js'
|
|
5
|
+
import * as Db from '../../../db/Db.js'
|
|
6
|
+
import * as Auth from '../../../internal/Auth.js'
|
|
7
|
+
import * as OpenApi from '../../../internal/OpenApi.js'
|
|
8
|
+
import * as Response from '../../../internal/Response.js'
|
|
9
|
+
import * as Webhooks from '../../../internal/Webhooks.js'
|
|
10
|
+
import { schema as webhookSchema } from '../../data/routes/webhooks.js'
|
|
11
|
+
import type { Environment } from '../App.js'
|
|
12
|
+
|
|
13
|
+
const defaultMaxPerOwner = 100
|
|
14
|
+
const redactedBetterstackToken = '[redacted]'
|
|
15
|
+
const redactedSlackUrl = 'https://hooks.slack.com/…'
|
|
16
|
+
|
|
17
|
+
/** OpenAPI schemas owned by console webhook management. */
|
|
18
|
+
export namespace schema {
|
|
19
|
+
/** Public webhook subscription representation. */
|
|
20
|
+
export const Subscription = webhookSchema.Subscription
|
|
21
|
+
|
|
22
|
+
/** Schemas for creating an organization webhook. */
|
|
23
|
+
export namespace createWebhook {
|
|
24
|
+
/** Organization webhook creation requires an explicit network. */
|
|
25
|
+
export const Body = z
|
|
26
|
+
.intersection(
|
|
27
|
+
webhookSchema.createWebhook.Body,
|
|
28
|
+
z.object({ chainId: webhookSchema.Subscription.shape.chainId }),
|
|
29
|
+
)
|
|
30
|
+
.check(z.describe('Details for creating an organization webhook subscription.'))
|
|
31
|
+
|
|
32
|
+
const secret = webhookSchema.createWebhook.Response.shape.secret
|
|
33
|
+
const urlDestination = z.object({
|
|
34
|
+
type: z.literal('url'),
|
|
35
|
+
url: z
|
|
36
|
+
.url()
|
|
37
|
+
.check(
|
|
38
|
+
z.describe('Your HTTPS endpoint where Tempo sends signed event POSTs.'),
|
|
39
|
+
z.meta({ examples: ['https://example.com/webhooks'] }),
|
|
40
|
+
),
|
|
41
|
+
})
|
|
42
|
+
const slackDestination = z.object({
|
|
43
|
+
type: z.literal('slack'),
|
|
44
|
+
url: z.literal(redactedSlackUrl).check(z.describe('Redacted Slack webhook URL.')),
|
|
45
|
+
})
|
|
46
|
+
const betterstackDestination = z.object({
|
|
47
|
+
token: z
|
|
48
|
+
.literal(redactedBetterstackToken)
|
|
49
|
+
.check(z.describe('Redacted Better Stack source token.')),
|
|
50
|
+
type: z.literal('betterstack'),
|
|
51
|
+
url: z
|
|
52
|
+
.url()
|
|
53
|
+
.check(
|
|
54
|
+
z.describe('Your Better Stack source ingest host URL.'),
|
|
55
|
+
z.meta({ examples: ['https://s1234567.eu-nbg-2.betterstackdata.com'] }),
|
|
56
|
+
),
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
/** Created webhook with transport credentials redacted. */
|
|
60
|
+
export const Response = z
|
|
61
|
+
.union([
|
|
62
|
+
z.object({ ...Subscription.shape, destination: urlDestination, secret }),
|
|
63
|
+
z.object({ ...Subscription.shape, destination: slackDestination }),
|
|
64
|
+
z.object({ ...Subscription.shape, destination: betterstackDestination }),
|
|
65
|
+
])
|
|
66
|
+
.check(
|
|
67
|
+
z.describe(
|
|
68
|
+
'The new webhook subscription. HTTPS endpoints include their one-time signing secret.',
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Organization webhook collection parameters. */
|
|
74
|
+
export const Params = z
|
|
75
|
+
.object({
|
|
76
|
+
orgId: z
|
|
77
|
+
.string()
|
|
78
|
+
.check(
|
|
79
|
+
z.describe('Organization id (`org_…`).'),
|
|
80
|
+
z.meta({ examples: ['org_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
|
|
81
|
+
),
|
|
82
|
+
})
|
|
83
|
+
.check(z.describe("Path parameters for an organization's webhooks."))
|
|
84
|
+
|
|
85
|
+
/** Parameters addressing one organization webhook. */
|
|
86
|
+
export const WebhookParams = z
|
|
87
|
+
.object({
|
|
88
|
+
id: z
|
|
89
|
+
.string()
|
|
90
|
+
.check(
|
|
91
|
+
z.describe('Webhook subscription id (`wh_…`).'),
|
|
92
|
+
z.meta({ examples: ['wh_001718668800000_2ZPE2gvateYEQ0dQslgvkhjx'] }),
|
|
93
|
+
),
|
|
94
|
+
orgId: Params.shape.orgId,
|
|
95
|
+
})
|
|
96
|
+
.check(z.describe("Path parameters for one organization's webhook."))
|
|
97
|
+
|
|
98
|
+
/** Schemas for listing an organization webhook's delivery attempts. */
|
|
99
|
+
export namespace listWebhookDeliveries {
|
|
100
|
+
export const Params = WebhookParams
|
|
101
|
+
export const Query = webhookSchema.listWebhookDeliveries.Query
|
|
102
|
+
export const Response = webhookSchema.listWebhookDeliveries.Response
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const DeliveryParams = z
|
|
106
|
+
.object({
|
|
107
|
+
deliveryId: webhookSchema.retryWebhookDelivery.Params.shape.deliveryId,
|
|
108
|
+
id: WebhookParams.shape.id,
|
|
109
|
+
orgId: WebhookParams.shape.orgId,
|
|
110
|
+
})
|
|
111
|
+
.check(z.describe("Path parameters for one organization's webhook delivery."))
|
|
112
|
+
|
|
113
|
+
/** Schemas for loading one organization webhook delivery. */
|
|
114
|
+
export namespace getWebhookDelivery {
|
|
115
|
+
export const Params = DeliveryParams
|
|
116
|
+
export const Response = z
|
|
117
|
+
.object({
|
|
118
|
+
...webhookSchema.Delivery.shape,
|
|
119
|
+
envelope: webhookSchema.Envelope,
|
|
120
|
+
})
|
|
121
|
+
.check(z.describe('A webhook delivery attempt with the exact JSON payload Tempo sent.'))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Schemas for replaying one organization webhook delivery. */
|
|
125
|
+
export namespace retryWebhookDelivery {
|
|
126
|
+
export const Params = DeliveryParams
|
|
127
|
+
export const Response = webhookSchema.retryWebhookDelivery.Response
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Non-paginated organization webhook list. */
|
|
131
|
+
export const ListResponse = z
|
|
132
|
+
.object({
|
|
133
|
+
data: z.array(Subscription).check(z.describe("The organization's webhooks, newest first.")),
|
|
134
|
+
})
|
|
135
|
+
.check(z.describe("An organization's webhook subscriptions."))
|
|
136
|
+
|
|
137
|
+
/** Lifecycle state editable from the console. */
|
|
138
|
+
export const UpdateBody = z
|
|
139
|
+
.object({ status: webhookSchema.Status })
|
|
140
|
+
.check(z.describe('New delivery state for a webhook subscription.'))
|
|
141
|
+
|
|
142
|
+
/** Webhook deletion confirmation. */
|
|
143
|
+
export const DeleteResponse = z
|
|
144
|
+
.object({
|
|
145
|
+
id: z
|
|
146
|
+
.string()
|
|
147
|
+
.check(
|
|
148
|
+
z.describe('Deleted webhook subscription id.'),
|
|
149
|
+
z.meta({ examples: ['wh_001718668800000_2ZPE2gvateYEQ0dQslgvkhjx'] }),
|
|
150
|
+
),
|
|
151
|
+
})
|
|
152
|
+
.check(z.describe('Confirmation that a webhook subscription was deleted.'))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const bodyValidation = {
|
|
156
|
+
code: 'body_invalid',
|
|
157
|
+
message: 'Check the request body and try again.',
|
|
158
|
+
} as const
|
|
159
|
+
const paramValidation = {
|
|
160
|
+
code: 'param_invalid',
|
|
161
|
+
message: 'Check the path parameters and try again.',
|
|
162
|
+
} as const
|
|
163
|
+
|
|
164
|
+
/** Mounts session-authenticated organization webhook management operations. */
|
|
165
|
+
export function webhooks(options: webhooks.Options = {}) {
|
|
166
|
+
const hidden = !options.webhook
|
|
167
|
+
return new Hono<Environment>()
|
|
168
|
+
.post(
|
|
169
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/webhooks',
|
|
170
|
+
Auth.policy({ session: true }),
|
|
171
|
+
Auth.ensureOrg({ role: 'admin' }),
|
|
172
|
+
OpenApi.validate('param', schema.Params, paramValidation),
|
|
173
|
+
OpenApi.validate('json', schema.createWebhook.Body, bodyValidation),
|
|
174
|
+
OpenApi.describeRoute({
|
|
175
|
+
hide: hidden,
|
|
176
|
+
operationId: 'createOrgWebhook',
|
|
177
|
+
responses: OpenApi.responses({
|
|
178
|
+
errors: {
|
|
179
|
+
400: {
|
|
180
|
+
codes: [
|
|
181
|
+
'body_invalid',
|
|
182
|
+
'chain_id_unsupported',
|
|
183
|
+
'filters_invalid',
|
|
184
|
+
'param_invalid',
|
|
185
|
+
'url_invalid',
|
|
186
|
+
],
|
|
187
|
+
description: 'The request or destination is invalid, or the chain is not polled.',
|
|
188
|
+
},
|
|
189
|
+
403: {
|
|
190
|
+
codes: ['forbidden', 'limit_exceeded'],
|
|
191
|
+
description: 'Admin access is required and the organization must be under its limit.',
|
|
192
|
+
},
|
|
193
|
+
404: {
|
|
194
|
+
codes: ['organization_not_found', 'webhooks_not_enabled'],
|
|
195
|
+
description: 'No accessible organization or webhook capability was found.',
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
success: {
|
|
199
|
+
description: 'Created webhook. HTTPS endpoints include a one-time signing secret.',
|
|
200
|
+
schema: schema.createWebhook.Response,
|
|
201
|
+
},
|
|
202
|
+
}),
|
|
203
|
+
summary: 'Create webhook',
|
|
204
|
+
tags: ['Webhooks'],
|
|
205
|
+
}),
|
|
206
|
+
async (c) => {
|
|
207
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
208
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
209
|
+
if (Auth.narrowOrgRole) return Auth.ensureOrgRoleError(c)
|
|
210
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
|
|
211
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, bodyValidation)
|
|
212
|
+
if (!options.webhook) return notEnabled(c)
|
|
213
|
+
|
|
214
|
+
const body = c.req.valid('json')
|
|
215
|
+
const chainId = body.chainId
|
|
216
|
+
const supportedChainIds = new Set(options.webhook.supportedChainIds)
|
|
217
|
+
if (!supportedChainIds.has(chainId))
|
|
218
|
+
return Response.unsupportedChainId(c, chainId, supportedChainIds)
|
|
219
|
+
try {
|
|
220
|
+
const subscription = await Webhooks.createSubscription(
|
|
221
|
+
Db.get(c.get('db')),
|
|
222
|
+
{
|
|
223
|
+
chainId,
|
|
224
|
+
...(body.context === undefined ? {} : { context: body.context }),
|
|
225
|
+
destination: body.destination,
|
|
226
|
+
eventType: body.eventType,
|
|
227
|
+
filters: body.filters,
|
|
228
|
+
owner: owner(Auth.org(c).id),
|
|
229
|
+
},
|
|
230
|
+
{ maxPerOwner: options.webhook.maxPerOwner ?? defaultMaxPerOwner },
|
|
231
|
+
)
|
|
232
|
+
return c.json(
|
|
233
|
+
Response.validated(schema.createWebhook.Response, created(subscription)),
|
|
234
|
+
200,
|
|
235
|
+
)
|
|
236
|
+
} catch (cause) {
|
|
237
|
+
return mutationError(c, cause)
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
)
|
|
241
|
+
.get(
|
|
242
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/webhooks',
|
|
243
|
+
Auth.policy({ session: true }),
|
|
244
|
+
Auth.ensureOrg(),
|
|
245
|
+
OpenApi.validate('param', schema.Params, paramValidation),
|
|
246
|
+
OpenApi.describeRoute({
|
|
247
|
+
hide: hidden,
|
|
248
|
+
operationId: 'listOrgWebhooks',
|
|
249
|
+
responses: OpenApi.responses({
|
|
250
|
+
errors: {
|
|
251
|
+
400: { codes: ['param_invalid'], description: 'The path parameters are invalid.' },
|
|
252
|
+
404: {
|
|
253
|
+
codes: ['organization_not_found', 'webhooks_not_enabled'],
|
|
254
|
+
description: 'No accessible organization or webhook capability was found.',
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
success: { description: 'Organization webhooks.', schema: schema.ListResponse },
|
|
258
|
+
}),
|
|
259
|
+
summary: 'List webhooks',
|
|
260
|
+
tags: ['Webhooks'],
|
|
261
|
+
}),
|
|
262
|
+
async (c) => {
|
|
263
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
264
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
265
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
|
|
266
|
+
if (!options.webhook) return notEnabled(c)
|
|
267
|
+
try {
|
|
268
|
+
const records = await Webhooks.listSubscriptions(
|
|
269
|
+
Db.get(c.get('db')),
|
|
270
|
+
owner(Auth.org(c).id),
|
|
271
|
+
)
|
|
272
|
+
return c.json(
|
|
273
|
+
Response.validated(schema.ListResponse, { data: records.map(publicSubscription) }),
|
|
274
|
+
200,
|
|
275
|
+
)
|
|
276
|
+
} catch (cause) {
|
|
277
|
+
return Response.upstream(c, cause)
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
)
|
|
281
|
+
.get(
|
|
282
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/webhooks/:id{wh_[A-Za-z0-9_-]+}/deliveries',
|
|
283
|
+
Auth.policy({ session: true }),
|
|
284
|
+
Auth.ensureOrg(),
|
|
285
|
+
OpenApi.validate('param', schema.listWebhookDeliveries.Params, paramValidation),
|
|
286
|
+
OpenApi.validate('query', schema.listWebhookDeliveries.Query, {
|
|
287
|
+
code: 'query_invalid',
|
|
288
|
+
message: 'Check the query parameters and try again.',
|
|
289
|
+
}),
|
|
290
|
+
OpenApi.describeRoute({
|
|
291
|
+
hide: hidden,
|
|
292
|
+
operationId: 'listOrgWebhookDeliveries',
|
|
293
|
+
responses: OpenApi.responses({
|
|
294
|
+
errors: {
|
|
295
|
+
400: {
|
|
296
|
+
codes: ['param_invalid', 'query_invalid'],
|
|
297
|
+
description: 'The path or query parameters are invalid.',
|
|
298
|
+
},
|
|
299
|
+
404: {
|
|
300
|
+
codes: ['organization_not_found', 'webhook_not_found', 'webhooks_not_enabled'],
|
|
301
|
+
description: 'No accessible organization, webhook, or webhook capability was found.',
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
success: {
|
|
305
|
+
description: 'A newest-first page of webhook delivery attempts.',
|
|
306
|
+
schema: schema.listWebhookDeliveries.Response,
|
|
307
|
+
},
|
|
308
|
+
}),
|
|
309
|
+
summary: 'List webhook deliveries',
|
|
310
|
+
tags: ['Webhooks'],
|
|
311
|
+
}),
|
|
312
|
+
async (c) => {
|
|
313
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
314
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
315
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
|
|
316
|
+
if (OpenApi.narrowValidation)
|
|
317
|
+
return OpenApi.validationError(c, {
|
|
318
|
+
code: 'query_invalid',
|
|
319
|
+
message: 'Check the query parameters and try again.',
|
|
320
|
+
})
|
|
321
|
+
if (!options.webhook) return notEnabled(c)
|
|
322
|
+
|
|
323
|
+
const db = Db.get(c.get('db'))
|
|
324
|
+
const { id } = c.req.valid('param')
|
|
325
|
+
const { cursor, include, limit, page } = c.req.valid('query')
|
|
326
|
+
try {
|
|
327
|
+
const subscription = await Webhooks.getSubscription(db, owner(Auth.org(c).id), id)
|
|
328
|
+
if (!subscription) return notFound(c)
|
|
329
|
+
|
|
330
|
+
const countPromise = include.includes('totalCount')
|
|
331
|
+
? Webhooks.countDeliveries(db, id).catch(() => undefined)
|
|
332
|
+
: undefined
|
|
333
|
+
const rows = await Webhooks.listDeliveries(db, id, {
|
|
334
|
+
cursor,
|
|
335
|
+
limit: limit + 1,
|
|
336
|
+
offset: page !== undefined && page > 1 ? (page - 1) * limit : undefined,
|
|
337
|
+
})
|
|
338
|
+
const hasMore = rows.length > limit
|
|
339
|
+
const data = hasMore ? rows.slice(0, limit) : rows
|
|
340
|
+
const nextCursor = hasMore ? (data[data.length - 1]?.id ?? null) : null
|
|
341
|
+
const totalCount = countPromise ? await countPromise : undefined
|
|
342
|
+
|
|
343
|
+
return c.json(
|
|
344
|
+
Response.validated(schema.listWebhookDeliveries.Response, {
|
|
345
|
+
data: data.map((delivery) => publicDelivery(delivery, subscription)),
|
|
346
|
+
...(totalCount === undefined
|
|
347
|
+
? {}
|
|
348
|
+
: { meta: { totalCountCapped: false, totalCount } }),
|
|
349
|
+
nextCursor,
|
|
350
|
+
}),
|
|
351
|
+
200,
|
|
352
|
+
)
|
|
353
|
+
} catch (cause) {
|
|
354
|
+
return Response.upstream(c, cause)
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
)
|
|
358
|
+
.get(
|
|
359
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/webhooks/:id{wh_[A-Za-z0-9_-]+}/deliveries/:deliveryId',
|
|
360
|
+
Auth.policy({ session: true }),
|
|
361
|
+
Auth.ensureOrg(),
|
|
362
|
+
OpenApi.validate('param', schema.getWebhookDelivery.Params, paramValidation),
|
|
363
|
+
OpenApi.describeRoute({
|
|
364
|
+
hide: hidden,
|
|
365
|
+
operationId: 'getOrgWebhookDelivery',
|
|
366
|
+
responses: OpenApi.responses({
|
|
367
|
+
errors: {
|
|
368
|
+
400: { codes: ['param_invalid'], description: 'The path parameters are invalid.' },
|
|
369
|
+
404: {
|
|
370
|
+
codes: [
|
|
371
|
+
'delivery_not_found',
|
|
372
|
+
'organization_not_found',
|
|
373
|
+
'webhook_not_found',
|
|
374
|
+
'webhooks_not_enabled',
|
|
375
|
+
],
|
|
376
|
+
description:
|
|
377
|
+
'No accessible organization, webhook, delivery, or webhook capability was found.',
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
success: {
|
|
381
|
+
description: 'The delivery attempt and exact JSON payload Tempo sent.',
|
|
382
|
+
schema: schema.getWebhookDelivery.Response,
|
|
383
|
+
},
|
|
384
|
+
}),
|
|
385
|
+
summary: 'Get webhook delivery',
|
|
386
|
+
tags: ['Webhooks'],
|
|
387
|
+
}),
|
|
388
|
+
async (c) => {
|
|
389
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
390
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
391
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
|
|
392
|
+
if (!options.webhook) return notEnabled(c)
|
|
393
|
+
|
|
394
|
+
const db = Db.get(c.get('db'))
|
|
395
|
+
const { deliveryId, id } = c.req.valid('param')
|
|
396
|
+
try {
|
|
397
|
+
const subscription = await Webhooks.getSubscription(db, owner(Auth.org(c).id), id)
|
|
398
|
+
if (!subscription) return notFound(c)
|
|
399
|
+
const delivery = await Webhooks.getDelivery(db, id, deliveryId)
|
|
400
|
+
if (!delivery) return deliveryNotFound(c)
|
|
401
|
+
|
|
402
|
+
return c.json(
|
|
403
|
+
Response.validated(schema.getWebhookDelivery.Response, {
|
|
404
|
+
...publicDelivery(delivery, subscription),
|
|
405
|
+
envelope: delivery.envelope,
|
|
406
|
+
}),
|
|
407
|
+
200,
|
|
408
|
+
)
|
|
409
|
+
} catch (cause) {
|
|
410
|
+
return Response.upstream(c, cause)
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
)
|
|
414
|
+
.post(
|
|
415
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/webhooks/:id{wh_[A-Za-z0-9_-]+}/deliveries/:deliveryId/retry',
|
|
416
|
+
Auth.policy({ session: true }),
|
|
417
|
+
Auth.ensureOrg({ role: 'admin' }),
|
|
418
|
+
OpenApi.validate('param', schema.retryWebhookDelivery.Params, paramValidation),
|
|
419
|
+
OpenApi.describeRoute({
|
|
420
|
+
hide: hidden,
|
|
421
|
+
operationId: 'retryOrgWebhookDelivery',
|
|
422
|
+
responses: OpenApi.responses({
|
|
423
|
+
errors: {
|
|
424
|
+
400: { codes: ['param_invalid'], description: 'The path parameters are invalid.' },
|
|
425
|
+
403: { codes: ['forbidden'], description: 'Organization admin access is required.' },
|
|
426
|
+
404: {
|
|
427
|
+
codes: [
|
|
428
|
+
'delivery_not_found',
|
|
429
|
+
'organization_not_found',
|
|
430
|
+
'webhook_not_found',
|
|
431
|
+
'webhooks_not_enabled',
|
|
432
|
+
],
|
|
433
|
+
description:
|
|
434
|
+
'No accessible organization, webhook, delivery, or webhook capability was found.',
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
success: {
|
|
438
|
+
description: 'Result of replaying the webhook delivery.',
|
|
439
|
+
schema: schema.retryWebhookDelivery.Response,
|
|
440
|
+
},
|
|
441
|
+
}),
|
|
442
|
+
summary: 'Retry webhook delivery',
|
|
443
|
+
tags: ['Webhooks'],
|
|
444
|
+
}),
|
|
445
|
+
async (c) => {
|
|
446
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
447
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
448
|
+
if (Auth.narrowOrgRole) return Auth.ensureOrgRoleError(c)
|
|
449
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
|
|
450
|
+
if (!options.webhook) return notEnabled(c)
|
|
451
|
+
|
|
452
|
+
const db = Db.get(c.get('db'))
|
|
453
|
+
const { deliveryId, id } = c.req.valid('param')
|
|
454
|
+
try {
|
|
455
|
+
const subscription = await Webhooks.getSubscription(db, owner(Auth.org(c).id), id)
|
|
456
|
+
if (!subscription) return notFound(c)
|
|
457
|
+
const delivery = await Webhooks.getDelivery(db, id, deliveryId)
|
|
458
|
+
if (!delivery) return deliveryNotFound(c)
|
|
459
|
+
|
|
460
|
+
const result = await Webhooks.deliverAndRecord(db, subscription, delivery.envelope, {
|
|
461
|
+
trigger: 'manual_retry',
|
|
462
|
+
})
|
|
463
|
+
return c.json(
|
|
464
|
+
Response.validated(schema.retryWebhookDelivery.Response, {
|
|
465
|
+
delivered: result.ok,
|
|
466
|
+
eventId: delivery.eventId,
|
|
467
|
+
...(result.error === undefined ? {} : { error: result.error }),
|
|
468
|
+
...(result.durationMs === undefined ? {} : { responseMs: result.durationMs }),
|
|
469
|
+
...(result.status === undefined ? {} : { responseStatus: result.status }),
|
|
470
|
+
}),
|
|
471
|
+
200,
|
|
472
|
+
)
|
|
473
|
+
} catch (cause) {
|
|
474
|
+
return Response.upstream(c, cause)
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
)
|
|
478
|
+
.patch(
|
|
479
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/webhooks/:id{wh_[A-Za-z0-9_-]+}',
|
|
480
|
+
Auth.policy({ session: true }),
|
|
481
|
+
Auth.ensureOrg({ role: 'admin' }),
|
|
482
|
+
OpenApi.validate('param', schema.WebhookParams, paramValidation),
|
|
483
|
+
OpenApi.validate('json', schema.UpdateBody, bodyValidation),
|
|
484
|
+
OpenApi.describeRoute({
|
|
485
|
+
hide: hidden,
|
|
486
|
+
operationId: 'updateOrgWebhook',
|
|
487
|
+
responses: OpenApi.responses({
|
|
488
|
+
errors: {
|
|
489
|
+
400: {
|
|
490
|
+
codes: ['body_invalid', 'param_invalid'],
|
|
491
|
+
description: 'The path parameters or request body are invalid.',
|
|
492
|
+
},
|
|
493
|
+
403: { codes: ['forbidden'], description: 'Organization admin access is required.' },
|
|
494
|
+
404: {
|
|
495
|
+
codes: ['organization_not_found', 'webhook_not_found', 'webhooks_not_enabled'],
|
|
496
|
+
description: 'No accessible organization, webhook, or webhook capability was found.',
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
success: {
|
|
500
|
+
description: 'Updated webhook.',
|
|
501
|
+
schema: webhookSchema.Subscription,
|
|
502
|
+
},
|
|
503
|
+
}),
|
|
504
|
+
summary: 'Update webhook',
|
|
505
|
+
tags: ['Webhooks'],
|
|
506
|
+
}),
|
|
507
|
+
async (c) => {
|
|
508
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
509
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
510
|
+
if (Auth.narrowOrgRole) return Auth.ensureOrgRoleError(c)
|
|
511
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
|
|
512
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, bodyValidation)
|
|
513
|
+
if (!options.webhook) return notEnabled(c)
|
|
514
|
+
try {
|
|
515
|
+
const subscription = await Webhooks.updateSubscription(
|
|
516
|
+
Db.get(c.get('db')),
|
|
517
|
+
owner(Auth.org(c).id),
|
|
518
|
+
c.req.valid('param').id,
|
|
519
|
+
c.req.valid('json'),
|
|
520
|
+
)
|
|
521
|
+
if (!subscription) return notFound(c)
|
|
522
|
+
return c.json(
|
|
523
|
+
Response.validated(webhookSchema.Subscription, publicSubscription(subscription)),
|
|
524
|
+
200,
|
|
525
|
+
)
|
|
526
|
+
} catch (cause) {
|
|
527
|
+
return Response.upstream(c, cause)
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
)
|
|
531
|
+
.delete(
|
|
532
|
+
'/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/webhooks/:id{wh_[A-Za-z0-9_-]+}',
|
|
533
|
+
Auth.policy({ session: true }),
|
|
534
|
+
Auth.ensureOrg({ role: 'admin' }),
|
|
535
|
+
OpenApi.validate('param', schema.WebhookParams, paramValidation),
|
|
536
|
+
OpenApi.describeRoute({
|
|
537
|
+
hide: hidden,
|
|
538
|
+
operationId: 'deleteOrgWebhook',
|
|
539
|
+
responses: OpenApi.responses({
|
|
540
|
+
errors: {
|
|
541
|
+
400: { codes: ['param_invalid'], description: 'The path parameters are invalid.' },
|
|
542
|
+
403: { codes: ['forbidden'], description: 'Organization admin access is required.' },
|
|
543
|
+
404: {
|
|
544
|
+
codes: ['organization_not_found', 'webhook_not_found', 'webhooks_not_enabled'],
|
|
545
|
+
description: 'No accessible organization, webhook, or webhook capability was found.',
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
success: { description: 'Deleted webhook.', schema: schema.DeleteResponse },
|
|
549
|
+
}),
|
|
550
|
+
summary: 'Delete webhook',
|
|
551
|
+
tags: ['Webhooks'],
|
|
552
|
+
}),
|
|
553
|
+
async (c) => {
|
|
554
|
+
if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
|
|
555
|
+
if (Auth.narrowScope) return Auth.ensureOrgError(c)
|
|
556
|
+
if (Auth.narrowOrgRole) return Auth.ensureOrgRoleError(c)
|
|
557
|
+
if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
|
|
558
|
+
if (!options.webhook) return notEnabled(c)
|
|
559
|
+
try {
|
|
560
|
+
const id = c.req.valid('param').id
|
|
561
|
+
const removed = await Webhooks.deleteSubscription(
|
|
562
|
+
Db.get(c.get('db')),
|
|
563
|
+
owner(Auth.org(c).id),
|
|
564
|
+
id,
|
|
565
|
+
)
|
|
566
|
+
if (!removed) return notFound(c)
|
|
567
|
+
return c.json(Response.validated(schema.DeleteResponse, { id }), 200)
|
|
568
|
+
} catch (cause) {
|
|
569
|
+
return Response.upstream(c, cause)
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
)
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export declare namespace webhooks {
|
|
576
|
+
/** Options for organization webhook management routes. */
|
|
577
|
+
type Options = {
|
|
578
|
+
/** Webhook capability shared with the data routes and host poller. */
|
|
579
|
+
webhook?: App.Webhook | undefined
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function owner(orgId: string): Webhooks.Owner {
|
|
584
|
+
return { orgId, type: 'api_key' }
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function publicSubscription(subscription: Webhooks.Subscription) {
|
|
588
|
+
const destination = (() => {
|
|
589
|
+
if (subscription.destination.type === 'slack')
|
|
590
|
+
return { ...subscription.destination, url: redactedSlackUrl }
|
|
591
|
+
if (subscription.destination.type === 'betterstack')
|
|
592
|
+
return { ...subscription.destination, token: redactedBetterstackToken }
|
|
593
|
+
return { ...subscription.destination, url: redactUrl(subscription.destination.url) }
|
|
594
|
+
})()
|
|
595
|
+
return {
|
|
596
|
+
chainId: subscription.chainId,
|
|
597
|
+
...(subscription.context === undefined ? {} : { context: subscription.context }),
|
|
598
|
+
createdAt: subscription.createdAt,
|
|
599
|
+
destination,
|
|
600
|
+
eventType: subscription.eventType,
|
|
601
|
+
...(subscription.expiresAt === undefined ? {} : { expiresAt: subscription.expiresAt }),
|
|
602
|
+
failureCount: subscription.failureCount,
|
|
603
|
+
filters: subscription.filters,
|
|
604
|
+
id: subscription.id,
|
|
605
|
+
...(subscription.lastDeliveryAt === undefined
|
|
606
|
+
? {}
|
|
607
|
+
: { lastDeliveryAt: subscription.lastDeliveryAt }),
|
|
608
|
+
status: subscription.status,
|
|
609
|
+
updatedAt: subscription.updatedAt,
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function created(subscription: Webhooks.Subscription) {
|
|
614
|
+
const record = publicSubscription(subscription)
|
|
615
|
+
if (subscription.destination.type !== 'url') return record
|
|
616
|
+
return {
|
|
617
|
+
...record,
|
|
618
|
+
destination: subscription.destination,
|
|
619
|
+
secret: subscription.secret,
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function publicDelivery(delivery: Webhooks.Delivery, subscription: Webhooks.Subscription) {
|
|
624
|
+
const { envelope: _, ...record } = delivery
|
|
625
|
+
return {
|
|
626
|
+
...record,
|
|
627
|
+
requestUrl: publicSubscription(subscription).destination.url,
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
function redactUrl(input: string) {
|
|
632
|
+
return `${new URL(input).origin}/…`
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function mutationError(c: Context<Environment>, cause: unknown) {
|
|
636
|
+
if (cause instanceof Webhooks.InvalidUrlError)
|
|
637
|
+
return Response.error(c, { code: 'url_invalid', message: cause.message, status: 400 })
|
|
638
|
+
if (cause instanceof Webhooks.InvalidFilterError)
|
|
639
|
+
return Response.error(c, {
|
|
640
|
+
code: 'filters_invalid',
|
|
641
|
+
details: cause.details,
|
|
642
|
+
message: cause.message,
|
|
643
|
+
status: 400,
|
|
644
|
+
})
|
|
645
|
+
if (cause instanceof Webhooks.LimitExceededError)
|
|
646
|
+
return Response.error(c, { code: 'limit_exceeded', message: cause.message, status: 403 })
|
|
647
|
+
return Response.upstream(c, cause)
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function notFound(c: Context<Environment>) {
|
|
651
|
+
return Response.error(c, {
|
|
652
|
+
code: 'webhook_not_found',
|
|
653
|
+
message: 'Webhook not found',
|
|
654
|
+
status: 404,
|
|
655
|
+
})
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function deliveryNotFound(c: Context<Environment>) {
|
|
659
|
+
return Response.error(c, {
|
|
660
|
+
code: 'delivery_not_found',
|
|
661
|
+
message: 'Delivery not found',
|
|
662
|
+
status: 404,
|
|
663
|
+
})
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function notEnabled(c: Context<Environment>) {
|
|
667
|
+
return Response.error(c, {
|
|
668
|
+
code: 'webhooks_not_enabled',
|
|
669
|
+
message: 'Webhooks are not enabled for this Tempo API deployment.',
|
|
670
|
+
status: 404,
|
|
671
|
+
})
|
|
672
|
+
}
|
package/src/apps/mcp.test.ts
CHANGED
|
@@ -136,6 +136,19 @@ function resultJson(result: Awaited<ReturnType<typeof toolsCall>>) {
|
|
|
136
136
|
return result.structuredContent ?? JSON.parse(result.content[0]!.text)
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
test('identifies as Tempo MCP', async () => {
|
|
140
|
+
const { host } = createHost()
|
|
141
|
+
|
|
142
|
+
expect((await initialize(host)).result).toMatchObject({
|
|
143
|
+
instructions: expect.stringContaining('Tempo MCP provides access'),
|
|
144
|
+
serverInfo: {
|
|
145
|
+
name: 'tempo',
|
|
146
|
+
title: 'Tempo MCP',
|
|
147
|
+
version: '0.0.0',
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
139
152
|
test('scopes tools to the data domain', async () => {
|
|
140
153
|
const { app, host } = createHost({ docs: docsStub() })
|
|
141
154
|
|