({
request,
workflowId,
workflow,
userId,
blocks,
requestId,
deploymentVersionId,
forceRecreateSubscriptions = false,
strictExternalCleanup = false,
}: SaveTriggerWebhooksInput)
| 485 | * Uses delete + create approach for changed/deleted webhooks. |
| 486 | */ |
| 487 | export async function saveTriggerWebhooksForDeploy({ |
| 488 | request, |
| 489 | workflowId, |
| 490 | workflow, |
| 491 | userId, |
| 492 | blocks, |
| 493 | requestId, |
| 494 | deploymentVersionId, |
| 495 | forceRecreateSubscriptions = false, |
| 496 | strictExternalCleanup = false, |
| 497 | }: SaveTriggerWebhooksInput): Promise<TriggerSaveResult> { |
| 498 | const validationResult = await validateTriggerWebhookConfigForDeploy(blocks) |
| 499 | if (!validationResult.success) return validationResult |
| 500 | |
| 501 | const triggerBlocks = Object.values(blocks || {}).filter((b) => b && b.enabled !== false) |
| 502 | const currentBlockIds = new Set(triggerBlocks.map((b) => b.id)) |
| 503 | |
| 504 | // 1. Get ALL webhooks for this workflow (all versions including draft) |
| 505 | const allWorkflowWebhooks = await db |
| 506 | .select() |
| 507 | .from(webhook) |
| 508 | .where(and(eq(webhook.workflowId, workflowId), isNull(webhook.archivedAt))) |
| 509 | |
| 510 | // Separate webhooks by version: current deployment vs others |
| 511 | const existingWebhooks: typeof allWorkflowWebhooks = [] |
| 512 | |
| 513 | for (const wh of allWorkflowWebhooks) { |
| 514 | if (deploymentVersionId && wh.deploymentVersionId === deploymentVersionId) { |
| 515 | existingWebhooks.push(wh) |
| 516 | } |
| 517 | } |
| 518 | |
| 519 | const webhooksByBlockId = new Map<string, typeof existingWebhooks>() |
| 520 | for (const wh of existingWebhooks) { |
| 521 | if (!wh.blockId) continue |
| 522 | const existingForBlock = webhooksByBlockId.get(wh.blockId) ?? [] |
| 523 | existingForBlock.push(wh) |
| 524 | webhooksByBlockId.set(wh.blockId, existingForBlock) |
| 525 | } |
| 526 | |
| 527 | logger.info(`[${requestId}] Starting webhook sync`, { |
| 528 | workflowId, |
| 529 | currentBlockIds: Array.from(currentBlockIds), |
| 530 | existingWebhookBlockIds: Array.from(webhooksByBlockId.keys()), |
| 531 | }) |
| 532 | |
| 533 | type WebhookConfig = { |
| 534 | provider: string |
| 535 | providerConfig: Record<string, unknown> |
| 536 | triggerPath: string |
| 537 | triggerDef: ReturnType<typeof getTrigger> |
| 538 | } |
| 539 | const webhookConfigs = new Map<string, WebhookConfig>() |
| 540 | |
| 541 | const webhooksToDelete: typeof existingWebhooks = [] |
| 542 | const blocksNeedingWebhook: BlockState[] = [] |
| 543 | const blocksNeedingCredentialSetSync: BlockState[] = [] |
| 544 |
no test coverage detected