Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions apps/sim/executor/execution/block-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,22 @@ export class BlockExecutor {
}
return filtered
}

const isTrigger =
block.metadata?.category === 'triggers' ||
block.config?.params?.triggerMode === true ||
block.metadata?.id === BlockType.STARTER

if (isTrigger) {
const filtered: NormalizedBlockOutput = {}
const internalKeys = ['webhook', 'workflowId', 'input']
for (const [key, value] of Object.entries(output)) {
if (internalKeys.includes(key)) continue
filtered[key] = value
}
return filtered
}

return output
}

Expand Down
1 change: 0 additions & 1 deletion apps/sim/executor/handlers/trigger/trigger-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ describe('TriggerBlockHandler', () => {

const result = await handler.execute(mockContext, scheduleBlock, {})

// Schedule triggers typically don't have input data, just trigger the workflow
expect(result).toEqual({})
})

Expand Down
89 changes: 3 additions & 86 deletions apps/sim/executor/handlers/trigger/trigger-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ export class TriggerBlockHandler implements BlockHandler {

const existingState = ctx.blockStates.get(block.id)
if (existingState?.output && Object.keys(existingState.output).length > 0) {
const existingOutput = existingState.output as any
const existingProvider = existingOutput?.webhook?.data?.provider

return existingOutput
return existingState.output
}

const starterBlock = ctx.workflow?.blocks?.find((b) => b.metadata?.id === 'starter')
Expand All @@ -44,88 +41,8 @@ export class TriggerBlockHandler implements BlockHandler {
const starterOutput = starterState.output

if (starterOutput.webhook?.data) {
const webhookData = starterOutput.webhook?.data || {}
const provider = webhookData.provider

if (provider === 'github') {
const payloadSource = webhookData.payload || {}
return {
...payloadSource,
webhook: starterOutput.webhook,
}
}

if (provider === 'microsoft-teams') {
const providerData = (starterOutput as any)[provider] || webhookData[provider] || {}
const payloadSource = providerData?.message?.raw || webhookData.payload || {}
return {
...payloadSource,
[provider]: providerData,
webhook: starterOutput.webhook,
}
}

if (provider === 'airtable') {
return starterOutput
}

const result: any = {
input: starterOutput.input,
}

for (const [key, value] of Object.entries(starterOutput)) {
if (key !== 'webhook' && key !== provider) {
result[key] = value
}
}

if (provider && starterOutput[provider]) {
const providerData = starterOutput[provider]

for (const [key, value] of Object.entries(providerData)) {
if (typeof value === 'object' && value !== null) {
if (!result[key]) {
result[key] = value
}
}
}

result[provider] = providerData
} else if (provider && webhookData[provider]) {
const providerData = webhookData[provider]

for (const [key, value] of Object.entries(providerData)) {
if (typeof value === 'object' && value !== null) {
if (!result[key]) {
result[key] = value
}
}
}

result[provider] = providerData
} else if (
provider &&
(provider === 'gmail' || provider === 'outlook') &&
webhookData.payload?.email
) {
const emailData = webhookData.payload.email

for (const [key, value] of Object.entries(emailData)) {
if (!result[key]) {
result[key] = value
}
}

result.email = emailData

if (webhookData.payload.timestamp) {
result.timestamp = webhookData.payload.timestamp
}
}

if (starterOutput.webhook) result.webhook = starterOutput.webhook

return result
const { webhook, workflowId, ...cleanOutput } = starterOutput
return cleanOutput
}

return starterOutput
Expand Down
80 changes: 40 additions & 40 deletions apps/sim/lib/webhooks/utils.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,6 @@ export async function formatWebhookInput(
}
}

// Fallback for unknown Telegram update types
logger.warn('Unknown Telegram update type', {
updateId: body.update_id,
bodyKeys: Object.keys(body || {}),
Expand Down Expand Up @@ -778,7 +777,6 @@ export async function formatWebhookInput(

if (foundWebhook.provider === 'twilio_voice') {
return {
// Root-level properties matching trigger outputs for easy access
callSid: body.CallSid,
accountSid: body.AccountSid,
from: body.From,
Expand All @@ -792,8 +790,6 @@ export async function formatWebhookInput(
speechResult: body.SpeechResult,
recordingUrl: body.RecordingUrl,
recordingSid: body.RecordingSid,

// Additional fields from Twilio payload
called: body.Called,
caller: body.Caller,
toCity: body.ToCity,
Expand Down Expand Up @@ -830,14 +826,48 @@ export async function formatWebhookInput(

if (foundWebhook.provider === 'gmail') {
if (body && typeof body === 'object' && 'email' in body) {
return body
const email = body.email as Record<string, any>
const timestamp = body.timestamp
return {
...email,
email,
...(timestamp !== undefined && { timestamp }),
webhook: {
data: {
provider: 'gmail',
path: foundWebhook.path,
providerConfig: foundWebhook.providerConfig,
payload: body,
headers: Object.fromEntries(request.headers.entries()),
method: request.method,
},
},
workflowId: foundWorkflow.id,
}
}
return body
}

if (foundWebhook.provider === 'outlook') {
if (body && typeof body === 'object' && 'email' in body) {
return body
const email = body.email as Record<string, any>
const timestamp = body.timestamp
return {
...email,
email,
...(timestamp !== undefined && { timestamp }),
webhook: {
data: {
provider: 'outlook',
path: foundWebhook.path,
providerConfig: foundWebhook.providerConfig,
payload: body,
headers: Object.fromEntries(request.headers.entries()),
method: request.method,
},
},
workflowId: foundWorkflow.id,
}
}
return body
}
Expand Down Expand Up @@ -926,19 +956,16 @@ export async function formatWebhookInput(
}

if (foundWebhook.provider === 'microsoft-teams') {
// Check if this is a Microsoft Graph change notification
if (body?.value && Array.isArray(body.value) && body.value.length > 0) {
return await formatTeamsGraphNotification(body, foundWebhook, foundWorkflow, request)
}

// Microsoft Teams outgoing webhook - Teams sending data to us
const messageText = body?.text || ''
const messageId = body?.id || ''
const timestamp = body?.timestamp || body?.localTimestamp || ''
const from = body?.from || {}
const conversation = body?.conversation || {}

// Construct the message object
const messageObj = {
raw: {
attachments: body?.attachments || [],
Expand All @@ -951,14 +978,12 @@ export async function formatWebhookInput(
},
}

// Construct the from object
const fromObj = {
id: from.id || '',
name: from.name || '',
aadObjectId: from.aadObjectId || '',
}

// Construct the conversation object
const conversationObj = {
id: conversation.id || '',
name: conversation.name || '',
Expand All @@ -968,13 +993,11 @@ export async function formatWebhookInput(
conversationType: conversation.conversationType || '',
}

// Construct the activity object
const activityObj = body || {}

return {
input: messageText, // Primary workflow input - the message text
input: messageText,

// Top-level properties for direct access with <microsoftteams.from.name> syntax
from: fromObj,
message: messageObj,
activity: activityObj,
Expand All @@ -995,11 +1018,9 @@ export async function formatWebhookInput(
}

if (foundWebhook.provider === 'slack') {
// Slack input formatting logic - check for valid event
const event = body?.event

if (event && body?.type === 'event_callback') {
// Extract event text with fallbacks for different event types
let input = ''

if (event.text) {
Expand All @@ -1010,26 +1031,22 @@ export async function formatWebhookInput(
input = 'Slack event received'
}

// Create the event object for easier access
const eventObj = {
event_type: event.type || '',
channel: event.channel || '',
channel_name: '', // Could be resolved via additional API calls if needed
channel_name: '',
user: event.user || '',
user_name: '', // Could be resolved via additional API calls if needed
user_name: '',
text: event.text || '',
timestamp: event.ts || event.event_ts || '',
team_id: body.team_id || event.team || '',
event_id: body.event_id || '',
}

return {
input, // Primary workflow input - the event content
input,

// // // Top-level properties for backward compatibility with <blockName.event> syntax
event: eventObj,

// Keep the nested structure for the new slack.event.text syntax
slack: {
event: eventObj,
},
Expand All @@ -1047,7 +1064,6 @@ export async function formatWebhookInput(
}
}

// Fallback for unknown Slack event types
logger.warn('Unknown Slack event type', {
type: body?.type,
hasEvent: !!body?.event,
Expand Down Expand Up @@ -1283,9 +1299,7 @@ export async function formatWebhookInput(
}

return {
// Expose raw GitHub payload at the root
...body,
// Include webhook metadata alongside
webhook: {
data: {
provider: 'github',
Expand Down Expand Up @@ -1364,10 +1378,7 @@ export async function formatWebhookInput(
}

if (foundWebhook.provider === 'linear') {
// Linear webhook payload structure:
// { action, type, webhookId, webhookTimestamp, organizationId, createdAt, actor, data, updatedFrom? }
return {
// Extract top-level fields from Linear payload
action: body.action || '',
type: body.type || '',
webhookId: body.webhookId || '',
Expand All @@ -1377,8 +1388,6 @@ export async function formatWebhookInput(
actor: body.actor || null,
data: body.data || null,
updatedFrom: body.updatedFrom || null,

// Keep webhook metadata
webhook: {
data: {
provider: 'linear',
Expand All @@ -1393,7 +1402,6 @@ export async function formatWebhookInput(
}
}

// Jira webhook format
if (foundWebhook.provider === 'jira') {
const { extractIssueData, extractCommentData, extractWorklogData } = await import(
'@/triggers/jira/utils'
Expand Down Expand Up @@ -1445,7 +1453,6 @@ export async function formatWebhookInput(
}

if (foundWebhook.provider === 'calendly') {
// Calendly webhook payload format matches the trigger outputs
return {
event: body.event,
created_at: body.created_at,
Expand All @@ -1466,9 +1473,7 @@ export async function formatWebhookInput(
}

if (foundWebhook.provider === 'circleback') {
// Circleback webhook payload - meeting notes, action items, transcript
return {
// Top-level fields from Circleback payload
id: body.id,
name: body.name,
createdAt: body.createdAt,
Expand All @@ -1482,10 +1487,7 @@ export async function formatWebhookInput(
actionItems: body.actionItems || [],
transcript: body.transcript || [],
insights: body.insights || {},

// Full meeting object for convenience
meeting: body,

webhook: {
data: {
provider: 'circleback',
Expand All @@ -1501,9 +1503,7 @@ export async function formatWebhookInput(
}

if (foundWebhook.provider === 'grain') {
// Grain webhook payload structure: { type, user_id, data: {...} }
return {
// Top-level fields from Grain payload
type: body.type,
user_id: body.user_id,
data: body.data || {},
Expand Down