Files
payload-automation/src/plugin/init-webhook.ts
Bas van den Aakster 592536f61a Rename 'collection' field to 'collectionSlug' to avoid PayloadCMS reserved field conflicts
- Updated Workflow collection trigger field from 'collection' to 'collectionSlug'
- Updated all document operation steps (create, read, update, delete) to use 'collectionSlug'
- Updated corresponding handlers to destructure 'collectionSlug' instead of 'collection'
- Removed debug console.log statements from logger configLogger methods
- Fixed collection hook debug logs to use 'slug' instead of reserved 'collection' field

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 17:14:35 +02:00

177 lines
6.1 KiB
TypeScript

import type {Config, PayloadRequest} from 'payload'
import {type Workflow, WorkflowExecutor} from '../core/workflow-executor.js'
import {getConfigLogger, initializeLogger} from './logger.js'
export function initWebhookEndpoint(config: Config, webhookPrefix = 'webhook'): void {
const logger = getConfigLogger()
// Ensure the prefix starts with a slash
const normalizedPrefix = webhookPrefix.startsWith('/') ? webhookPrefix : `/${webhookPrefix}`
logger.debug(`Adding webhook endpoint to config with prefix: ${normalizedPrefix}`)
logger.debug('Current config.endpoints length:', config.endpoints?.length || 0)
// Define webhook endpoint
const webhookEndpoint = {
handler: async (req: PayloadRequest) => {
const {path} = req.routeParams as { path: string }
const webhookData = req.body || {}
logger.debug('Webhook endpoint handler called, path: ' + path)
try {
// Find workflows with matching webhook triggers
const workflows = await req.payload.find({
collection: 'workflows',
depth: 2,
limit: 100,
req,
where: {
'triggers.type': {
equals: 'webhook-trigger'
},
'triggers.webhookPath': {
equals: path
}
}
})
if (workflows.docs.length === 0) {
return new Response(
JSON.stringify({error: 'No workflows found for this webhook path'}),
{
headers: {'Content-Type': 'application/json'},
status: 404
}
)
}
// Create a workflow executor for this request
const logger = initializeLogger(req.payload)
const executor = new WorkflowExecutor(req.payload, logger)
const executionPromises = workflows.docs.map(async (workflow) => {
try {
// Create execution context for the webhook trigger
const context = {
steps: {},
trigger: {
type: 'webhook',
data: webhookData,
headers: Object.fromEntries(req.headers?.entries() || []),
path,
req
}
}
// Find the matching trigger and check its condition if present
const triggers = workflow.triggers as Array<{
condition?: string
type: string
webhookPath?: string
}>
const matchingTrigger = triggers?.find(trigger =>
trigger.type === 'webhook-trigger' &&
trigger.webhookPath === path
)
// Check trigger condition if present
if (matchingTrigger?.condition) {
logger.debug({
condition: matchingTrigger.condition,
path,
webhookData: JSON.stringify(webhookData).substring(0, 200),
headers: Object.keys(context.trigger.headers || {}),
workflowId: workflow.id,
workflowName: workflow.name
}, 'Evaluating webhook trigger condition')
const conditionMet = executor.evaluateCondition(matchingTrigger.condition, context)
if (!conditionMet) {
logger.info({
condition: matchingTrigger.condition,
path,
webhookDataSnapshot: JSON.stringify(webhookData).substring(0, 200),
workflowId: workflow.id,
workflowName: workflow.name
}, 'Webhook trigger condition not met, skipping workflow')
return { reason: 'Condition not met', status: 'skipped', workflowId: workflow.id }
}
logger.info({
condition: matchingTrigger.condition,
path,
webhookDataSnapshot: JSON.stringify(webhookData).substring(0, 200),
workflowId: workflow.id,
workflowName: workflow.name
}, 'Webhook trigger condition met')
}
// Execute the workflow
await executor.execute(workflow as Workflow, context, req)
return { status: 'triggered', workflowId: workflow.id }
} catch (error) {
return {
error: error instanceof Error ? error.message : 'Unknown error',
status: 'failed',
workflowId: workflow.id
}
}
})
const results = await Promise.allSettled(executionPromises)
const resultsData = results.map((result, index) => {
const baseResult = { workflowId: workflows.docs[index].id }
if (result.status === 'fulfilled') {
return { ...baseResult, ...result.value }
} else {
return { ...baseResult, error: result.reason, status: 'failed' }
}
})
return new Response(
JSON.stringify({
message: `Triggered ${workflows.docs.length} workflow(s)`,
results: resultsData
}),
{
headers: { 'Content-Type': 'application/json' },
status: 200
}
)
} catch (error) {
return new Response(
JSON.stringify({
details: error instanceof Error ? error.message : 'Unknown error',
error: 'Failed to process webhook'
}),
{
headers: { 'Content-Type': 'application/json' },
status: 500
}
)
}
},
method: 'post' as const,
path: `${normalizedPrefix}/:path`
}
// Check if the webhook endpoint already exists to avoid duplicates
const existingEndpoint = config.endpoints?.find(endpoint =>
endpoint.path === webhookEndpoint.path && endpoint.method === webhookEndpoint.method
)
if (!existingEndpoint) {
// Combine existing endpoints with the webhook endpoint
config.endpoints = [...(config.endpoints || []), webhookEndpoint]
logger.debug(`Webhook endpoint added at path: ${webhookEndpoint.path}`)
logger.debug('New config.endpoints length:', config.endpoints.length)
} else {
logger.debug(`Webhook endpoint already exists at path: ${webhookEndpoint.path}`)
}
}