Skip to content

Commit 41cc0cd

Browse files
aadamgoughAdam GoughAdam Gough
authored
fix(webhooks): fixed all webhook structures (#935)
* fix for variable format + trig * fixed slack variable * microsoft teams working * fixed outlook, plus added other minor documentation changes and fixed subblock * removed discord webhook logic * added airtable logic * bun run lint * test * test again * test again 2 * test again 3 * test again 4 * test again 4 * test again 4 * bun run lint * test 5 * test 6 * test 7 * test 7 * test 7 * test 7 * test 7 * test 7 * test 8 * test 9 * test 9 * test 9 * test 10 * test 10 * bun run lint, plus github fixed * removed some debug statements #935 * testing resolver removing * testing trig --------- Co-authored-by: Adam Gough <adamgough@Adams-MacBook-Pro.local> Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net>
1 parent 70aeb0c commit 41cc0cd

File tree

24 files changed

+1132
-508
lines changed

24 files changed

+1132
-508
lines changed

apps/sim/app/api/webhooks/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,12 +352,15 @@ async function createAirtableWebhookSubscription(
352352
return // Cannot proceed without base/table IDs
353353
}
354354

355-
const accessToken = await getOAuthToken(userId, 'airtable') // Use 'airtable' as the providerId key
355+
const accessToken = await getOAuthToken(userId, 'airtable')
356356
if (!accessToken) {
357357
logger.warn(
358358
`[${requestId}] Could not retrieve Airtable access token for user ${userId}. Cannot create webhook in Airtable.`
359359
)
360-
return
360+
// Instead of silently returning, throw an error with clear user guidance
361+
throw new Error(
362+
'Airtable account connection required. Please connect your Airtable account in the trigger configuration and try again.'
363+
)
361364
}
362365

363366
const requestOrigin = new URL(request.url).origin

apps/sim/app/api/webhooks/trigger/[path]/route.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,41 @@ export async function POST(
100100
return new NextResponse('Failed to read request body', { status: 400 })
101101
}
102102

103-
// Parse the body as JSON
103+
// Parse the body - handle both JSON and form-encoded payloads
104104
let body: any
105105
try {
106-
body = JSON.parse(rawBody)
106+
// Check content type to handle both JSON and form-encoded payloads
107+
const contentType = request.headers.get('content-type') || ''
108+
109+
if (contentType.includes('application/x-www-form-urlencoded')) {
110+
// GitHub sends form-encoded data with JSON in the 'payload' field
111+
const formData = new URLSearchParams(rawBody)
112+
const payloadString = formData.get('payload')
113+
114+
if (!payloadString) {
115+
logger.warn(`[${requestId}] No payload field found in form-encoded data`)
116+
return new NextResponse('Missing payload field', { status: 400 })
117+
}
118+
119+
body = JSON.parse(payloadString)
120+
logger.debug(`[${requestId}] Parsed form-encoded GitHub webhook payload`)
121+
} else {
122+
// Default to JSON parsing
123+
body = JSON.parse(rawBody)
124+
logger.debug(`[${requestId}] Parsed JSON webhook payload`)
125+
}
107126

108127
if (Object.keys(body).length === 0) {
109128
logger.warn(`[${requestId}] Rejecting empty JSON object`)
110129
return new NextResponse('Empty JSON payload', { status: 400 })
111130
}
112131
} catch (parseError) {
113-
logger.error(`[${requestId}] Failed to parse JSON body`, {
132+
logger.error(`[${requestId}] Failed to parse webhook body`, {
114133
error: parseError instanceof Error ? parseError.message : String(parseError),
134+
contentType: request.headers.get('content-type'),
135+
bodyPreview: `${rawBody?.slice(0, 100)}...`,
115136
})
116-
return new NextResponse('Invalid JSON payload', { status: 400 })
137+
return new NextResponse('Invalid payload format', { status: 400 })
117138
}
118139

119140
// Handle Slack challenge

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/trigger-config/components/trigger-modal.tsx

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ export function TriggerModal({
9494
setSelectedCredentialId(credentialValue)
9595
if (triggerDef.provider === 'gmail') {
9696
loadGmailLabels(credentialValue)
97+
} else if (triggerDef.provider === 'outlook') {
98+
loadOutlookFolders(credentialValue)
9799
}
98100
}
99101
}
@@ -139,6 +141,30 @@ export function TriggerModal({
139141
}
140142
}
141143

144+
// Load Outlook folders for the selected credential
145+
const loadOutlookFolders = async (credentialId: string) => {
146+
try {
147+
const response = await fetch(`/api/tools/outlook/folders?credentialId=${credentialId}`)
148+
if (response.ok) {
149+
const data = await response.json()
150+
if (data.folders && Array.isArray(data.folders)) {
151+
const folderOptions = data.folders.map((folder: any) => ({
152+
id: folder.id,
153+
name: folder.name,
154+
}))
155+
setDynamicOptions((prev) => ({
156+
...prev,
157+
folderIds: folderOptions,
158+
}))
159+
}
160+
} else {
161+
logger.error('Failed to load Outlook folders:', response.statusText)
162+
}
163+
} catch (error) {
164+
logger.error('Error loading Outlook folders:', error)
165+
}
166+
}
167+
142168
// Generate webhook path and URL
143169
useEffect(() => {
144170
// For triggers that don't use webhooks (like Gmail polling), skip URL generation
@@ -152,15 +178,14 @@ export function TriggerModal({
152178

153179
// If no path exists, generate one automatically
154180
if (!finalPath) {
155-
const timestamp = Date.now()
156-
const randomId = Math.random().toString(36).substring(2, 8)
157-
finalPath = `/${triggerDef.provider}/${timestamp}-${randomId}`
181+
// Use UUID format consistent with other webhooks
182+
finalPath = crypto.randomUUID()
158183
setGeneratedPath(finalPath)
159184
}
160185

161186
if (finalPath) {
162187
const baseUrl = window.location.origin
163-
setWebhookUrl(`${baseUrl}/api/webhooks/trigger${finalPath}`)
188+
setWebhookUrl(`${baseUrl}/api/webhooks/trigger/${finalPath}`)
164189
}
165190
}, [triggerPath, triggerDef.provider, triggerDef.requiresCredentials, triggerDef.webhook])
166191

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
export {
22
AirtableConfig,
3-
DiscordConfig,
43
GenericConfig,
54
GithubConfig,
65
GmailConfig,

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/providers/discord.tsx

Lines changed: 0 additions & 125 deletions
This file was deleted.

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/providers/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export { AirtableConfig } from './airtable'
2-
export { DiscordConfig } from './discord'
32
export { GenericConfig } from './generic'
43
export { GithubConfig } from './github'
54
export { GmailConfig } from './gmail'

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/providers/slack.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ export function SlackConfig({
137137
<li>Paste the Webhook URL (from above) into the "Request URL" field</li>
138138
</ol>
139139
</li>
140+
<li>
141+
Go to <strong>Install App</strong> in the left sidebar and install the app into your
142+
desired Slack workspace and channel.
143+
</li>
140144
<li>Save changes in both Slack and here.</li>
141145
</ol>
142146
</InstructionsSection>

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { createLogger } from '@/lib/logs/console/logger'
1212
import {
1313
AirtableConfig,
1414
DeleteConfirmDialog,
15-
DiscordConfig,
1615
GenericConfig,
1716
GithubConfig,
1817
GmailConfig,
@@ -83,8 +82,7 @@ export function WebhookModal({
8382
// Provider-specific state
8483
const [whatsappVerificationToken, setWhatsappVerificationToken] = useState('')
8584
const [githubContentType, setGithubContentType] = useState('application/json')
86-
const [discordWebhookName, setDiscordWebhookName] = useState('')
87-
const [discordAvatarUrl, setDiscordAvatarUrl] = useState('')
85+
8886
const [slackSigningSecret, setSlackSigningSecret] = useState('')
8987
const [telegramBotToken, setTelegramBotToken] = useState('')
9088
// Microsoft Teams-specific state
@@ -106,8 +104,7 @@ export function WebhookModal({
106104
secretHeaderName: '',
107105
requireAuth: false,
108106
allowedIps: '',
109-
discordWebhookName: '',
110-
discordAvatarUrl: '',
107+
111108
airtableWebhookSecret: '',
112109
airtableBaseId: '',
113110
airtableTableId: '',
@@ -184,18 +181,6 @@ export function WebhookModal({
184181
const contentType = config.contentType || 'application/json'
185182
setGithubContentType(contentType)
186183
setOriginalValues((prev) => ({ ...prev, githubContentType: contentType }))
187-
} else if (webhookProvider === 'discord') {
188-
const webhookName = config.webhookName || ''
189-
const avatarUrl = config.avatarUrl || ''
190-
191-
setDiscordWebhookName(webhookName)
192-
setDiscordAvatarUrl(avatarUrl)
193-
194-
setOriginalValues((prev) => ({
195-
...prev,
196-
discordWebhookName: webhookName,
197-
discordAvatarUrl: avatarUrl,
198-
}))
199184
} else if (webhookProvider === 'generic') {
200185
// Set general webhook configuration
201186
const token = config.token || ''
@@ -328,9 +313,6 @@ export function WebhookModal({
328313
(webhookProvider === 'whatsapp' &&
329314
whatsappVerificationToken !== originalValues.whatsappVerificationToken) ||
330315
(webhookProvider === 'github' && githubContentType !== originalValues.githubContentType) ||
331-
(webhookProvider === 'discord' &&
332-
(discordWebhookName !== originalValues.discordWebhookName ||
333-
discordAvatarUrl !== originalValues.discordAvatarUrl)) ||
334316
(webhookProvider === 'generic' &&
335317
(generalToken !== originalValues.generalToken ||
336318
secretHeaderName !== originalValues.secretHeaderName ||
@@ -357,8 +339,6 @@ export function WebhookModal({
357339
webhookProvider,
358340
whatsappVerificationToken,
359341
githubContentType,
360-
discordWebhookName,
361-
discordAvatarUrl,
362342
generalToken,
363343
secretHeaderName,
364344
requireAuth,
@@ -393,9 +373,7 @@ export function WebhookModal({
393373
case 'github':
394374
isValid = generalToken.trim() !== ''
395375
break
396-
case 'discord':
397-
isValid = discordWebhookName.trim() !== ''
398-
break
376+
399377
case 'telegram':
400378
isValid = telegramBotToken.trim() !== ''
401379
break
@@ -442,11 +420,6 @@ export function WebhookModal({
442420
return { verificationToken: whatsappVerificationToken }
443421
case 'github':
444422
return { contentType: githubContentType }
445-
case 'discord':
446-
return {
447-
webhookName: discordWebhookName || undefined,
448-
avatarUrl: discordAvatarUrl || undefined,
449-
}
450423
case 'stripe':
451424
return {}
452425
case 'gmail':
@@ -539,8 +512,6 @@ export function WebhookModal({
539512
secretHeaderName,
540513
requireAuth,
541514
allowedIps,
542-
discordWebhookName,
543-
discordAvatarUrl,
544515
slackSigningSecret,
545516
airtableWebhookSecret,
546517
airtableBaseId,
@@ -738,20 +709,7 @@ export function WebhookModal({
738709
setIncludeRawEmail={setIncludeRawEmail}
739710
/>
740711
)
741-
case 'discord':
742-
return (
743-
<DiscordConfig
744-
webhookName={discordWebhookName}
745-
setWebhookName={setDiscordWebhookName}
746-
avatarUrl={discordAvatarUrl}
747-
setAvatarUrl={setDiscordAvatarUrl}
748-
isLoadingToken={isLoadingToken}
749-
testResult={testResult}
750-
copied={copied}
751-
copyToClipboard={copyToClipboard}
752-
testWebhook={testWebhook}
753-
/>
754-
)
712+
755713
case 'stripe':
756714
return (
757715
<StripeConfig

0 commit comments

Comments
 (0)