( credentialSetId: string, requestId: string )
| 313 | * Must run OUTSIDE any open transaction — see {@link syncWebhooksForCredentialSet}. |
| 314 | */ |
| 315 | export async function syncAllWebhooksForCredentialSet( |
| 316 | credentialSetId: string, |
| 317 | requestId: string |
| 318 | ): Promise<{ workflowsUpdated: number; totalCreated: number; totalDeleted: number }> { |
| 319 | const syncLogger = createLogger('CredentialSetMembershipSync') |
| 320 | syncLogger.info(`[${requestId}] Syncing all webhooks for credential set ${credentialSetId}`) |
| 321 | |
| 322 | const webhooksForSet = await db |
| 323 | .select({ webhook }) |
| 324 | .from(webhook) |
| 325 | .leftJoin( |
| 326 | workflowDeploymentVersion, |
| 327 | and( |
| 328 | eq(workflowDeploymentVersion.workflowId, webhook.workflowId), |
| 329 | eq(workflowDeploymentVersion.isActive, true) |
| 330 | ) |
| 331 | ) |
| 332 | .where( |
| 333 | and( |
| 334 | eq(webhook.credentialSetId, credentialSetId), |
| 335 | isNull(webhook.archivedAt), |
| 336 | or( |
| 337 | eq(webhook.deploymentVersionId, workflowDeploymentVersion.id), |
| 338 | and(isNull(workflowDeploymentVersion.id), isNull(webhook.deploymentVersionId)) |
| 339 | ) |
| 340 | ) |
| 341 | ) |
| 342 | |
| 343 | if (webhooksForSet.length === 0) { |
| 344 | syncLogger.info(`[${requestId}] No webhooks found using credential set ${credentialSetId}`) |
| 345 | return { workflowsUpdated: 0, totalCreated: 0, totalDeleted: 0 } |
| 346 | } |
| 347 | |
| 348 | const triggerGroups = new Map<string, (typeof webhooksForSet)[number]['webhook']>() |
| 349 | for (const row of webhooksForSet) { |
| 350 | const wh = row.webhook |
| 351 | const key = `${wh.workflowId}:${wh.blockId}` |
| 352 | if (!triggerGroups.has(key)) { |
| 353 | triggerGroups.set(key, wh) |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | syncLogger.info( |
| 358 | `[${requestId}] Found ${triggerGroups.size} triggers using credential set ${credentialSetId}` |
| 359 | ) |
| 360 | |
| 361 | let workflowsUpdated = 0 |
| 362 | let totalCreated = 0 |
| 363 | let totalDeleted = 0 |
| 364 | |
| 365 | for (const [key, representativeWebhook] of triggerGroups) { |
| 366 | if (!representativeWebhook.provider) { |
| 367 | syncLogger.warn(`[${requestId}] Skipping webhook without provider: ${key}`) |
| 368 | continue |
| 369 | } |
| 370 | |
| 371 | const config = representativeWebhook.providerConfig as Record<string, unknown> |
| 372 | const oauthProviderId = getProviderIdFromServiceId(representativeWebhook.provider) |
no test coverage detected