mirror of
https://github.com/xtr-dev/payload-automation.git
synced 2025-12-10 00:43:23 +00:00
Initial commit
This commit is contained in:
165
src/plugin/init-webhook.ts
Normal file
165
src/plugin/init-webhook.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
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 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) {
|
||||
const conditionMet = executor.evaluateCondition(matchingTrigger.condition, context)
|
||||
|
||||
if (!conditionMet) {
|
||||
logger.info({
|
||||
condition: matchingTrigger.condition,
|
||||
path,
|
||||
workflowId: workflow.id,
|
||||
workflowName: workflow.name
|
||||
}, 'Webhook trigger condition not met, skipping workflow')
|
||||
|
||||
return { status: 'skipped', workflowId: workflow.id, reason: 'Condition not met' }
|
||||
}
|
||||
|
||||
logger.info({
|
||||
condition: matchingTrigger.condition,
|
||||
path,
|
||||
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 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}`)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user