@trigger.dev/sdk 4.7.4 → 4.8.0-webhooks.20261015065339

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.
Files changed (77) hide show
  1. package/dist/commonjs/v3/ai.d.ts +560 -8
  2. package/dist/commonjs/v3/ai.js +2263 -178
  3. package/dist/commonjs/v3/ai.js.map +1 -1
  4. package/dist/commonjs/v3/chat.d.ts +23 -0
  5. package/dist/commonjs/v3/chat.js.map +1 -1
  6. package/dist/commonjs/v3/index.d.ts +2 -0
  7. package/dist/commonjs/v3/index.js +23 -17
  8. package/dist/commonjs/v3/index.js.map +1 -1
  9. package/dist/commonjs/v3/modelFileDownload.d.ts +10 -0
  10. package/dist/commonjs/v3/modelFileDownload.js +164 -0
  11. package/dist/commonjs/v3/modelFileDownload.js.map +1 -0
  12. package/dist/commonjs/v3/test/index.d.ts +2 -1
  13. package/dist/commonjs/v3/test/index.js +4 -1
  14. package/dist/commonjs/v3/test/index.js.map +1 -1
  15. package/dist/commonjs/v3/test/mock-channel-connector.d.ts +172 -0
  16. package/dist/commonjs/v3/test/mock-channel-connector.js +173 -0
  17. package/dist/commonjs/v3/test/mock-channel-connector.js.map +1 -0
  18. package/dist/commonjs/v3/test/mock-chat-agent.d.ts +81 -1
  19. package/dist/commonjs/v3/test/mock-chat-agent.js +137 -10
  20. package/dist/commonjs/v3/test/mock-chat-agent.js.map +1 -1
  21. package/dist/commonjs/v3/transcriptStorage.d.ts +44 -1
  22. package/dist/commonjs/v3/transcriptStorage.js +24 -0
  23. package/dist/commonjs/v3/transcriptStorage.js.map +1 -1
  24. package/dist/commonjs/v3/webhookWaiters.d.ts +80 -0
  25. package/dist/commonjs/v3/webhookWaiters.js +156 -0
  26. package/dist/commonjs/v3/webhookWaiters.js.map +1 -0
  27. package/dist/commonjs/v3/webhooks.d.ts +178 -2
  28. package/dist/commonjs/v3/webhooks.js +322 -1
  29. package/dist/commonjs/v3/webhooks.js.map +1 -1
  30. package/dist/commonjs/version.js +1 -1
  31. package/dist/esm/v3/ai.d.ts +560 -8
  32. package/dist/esm/v3/ai.js +2257 -178
  33. package/dist/esm/v3/ai.js.map +1 -1
  34. package/dist/esm/v3/chat.d.ts +23 -0
  35. package/dist/esm/v3/chat.js.map +1 -1
  36. package/dist/esm/v3/index.d.ts +2 -0
  37. package/dist/esm/v3/index.js +1 -0
  38. package/dist/esm/v3/index.js.map +1 -1
  39. package/dist/esm/v3/modelFileDownload.d.ts +10 -0
  40. package/dist/esm/v3/modelFileDownload.js +161 -0
  41. package/dist/esm/v3/modelFileDownload.js.map +1 -0
  42. package/dist/esm/v3/test/index.d.ts +2 -1
  43. package/dist/esm/v3/test/index.js +2 -1
  44. package/dist/esm/v3/test/index.js.map +1 -1
  45. package/dist/esm/v3/test/mock-channel-connector.d.ts +172 -0
  46. package/dist/esm/v3/test/mock-channel-connector.js +170 -0
  47. package/dist/esm/v3/test/mock-channel-connector.js.map +1 -0
  48. package/dist/esm/v3/test/mock-chat-agent.d.ts +81 -1
  49. package/dist/esm/v3/test/mock-chat-agent.js +137 -11
  50. package/dist/esm/v3/test/mock-chat-agent.js.map +1 -1
  51. package/dist/esm/v3/transcriptStorage.d.ts +44 -1
  52. package/dist/esm/v3/transcriptStorage.js +24 -0
  53. package/dist/esm/v3/transcriptStorage.js.map +1 -1
  54. package/dist/esm/v3/webhookWaiters.d.ts +80 -0
  55. package/dist/esm/v3/webhookWaiters.js +149 -0
  56. package/dist/esm/v3/webhookWaiters.js.map +1 -0
  57. package/dist/esm/v3/webhooks.d.ts +178 -2
  58. package/dist/esm/v3/webhooks.js +318 -1
  59. package/dist/esm/v3/webhooks.js.map +1 -1
  60. package/dist/esm/version.js +1 -1
  61. package/docs/ai-chat/actions.mdx +6 -1
  62. package/docs/ai-chat/backend.mdx +34 -0
  63. package/docs/ai-chat/pending-messages.mdx +2 -0
  64. package/docs/ai-chat/reference.mdx +50 -2
  65. package/docs/mcp-tools.mdx +76 -0
  66. package/docs/webhooks/channels.mdx +128 -0
  67. package/docs/webhooks/connect.mdx +80 -0
  68. package/docs/webhooks/deliveries.mdx +92 -0
  69. package/docs/webhooks/filters.mdx +109 -0
  70. package/docs/webhooks/human-in-the-loop.mdx +149 -0
  71. package/docs/webhooks/linear.mdx +185 -0
  72. package/docs/webhooks/overview.mdx +99 -0
  73. package/docs/webhooks/session-routing.mdx +132 -0
  74. package/docs/webhooks/slack.mdx +360 -0
  75. package/docs/webhooks/sources.mdx +217 -0
  76. package/docs/webhooks/waiters.mdx +170 -0
  77. package/package.json +3 -2
@@ -1,4 +1,8 @@
1
1
  import { Webhook } from "@trigger.dev/core/v3";
2
+ import type { WebhookSource, InferWebhookEvent, AnyWebhookSource, ValidateWebhookFilter, NarrowWebhookEvent, ChatEvent, ValidatedWebhookKey, WebhookResponseConfig, WebhookUrlSecretConfig, WebhookVerifierConfig, StripeWebhookEvent, GitHubWebhookEvent, TaskRunContext, AnyWebhookEndpoint, InferWebhookEndpointEvent, WebhookEndpoint, WebhookEndpointContext } from "@trigger.dev/core/v3";
3
+ import { cancelWebhookWaiter, createWebhookWaiter, waitForWebhookWaiter } from "./webhookWaiters.js";
4
+ import { type Task } from "./shared.js";
5
+ import { type WebhookProviderId } from "@trigger.dev/core/webhooks";
2
6
  /**
3
7
  * The type of error thrown when a webhook fails to parse or verify
4
8
  */
@@ -14,6 +18,153 @@ type ConstructEventOptions = {
14
18
  /** Signature header as string, Buffer, or string array */
15
19
  header: string | Buffer | Array<string>;
16
20
  };
21
+ /**
22
+ * The verifier configs a hosted endpoint can enforce. A `url-secret` placed in the path is excluded:
23
+ * the hosted ingress URL is fixed per endpoint, so there is no path segment for the caller to choose,
24
+ * and the server refuses such a declaration at deploy time. Use `placement: "query"` instead.
25
+ */
26
+ export type HostedWebhookVerifierConfig = Exclude<WebhookVerifierConfig, WebhookUrlSecretConfig> | (Omit<WebhookUrlSecretConfig, "placement"> & {
27
+ placement: "query";
28
+ });
29
+ export declare const webhookSources: {
30
+ readonly custom: <T = unknown>(config: HostedWebhookVerifierConfig, options?: {
31
+ /** Instructions for an AI agent registering an endpoint on this source with the provider. */
32
+ setupPrompt?: string;
33
+ /**
34
+ * How the endpoint answers the provider. `{ acceptedBody: "empty" }` acknowledges with an empty
35
+ * 200, for providers that show the response to a user (Slack slash commands).
36
+ */
37
+ response?: WebhookResponseConfig;
38
+ }) => WebhookSource<T>;
39
+ readonly stripe: <TEvent = StripeWebhookEvent>(opts?: {
40
+ toleranceSeconds?: number;
41
+ }) => WebhookSource<TEvent>;
42
+ readonly github: <TEvent = GitHubWebhookEvent>() => WebhookSource<TEvent>;
43
+ readonly svix: <T = unknown>() => WebhookSource<T>;
44
+ readonly standardWebhooks: <T = unknown>() => WebhookSource<T>;
45
+ readonly square: <T = unknown>() => WebhookSource<T>;
46
+ /**
47
+ * Discord: asymmetric Ed25519 over `{timestamp}{body}`. The "secret" stored on the endpoint is the
48
+ * application PUBLIC KEY (hex by default); there is no shared secret. Discord's response contract
49
+ * is declared as data on the artifact: the `{ type: 0 }` PING sent when the URL is saved is answered
50
+ * with a bodiless 204 and never recorded, accepted events are acknowledged with 204, and a bad
51
+ * signature gets 401.
52
+ */
53
+ readonly discord: <T = unknown>(opts?: {
54
+ publicKeyEncoding?: "raw-hex" | "pem";
55
+ }) => WebhookSource<T>;
56
+ /**
57
+ * Per-provider producers over shared presets. Each is a thin wrapper: same verifier config as the
58
+ * preset it references, differing only in `provider` (routing + picker identity) and who provisions
59
+ * the secret. Pass the provider's own published type for full typing, e.g. clerk<WebhookEvent>().
60
+ */
61
+ readonly clerk: <T = unknown>() => WebhookSource<T>;
62
+ readonly resend: <T = unknown>() => WebhookSource<T>;
63
+ readonly openai: <T = unknown>() => WebhookSource<T>;
64
+ readonly replicate: <T = unknown>() => WebhookSource<T>;
65
+ readonly recallai: <T = unknown>() => WebhookSource<T>;
66
+ readonly brex: <T = unknown>() => WebhookSource<T>;
67
+ readonly composio: <T = unknown>() => WebhookSource<T>;
68
+ readonly gitlab: <T = unknown>() => WebhookSource<T>;
69
+ /**
70
+ * WhatsApp Cloud API (Meta): `X-Hub-Signature-256` HMAC over the raw body, keyed by the App Secret,
71
+ * which Meta issues and you paste in as the endpoint's signing secret (it cannot be generated here).
72
+ * Meta verifies the callback URL with a GET carrying `hub.mode`, `hub.verify_token` and
73
+ * `hub.challenge`; the endpoint answers it when the token equals the verify token generated in
74
+ * the endpoint's Connect panel, which you paste into Meta's Verify Token field.
75
+ */
76
+ readonly whatsapp: <T = unknown>() => WebhookSource<T>;
77
+ };
78
+ type CamelCase<S extends string> = S extends `${infer Head}-${infer Tail}` ? `${Head}${Capitalize<CamelCase<Tail>>}` : S;
79
+ /**
80
+ * Per-provider producers generated from the core config table (kind "config"). Each carries the
81
+ * provider's own HMAC verifier config and stays in lockstep with the round-trip-tested configs.
82
+ * The method is the provider id in camel case (`cal-com` is `webhooks.calCom()`); the emitted
83
+ * `provider` keeps the id itself.
84
+ */
85
+ export type ProviderProducers = {
86
+ [K in Exclude<WebhookProviderId, "zoom"> as CamelCase<K>]: <TEvent = unknown>() => WebhookSource<TEvent>;
87
+ };
88
+ export declare const providerProducers: Omit<ProviderProducers, "slack">;
89
+ export type WebhookEndpointOptions<TIdentifier extends string, TSource extends AnyWebhookSource> = {
90
+ /** The endpoint id. Subscribers reference the endpoint, and it names the endpoint's URL. */
91
+ id: TIdentifier;
92
+ /** The provider source: how deliveries are verified and who issues the signing secret. */
93
+ source: TSource;
94
+ description?: string;
95
+ /** Arbitrary metadata, passed to every subscriber and waiter as `endpoint.metadata`. */
96
+ metadata?: Record<string, unknown>;
97
+ };
98
+ /**
99
+ * Declare a webhook endpoint: one URL you register with the provider. Subscribe to it with
100
+ * `webhook({ endpoint })`, `chat.event({ endpoint })` or a channel connector, and wait on it with
101
+ * `webhooks.waiter.create(endpoint, ...)`. An endpoint with no subscribers still gets a URL.
102
+ */
103
+ export declare function defineWebhookEndpoint<TIdentifier extends string, TSource extends AnyWebhookSource>(options: WebhookEndpointOptions<TIdentifier, TSource>): WebhookEndpoint<InferWebhookEvent<TSource>> & {
104
+ id: TIdentifier;
105
+ };
106
+ export type WebhookOnEventParams<TEvent> = {
107
+ /** The verified event body, typed by the endpoint's source. */
108
+ event: TEvent;
109
+ /** The inbound request headers (case-insensitive, Web `Headers`). e.g. headers.get("x-github-event"). */
110
+ headers: Headers;
111
+ /** The endpoint the delivery arrived on. Unset when the task is triggered by hand without one. */
112
+ endpoint?: WebhookEndpointContext;
113
+ ctx: TaskRunContext;
114
+ };
115
+ export type WebhookOptions<TIdentifier extends string, TEndpoint extends AnyWebhookEndpoint, TEvent = InferWebhookEndpointEvent<TEndpoint>> = {
116
+ id: TIdentifier;
117
+ /** The endpoint this task subscribes to. */
118
+ endpoint: TEndpoint;
119
+ /**
120
+ * Optional server-side filter (a type-safe string DSL checked against the event shape). A delivery
121
+ * this subscriber's filter rejects is still recorded, and other subscribers on the endpoint still
122
+ * get it. e.g. `"event.action == 'created' && event.repository.private == false"`.
123
+ */
124
+ filter?: string;
125
+ /** Gets the event narrowed by the filter's `event.<field> == '<value>'` clauses. */
126
+ onEvent: (params: WebhookOnEventParams<TEvent>) => Promise<void> | void;
127
+ };
128
+ /**
129
+ * What a webhook task runs on: the verified event, the delivery headers and the endpoint. The hosted
130
+ * ingress sends it for every delivery; triggering the handle by hand (`myWebhook.trigger({ event })`,
131
+ * a replay, a test) sends the same shape, so `onEvent` sees the event either way.
132
+ */
133
+ export type WebhookTaskPayload<TEvent> = {
134
+ event: TEvent;
135
+ headers?: Record<string, string>;
136
+ endpoint?: WebhookEndpointContext;
137
+ };
138
+ export type WebhookHandle<TIdentifier extends string, TEvent> = Task<TIdentifier, WebhookTaskPayload<TEvent>, void>;
139
+ export declare function webhook<TIdentifier extends string, TEndpoint extends AnyWebhookEndpoint, const TFilter extends string = string>(options: WebhookOptions<TIdentifier, TEndpoint, NarrowWebhookEvent<InferWebhookEndpointEvent<TEndpoint>, TFilter>> & {
140
+ filter?: ValidateWebhookFilter<InferWebhookEndpointEvent<TEndpoint>, TFilter>;
141
+ }): WebhookHandle<TIdentifier, NarrowWebhookEvent<InferWebhookEndpointEvent<TEndpoint>, TFilter>>;
142
+ export declare function chatEvent<TEndpoint extends AnyWebhookEndpoint, const TId extends string = string, const TKey extends string = string, const TType extends string = TId, const TFilter extends string = string>(options: {
143
+ id: TId;
144
+ /** The endpoint this event subscribes to. */
145
+ endpoint: TEndpoint;
146
+ /**
147
+ * The session each delivery goes to, as a template: `{event.x}` reads the event, `{header.x}` a
148
+ * header and `{webhook.x}` the endpoint, and `{a || b}` falls back to `b` when `a` is empty. e.g.
149
+ * `"{webhook.externalRef}:{event.data.object.customer}"`.
150
+ */
151
+ key: ValidatedWebhookKey<NarrowWebhookEvent<InferWebhookEndpointEvent<TEndpoint>, TFilter>, TKey>;
152
+ /** The `action.type` the handler reads. Optional; defaults to `id`. */
153
+ type?: TType;
154
+ /**
155
+ * Optional server-side filter (same type-safe DSL as `webhook()`); a non-match is recorded FILTERED
156
+ * and not routed. Narrows the action's `event` like `webhook()`'s `onEvent`.
157
+ */
158
+ filter?: ValidateWebhookFilter<InferWebhookEndpointEvent<TEndpoint>, TFilter>;
159
+ }): ChatEvent<TType, NarrowWebhookEvent<InferWebhookEndpointEvent<TEndpoint>, TFilter>>;
160
+ export type { ChatEvent, AnyChatEvent, ChatEventAction, ChatEventActions, WebhookKeyMeta, } from "@trigger.dev/core/v3";
161
+ /**
162
+ * Compiles a key template to its stored form. Each placeholder names its namespace the way a filter
163
+ * path does: `{event.x}` reads the event body (stored as `{body.x}`), `{header.x}` a header and
164
+ * `{webhook.x}` the endpoint. A placeholder without one of those namespaces throws.
165
+ */
166
+ export declare function normalizeKeyString(key: string): string;
167
+ export type { CreateWebhookEndpointParams } from "@trigger.dev/core/v3";
17
168
  /**
18
169
  * Interface describing the webhook utilities
19
170
  */
@@ -39,9 +190,34 @@ interface Webhooks {
39
190
  constructEvent(request: ConstructEventOptions | Request, secret: string): Promise<Webhook>;
40
191
  /** Header name used for webhook signatures */
41
192
  SIGNATURE_HEADER_NAME: string;
193
+ custom: typeof webhookSources.custom;
194
+ stripe: typeof webhookSources.stripe;
195
+ github: typeof webhookSources.github;
196
+ svix: typeof webhookSources.svix;
197
+ standardWebhooks: typeof webhookSources.standardWebhooks;
198
+ square: typeof webhookSources.square;
199
+ discord: typeof webhookSources.discord;
200
+ clerk: typeof webhookSources.clerk;
201
+ resend: typeof webhookSources.resend;
202
+ openai: typeof webhookSources.openai;
203
+ replicate: typeof webhookSources.replicate;
204
+ recallai: typeof webhookSources.recallai;
205
+ brex: typeof webhookSources.brex;
206
+ composio: typeof webhookSources.composio;
207
+ gitlab: typeof webhookSources.gitlab;
208
+ whatsapp: typeof webhookSources.whatsapp;
209
+ /** Declare the URLs providers deliver to. */
210
+ endpoint: {
211
+ define: typeof defineWebhookEndpoint;
212
+ };
213
+ /** Suspend a run until a matching webhook arrives. */
214
+ waiter: {
215
+ create: typeof createWebhookWaiter;
216
+ wait: typeof waitForWebhookWaiter;
217
+ cancel: typeof cancelWebhookWaiter;
218
+ };
42
219
  }
43
220
  /**
44
221
  * Webhook utilities for handling incoming webhook requests
45
222
  */
46
- export declare const webhooks: Webhooks;
47
- export {};
223
+ export declare const webhooks: Webhooks & Omit<ProviderProducers, "slack">;
@@ -1,5 +1,8 @@
1
- import { Webhook } from "@trigger.dev/core/v3";
1
+ import { Webhook, resourceCatalog } from "@trigger.dev/core/v3";
2
2
  import { subtle } from "../imports/uncrypto.js";
3
+ import { cancelWebhookWaiter, createWebhookWaiter, waitForWebhookWaiter, } from "./webhookWaiters.js";
4
+ import { createTask } from "./shared.js";
5
+ import { discordVerifierConfig, githubVerifierConfig, squareVerifierConfig, standardWebhooksVerifierConfig, stripeVerifierConfig, svixVerifierConfig, webhookProviderConfigs, webhookSetupPrompts, } from "@trigger.dev/core/webhooks";
3
6
  /**
4
7
  * The type of error thrown when a webhook fails to parse or verify
5
8
  */
@@ -11,12 +14,326 @@ export class WebhookError extends Error {
11
14
  }
12
15
  /** Header name used for webhook signatures */
13
16
  const SIGNATURE_HEADER_NAME = "x-trigger-signature-hmacsha256";
17
+ // ── Source producers (presets carry the event type) ──
18
+ export const webhookSources = {
19
+ custom(config, options) {
20
+ if (config.scheme === "url-secret" && config.placement === "path") {
21
+ throw new Error('webhooks.custom(): url-secret verification cannot use placement "path" on the hosted ingress URL. Use placement "query" or a header-based scheme.');
22
+ }
23
+ // Roll-your-own webhooks: you control both ends, so offer paste AND generate.
24
+ return {
25
+ provider: "custom",
26
+ verifier: {
27
+ kind: "config",
28
+ config,
29
+ ...(options?.response ? { response: options.response } : {}),
30
+ },
31
+ secretProvisioning: "either",
32
+ ...(options?.setupPrompt ? { setupPrompt: options.setupPrompt } : {}),
33
+ };
34
+ },
35
+ // Stripe: `Stripe-Signature: t=…,v1=…` (comma-kv), signed `{t}.{body}`, hex.
36
+ // Defaults to a minimal event shape; pass the official type for full typing: stripe<Stripe.Event>().
37
+ stripe(opts) {
38
+ return {
39
+ provider: "stripe",
40
+ verifier: { kind: "preset", preset: "stripe", config: stripeVerifierConfig(opts) },
41
+ secretProvisioning: "provider",
42
+ };
43
+ },
44
+ // GitHub: `X-Hub-Signature-256: sha256=<hex>` (prefixed), signed raw body.
45
+ // Defaults to an open shape; pass your event type for full typing: github<MyPushEvent>().
46
+ github() {
47
+ return {
48
+ provider: "github",
49
+ verifier: { kind: "preset", preset: "github", config: githubVerifierConfig() },
50
+ secretProvisioning: "integrator",
51
+ };
52
+ },
53
+ // Svix family (Svix, Clerk, Resend): `svix-signature: v1,<b64> v1,<b64>` (space-list),
54
+ // signed `{id}.{timestamp}.{body}`, base64; the `whsec_` secret is base64-decoded. Providers that
55
+ // send the spec's `webhook-*` header names instead use `standardWebhooks()`.
56
+ svix() {
57
+ return {
58
+ provider: "svix",
59
+ verifier: { kind: "preset", preset: "svix", config: svixVerifierConfig() },
60
+ secretProvisioning: "provider",
61
+ };
62
+ },
63
+ // Standard Webhooks (Composio, and any provider implementing the spec directly): the Svix scheme under
64
+ // the spec's `webhook-id` / `webhook-timestamp` / `webhook-signature` header names.
65
+ standardWebhooks() {
66
+ return {
67
+ provider: "standard-webhooks",
68
+ verifier: {
69
+ kind: "preset",
70
+ preset: "standard-webhooks",
71
+ config: standardWebhooksVerifierConfig(),
72
+ },
73
+ secretProvisioning: "provider",
74
+ };
75
+ },
76
+ // Square: bare base64 signature over `{notificationURL}{body}` (URL template var, no separator).
77
+ square() {
78
+ return {
79
+ provider: "square",
80
+ verifier: { kind: "preset", preset: "square", config: squareVerifierConfig() },
81
+ secretProvisioning: "provider",
82
+ };
83
+ },
84
+ /**
85
+ * Discord: asymmetric Ed25519 over `{timestamp}{body}`. The "secret" stored on the endpoint is the
86
+ * application PUBLIC KEY (hex by default); there is no shared secret. Discord's response contract
87
+ * is declared as data on the artifact: the `{ type: 0 }` PING sent when the URL is saved is answered
88
+ * with a bodiless 204 and never recorded, accepted events are acknowledged with 204, and a bad
89
+ * signature gets 401.
90
+ */
91
+ discord(opts = {}) {
92
+ return {
93
+ provider: "discord",
94
+ verifier: {
95
+ kind: "preset",
96
+ preset: "discord",
97
+ config: discordVerifierConfig(opts),
98
+ handshake: { matchPath: "type", matchValue: "0", respondStatus: 204 },
99
+ response: { acceptedStatus: 204, rejectedStatus: 401 },
100
+ },
101
+ secretProvisioning: "provider",
102
+ };
103
+ },
104
+ /**
105
+ * Per-provider producers over shared presets. Each is a thin wrapper: same verifier config as the
106
+ * preset it references, differing only in `provider` (routing + picker identity) and who provisions
107
+ * the secret. Pass the provider's own published type for full typing, e.g. clerk<WebhookEvent>().
108
+ */
109
+ clerk() {
110
+ return {
111
+ provider: "clerk",
112
+ verifier: { kind: "preset", preset: "svix", config: svixVerifierConfig() },
113
+ secretProvisioning: "provider",
114
+ };
115
+ },
116
+ resend() {
117
+ return {
118
+ provider: "resend",
119
+ verifier: { kind: "preset", preset: "svix", config: svixVerifierConfig() },
120
+ secretProvisioning: "provider",
121
+ };
122
+ },
123
+ openai() {
124
+ return {
125
+ provider: "openai",
126
+ verifier: {
127
+ kind: "preset",
128
+ preset: "standard-webhooks",
129
+ config: standardWebhooksVerifierConfig(),
130
+ },
131
+ secretProvisioning: "provider",
132
+ };
133
+ },
134
+ replicate() {
135
+ return {
136
+ provider: "replicate",
137
+ verifier: {
138
+ kind: "preset",
139
+ preset: "standard-webhooks",
140
+ config: standardWebhooksVerifierConfig(),
141
+ },
142
+ secretProvisioning: "provider",
143
+ };
144
+ },
145
+ recallai() {
146
+ return {
147
+ provider: "recall-ai",
148
+ verifier: {
149
+ kind: "preset",
150
+ preset: "standard-webhooks",
151
+ config: standardWebhooksVerifierConfig(),
152
+ },
153
+ secretProvisioning: "provider",
154
+ };
155
+ },
156
+ brex() {
157
+ return {
158
+ provider: "brex",
159
+ verifier: { kind: "preset", preset: "svix", config: svixVerifierConfig() },
160
+ secretProvisioning: "provider",
161
+ };
162
+ },
163
+ composio() {
164
+ return {
165
+ provider: "composio",
166
+ verifier: {
167
+ kind: "preset",
168
+ preset: "standard-webhooks",
169
+ config: standardWebhooksVerifierConfig(),
170
+ },
171
+ secretProvisioning: "provider",
172
+ };
173
+ },
174
+ gitlab() {
175
+ return {
176
+ provider: "gitlab",
177
+ verifier: {
178
+ kind: "config",
179
+ config: { scheme: "shared-secret", placement: "header", fieldName: "x-gitlab-token" },
180
+ },
181
+ secretProvisioning: "integrator",
182
+ };
183
+ },
184
+ /**
185
+ * WhatsApp Cloud API (Meta): `X-Hub-Signature-256` HMAC over the raw body, keyed by the App Secret,
186
+ * which Meta issues and you paste in as the endpoint's signing secret (it cannot be generated here).
187
+ * Meta verifies the callback URL with a GET carrying `hub.mode`, `hub.verify_token` and
188
+ * `hub.challenge`; the endpoint answers it when the token equals the verify token generated in
189
+ * the endpoint's Connect panel, which you paste into Meta's Verify Token field.
190
+ */
191
+ whatsapp() {
192
+ return {
193
+ provider: "whatsapp",
194
+ verifier: {
195
+ kind: "preset",
196
+ preset: "github",
197
+ config: githubVerifierConfig(),
198
+ getHandshake: {
199
+ matchParam: "hub.mode",
200
+ matchValue: "subscribe",
201
+ tokenParam: "hub.verify_token",
202
+ challengeParam: "hub.challenge",
203
+ },
204
+ },
205
+ secretProvisioning: "provider",
206
+ };
207
+ },
208
+ };
209
+ function producerName(provider) {
210
+ return provider.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
211
+ }
212
+ export const providerProducers = Object.fromEntries(Object.entries(webhookProviderConfigs)
213
+ // Zoom needs a computed URL-validation response that the hosted ingress does not support yet.
214
+ .filter(([provider]) => provider !== "slack" && provider !== "zoom")
215
+ .map(([provider, entry]) => [
216
+ producerName(provider),
217
+ () => {
218
+ const setupPrompt = webhookSetupPrompts[provider];
219
+ return {
220
+ provider,
221
+ verifier: { kind: "config", config: entry.config() },
222
+ secretProvisioning: entry.secretProvisioning,
223
+ ...(setupPrompt ? { setupPrompt } : {}),
224
+ };
225
+ },
226
+ ]));
227
+ /**
228
+ * Declare a webhook endpoint: one URL you register with the provider. Subscribe to it with
229
+ * `webhook({ endpoint })`, `chat.event({ endpoint })` or a channel connector, and wait on it with
230
+ * `webhooks.waiter.create(endpoint, ...)`. An endpoint with no subscribers still gets a URL.
231
+ */
232
+ export function defineWebhookEndpoint(options) {
233
+ const { id, source, description, metadata } = options;
234
+ if (id.startsWith("wh_")) {
235
+ throw new Error(`webhooks.endpoint.define("${id}"): an endpoint id can't start with "wh_"; that prefix is reserved for generated endpoint ids.`);
236
+ }
237
+ const setupPrompt = source.setupPrompt ??
238
+ (source.verifier.kind === "preset"
239
+ ? webhookSetupPrompts[source.verifier.preset]
240
+ : undefined);
241
+ resourceCatalog.registerWebhookEndpointMetadata({
242
+ id,
243
+ source: source.provider,
244
+ verifierArtifact: source.verifier,
245
+ ...(description ? { description } : {}),
246
+ ...(source.secretProvisioning ? { secretProvisioning: source.secretProvisioning } : {}),
247
+ ...(setupPrompt ? { setupPrompt } : {}),
248
+ ...(metadata ? { metadata } : {}),
249
+ });
250
+ return { id, source: source.provider };
251
+ }
252
+ export function webhook(options) {
253
+ const { id, endpoint, onEvent, filter } = options;
254
+ if (!endpoint?.id) {
255
+ throw new Error(`webhook("${id}"): an endpoint is required. Declare one with webhooks.endpoint.define() and pass it as { endpoint }.`);
256
+ }
257
+ const task = createTask({
258
+ id,
259
+ triggerSource: "webhook",
260
+ run: async (payload, runOptions) => {
261
+ await onEvent({
262
+ event: payload.event,
263
+ headers: new Headers(payload.headers ?? {}),
264
+ endpoint: payload.endpoint,
265
+ ctx: runOptions.ctx,
266
+ });
267
+ },
268
+ });
269
+ resourceCatalog.registerWebhookSubscriber({
270
+ endpointId: endpoint.id,
271
+ target: { type: "task", id, taskId: id, ...(filter ? { filter } : {}) },
272
+ });
273
+ return task;
274
+ }
275
+ // ── chat.event(): a session subscriber an agent claims via chat.agent({ events }). No handler. ──
276
+ // Carries the endpoint, a validated string `key`, and a `type` discriminant. The `key` validates
277
+ // against the event/header/webhook namespaces, like a filter path, and compiles to the stored
278
+ // {body.x} wire template.
279
+ export function chatEvent(options) {
280
+ const { id, endpoint, key, type, filter } = options;
281
+ if (!endpoint?.id) {
282
+ throw new Error(`chat.event("${id}"): an endpoint is required. Declare one with webhooks.endpoint.define() and pass it as { endpoint }.`);
283
+ }
284
+ // Record the descriptor as declared so the indexer can flag it if no agent ever claims it.
285
+ resourceCatalog.registerDeclaredSessionWebhook(id);
286
+ return {
287
+ id,
288
+ type: type ?? id,
289
+ key: normalizeKeyString(key),
290
+ endpointId: endpoint.id,
291
+ source: endpoint.source,
292
+ filter,
293
+ };
294
+ }
295
+ /**
296
+ * Compiles a key template to its stored form. Each placeholder names its namespace the way a filter
297
+ * path does: `{event.x}` reads the event body (stored as `{body.x}`), `{header.x}` a header and
298
+ * `{webhook.x}` the endpoint. A placeholder without one of those namespaces throws.
299
+ */
300
+ export function normalizeKeyString(key) {
301
+ const namespaceAlternative = (alternative) => {
302
+ const trimmed = alternative.trim();
303
+ if (trimmed.startsWith("event."))
304
+ return `body.${trimmed.slice("event.".length)}`;
305
+ if (trimmed.startsWith("webhook.") || trimmed.startsWith("header."))
306
+ return trimmed;
307
+ const path = trimmed.startsWith("body.") ? trimmed.slice("body.".length) : trimmed;
308
+ throw new Error(`Invalid key "${key}": "{${trimmed}}" needs a namespace. Use {event.${path}} for the event body, {header.<name>} or {webhook.<field>}.`);
309
+ };
310
+ return key.replace(/\{([^{}]+)\}/g, (_match, path) => `{${path.split("||").map(namespaceAlternative).join(" || ")}}`);
311
+ }
14
312
  /**
15
313
  * Webhook utilities for handling incoming webhook requests
16
314
  */
17
315
  export const webhooks = {
316
+ ...providerProducers,
18
317
  constructEvent,
19
318
  SIGNATURE_HEADER_NAME,
319
+ custom: webhookSources.custom,
320
+ stripe: webhookSources.stripe,
321
+ github: webhookSources.github,
322
+ svix: webhookSources.svix,
323
+ standardWebhooks: webhookSources.standardWebhooks,
324
+ square: webhookSources.square,
325
+ discord: webhookSources.discord,
326
+ clerk: webhookSources.clerk,
327
+ resend: webhookSources.resend,
328
+ openai: webhookSources.openai,
329
+ replicate: webhookSources.replicate,
330
+ recallai: webhookSources.recallai,
331
+ brex: webhookSources.brex,
332
+ composio: webhookSources.composio,
333
+ gitlab: webhookSources.gitlab,
334
+ whatsapp: webhookSources.whatsapp,
335
+ endpoint: { define: defineWebhookEndpoint },
336
+ waiter: { create: createWebhookWaiter, wait: waitForWebhookWaiter, cancel: cancelWebhookWaiter },
20
337
  };
21
338
  async function constructEvent(request, secret) {
22
339
  let payload;
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../../src/v3/webhooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../../src/v3/webhooks.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export const VERSION = "4.7.4";
1
+ export const VERSION = "4.8.0-webhooks.20261015065339";
2
2
  //# sourceMappingURL=version.js.map
@@ -73,11 +73,16 @@ onAction: async ({ action }) => {
73
73
  chat.history.slice(0, -1);
74
74
  chat.inject([{ role: "system", content: "Answer formally this time." }]);
75
75
  return chat.turn(); // with a one-shot instruction
76
+
77
+ case "ask":
78
+ return chat.turn(action.question); // answer a new user message
76
79
  }
77
80
  }
78
81
  ```
79
82
 
80
- `run()` receives the edited history with no incoming user message, the same shape as a `regenerate-message` turn, and its `trigger` is `"action-turn"`, so a `run()` that returns early on `"action"` (the pre-May behaviour, when actions invoked `run()` directly) still answers. Returning anything other than `chat.turn()` or nothing is an error; a response can no longer be returned from `onAction` directly.
83
+ `chat.turn(message)` appends `message` (a string, or a `UIMessage`) to the history as a user message after the edit, and the turn answers it. That is how a button click becomes a question, such as a follow-up suggestion in [Slack](/webhooks/slack#buttons-that-send-the-agent-an-action).
84
+
85
+ Without a message, `run()` receives the edited history with no incoming user message, the same shape as a `regenerate-message` turn, and its `trigger` is `"action-turn"`, so a `run()` that returns early on `"action"` (the pre-May behaviour, when actions invoked `run()` directly) still answers. Returning anything other than `chat.turn()` or nothing is an error; a response can no longer be returned from `onAction` directly.
81
86
 
82
87
  ### Actions and persistence
83
88
 
@@ -497,6 +497,40 @@ Custom actions let the frontend send structured commands (undo, rollback, edit,
497
497
 
498
498
  See [Actions](/ai-chat/actions).
499
499
 
500
+ ### Webhook events and channels
501
+
502
+ Two `chat.agent()` options wire an agent to verified inbound webhooks. `events` claims [`chat.event(...)`](/webhooks/session-routing) descriptors: each verified delivery is routed to this agent's session and arrives at `onAction` as an action (not a turn), so [session routing](/webhooks/session-routing) decides which conversation it lands on. `channels` claims channel connectors that turn an external chat surface into a frontend for the agent: an inbound message runs as a turn through `run()` and the reply is posted back. `slack()` ships in `@trigger.dev/slack`, and `chat.channels.custom(...)` builds a connector for any endpoint without a preset.
503
+
504
+ ```ts
505
+ import { webhooks } from "@trigger.dev/sdk";
506
+ import { chat } from "@trigger.dev/sdk/ai";
507
+ import { slack, webhookSource } from "@trigger.dev/slack";
508
+
509
+ const slackEvents = webhooks.endpoint.define({ id: "slack", source: webhookSource() });
510
+ const stripe = webhooks.endpoint.define({ id: "stripe", source: webhooks.stripe() });
511
+
512
+ export const orderEvents = chat.event({
513
+ id: "order-events",
514
+ endpoint: stripe,
515
+ key: "{event.data.object.customer}",
516
+ type: "order.event",
517
+ });
518
+
519
+ export const myChat = chat.agent({
520
+ id: "my-chat",
521
+ events: [orderEvents],
522
+ channels: [slack({ id: "support-slack", endpoint: slackEvents, token: process.env.SLACK_BOT_TOKEN! })],
523
+ onAction: async ({ action }) => {
524
+ // A verified order-events delivery arrives here as an action.
525
+ },
526
+ run: async (payload) => {
527
+ // Inbound Slack messages run here as normal turns.
528
+ },
529
+ });
530
+ ```
531
+
532
+ See [session routing](/webhooks/session-routing) and [channels](/webhooks/channels). For the interactive approvals layer, where a turn pauses on a human decision (buttons in the thread) and resumes on the click, see [human-in-the-loop](/webhooks/human-in-the-loop).
533
+
500
534
  ### Chat history
501
535
 
502
536
  Imperative API for reading and modifying the accumulated message history. Works from any hook (`onAction`, `onTurnStart`, `onBeforeTurnComplete`, `onTurnComplete`, `hydrateMessages`) or from `run()` and AI SDK tools.
@@ -12,6 +12,8 @@ By default (without `pendingMessages`), a message sent while the agent is respon
12
12
 
13
13
  The `pendingMessages` option enables steering instead, injecting user messages between tool-call steps via the AI SDK's `prepareStep`. Messages that arrive during streaming are queued and injected at the next step boundary. A message that is not injected becomes the next turn instead, whether that is because `shouldInject` returned `false` or because there were no more step boundaries (single-step response or final text generation). The backend handles that, so no client-side re-send is involved.
14
14
 
15
+ Messages from a [channel](/webhooks/channels) such as [Slack](/webhooks/slack) are offered the same way, with `metadata.source` set to `"channel"` so `shouldInject` can tell them apart. A channel's stop control and approval clicks are never offered. The connector acknowledges a channel message as soon as it arrives (Slack reacts with 👀, Linear posts a thought), before `shouldInject` decides, so the acknowledgement is the same whether the message is folded in or answered next.
16
+
15
17
  Use the `streamText` passed to your agent's `run` callback. It wires up pending-message injection automatically. If you import `streamText` directly from `ai`, spread `chat.toStreamTextOptions()` into its options to connect injection.
16
18
 
17
19
  ## How it works