Skip to content

Commit 1398154

Browse files
authored
fix(grain): grain trigger update (#2739)
* grain trigger new requirements * removed comment * made it generic for all triggers * fire only for specific trigger type * removed comments
1 parent 554dcdf commit 1398154

File tree

5 files changed

+82
-9
lines changed

5 files changed

+82
-9
lines changed

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

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ export async function POST(request: NextRequest) {
744744
if (savedWebhook && provider === 'grain') {
745745
logger.info(`[${requestId}] Grain provider detected. Creating Grain webhook subscription.`)
746746
try {
747-
const grainHookId = await createGrainWebhookSubscription(
747+
const grainResult = await createGrainWebhookSubscription(
748748
request,
749749
{
750750
id: savedWebhook.id,
@@ -754,11 +754,12 @@ export async function POST(request: NextRequest) {
754754
requestId
755755
)
756756

757-
if (grainHookId) {
758-
// Update the webhook record with the external Grain hook ID
757+
if (grainResult) {
758+
// Update the webhook record with the external Grain hook ID and event types for filtering
759759
const updatedConfig = {
760760
...(savedWebhook.providerConfig as Record<string, any>),
761-
externalId: grainHookId,
761+
externalId: grainResult.id,
762+
eventTypes: grainResult.eventTypes,
762763
}
763764
await db
764765
.update(webhook)
@@ -770,7 +771,8 @@ export async function POST(request: NextRequest) {
770771

771772
savedWebhook.providerConfig = updatedConfig
772773
logger.info(`[${requestId}] Successfully created Grain webhook`, {
773-
grainHookId,
774+
grainHookId: grainResult.id,
775+
eventTypes: grainResult.eventTypes,
774776
webhookId: savedWebhook.id,
775777
})
776778
}
@@ -1176,10 +1178,10 @@ async function createGrainWebhookSubscription(
11761178
request: NextRequest,
11771179
webhookData: any,
11781180
requestId: string
1179-
): Promise<string | undefined> {
1181+
): Promise<{ id: string; eventTypes: string[] } | undefined> {
11801182
try {
11811183
const { path, providerConfig } = webhookData
1182-
const { apiKey, includeHighlights, includeParticipants, includeAiSummary } =
1184+
const { apiKey, triggerId, includeHighlights, includeParticipants, includeAiSummary } =
11831185
providerConfig || {}
11841186

11851187
if (!apiKey) {
@@ -1191,12 +1193,53 @@ async function createGrainWebhookSubscription(
11911193
)
11921194
}
11931195

1196+
// Map trigger IDs to Grain API hook_type (only 2 options: recording_added, upload_status)
1197+
const hookTypeMap: Record<string, string> = {
1198+
grain_webhook: 'recording_added',
1199+
grain_recording_created: 'recording_added',
1200+
grain_recording_updated: 'recording_added',
1201+
grain_highlight_created: 'recording_added',
1202+
grain_highlight_updated: 'recording_added',
1203+
grain_story_created: 'recording_added',
1204+
grain_upload_status: 'upload_status',
1205+
}
1206+
1207+
const eventTypeMap: Record<string, string[]> = {
1208+
grain_webhook: [],
1209+
grain_recording_created: ['recording_added'],
1210+
grain_recording_updated: ['recording_updated'],
1211+
grain_highlight_created: ['highlight_created'],
1212+
grain_highlight_updated: ['highlight_updated'],
1213+
grain_story_created: ['story_created'],
1214+
grain_upload_status: ['upload_status'],
1215+
}
1216+
1217+
const hookType = hookTypeMap[triggerId] ?? 'recording_added'
1218+
const eventTypes = eventTypeMap[triggerId] ?? []
1219+
1220+
if (!hookTypeMap[triggerId]) {
1221+
logger.warn(
1222+
`[${requestId}] Unknown triggerId for Grain: ${triggerId}, defaulting to recording_added`,
1223+
{
1224+
webhookId: webhookData.id,
1225+
}
1226+
)
1227+
}
1228+
1229+
logger.info(`[${requestId}] Creating Grain webhook`, {
1230+
triggerId,
1231+
hookType,
1232+
eventTypes,
1233+
webhookId: webhookData.id,
1234+
})
1235+
11941236
const notificationUrl = `${getBaseUrl()}/api/webhooks/trigger/${path}`
11951237

11961238
const grainApiUrl = 'https://api.grain.com/_/public-api/v2/hooks/create'
11971239

11981240
const requestBody: Record<string, any> = {
11991241
hook_url: notificationUrl,
1242+
hook_type: hookType,
12001243
}
12011244

12021245
// Build include object based on configuration
@@ -1226,8 +1269,10 @@ async function createGrainWebhookSubscription(
12261269

12271270
const responseBody = await grainResponse.json()
12281271

1229-
if (!grainResponse.ok || responseBody.error) {
1272+
if (!grainResponse.ok || responseBody.error || responseBody.errors) {
1273+
logger.warn('[App] Grain response body:', responseBody)
12301274
const errorMessage =
1275+
responseBody.errors?.detail ||
12311276
responseBody.error?.message ||
12321277
responseBody.error ||
12331278
responseBody.message ||
@@ -1255,10 +1300,11 @@ async function createGrainWebhookSubscription(
12551300
`[${requestId}] Successfully created webhook in Grain for webhook ${webhookData.id}.`,
12561301
{
12571302
grainWebhookId: responseBody.id,
1303+
eventTypes,
12581304
}
12591305
)
12601306

1261-
return responseBody.id
1307+
return { id: responseBody.id, eventTypes }
12621308
} catch (error: any) {
12631309
logger.error(
12641310
`[${requestId}] Exception during Grain webhook creation for webhook ${webhookData.id}.`,

apps/sim/lib/webhooks/processor.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,19 @@ export function shouldSkipWebhookEvent(webhook: any, body: any, requestId: strin
239239
}
240240
}
241241

242+
if (webhook.provider === 'grain') {
243+
const eventTypes = providerConfig.eventTypes
244+
if (eventTypes && Array.isArray(eventTypes) && eventTypes.length > 0) {
245+
const eventType = body?.type
246+
if (eventType && !eventTypes.includes(eventType)) {
247+
logger.info(
248+
`[${requestId}] Grain event type '${eventType}' not in allowed list for webhook ${webhook.id}, skipping`
249+
)
250+
return true
251+
}
252+
}
253+
}
254+
242255
return false
243256
}
244257

apps/sim/tools/grain/create_hook.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export const grainCreateHookTool: ToolConfig<GrainCreateHookParams, GrainCreateH
2020
visibility: 'user-or-llm',
2121
description: 'Webhook endpoint URL (must respond 2xx)',
2222
},
23+
hookType: {
24+
type: 'string',
25+
required: true,
26+
visibility: 'user-or-llm',
27+
description: 'Type of webhook: "recording_added" or "upload_status"',
28+
},
2329
filterBeforeDatetime: {
2430
type: 'string',
2531
required: false,
@@ -81,6 +87,7 @@ export const grainCreateHookTool: ToolConfig<GrainCreateHookParams, GrainCreateH
8187
body: (params) => {
8288
const body: Record<string, any> = {
8389
hook_url: params.hookUrl,
90+
hook_type: params.hookType,
8491
}
8592

8693
const filter: Record<string, any> = {}
@@ -147,6 +154,10 @@ export const grainCreateHookTool: ToolConfig<GrainCreateHookParams, GrainCreateH
147154
type: 'string',
148155
description: 'The webhook URL',
149156
},
157+
hook_type: {
158+
type: 'string',
159+
description: 'Type of hook: recording_added or upload_status',
160+
},
150161
filter: {
151162
type: 'object',
152163
description: 'Applied filters',

apps/sim/tools/grain/list_hooks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const grainListHooksTool: ToolConfig<GrainListHooksParams, GrainListHooks
5151
id: { type: 'string', description: 'Hook UUID' },
5252
enabled: { type: 'boolean', description: 'Whether hook is active' },
5353
hook_url: { type: 'string', description: 'Webhook URL' },
54+
hook_type: { type: 'string', description: 'Type: recording_added or upload_status' },
5455
filter: { type: 'object', description: 'Applied filters' },
5556
include: { type: 'object', description: 'Included fields' },
5657
inserted_at: { type: 'string', description: 'Creation timestamp' },

apps/sim/tools/grain/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export interface GrainHook {
9595
id: string
9696
enabled: boolean
9797
hook_url: string
98+
hook_type: 'recording_added' | 'upload_status'
9899
filter: GrainRecordingFilter
99100
include: GrainRecordingInclude
100101
inserted_at: string
@@ -192,6 +193,7 @@ export interface GrainListMeetingTypesResponse extends ToolResponse {
192193
export interface GrainCreateHookParams {
193194
apiKey: string
194195
hookUrl: string
196+
hookType: 'recording_added' | 'upload_status'
195197
filterBeforeDatetime?: string
196198
filterAfterDatetime?: string
197199
filterParticipantScope?: 'internal' | 'external'

0 commit comments

Comments
 (0)