Skip to content

Commit f4c8fea

Browse files
committed
fix lint
1 parent 0f0292d commit f4c8fea

File tree

6 files changed

+229
-176
lines changed

6 files changed

+229
-176
lines changed

apps/sim/app/api/workflows/[id]/state/route.ts

Lines changed: 2 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { db } from '@sim/db'
2-
import { webhook, workflow, workflowBlocks } from '@sim/db/schema'
2+
import { workflow } from '@sim/db/schema'
33
import { createLogger } from '@sim/logger'
4-
import { eq, inArray } from 'drizzle-orm'
4+
import { eq } from 'drizzle-orm'
55
import { type NextRequest, NextResponse } from 'next/server'
66
import { z } from 'zod'
77
import { getSession } from '@/lib/auth'
88
import { env } from '@/lib/core/config/env'
99
import { generateRequestId } from '@/lib/core/utils/request'
10-
import { cleanupExternalWebhook } from '@/lib/webhooks/provider-subscriptions'
1110
import { extractAndPersistCustomTools } from '@/lib/workflows/persistence/custom-tools-persistence'
1211
import { saveWorkflowToNormalizedTables } from '@/lib/workflows/persistence/utils'
1312
import { sanitizeAgentToolsInBlocks } from '@/lib/workflows/sanitization/validation'
@@ -193,59 +192,6 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
193192
deployedAt: state.deployedAt,
194193
}
195194

196-
// Find blocks that were deleted or edited
197-
const currentBlockIds = new Set(Object.keys(filteredBlocks))
198-
const previousBlocks = await db
199-
.select({ id: workflowBlocks.id, data: workflowBlocks.data })
200-
.from(workflowBlocks)
201-
.where(eq(workflowBlocks.workflowId, workflowId))
202-
203-
const blocksToCleanup: string[] = []
204-
for (const prevBlock of previousBlocks) {
205-
if (!currentBlockIds.has(prevBlock.id)) {
206-
// Block was deleted
207-
blocksToCleanup.push(prevBlock.id)
208-
} else {
209-
// Block still exists - check if it was edited
210-
const newBlock = filteredBlocks[prevBlock.id]
211-
const prevData = prevBlock.data as Record<string, unknown> | null
212-
if (prevData && JSON.stringify(prevData) !== JSON.stringify(newBlock)) {
213-
blocksToCleanup.push(prevBlock.id)
214-
}
215-
}
216-
}
217-
218-
if (blocksToCleanup.length > 0) {
219-
const webhooksToCleanup = await db
220-
.select()
221-
.from(webhook)
222-
.where(inArray(webhook.blockId, blocksToCleanup))
223-
224-
if (webhooksToCleanup.length > 0) {
225-
logger.info(`[${requestId}] Cleaning up ${webhooksToCleanup.length} webhook(s)`, {
226-
workflowId,
227-
blocksEdited: blocksToCleanup.length,
228-
})
229-
230-
const webhookIdsToDelete: string[] = []
231-
for (const wh of webhooksToCleanup) {
232-
try {
233-
await cleanupExternalWebhook(wh, workflowData, requestId)
234-
} catch (cleanupError) {
235-
logger.warn(
236-
`[${requestId}] Failed to cleanup external webhook ${wh.id} during workflow save`,
237-
cleanupError
238-
)
239-
}
240-
webhookIdsToDelete.push(wh.id)
241-
}
242-
243-
if (webhookIdsToDelete.length > 0) {
244-
await db.delete(webhook).where(inArray(webhook.id, webhookIdsToDelete))
245-
}
246-
}
247-
}
248-
249195
const saveResult = await saveWorkflowToNormalizedTables(workflowId, workflowState as any)
250196

251197
if (!saveResult.success) {

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ export function DeployModal({
189189
useEffect(() => {
190190
if (open && workflowId) {
191191
setActiveTab('general')
192+
setApiDeployError(null)
192193
fetchChatDeploymentInfo()
193194
}
194195
}, [open, workflowId, fetchChatDeploymentInfo])
@@ -507,6 +508,7 @@ export function DeployModal({
507508
const handleCloseModal = () => {
508509
setIsSubmitting(false)
509510
setChatSubmitting(false)
511+
setApiDeployError(null)
510512
onOpenChange(false)
511513
}
512514

apps/sim/blocks/blocks/langsmith.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ export const LangsmithBlock: BlockConfig<LangsmithResponse> = {
199199
switch (params.operation) {
200200
case 'create_runs_batch':
201201
return 'langsmith_create_runs_batch'
202-
case 'create_run':
203202
default:
204203
return 'langsmith_create_run'
205204
}

apps/sim/lib/webhooks/deploy.ts

Lines changed: 91 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { db } from '@sim/db'
22
import { webhook } from '@sim/db/schema'
33
import { createLogger } from '@sim/logger'
4-
import { and, eq } from 'drizzle-orm'
4+
import { eq, inArray } from 'drizzle-orm'
55
import { nanoid } from 'nanoid'
66
import type { NextRequest } from 'next/server'
77
import { getProviderIdFromServiceId } from '@/lib/oauth'
@@ -298,7 +298,7 @@ async function syncCredentialSetWebhooks(params: {
298298
return null
299299
}
300300

301-
async function upsertSingleWebhook(params: {
301+
async function createWebhookForBlock(params: {
302302
request: NextRequest
303303
workflowId: string
304304
workflow: Record<string, unknown>
@@ -321,66 +321,6 @@ async function upsertSingleWebhook(params: {
321321
requestId,
322322
} = params
323323

324-
const existingWebhooks = await db
325-
.select()
326-
.from(webhook)
327-
.where(and(eq(webhook.workflowId, workflowId), eq(webhook.blockId, block.id)))
328-
.limit(1)
329-
330-
const existing = existingWebhooks[0]
331-
if (existing) {
332-
const existingConfig = (existing.providerConfig as Record<string, unknown>) || {}
333-
let nextProviderConfig = providerConfig
334-
335-
if (
336-
shouldRecreateExternalWebhookSubscription({
337-
previousProvider: existing.provider as string,
338-
nextProvider: provider,
339-
previousConfig: existingConfig,
340-
nextConfig: nextProviderConfig,
341-
})
342-
) {
343-
await cleanupExternalWebhook(existing, workflow, requestId)
344-
const result = await createExternalWebhookSubscription(
345-
request,
346-
{
347-
...existing,
348-
provider,
349-
path: triggerPath,
350-
providerConfig: nextProviderConfig,
351-
},
352-
workflow,
353-
userId,
354-
requestId
355-
)
356-
nextProviderConfig = result.updatedProviderConfig as Record<string, unknown>
357-
}
358-
359-
const finalProviderConfig = {
360-
...nextProviderConfig,
361-
credentialId: nextProviderConfig.credentialId ?? existingConfig.credentialId,
362-
credentialSetId: nextProviderConfig.credentialSetId ?? existingConfig.credentialSetId,
363-
userId: nextProviderConfig.userId ?? existingConfig.userId,
364-
historyId: existingConfig.historyId,
365-
lastCheckedTimestamp: existingConfig.lastCheckedTimestamp,
366-
setupCompleted: existingConfig.setupCompleted,
367-
externalId: nextProviderConfig.externalId ?? existingConfig.externalId,
368-
}
369-
370-
await db
371-
.update(webhook)
372-
.set({
373-
path: triggerPath,
374-
provider,
375-
providerConfig: finalProviderConfig,
376-
isActive: true,
377-
updatedAt: new Date(),
378-
})
379-
.where(eq(webhook.id, existing.id))
380-
381-
return null
382-
}
383-
384324
const webhookId = nanoid()
385325
const createPayload = {
386326
id: webhookId,
@@ -434,6 +374,7 @@ async function upsertSingleWebhook(params: {
434374

435375
/**
436376
* Saves trigger webhook configurations as part of workflow deployment.
377+
* Uses delete + create approach for changed/deleted webhooks.
437378
*/
438379
export async function saveTriggerWebhooksForDeploy({
439380
request,
@@ -444,22 +385,31 @@ export async function saveTriggerWebhooksForDeploy({
444385
requestId,
445386
}: SaveTriggerWebhooksInput): Promise<TriggerSaveResult> {
446387
const triggerBlocks = Object.values(blocks || {}).filter(Boolean)
388+
const currentBlockIds = new Set(triggerBlocks.map((b) => b.id))
447389

448-
if (triggerBlocks.length === 0) {
449-
return { success: true }
450-
}
390+
// 1. Get all existing webhooks for this workflow
391+
const existingWebhooks = await db.select().from(webhook).where(eq(webhook.workflowId, workflowId))
392+
393+
const webhooksByBlockId = new Map(
394+
existingWebhooks.filter((wh) => wh.blockId).map((wh) => [wh.blockId!, wh])
395+
)
396+
397+
logger.info(`[${requestId}] Starting webhook sync`, {
398+
workflowId,
399+
currentBlockIds: Array.from(currentBlockIds),
400+
existingWebhookBlockIds: Array.from(webhooksByBlockId.keys()),
401+
})
402+
403+
// 2. Determine which webhooks to delete (orphaned or config changed)
404+
const webhooksToDelete: typeof existingWebhooks = []
405+
const blocksNeedingWebhook: BlockState[] = []
451406

452407
for (const block of triggerBlocks) {
453408
const triggerId = resolveTriggerId(block)
454-
if (!triggerId) continue
455-
456-
if (!isTriggerValid(triggerId)) {
457-
continue
458-
}
409+
if (!triggerId || !isTriggerValid(triggerId)) continue
459410

460411
const triggerDef = getTrigger(triggerId)
461412
const provider = triggerDef.provider
462-
463413
const { providerConfig, missingFields, triggerPath } = buildProviderConfig(
464414
block,
465415
triggerId,
@@ -475,8 +425,69 @@ export async function saveTriggerWebhooksForDeploy({
475425
},
476426
}
477427
}
428+
// Store config for later use
429+
430+
;(block as any)._webhookConfig = { provider, providerConfig, triggerPath, triggerDef }
431+
432+
const existingWh = webhooksByBlockId.get(block.id)
433+
if (!existingWh) {
434+
// No existing webhook - needs creation
435+
blocksNeedingWebhook.push(block)
436+
} else {
437+
// Check if config changed
438+
const existingConfig = (existingWh.providerConfig as Record<string, unknown>) || {}
439+
if (
440+
shouldRecreateExternalWebhookSubscription({
441+
previousProvider: existingWh.provider as string,
442+
nextProvider: provider,
443+
previousConfig: existingConfig,
444+
nextConfig: providerConfig,
445+
})
446+
) {
447+
// Config changed - delete and recreate
448+
webhooksToDelete.push(existingWh)
449+
blocksNeedingWebhook.push(block)
450+
logger.info(`[${requestId}] Webhook config changed for block ${block.id}, will recreate`)
451+
}
452+
// else: config unchanged, keep existing webhook
453+
}
454+
}
455+
456+
// Add orphaned webhooks (block no longer exists)
457+
for (const wh of existingWebhooks) {
458+
if (wh.blockId && !currentBlockIds.has(wh.blockId)) {
459+
webhooksToDelete.push(wh)
460+
logger.info(`[${requestId}] Webhook orphaned (block deleted): ${wh.blockId}`)
461+
}
462+
}
463+
464+
// 3. Delete webhooks that need deletion
465+
if (webhooksToDelete.length > 0) {
466+
logger.info(`[${requestId}] Deleting ${webhooksToDelete.length} webhook(s)`, {
467+
webhookIds: webhooksToDelete.map((wh) => wh.id),
468+
})
469+
470+
for (const wh of webhooksToDelete) {
471+
try {
472+
await cleanupExternalWebhook(wh, workflow, requestId)
473+
} catch (cleanupError) {
474+
logger.warn(`[${requestId}] Failed to cleanup external webhook ${wh.id}`, cleanupError)
475+
}
476+
}
477+
478+
const idsToDelete = webhooksToDelete.map((wh) => wh.id)
479+
await db.delete(webhook).where(inArray(webhook.id, idsToDelete))
480+
}
481+
482+
// 4. Create webhooks for blocks that need them
483+
for (const block of blocksNeedingWebhook) {
484+
const config = (block as any)._webhookConfig
485+
if (!config) continue
486+
487+
const { provider, providerConfig, triggerPath } = config
478488

479489
try {
490+
// Handle credential sets
480491
const credentialSetError = await syncCredentialSetWebhooks({
481492
workflowId,
482493
blockId: block.id,
@@ -494,7 +505,7 @@ export async function saveTriggerWebhooksForDeploy({
494505
continue
495506
}
496507

497-
const upsertError = await upsertSingleWebhook({
508+
const createError = await createWebhookForBlock({
498509
request,
499510
workflowId,
500511
workflow,
@@ -506,11 +517,11 @@ export async function saveTriggerWebhooksForDeploy({
506517
requestId,
507518
})
508519

509-
if (upsertError) {
510-
return { success: false, error: upsertError }
520+
if (createError) {
521+
return { success: false, error: createError }
511522
}
512523
} catch (error: any) {
513-
logger.error(`[${requestId}] Failed to save trigger config for ${block.id}`, error)
524+
logger.error(`[${requestId}] Failed to create webhook for ${block.id}`, error)
514525
return {
515526
success: false,
516527
error: {
@@ -521,5 +532,10 @@ export async function saveTriggerWebhooksForDeploy({
521532
}
522533
}
523534

535+
// Clean up temp config
536+
for (const block of triggerBlocks) {
537+
;(block as any)._webhookConfig = undefined
538+
}
539+
524540
return { success: true }
525541
}

0 commit comments

Comments
 (0)