From 972daa4c88f7a8e0d34d84891df064a0573e31d2 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 7 Jan 2026 10:54:48 -0800 Subject: [PATCH 1/2] fix(grain): add grain key to idempotency service --- apps/sim/lib/webhooks/provider-utils.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/sim/lib/webhooks/provider-utils.ts b/apps/sim/lib/webhooks/provider-utils.ts index 2ae0681e94..c475d1205e 100644 --- a/apps/sim/lib/webhooks/provider-utils.ts +++ b/apps/sim/lib/webhooks/provider-utils.ts @@ -63,6 +63,13 @@ function extractAirtableIdentifier(body: any): string | null { return null } +function extractGrainIdentifier(body: any): string | null { + if (body.type && body.data?.id) { + return `${body.type}:${body.data.id}` + } + return null +} + const PROVIDER_EXTRACTORS: Record string | null> = { slack: extractSlackIdentifier, twilio: extractTwilioIdentifier, @@ -73,6 +80,7 @@ const PROVIDER_EXTRACTORS: Record string | null> = { jira: extractJiraIdentifier, 'microsoft-teams': extractMicrosoftTeamsIdentifier, airtable: extractAirtableIdentifier, + grain: extractGrainIdentifier, } export function extractProviderIdentifierFromBody(provider: string, body: any): string | null { From 3bd8454e33e2ad83d638656be6a540fdd20a7b56 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 7 Jan 2026 11:52:08 -0800 Subject: [PATCH 2/2] fixed dropdown issue for grain, webhook registration --- apps/sim/app/api/webhooks/trigger/[path]/route.ts | 9 +++++++++ apps/sim/blocks/blocks/grain.ts | 12 ++++++------ apps/sim/triggers/grain/highlight_created.ts | 11 +---------- apps/sim/triggers/grain/highlight_updated.ts | 11 +---------- apps/sim/triggers/grain/recording_created.ts | 11 +---------- apps/sim/triggers/grain/recording_updated.ts | 11 +---------- apps/sim/triggers/grain/story_created.ts | 11 +---------- apps/sim/triggers/grain/webhook.ts | 11 +---------- 8 files changed, 21 insertions(+), 66 deletions(-) diff --git a/apps/sim/app/api/webhooks/trigger/[path]/route.ts b/apps/sim/app/api/webhooks/trigger/[path]/route.ts index 9cdff87dc5..96ad8492f1 100644 --- a/apps/sim/app/api/webhooks/trigger/[path]/route.ts +++ b/apps/sim/app/api/webhooks/trigger/[path]/route.ts @@ -162,6 +162,15 @@ export async function POST( if (foundWebhook.blockId) { const blockExists = await blockExistsInDeployment(foundWorkflow.id, foundWebhook.blockId) if (!blockExists) { + // For Grain, if block doesn't exist in deployment, treat as verification request + // Grain validates webhook URLs during creation, and the block may not be deployed yet + if (foundWebhook.provider === 'grain') { + logger.info( + `[${requestId}] Grain webhook verification - block not in deployment, returning 200 OK` + ) + return NextResponse.json({ status: 'ok', message: 'Webhook endpoint verified' }) + } + logger.info( `[${requestId}] Trigger block ${foundWebhook.blockId} not found in deployment for workflow ${foundWorkflow.id}` ) diff --git a/apps/sim/blocks/blocks/grain.ts b/apps/sim/blocks/blocks/grain.ts index 97ea198475..50bd0c61dd 100644 --- a/apps/sim/blocks/blocks/grain.ts +++ b/apps/sim/blocks/blocks/grain.ts @@ -217,12 +217,12 @@ export const GrainBlock: BlockConfig = { value: () => 'grain_webhook', required: true, }, - ...getTrigger('grain_recording_created').subBlocks.slice(1), - ...getTrigger('grain_recording_updated').subBlocks.slice(1), - ...getTrigger('grain_highlight_created').subBlocks.slice(1), - ...getTrigger('grain_highlight_updated').subBlocks.slice(1), - ...getTrigger('grain_story_created').subBlocks.slice(1), - ...getTrigger('grain_webhook').subBlocks.slice(1), + ...getTrigger('grain_recording_created').subBlocks, + ...getTrigger('grain_recording_updated').subBlocks, + ...getTrigger('grain_highlight_created').subBlocks, + ...getTrigger('grain_highlight_updated').subBlocks, + ...getTrigger('grain_story_created').subBlocks, + ...getTrigger('grain_webhook').subBlocks, ], tools: { access: [ diff --git a/apps/sim/triggers/grain/highlight_created.ts b/apps/sim/triggers/grain/highlight_created.ts index d1347a4f31..2c03cfa360 100644 --- a/apps/sim/triggers/grain/highlight_created.ts +++ b/apps/sim/triggers/grain/highlight_created.ts @@ -1,6 +1,6 @@ import { GrainIcon } from '@/components/icons' import type { TriggerConfig } from '@/triggers/types' -import { buildHighlightOutputs, grainSetupInstructions, grainTriggerOptions } from './utils' +import { buildHighlightOutputs, grainSetupInstructions } from './utils' export const grainHighlightCreatedTrigger: TriggerConfig = { id: 'grain_highlight_created', @@ -11,15 +11,6 @@ export const grainHighlightCreatedTrigger: TriggerConfig = { icon: GrainIcon, subBlocks: [ - { - id: 'selectedTriggerId', - title: 'Trigger Type', - type: 'dropdown', - mode: 'trigger', - options: grainTriggerOptions, - value: () => 'grain_highlight_created', - required: true, - }, { id: 'apiKey', title: 'API Key', diff --git a/apps/sim/triggers/grain/highlight_updated.ts b/apps/sim/triggers/grain/highlight_updated.ts index 9c770e5f82..d2047023db 100644 --- a/apps/sim/triggers/grain/highlight_updated.ts +++ b/apps/sim/triggers/grain/highlight_updated.ts @@ -1,6 +1,6 @@ import { GrainIcon } from '@/components/icons' import type { TriggerConfig } from '@/triggers/types' -import { buildHighlightOutputs, grainSetupInstructions, grainTriggerOptions } from './utils' +import { buildHighlightOutputs, grainSetupInstructions } from './utils' export const grainHighlightUpdatedTrigger: TriggerConfig = { id: 'grain_highlight_updated', @@ -11,15 +11,6 @@ export const grainHighlightUpdatedTrigger: TriggerConfig = { icon: GrainIcon, subBlocks: [ - { - id: 'selectedTriggerId', - title: 'Trigger Type', - type: 'dropdown', - mode: 'trigger', - options: grainTriggerOptions, - value: () => 'grain_highlight_updated', - required: true, - }, { id: 'apiKey', title: 'API Key', diff --git a/apps/sim/triggers/grain/recording_created.ts b/apps/sim/triggers/grain/recording_created.ts index f8c592081f..da1c6096ef 100644 --- a/apps/sim/triggers/grain/recording_created.ts +++ b/apps/sim/triggers/grain/recording_created.ts @@ -1,6 +1,6 @@ import { GrainIcon } from '@/components/icons' import type { TriggerConfig } from '@/triggers/types' -import { buildRecordingOutputs, grainSetupInstructions, grainTriggerOptions } from './utils' +import { buildRecordingOutputs, grainSetupInstructions } from './utils' export const grainRecordingCreatedTrigger: TriggerConfig = { id: 'grain_recording_created', @@ -11,15 +11,6 @@ export const grainRecordingCreatedTrigger: TriggerConfig = { icon: GrainIcon, subBlocks: [ - { - id: 'selectedTriggerId', - title: 'Trigger Type', - type: 'dropdown', - mode: 'trigger', - options: grainTriggerOptions, - value: () => 'grain_recording_created', - required: true, - }, { id: 'apiKey', title: 'API Key', diff --git a/apps/sim/triggers/grain/recording_updated.ts b/apps/sim/triggers/grain/recording_updated.ts index c64bb0f656..d7afdddfa0 100644 --- a/apps/sim/triggers/grain/recording_updated.ts +++ b/apps/sim/triggers/grain/recording_updated.ts @@ -1,6 +1,6 @@ import { GrainIcon } from '@/components/icons' import type { TriggerConfig } from '@/triggers/types' -import { buildRecordingOutputs, grainSetupInstructions, grainTriggerOptions } from './utils' +import { buildRecordingOutputs, grainSetupInstructions } from './utils' export const grainRecordingUpdatedTrigger: TriggerConfig = { id: 'grain_recording_updated', @@ -11,15 +11,6 @@ export const grainRecordingUpdatedTrigger: TriggerConfig = { icon: GrainIcon, subBlocks: [ - { - id: 'selectedTriggerId', - title: 'Trigger Type', - type: 'dropdown', - mode: 'trigger', - options: grainTriggerOptions, - value: () => 'grain_recording_updated', - required: true, - }, { id: 'apiKey', title: 'API Key', diff --git a/apps/sim/triggers/grain/story_created.ts b/apps/sim/triggers/grain/story_created.ts index 32267976ae..abe86698b1 100644 --- a/apps/sim/triggers/grain/story_created.ts +++ b/apps/sim/triggers/grain/story_created.ts @@ -1,6 +1,6 @@ import { GrainIcon } from '@/components/icons' import type { TriggerConfig } from '@/triggers/types' -import { buildStoryOutputs, grainSetupInstructions, grainTriggerOptions } from './utils' +import { buildStoryOutputs, grainSetupInstructions } from './utils' export const grainStoryCreatedTrigger: TriggerConfig = { id: 'grain_story_created', @@ -11,15 +11,6 @@ export const grainStoryCreatedTrigger: TriggerConfig = { icon: GrainIcon, subBlocks: [ - { - id: 'selectedTriggerId', - title: 'Trigger Type', - type: 'dropdown', - mode: 'trigger', - options: grainTriggerOptions, - value: () => 'grain_story_created', - required: true, - }, { id: 'apiKey', title: 'API Key', diff --git a/apps/sim/triggers/grain/webhook.ts b/apps/sim/triggers/grain/webhook.ts index 93154193b3..4cbe0c3a89 100644 --- a/apps/sim/triggers/grain/webhook.ts +++ b/apps/sim/triggers/grain/webhook.ts @@ -1,6 +1,6 @@ import { GrainIcon } from '@/components/icons' import type { TriggerConfig } from '@/triggers/types' -import { buildGenericOutputs, grainSetupInstructions, grainTriggerOptions } from './utils' +import { buildGenericOutputs, grainSetupInstructions } from './utils' export const grainWebhookTrigger: TriggerConfig = { id: 'grain_webhook', @@ -11,15 +11,6 @@ export const grainWebhookTrigger: TriggerConfig = { icon: GrainIcon, subBlocks: [ - { - id: 'selectedTriggerId', - title: 'Trigger Type', - type: 'dropdown', - mode: 'trigger', - options: grainTriggerOptions, - value: () => 'grain_webhook', - required: true, - }, { id: 'apiKey', title: 'API Key',