fix(grain): add grain key to idempotency service (#2712)

* fix(grain): add grain key to idempotency service

* fixed dropdown issue for grain, webhook registration
This commit is contained in:
Waleed
2026-01-07 12:00:32 -08:00
committed by GitHub
parent 9dc02f3728
commit 142c9a0428
9 changed files with 29 additions and 66 deletions

View File

@@ -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}`
)

View File

@@ -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: [

View File

@@ -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, (body: any) => string | null> = {
slack: extractSlackIdentifier,
twilio: extractTwilioIdentifier,
@@ -73,6 +80,7 @@ const PROVIDER_EXTRACTORS: Record<string, (body: any) => string | null> = {
jira: extractJiraIdentifier,
'microsoft-teams': extractMicrosoftTeamsIdentifier,
airtable: extractAirtableIdentifier,
grain: extractGrainIdentifier,
}
export function extractProviderIdentifierFromBody(provider: string, body: any): string | null {

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',