feat(webhook): add WebhookTrigger class for Workflow Builder triggers - #2615
Conversation
Add a new WebhookTrigger class that mirrors IncomingWebhook but handles
Workflow Builder webhook triggers which return JSON responses with
arbitrary payloads (vs plain text "ok" from incoming webhooks).
- Constructor takes URL + defaults (timeout, agent) — same pattern
- send() accepts arbitrary key-value payload, returns { ok, body }
- Reuses existing error infrastructure and User-Agent instrumentation
- Enables consumers like slack-github-action to use the SDK instead
of raw fetch for WFB triggers
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
🦋 Changeset detectedLatest commit: 5ddeb03 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2615 +/- ##
==========================================
+ Coverage 88.90% 88.97% +0.06%
==========================================
Files 63 64 +1
Lines 10256 10363 +107
Branches 452 467 +15
==========================================
+ Hits 9118 9220 +102
- Misses 1117 1122 +5
Partials 21 21
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Workflow Builder webhook trigger inputs are always string values. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
WilliamBergamin
left a comment
There was a problem hiding this comment.
Gave this a quick look and it looks good 💯
if we need to dry this up in the future we can look into it at that time
# Conflicts: # packages/webhook/package.json # packages/webhook/src/index.ts
Allow send() to be called with no arguments, POSTing an empty body.
send({}) continues to work unchanged.
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Use a falsy check so an empty-string URL is rejected up front rather than failing later at request time. Adds a guard test. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
…s test
Add a test that a 401 with { ok: false, error: 'invalid_auth' } rejects
with an HTTPError exposing the response status and body. Remove the
success test asserting workflow_run_id so success cases only assert
result.ok === true.
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
WebhookTrigger throws the same coded errors as IncomingWebhook but had no correspondingly named types. Add WebhookTriggerSendError / WebhookTriggerHTTPError / WebhookTriggerRequestError aliases and export them so consumers have properly-named errors to catch. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
…source Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Coerce result.ok from body.ok instead of defaulting a missing field to true, so only an explicit ok:true reports success. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
zimeg
left a comment
There was a problem hiding this comment.
🗣️ Words I think for the readers and reviewers!
| } | ||
|
|
||
| export type IncomingWebhookSendError = IncomingWebhookRequestError | IncomingWebhookHTTPError; | ||
| export type WebhookTriggerSendError = WebhookTriggerRequestError | WebhookTriggerHTTPError; |
There was a problem hiding this comment.
| * Processes an HTTP response into a WebhookTriggerResult. | ||
| */ | ||
| private buildResult(response: AxiosResponse): WebhookTriggerResult { | ||
| const body = typeof response.data === 'string' ? JSON.parse(response.data) : response.data; |
There was a problem hiding this comment.
🔬 note: This feels defensive to me and might be removed as response is unpacked to match standard "fetch"!
| code: ErrorCode.RequestError; | ||
| original: Error; | ||
| } | ||
| export type WebhookTriggerRequestError = IncomingWebhookRequestError; |
There was a problem hiding this comment.
Safe move 🧠 I like it 💯
| }); | ||
| }); | ||
|
|
||
| describe('User-Agent header', () => { |
There was a problem hiding this comment.
Nice 💯
should we also add a tests that covers using addAppMetadata to expand the user-agent value?
There was a problem hiding this comment.
@WilliamBergamin Thanks for calling this out! We're introducing a test in 3bed3dc for this.
| * A client for Slack's Workflow Builder webhook triggers | ||
| * @see {@link https://slack.com/help/articles/360041352714-Build-a-workflow--Create-a-workflow-that-starts-outside-of-Slack} | ||
| */ | ||
| export class WebhookTrigger { |
There was a problem hiding this comment.
Paise for mirroring existing behaviors 💯
Drop the { ok, body } wrapper so send() resolves to the parsed response
body itself, exposing ok/error without nesting or a duplicated ok field.
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Assert that metadata added via addAppMetadata is sent in the User-Agent header on a WebhookTrigger request, alongside the base webhook agent. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
send() now returns response.data directly; the string-vs-object parse branch was dead code since axios already parses JSON responses. Removes the now-unused AxiosResponse import. Simplifies the eventual fetch swap. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
The trigger endpoint responds with { ok: true } or { ok: false, error },
so type the result closed rather than an open index signature. Widening
later is backward-compatible; tightening a released `any` would not be.
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
The package now covers both Incoming Webhooks and Workflow Builder triggers, so the narrower "Incoming Webhooks" title is outdated. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
zimeg
left a comment
There was a problem hiding this comment.
🔏 A few more comments of confidence!
| }); | ||
| }); | ||
|
|
||
| describe('User-Agent header', () => { |
There was a problem hiding this comment.
@WilliamBergamin Thanks for calling this out! We're introducing a test in 3bed3dc for this.
| public async send(payload: WebhookTriggerSendArguments = {}): Promise<WebhookTriggerResult> { | ||
| try { | ||
| const response = await this.axios.post(this.url, payload); | ||
| return response.data; | ||
| // biome-ignore lint/suspicious/noExplicitAny: errors can be anything | ||
| } catch (error: any) { | ||
| if (error.response !== undefined) { | ||
| throw httpErrorWithOriginal(error); | ||
| } | ||
| if (error.request !== undefined) { | ||
| throw requestErrorWithOriginal(error); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
👁️🗨️ note: Our return inlines the response values without more change to mirror implementations of the @slack/web-api package a bit more!
| export interface WebhookTriggerResult { | ||
| ok: boolean; | ||
| error?: string; | ||
| } |
There was a problem hiding this comment.
🪬 note: These values are more strict now too!
There was a problem hiding this comment.
This looks good 💯
If we need to add more fields in the future we can
There was a problem hiding this comment.
📚 note: I hoped to generalize this package README for now with added information but think we might revise this ongoing?
| export interface WebhookTriggerResult { | ||
| ok: boolean; | ||
| error?: string; | ||
| } |
There was a problem hiding this comment.
This looks good 💯
If we need to add more fields in the future we can
|
@WilliamBergamin So exciting! Thanks for sharing big ideas and kind thoughts toward this 🧠 💡 |
Bring the new @slack/webhook features from main into v8: - WebhookTrigger class for Workflow Builder triggers (#2615) - opt-in retries for IncomingWebhook and WebhookTrigger (#2641) Re-expressed on v8's fetch + Error-subclass architecture (main built them on axios + error-factory functions). Non-webhook release churn from main's parallel 7.x line (docs, web-api version bumps, CHANGELOGs) resolved to v8. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Summary
This pull request adds a minimal
WebhookTriggerclass to@slack/webhookfor Workflow Builder webhook triggers.The package previously only supported incoming webhooks (
IncomingWebhook). Workflow Builder triggers accept arbitrary JSON payloads and return JSON responses, so consumers likeslack-github-actioncurrently fall back to rawfetch.The implementation is intentionally small and mirrors
IncomingWebhook:timeout,agent); rejects a missing or empty URL.send(payload?)POSTs the payload (defaults to{}) and resolves to the parsed JSON response body (WebhookTriggerResult, typed{ ok, error? }); HTTP and request failures reject.WebhookTrigger-named error types.Notes for reviewers
!url), so it rejects an empty string as well asundefined. This intentionally differs fromIncomingWebhook, which only guardsundefined.WebhookTriggerResultis typed closed as{ ok: boolean; error?: string }— matching what the trigger endpoint returns ({ ok: true }or{ ok: false, error }). Widening this later is backward-compatible; tightening a released open type would not be.Preview
🔗 https://github.com/slackapi/node-slack-sdk/tree/eden/webhook-trigger/packages/webhook#trigger-a-workflow-builder-workflow
Requirements