@xtr-dev/payload-automation 0.0.22 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -2
- package/dist/collections/Workflow.js +12 -2
- package/dist/collections/Workflow.js.map +1 -1
- package/dist/collections/WorkflowRuns.js +14 -7
- package/dist/collections/WorkflowRuns.js.map +1 -1
- package/dist/components/StatusCell.d.ts +6 -0
- package/dist/components/StatusCell.js +75 -0
- package/dist/components/StatusCell.js.map +1 -0
- package/dist/components/WorkflowExecutionStatus.d.ts +6 -0
- package/dist/components/WorkflowExecutionStatus.js +287 -0
- package/dist/components/WorkflowExecutionStatus.js.map +1 -0
- package/dist/core/workflow-executor.d.ts +32 -0
- package/dist/core/workflow-executor.js +162 -7
- package/dist/core/workflow-executor.js.map +1 -1
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.js +4 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/plugin/index.js +131 -42
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/init-step-tasks.js +15 -1
- package/dist/plugin/init-step-tasks.js.map +1 -1
- package/dist/steps/create-document.js +1 -1
- package/dist/steps/create-document.js.map +1 -1
- package/dist/steps/delete-document.js +2 -2
- package/dist/steps/delete-document.js.map +1 -1
- package/dist/steps/http-request-handler.js +229 -10
- package/dist/steps/http-request-handler.js.map +1 -1
- package/dist/steps/http-request.d.ts +147 -4
- package/dist/steps/http-request.js +189 -3
- package/dist/steps/http-request.js.map +1 -1
- package/dist/steps/read-document.js +2 -2
- package/dist/steps/read-document.js.map +1 -1
- package/dist/steps/send-email.js +5 -5
- package/dist/steps/send-email.js.map +1 -1
- package/dist/steps/update-document.js +2 -2
- package/dist/steps/update-document.js.map +1 -1
- package/dist/test/create-document-step.test.js +378 -0
- package/dist/test/create-document-step.test.js.map +1 -0
- package/dist/test/http-request-step.test.js +361 -0
- package/dist/test/http-request-step.test.js.map +1 -0
- package/dist/test/workflow-executor.test.js +530 -0
- package/dist/test/workflow-executor.test.js.map +1 -0
- package/package.json +4 -1
- package/dist/test/basic.test.d.ts +0 -1
package/dist/plugin/index.js
CHANGED
|
@@ -8,19 +8,93 @@ import { initWebhookEndpoint } from "./init-webhook.js";
|
|
|
8
8
|
import { initWorkflowHooks } from './init-workflow-hooks.js';
|
|
9
9
|
import { getConfigLogger, initializeLogger } from './logger.js';
|
|
10
10
|
export { getLogger } from './logger.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
const executorRegistry = {
|
|
12
|
+
executor: null,
|
|
13
|
+
logger: null,
|
|
14
|
+
isInitialized: false
|
|
15
|
+
};
|
|
16
|
+
const setWorkflowExecutor = (executor, logger)=>{
|
|
17
|
+
executorRegistry.executor = executor;
|
|
18
|
+
executorRegistry.logger = logger;
|
|
19
|
+
executorRegistry.isInitialized = true;
|
|
20
|
+
logger.info('Workflow executor initialized and registered successfully');
|
|
21
21
|
};
|
|
22
|
-
const
|
|
23
|
-
return
|
|
22
|
+
const getExecutorRegistry = ()=>{
|
|
23
|
+
return executorRegistry;
|
|
24
|
+
};
|
|
25
|
+
// Helper function to create failed workflow runs for tracking errors
|
|
26
|
+
const createFailedWorkflowRun = async (args, errorMessage, logger)=>{
|
|
27
|
+
try {
|
|
28
|
+
// Only create failed workflow runs if we have enough context
|
|
29
|
+
if (!args?.req?.payload || !args?.collection?.slug) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Find workflows that should have been triggered
|
|
33
|
+
const workflows = await args.req.payload.find({
|
|
34
|
+
collection: 'workflows',
|
|
35
|
+
where: {
|
|
36
|
+
'triggers.type': {
|
|
37
|
+
equals: 'collection-trigger'
|
|
38
|
+
},
|
|
39
|
+
'triggers.collectionSlug': {
|
|
40
|
+
equals: args.collection.slug
|
|
41
|
+
},
|
|
42
|
+
'triggers.operation': {
|
|
43
|
+
equals: args.operation
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
limit: 10,
|
|
47
|
+
req: args.req
|
|
48
|
+
});
|
|
49
|
+
// Create failed workflow runs for each matching workflow
|
|
50
|
+
for (const workflow of workflows.docs){
|
|
51
|
+
await args.req.payload.create({
|
|
52
|
+
collection: 'workflow-runs',
|
|
53
|
+
data: {
|
|
54
|
+
workflow: workflow.id,
|
|
55
|
+
workflowVersion: 1,
|
|
56
|
+
status: 'failed',
|
|
57
|
+
startedAt: new Date().toISOString(),
|
|
58
|
+
completedAt: new Date().toISOString(),
|
|
59
|
+
error: `Hook execution failed: ${errorMessage}`,
|
|
60
|
+
triggeredBy: args?.req?.user?.email || 'system',
|
|
61
|
+
context: {
|
|
62
|
+
trigger: {
|
|
63
|
+
type: 'collection',
|
|
64
|
+
collection: args.collection.slug,
|
|
65
|
+
operation: args.operation,
|
|
66
|
+
doc: args.doc,
|
|
67
|
+
previousDoc: args.previousDoc,
|
|
68
|
+
triggeredAt: new Date().toISOString()
|
|
69
|
+
},
|
|
70
|
+
steps: {}
|
|
71
|
+
},
|
|
72
|
+
inputs: {},
|
|
73
|
+
outputs: {},
|
|
74
|
+
steps: [],
|
|
75
|
+
logs: [
|
|
76
|
+
{
|
|
77
|
+
level: 'error',
|
|
78
|
+
message: `Hook execution failed: ${errorMessage}`,
|
|
79
|
+
timestamp: new Date().toISOString()
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
req: args.req
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (workflows.docs.length > 0) {
|
|
87
|
+
logger.info({
|
|
88
|
+
workflowCount: workflows.docs.length,
|
|
89
|
+
errorMessage
|
|
90
|
+
}, 'Created failed workflow runs for hook execution error');
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
// Don't let workflow run creation failures break the original operation
|
|
94
|
+
logger.warn({
|
|
95
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
96
|
+
}, 'Failed to create failed workflow run record');
|
|
97
|
+
}
|
|
24
98
|
};
|
|
25
99
|
const applyCollectionsConfig = (pluginOptions, config)=>{
|
|
26
100
|
// Add workflow collections
|
|
@@ -58,43 +132,58 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
|
|
|
58
132
|
if (!collection.hooks.afterChange) {
|
|
59
133
|
collection.hooks.afterChange = [];
|
|
60
134
|
}
|
|
61
|
-
// Create a
|
|
62
|
-
// Use a simple function that PayloadCMS can definitely execute
|
|
135
|
+
// Create a reliable hook function with proper dependency injection
|
|
63
136
|
const automationHook = Object.assign(async function payloadAutomationHook(args) {
|
|
137
|
+
const registry = getExecutorRegistry();
|
|
138
|
+
// Use proper logger if available, fallback to args.req.payload.logger
|
|
139
|
+
const logger = registry.logger || args?.req?.payload?.logger || console;
|
|
64
140
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
executor = getWorkflowExecutor();
|
|
141
|
+
logger.info({
|
|
142
|
+
collection: args?.collection?.slug,
|
|
143
|
+
operation: args?.operation,
|
|
144
|
+
docId: args?.doc?.id,
|
|
145
|
+
hookType: 'automation'
|
|
146
|
+
}, 'Collection automation hook triggered');
|
|
147
|
+
if (!registry.isInitialized) {
|
|
148
|
+
logger.warn('Workflow executor not yet initialized, skipping execution');
|
|
149
|
+
return undefined;
|
|
75
150
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (executor) {
|
|
82
|
-
global.console.log('✅ Executor found - executing workflows!');
|
|
83
|
-
await executor.executeTriggeredWorkflows(args.collection.slug, args.operation, args.doc, args.previousDoc, args.req);
|
|
84
|
-
global.console.log('✅ Workflow execution completed!');
|
|
85
|
-
} else {
|
|
86
|
-
global.console.log('⚠️ No executor available');
|
|
151
|
+
if (!registry.executor) {
|
|
152
|
+
logger.error('Workflow executor is null despite being marked as initialized');
|
|
153
|
+
// Create a failed workflow run to track this issue
|
|
154
|
+
await createFailedWorkflowRun(args, 'Executor not available', logger);
|
|
155
|
+
return undefined;
|
|
87
156
|
}
|
|
157
|
+
logger.debug('Executing triggered workflows...');
|
|
158
|
+
await registry.executor.executeTriggeredWorkflows(args.collection.slug, args.operation, args.doc, args.previousDoc, args.req);
|
|
159
|
+
logger.info({
|
|
160
|
+
collection: args?.collection?.slug,
|
|
161
|
+
operation: args?.operation,
|
|
162
|
+
docId: args?.doc?.id
|
|
163
|
+
}, 'Workflow execution completed successfully');
|
|
88
164
|
} catch (error) {
|
|
89
|
-
|
|
90
|
-
|
|
165
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
166
|
+
logger.error({
|
|
167
|
+
error: errorMessage,
|
|
168
|
+
errorStack: error instanceof Error ? error.stack : undefined,
|
|
169
|
+
collection: args?.collection?.slug,
|
|
170
|
+
operation: args?.operation,
|
|
171
|
+
docId: args?.doc?.id
|
|
172
|
+
}, 'Hook execution failed');
|
|
173
|
+
// Create a failed workflow run to track this error
|
|
174
|
+
try {
|
|
175
|
+
await createFailedWorkflowRun(args, errorMessage, logger);
|
|
176
|
+
} catch (createError) {
|
|
177
|
+
logger.error({
|
|
178
|
+
error: createError instanceof Error ? createError.message : 'Unknown error'
|
|
179
|
+
}, 'Failed to create workflow run for hook error');
|
|
180
|
+
}
|
|
181
|
+
// Don't throw to prevent breaking the original operation
|
|
91
182
|
}
|
|
92
|
-
// Always return undefined to match other hooks
|
|
93
183
|
return undefined;
|
|
94
184
|
}, {
|
|
95
|
-
// Add metadata to help debugging
|
|
96
185
|
__isAutomationHook: true,
|
|
97
|
-
__version: '0.0.
|
|
186
|
+
__version: '0.0.22'
|
|
98
187
|
});
|
|
99
188
|
// Add the hook to the collection config
|
|
100
189
|
collection.hooks.afterChange.push(automationHook);
|
|
@@ -139,8 +228,8 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
|
|
|
139
228
|
const executor = new WorkflowExecutor(payload, logger);
|
|
140
229
|
console.log('🚨 EXECUTOR CREATED:', typeof executor);
|
|
141
230
|
console.log('🚨 EXECUTOR METHODS:', Object.getOwnPropertyNames(Object.getPrototypeOf(executor)));
|
|
142
|
-
// Register executor
|
|
143
|
-
setWorkflowExecutor(executor);
|
|
231
|
+
// Register executor with proper dependency injection
|
|
232
|
+
setWorkflowExecutor(executor, logger);
|
|
144
233
|
// Hooks are now registered during config phase - just log status
|
|
145
234
|
logger.info('Hooks were registered during config phase - executor now available');
|
|
146
235
|
logger.info('Initializing global hooks...');
|
package/dist/plugin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugin/index.ts"],"sourcesContent":["import type {Config} from 'payload'\n\nimport type {WorkflowsPluginConfig, CollectionTriggerConfigCrud} from \"./config-types.js\"\n\nimport {createWorkflowCollection} from '../collections/Workflow.js'\nimport {WorkflowRunsCollection} from '../collections/WorkflowRuns.js'\nimport {WorkflowExecutor} from '../core/workflow-executor.js'\nimport {generateCronTasks, registerCronJobs} from './cron-scheduler.js'\nimport {initCollectionHooks} from \"./init-collection-hooks.js\"\nimport {initGlobalHooks} from \"./init-global-hooks.js\"\nimport {initStepTasks} from \"./init-step-tasks.js\"\nimport {initWebhookEndpoint} from \"./init-webhook.js\"\nimport {initWorkflowHooks} from './init-workflow-hooks.js'\nimport {getConfigLogger, initializeLogger} from './logger.js'\n\nexport {getLogger} from './logger.js'\n\n// Global executor registry for config-phase hooks\nlet globalExecutor: WorkflowExecutor | null = null\n\nconst setWorkflowExecutor = (executor: WorkflowExecutor) => {\n console.log('🚨 SETTING GLOBAL EXECUTOR')\n globalExecutor = executor\n \n // Also set on global object as fallback\n if (typeof global !== 'undefined') {\n (global as any).__workflowExecutor = executor\n console.log('🚨 EXECUTOR ALSO SET ON GLOBAL OBJECT')\n }\n}\n\nconst getWorkflowExecutor = (): WorkflowExecutor | null => {\n return globalExecutor\n}\n\nconst applyCollectionsConfig = <T extends string>(pluginOptions: WorkflowsPluginConfig<T>, config: Config) => {\n // Add workflow collections\n if (!config.collections) {\n config.collections = []\n }\n\n config.collections.push(\n createWorkflowCollection(pluginOptions),\n WorkflowRunsCollection\n )\n}\n\n// Removed config-phase hook registration - user collections don't exist during config phase\n\n\nexport const workflowsPlugin =\n <TSlug extends string>(pluginOptions: WorkflowsPluginConfig<TSlug>) =>\n (config: Config): Config => {\n // If the plugin is disabled, return config unchanged\n if (pluginOptions.enabled === false) {\n return config\n }\n\n applyCollectionsConfig<TSlug>(pluginOptions, config)\n \n // CRITICAL: Modify existing collection configs BEFORE PayloadCMS processes them\n // This is the ONLY time we can add hooks that will actually work\n const logger = getConfigLogger()\n logger.info('Attempting to modify collection configs before PayloadCMS initialization...')\n \n if (config.collections && pluginOptions.collectionTriggers) {\n for (const [triggerSlug, triggerConfig] of Object.entries(pluginOptions.collectionTriggers)) {\n if (!triggerConfig) continue\n \n // Find the collection config that matches\n const collectionIndex = config.collections.findIndex(c => c.slug === triggerSlug)\n if (collectionIndex === -1) {\n logger.warn(`Collection '${triggerSlug}' not found in config.collections`)\n continue\n }\n \n const collection = config.collections[collectionIndex]\n logger.info(`Found collection '${triggerSlug}' - modifying its hooks...`)\n \n // Initialize hooks if needed\n if (!collection.hooks) {\n collection.hooks = {}\n }\n if (!collection.hooks.afterChange) {\n collection.hooks.afterChange = []\n }\n \n // Create a properly bound hook function that doesn't rely on closures\n // Use a simple function that PayloadCMS can definitely execute\n const automationHook = Object.assign(\n async function payloadAutomationHook(args: any) {\n try {\n // Use global console to ensure output\n global.console.log('🔥🔥🔥 AUTOMATION HOOK EXECUTED! 🔥🔥🔥')\n global.console.log('Collection:', args?.collection?.slug)\n global.console.log('Operation:', args?.operation)\n global.console.log('Doc ID:', args?.doc?.id)\n \n // Try multiple ways to get the executor\n let executor = null\n \n // Method 1: Global registry\n if (typeof getWorkflowExecutor === 'function') {\n executor = getWorkflowExecutor()\n }\n \n // Method 2: Global variable fallback\n if (!executor && typeof global !== 'undefined' && (global as any).__workflowExecutor) {\n executor = (global as any).__workflowExecutor\n global.console.log('Got executor from global variable')\n }\n \n if (executor) {\n global.console.log('✅ Executor found - executing workflows!')\n await executor.executeTriggeredWorkflows(\n args.collection.slug,\n args.operation,\n args.doc,\n args.previousDoc,\n args.req\n )\n global.console.log('✅ Workflow execution completed!')\n } else {\n global.console.log('⚠️ No executor available')\n }\n } catch (error) {\n global.console.error('❌ Hook execution error:', error)\n // Don't throw - just log\n }\n \n // Always return undefined to match other hooks\n return undefined\n },\n {\n // Add metadata to help debugging\n __isAutomationHook: true,\n __version: '0.0.21'\n }\n )\n \n // Add the hook to the collection config\n collection.hooks.afterChange.push(automationHook)\n logger.info(`Added automation hook to '${triggerSlug}' - hook count: ${collection.hooks.afterChange.length}`)\n }\n }\n\n if (!config.jobs) {\n config.jobs = {tasks: []}\n }\n\n const configLogger = getConfigLogger()\n configLogger.info(`Configuring workflow plugin with ${Object.keys(pluginOptions.collectionTriggers || {}).length} collection triggers`)\n\n // Generate cron tasks for workflows with cron triggers\n generateCronTasks(config)\n\n for (const step of pluginOptions.steps) {\n if (!config.jobs?.tasks?.find(task => task.slug === step.slug)) {\n configLogger.debug(`Registering task: ${step.slug}`)\n config.jobs?.tasks?.push(step)\n } else {\n configLogger.debug(`Task ${step.slug} already registered, skipping`)\n }\n }\n\n // Initialize webhook endpoint\n initWebhookEndpoint(config, pluginOptions.webhookPrefix || 'webhook')\n\n // Set up onInit to register collection hooks and initialize features\n const incomingOnInit = config.onInit\n config.onInit = async (payload) => {\n configLogger.info(`onInit called - collections: ${Object.keys(payload.collections).length}`)\n \n // Execute any existing onInit functions first\n if (incomingOnInit) {\n configLogger.debug('Executing existing onInit function')\n await incomingOnInit(payload)\n }\n\n // Initialize the logger with the payload instance\n const logger = initializeLogger(payload)\n logger.info('Logger initialized with payload instance')\n\n // Log collection trigger configuration\n logger.info(`Plugin configuration: ${Object.keys(pluginOptions.collectionTriggers || {}).length} collection triggers, ${pluginOptions.steps?.length || 0} steps`)\n\n // Create workflow executor instance\n console.log('🚨 CREATING WORKFLOW EXECUTOR INSTANCE')\n const executor = new WorkflowExecutor(payload, logger)\n console.log('🚨 EXECUTOR CREATED:', typeof executor)\n console.log('🚨 EXECUTOR METHODS:', Object.getOwnPropertyNames(Object.getPrototypeOf(executor)))\n \n // Register executor globally\n setWorkflowExecutor(executor)\n\n // Hooks are now registered during config phase - just log status\n logger.info('Hooks were registered during config phase - executor now available')\n \n logger.info('Initializing global hooks...')\n initGlobalHooks(payload, logger, executor)\n \n logger.info('Initializing workflow hooks...')\n initWorkflowHooks(payload, logger)\n \n logger.info('Initializing step tasks...')\n initStepTasks(pluginOptions, payload, logger)\n\n // Register cron jobs for workflows with cron triggers\n logger.info('Registering cron jobs...')\n await registerCronJobs(payload, logger)\n\n logger.info('Plugin initialized successfully - all hooks registered')\n }\n\n return config\n }\n"],"names":["createWorkflowCollection","WorkflowRunsCollection","WorkflowExecutor","generateCronTasks","registerCronJobs","initGlobalHooks","initStepTasks","initWebhookEndpoint","initWorkflowHooks","getConfigLogger","initializeLogger","getLogger","globalExecutor","setWorkflowExecutor","executor","console","log","global","__workflowExecutor","getWorkflowExecutor","applyCollectionsConfig","pluginOptions","config","collections","push","workflowsPlugin","enabled","logger","info","collectionTriggers","triggerSlug","triggerConfig","Object","entries","collectionIndex","findIndex","c","slug","warn","collection","hooks","afterChange","automationHook","assign","payloadAutomationHook","args","operation","doc","id","executeTriggeredWorkflows","previousDoc","req","error","undefined","__isAutomationHook","__version","length","jobs","tasks","configLogger","keys","step","steps","find","task","debug","webhookPrefix","incomingOnInit","onInit","payload","getOwnPropertyNames","getPrototypeOf"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/index.ts"],"sourcesContent":["import type {Config} from 'payload'\n\nimport type {WorkflowsPluginConfig, CollectionTriggerConfigCrud} from \"./config-types.js\"\n\nimport {createWorkflowCollection} from '../collections/Workflow.js'\nimport {WorkflowRunsCollection} from '../collections/WorkflowRuns.js'\nimport {WorkflowExecutor} from '../core/workflow-executor.js'\nimport {generateCronTasks, registerCronJobs} from './cron-scheduler.js'\nimport {initCollectionHooks} from \"./init-collection-hooks.js\"\nimport {initGlobalHooks} from \"./init-global-hooks.js\"\nimport {initStepTasks} from \"./init-step-tasks.js\"\nimport {initWebhookEndpoint} from \"./init-webhook.js\"\nimport {initWorkflowHooks} from './init-workflow-hooks.js'\nimport {getConfigLogger, initializeLogger} from './logger.js'\n\nexport {getLogger} from './logger.js'\n\n// Improved executor registry with proper error handling and logging\ninterface ExecutorRegistry {\n executor: WorkflowExecutor | null\n logger: any | null\n isInitialized: boolean\n}\n\nconst executorRegistry: ExecutorRegistry = {\n executor: null,\n logger: null,\n isInitialized: false\n}\n\nconst setWorkflowExecutor = (executor: WorkflowExecutor, logger: any) => {\n executorRegistry.executor = executor\n executorRegistry.logger = logger\n executorRegistry.isInitialized = true\n \n logger.info('Workflow executor initialized and registered successfully')\n}\n\nconst getExecutorRegistry = (): ExecutorRegistry => {\n return executorRegistry\n}\n\n// Helper function to create failed workflow runs for tracking errors\nconst createFailedWorkflowRun = async (args: any, errorMessage: string, logger: any) => {\n try {\n // Only create failed workflow runs if we have enough context\n if (!args?.req?.payload || !args?.collection?.slug) {\n return\n }\n \n // Find workflows that should have been triggered\n const workflows = await args.req.payload.find({\n collection: 'workflows',\n where: {\n 'triggers.type': {\n equals: 'collection-trigger'\n },\n 'triggers.collectionSlug': {\n equals: args.collection.slug\n },\n 'triggers.operation': {\n equals: args.operation\n }\n },\n limit: 10,\n req: args.req\n })\n \n // Create failed workflow runs for each matching workflow\n for (const workflow of workflows.docs) {\n await args.req.payload.create({\n collection: 'workflow-runs',\n data: {\n workflow: workflow.id,\n workflowVersion: 1,\n status: 'failed',\n startedAt: new Date().toISOString(),\n completedAt: new Date().toISOString(),\n error: `Hook execution failed: ${errorMessage}`,\n triggeredBy: args?.req?.user?.email || 'system',\n context: {\n trigger: {\n type: 'collection',\n collection: args.collection.slug,\n operation: args.operation,\n doc: args.doc,\n previousDoc: args.previousDoc,\n triggeredAt: new Date().toISOString()\n },\n steps: {}\n },\n inputs: {},\n outputs: {},\n steps: [],\n logs: [{\n level: 'error',\n message: `Hook execution failed: ${errorMessage}`,\n timestamp: new Date().toISOString()\n }]\n },\n req: args.req\n })\n }\n \n if (workflows.docs.length > 0) {\n logger.info({\n workflowCount: workflows.docs.length,\n errorMessage\n }, 'Created failed workflow runs for hook execution error')\n }\n \n } catch (error) {\n // Don't let workflow run creation failures break the original operation\n logger.warn({\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to create failed workflow run record')\n }\n}\n\nconst applyCollectionsConfig = <T extends string>(pluginOptions: WorkflowsPluginConfig<T>, config: Config) => {\n // Add workflow collections\n if (!config.collections) {\n config.collections = []\n }\n\n config.collections.push(\n createWorkflowCollection(pluginOptions),\n WorkflowRunsCollection\n )\n}\n\n// Removed config-phase hook registration - user collections don't exist during config phase\n\n\nexport const workflowsPlugin =\n <TSlug extends string>(pluginOptions: WorkflowsPluginConfig<TSlug>) =>\n (config: Config): Config => {\n // If the plugin is disabled, return config unchanged\n if (pluginOptions.enabled === false) {\n return config\n }\n\n applyCollectionsConfig<TSlug>(pluginOptions, config)\n \n // CRITICAL: Modify existing collection configs BEFORE PayloadCMS processes them\n // This is the ONLY time we can add hooks that will actually work\n const logger = getConfigLogger()\n logger.info('Attempting to modify collection configs before PayloadCMS initialization...')\n \n if (config.collections && pluginOptions.collectionTriggers) {\n for (const [triggerSlug, triggerConfig] of Object.entries(pluginOptions.collectionTriggers)) {\n if (!triggerConfig) continue\n \n // Find the collection config that matches\n const collectionIndex = config.collections.findIndex(c => c.slug === triggerSlug)\n if (collectionIndex === -1) {\n logger.warn(`Collection '${triggerSlug}' not found in config.collections`)\n continue\n }\n \n const collection = config.collections[collectionIndex]\n logger.info(`Found collection '${triggerSlug}' - modifying its hooks...`)\n \n // Initialize hooks if needed\n if (!collection.hooks) {\n collection.hooks = {}\n }\n if (!collection.hooks.afterChange) {\n collection.hooks.afterChange = []\n }\n \n // Create a reliable hook function with proper dependency injection\n const automationHook = Object.assign(\n async function payloadAutomationHook(args: any) {\n const registry = getExecutorRegistry()\n \n // Use proper logger if available, fallback to args.req.payload.logger\n const logger = registry.logger || args?.req?.payload?.logger || console\n \n try {\n logger.info({\n collection: args?.collection?.slug,\n operation: args?.operation,\n docId: args?.doc?.id,\n hookType: 'automation'\n }, 'Collection automation hook triggered')\n \n if (!registry.isInitialized) {\n logger.warn('Workflow executor not yet initialized, skipping execution')\n return undefined\n }\n \n if (!registry.executor) {\n logger.error('Workflow executor is null despite being marked as initialized')\n // Create a failed workflow run to track this issue\n await createFailedWorkflowRun(args, 'Executor not available', logger)\n return undefined\n }\n \n logger.debug('Executing triggered workflows...')\n await registry.executor.executeTriggeredWorkflows(\n args.collection.slug,\n args.operation,\n args.doc,\n args.previousDoc,\n args.req\n )\n \n logger.info({\n collection: args?.collection?.slug,\n operation: args?.operation,\n docId: args?.doc?.id\n }, 'Workflow execution completed successfully')\n \n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n \n logger.error({\n error: errorMessage,\n errorStack: error instanceof Error ? error.stack : undefined,\n collection: args?.collection?.slug,\n operation: args?.operation,\n docId: args?.doc?.id\n }, 'Hook execution failed')\n \n // Create a failed workflow run to track this error\n try {\n await createFailedWorkflowRun(args, errorMessage, logger)\n } catch (createError) {\n logger.error({\n error: createError instanceof Error ? createError.message : 'Unknown error'\n }, 'Failed to create workflow run for hook error')\n }\n \n // Don't throw to prevent breaking the original operation\n }\n \n return undefined\n },\n {\n __isAutomationHook: true,\n __version: '0.0.22'\n }\n )\n \n // Add the hook to the collection config\n collection.hooks.afterChange.push(automationHook)\n logger.info(`Added automation hook to '${triggerSlug}' - hook count: ${collection.hooks.afterChange.length}`)\n }\n }\n\n if (!config.jobs) {\n config.jobs = {tasks: []}\n }\n\n const configLogger = getConfigLogger()\n configLogger.info(`Configuring workflow plugin with ${Object.keys(pluginOptions.collectionTriggers || {}).length} collection triggers`)\n\n // Generate cron tasks for workflows with cron triggers\n generateCronTasks(config)\n\n for (const step of pluginOptions.steps) {\n if (!config.jobs?.tasks?.find(task => task.slug === step.slug)) {\n configLogger.debug(`Registering task: ${step.slug}`)\n config.jobs?.tasks?.push(step)\n } else {\n configLogger.debug(`Task ${step.slug} already registered, skipping`)\n }\n }\n\n // Initialize webhook endpoint\n initWebhookEndpoint(config, pluginOptions.webhookPrefix || 'webhook')\n\n // Set up onInit to register collection hooks and initialize features\n const incomingOnInit = config.onInit\n config.onInit = async (payload) => {\n configLogger.info(`onInit called - collections: ${Object.keys(payload.collections).length}`)\n \n // Execute any existing onInit functions first\n if (incomingOnInit) {\n configLogger.debug('Executing existing onInit function')\n await incomingOnInit(payload)\n }\n\n // Initialize the logger with the payload instance\n const logger = initializeLogger(payload)\n logger.info('Logger initialized with payload instance')\n\n // Log collection trigger configuration\n logger.info(`Plugin configuration: ${Object.keys(pluginOptions.collectionTriggers || {}).length} collection triggers, ${pluginOptions.steps?.length || 0} steps`)\n\n // Create workflow executor instance\n console.log('🚨 CREATING WORKFLOW EXECUTOR INSTANCE')\n const executor = new WorkflowExecutor(payload, logger)\n console.log('🚨 EXECUTOR CREATED:', typeof executor)\n console.log('🚨 EXECUTOR METHODS:', Object.getOwnPropertyNames(Object.getPrototypeOf(executor)))\n \n // Register executor with proper dependency injection\n setWorkflowExecutor(executor, logger)\n\n // Hooks are now registered during config phase - just log status\n logger.info('Hooks were registered during config phase - executor now available')\n \n logger.info('Initializing global hooks...')\n initGlobalHooks(payload, logger, executor)\n \n logger.info('Initializing workflow hooks...')\n initWorkflowHooks(payload, logger)\n \n logger.info('Initializing step tasks...')\n initStepTasks(pluginOptions, payload, logger)\n\n // Register cron jobs for workflows with cron triggers\n logger.info('Registering cron jobs...')\n await registerCronJobs(payload, logger)\n\n logger.info('Plugin initialized successfully - all hooks registered')\n }\n\n return config\n }\n"],"names":["createWorkflowCollection","WorkflowRunsCollection","WorkflowExecutor","generateCronTasks","registerCronJobs","initGlobalHooks","initStepTasks","initWebhookEndpoint","initWorkflowHooks","getConfigLogger","initializeLogger","getLogger","executorRegistry","executor","logger","isInitialized","setWorkflowExecutor","info","getExecutorRegistry","createFailedWorkflowRun","args","errorMessage","req","payload","collection","slug","workflows","find","where","equals","operation","limit","workflow","docs","create","data","id","workflowVersion","status","startedAt","Date","toISOString","completedAt","error","triggeredBy","user","email","context","trigger","type","doc","previousDoc","triggeredAt","steps","inputs","outputs","logs","level","message","timestamp","length","workflowCount","warn","Error","applyCollectionsConfig","pluginOptions","config","collections","push","workflowsPlugin","enabled","collectionTriggers","triggerSlug","triggerConfig","Object","entries","collectionIndex","findIndex","c","hooks","afterChange","automationHook","assign","payloadAutomationHook","registry","console","docId","hookType","undefined","debug","executeTriggeredWorkflows","errorStack","stack","createError","__isAutomationHook","__version","jobs","tasks","configLogger","keys","step","task","webhookPrefix","incomingOnInit","onInit","log","getOwnPropertyNames","getPrototypeOf"],"mappings":"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"}
|
|
@@ -2,7 +2,21 @@ export function initStepTasks(pluginOptions, payload, logger) {
|
|
|
2
2
|
logger.info({
|
|
3
3
|
stepCount: pluginOptions.steps.length,
|
|
4
4
|
steps: pluginOptions.steps.map((s)=>s.slug)
|
|
5
|
-
}, '
|
|
5
|
+
}, 'Step tasks were registered during config phase');
|
|
6
|
+
// Verify that the tasks are available in the job system
|
|
7
|
+
const availableTasks = payload.config.jobs?.tasks?.map((t)=>t.slug) || [];
|
|
8
|
+
const pluginTasks = pluginOptions.steps.map((s)=>s.slug);
|
|
9
|
+
pluginTasks.forEach((taskSlug)=>{
|
|
10
|
+
if (availableTasks.includes(taskSlug)) {
|
|
11
|
+
logger.info({
|
|
12
|
+
taskSlug
|
|
13
|
+
}, 'Step task confirmed available in job system');
|
|
14
|
+
} else {
|
|
15
|
+
logger.error({
|
|
16
|
+
taskSlug
|
|
17
|
+
}, 'Step task not found in job system - this will cause execution failures');
|
|
18
|
+
}
|
|
19
|
+
});
|
|
6
20
|
}
|
|
7
21
|
|
|
8
22
|
//# sourceMappingURL=init-step-tasks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugin/init-step-tasks.ts"],"sourcesContent":["import type {Payload} from \"payload\"\nimport type {Logger} from \"pino\"\n\nimport type {WorkflowsPluginConfig} from \"./config-types.js\"\n\nexport function initStepTasks<T extends string>(pluginOptions: WorkflowsPluginConfig<T>, payload: Payload, logger: Payload['logger']) {\n logger.info({ stepCount: pluginOptions.steps.length, steps: pluginOptions.steps.map(s => s.slug) }, '
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/init-step-tasks.ts"],"sourcesContent":["import type {Payload} from \"payload\"\nimport type {Logger} from \"pino\"\n\nimport type {WorkflowsPluginConfig} from \"./config-types.js\"\n\nexport function initStepTasks<T extends string>(pluginOptions: WorkflowsPluginConfig<T>, payload: Payload, logger: Payload['logger']) {\n logger.info({ stepCount: pluginOptions.steps.length, steps: pluginOptions.steps.map(s => s.slug) }, 'Step tasks were registered during config phase')\n\n // Verify that the tasks are available in the job system\n const availableTasks = payload.config.jobs?.tasks?.map(t => t.slug) || []\n const pluginTasks = pluginOptions.steps.map(s => s.slug)\n \n pluginTasks.forEach(taskSlug => {\n if (availableTasks.includes(taskSlug)) {\n logger.info({ taskSlug }, 'Step task confirmed available in job system')\n } else {\n logger.error({ taskSlug }, 'Step task not found in job system - this will cause execution failures')\n }\n })\n}\n"],"names":["initStepTasks","pluginOptions","payload","logger","info","stepCount","steps","length","map","s","slug","availableTasks","config","jobs","tasks","t","pluginTasks","forEach","taskSlug","includes","error"],"mappings":"AAKA,OAAO,SAASA,cAAgCC,aAAuC,EAAEC,OAAgB,EAAEC,MAAyB;IAClIA,OAAOC,IAAI,CAAC;QAAEC,WAAWJ,cAAcK,KAAK,CAACC,MAAM;QAAED,OAAOL,cAAcK,KAAK,CAACE,GAAG,CAACC,CAAAA,IAAKA,EAAEC,IAAI;IAAE,GAAG;IAEpG,wDAAwD;IACxD,MAAMC,iBAAiBT,QAAQU,MAAM,CAACC,IAAI,EAAEC,OAAON,IAAIO,CAAAA,IAAKA,EAAEL,IAAI,KAAK,EAAE;IACzE,MAAMM,cAAcf,cAAcK,KAAK,CAACE,GAAG,CAACC,CAAAA,IAAKA,EAAEC,IAAI;IAEvDM,YAAYC,OAAO,CAACC,CAAAA;QAClB,IAAIP,eAAeQ,QAAQ,CAACD,WAAW;YACrCf,OAAOC,IAAI,CAAC;gBAAEc;YAAS,GAAG;QAC5B,OAAO;YACLf,OAAOiB,KAAK,CAAC;gBAAEF;YAAS,GAAG;QAC7B;IACF;AACF"}
|
|
@@ -15,7 +15,7 @@ export const CreateDocumentStepTask = {
|
|
|
15
15
|
name: 'data',
|
|
16
16
|
type: 'json',
|
|
17
17
|
admin: {
|
|
18
|
-
description: 'The document data to create'
|
|
18
|
+
description: 'The document data to create. Use JSONPath to reference trigger data (e.g., {"title": "$.trigger.doc.title", "author": "$.trigger.doc.author"})'
|
|
19
19
|
},
|
|
20
20
|
required: true
|
|
21
21
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/steps/create-document.ts"],"sourcesContent":["import type { TaskConfig } from \"payload\"\n\nimport { createDocumentHandler } from \"./create-document-handler.js\"\n\nexport const CreateDocumentStepTask = {\n slug: 'create-document',\n handler: createDocumentHandler,\n inputSchema: [\n {\n name: 'collectionSlug',\n type: 'text',\n admin: {\n description: 'The collection slug to create a document in'\n },\n required: true\n },\n {\n name: 'data',\n type: 'json',\n admin: {\n description: 'The document data to create'\n },\n required: true\n },\n {\n name: 'draft',\n type: 'checkbox',\n admin: {\n description: 'Create as draft (if collection has drafts enabled)'\n }\n },\n {\n name: 'locale',\n type: 'text',\n admin: {\n description: 'Locale for the document (if localization is enabled)'\n }\n }\n ],\n outputSchema: [\n {\n name: 'doc',\n type: 'json',\n admin: {\n description: 'The created document'\n }\n },\n {\n name: 'id',\n type: 'text',\n admin: {\n description: 'The ID of the created document'\n }\n }\n ]\n} satisfies TaskConfig<'create-document'>"],"names":["createDocumentHandler","CreateDocumentStepTask","slug","handler","inputSchema","name","type","admin","description","required","outputSchema"],"mappings":"AAEA,SAASA,qBAAqB,QAAQ,+BAA8B;AAEpE,OAAO,MAAMC,yBAAyB;IACpCC,MAAM;IACNC,SAASH;IACTI,aAAa;QACX;YACEC,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAC,UAAU;QACZ;QACA;YACEJ,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAC,UAAU;QACZ;QACA;YACEJ,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;KACD;IACDE,cAAc;QACZ;YACEL,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;KACD;AACH,EAAyC"}
|
|
1
|
+
{"version":3,"sources":["../../src/steps/create-document.ts"],"sourcesContent":["import type { TaskConfig } from \"payload\"\n\nimport { createDocumentHandler } from \"./create-document-handler.js\"\n\nexport const CreateDocumentStepTask = {\n slug: 'create-document',\n handler: createDocumentHandler,\n inputSchema: [\n {\n name: 'collectionSlug',\n type: 'text',\n admin: {\n description: 'The collection slug to create a document in'\n },\n required: true\n },\n {\n name: 'data',\n type: 'json',\n admin: {\n description: 'The document data to create. Use JSONPath to reference trigger data (e.g., {\"title\": \"$.trigger.doc.title\", \"author\": \"$.trigger.doc.author\"})'\n },\n required: true\n },\n {\n name: 'draft',\n type: 'checkbox',\n admin: {\n description: 'Create as draft (if collection has drafts enabled)'\n }\n },\n {\n name: 'locale',\n type: 'text',\n admin: {\n description: 'Locale for the document (if localization is enabled)'\n }\n }\n ],\n outputSchema: [\n {\n name: 'doc',\n type: 'json',\n admin: {\n description: 'The created document'\n }\n },\n {\n name: 'id',\n type: 'text',\n admin: {\n description: 'The ID of the created document'\n }\n }\n ]\n} satisfies TaskConfig<'create-document'>"],"names":["createDocumentHandler","CreateDocumentStepTask","slug","handler","inputSchema","name","type","admin","description","required","outputSchema"],"mappings":"AAEA,SAASA,qBAAqB,QAAQ,+BAA8B;AAEpE,OAAO,MAAMC,yBAAyB;IACpCC,MAAM;IACNC,SAASH;IACTI,aAAa;QACX;YACEC,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAC,UAAU;QACZ;QACA;YACEJ,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAC,UAAU;QACZ;QACA;YACEJ,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;KACD;IACDE,cAAc;QACZ;YACEL,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;KACD;AACH,EAAyC"}
|
|
@@ -15,14 +15,14 @@ export const DeleteDocumentStepTask = {
|
|
|
15
15
|
name: 'id',
|
|
16
16
|
type: 'text',
|
|
17
17
|
admin: {
|
|
18
|
-
description: 'The ID of a specific document to delete (
|
|
18
|
+
description: 'The ID of a specific document to delete. Use JSONPath (e.g., "$.trigger.doc.id"). Leave empty to delete multiple.'
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
name: 'where',
|
|
23
23
|
type: 'json',
|
|
24
24
|
admin: {
|
|
25
|
-
description: 'Query conditions to find documents to delete
|
|
25
|
+
description: 'Query conditions to find documents to delete when ID is not provided. Use JSONPath in values (e.g., {"author": "$.trigger.doc.author"})'
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/steps/delete-document.ts"],"sourcesContent":["import type { TaskConfig } from \"payload\"\n\nimport { deleteDocumentHandler } from \"./delete-document-handler.js\"\n\nexport const DeleteDocumentStepTask = {\n slug: 'delete-document',\n handler: deleteDocumentHandler,\n inputSchema: [\n {\n name: 'collectionSlug',\n type: 'text',\n admin: {\n description: 'The collection slug to delete from'\n },\n required: true\n },\n {\n name: 'id',\n type: 'text',\n admin: {\n description: 'The ID of a specific document to delete (
|
|
1
|
+
{"version":3,"sources":["../../src/steps/delete-document.ts"],"sourcesContent":["import type { TaskConfig } from \"payload\"\n\nimport { deleteDocumentHandler } from \"./delete-document-handler.js\"\n\nexport const DeleteDocumentStepTask = {\n slug: 'delete-document',\n handler: deleteDocumentHandler,\n inputSchema: [\n {\n name: 'collectionSlug',\n type: 'text',\n admin: {\n description: 'The collection slug to delete from'\n },\n required: true\n },\n {\n name: 'id',\n type: 'text',\n admin: {\n description: 'The ID of a specific document to delete. Use JSONPath (e.g., \"$.trigger.doc.id\"). Leave empty to delete multiple.'\n }\n },\n {\n name: 'where',\n type: 'json',\n admin: {\n description: 'Query conditions to find documents to delete when ID is not provided. Use JSONPath in values (e.g., {\"author\": \"$.trigger.doc.author\"})'\n }\n }\n ],\n outputSchema: [\n {\n name: 'doc',\n type: 'json',\n admin: {\n description: 'The deleted document(s)'\n }\n },\n {\n name: 'deletedCount',\n type: 'number',\n admin: {\n description: 'Number of documents deleted'\n }\n }\n ]\n} satisfies TaskConfig<'delete-document'>"],"names":["deleteDocumentHandler","DeleteDocumentStepTask","slug","handler","inputSchema","name","type","admin","description","required","outputSchema"],"mappings":"AAEA,SAASA,qBAAqB,QAAQ,+BAA8B;AAEpE,OAAO,MAAMC,yBAAyB;IACpCC,MAAM;IACNC,SAASH;IACTI,aAAa;QACX;YACEC,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAC,UAAU;QACZ;QACA;YACEJ,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;KACD;IACDE,cAAc;QACZ;YACEL,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;QACF;KACD;AACH,EAAyC"}
|
|
@@ -1,14 +1,233 @@
|
|
|
1
|
-
export const httpStepHandler = async ({ input })=>{
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export const httpStepHandler = async ({ input, req })=>{
|
|
2
|
+
const startTime = Date.now() // Move startTime to outer scope
|
|
3
|
+
;
|
|
4
|
+
try {
|
|
5
|
+
if (!input || !input.url) {
|
|
6
|
+
return {
|
|
7
|
+
output: {
|
|
8
|
+
status: 0,
|
|
9
|
+
statusText: 'Invalid Input',
|
|
10
|
+
headers: {},
|
|
11
|
+
body: '',
|
|
12
|
+
data: null,
|
|
13
|
+
duration: 0,
|
|
14
|
+
error: 'URL is required for HTTP request'
|
|
15
|
+
},
|
|
16
|
+
state: 'failed'
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const typedInput = input;
|
|
20
|
+
// Validate URL
|
|
21
|
+
try {
|
|
22
|
+
new URL(typedInput.url);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
return {
|
|
25
|
+
output: {
|
|
26
|
+
status: 0,
|
|
27
|
+
statusText: 'Invalid URL',
|
|
28
|
+
headers: {},
|
|
29
|
+
body: '',
|
|
30
|
+
data: null,
|
|
31
|
+
duration: 0,
|
|
32
|
+
error: `Invalid URL: ${typedInput.url}`
|
|
33
|
+
},
|
|
34
|
+
state: 'failed'
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// Prepare request options
|
|
38
|
+
const method = (typedInput.method || 'GET').toUpperCase();
|
|
39
|
+
const timeout = typedInput.timeout || 30000;
|
|
40
|
+
const headers = {
|
|
41
|
+
'User-Agent': 'PayloadCMS-Automation/1.0',
|
|
42
|
+
...typedInput.headers
|
|
43
|
+
};
|
|
44
|
+
// Handle authentication
|
|
45
|
+
if (typedInput.authentication) {
|
|
46
|
+
switch(typedInput.authentication.type){
|
|
47
|
+
case 'bearer':
|
|
48
|
+
if (typedInput.authentication.token) {
|
|
49
|
+
headers['Authorization'] = `Bearer ${typedInput.authentication.token}`;
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case 'basic':
|
|
53
|
+
if (typedInput.authentication.username && typedInput.authentication.password) {
|
|
54
|
+
const credentials = btoa(`${typedInput.authentication.username}:${typedInput.authentication.password}`);
|
|
55
|
+
headers['Authorization'] = `Basic ${credentials}`;
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
case 'apikey':
|
|
59
|
+
if (typedInput.authentication.headerName && typedInput.authentication.headerValue) {
|
|
60
|
+
headers[typedInput.authentication.headerName] = typedInput.authentication.headerValue;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Prepare request body
|
|
66
|
+
let requestBody;
|
|
67
|
+
if ([
|
|
68
|
+
'POST',
|
|
69
|
+
'PUT',
|
|
70
|
+
'PATCH'
|
|
71
|
+
].includes(method) && typedInput.body) {
|
|
72
|
+
if (typeof typedInput.body === 'string') {
|
|
73
|
+
requestBody = typedInput.body;
|
|
74
|
+
} else {
|
|
75
|
+
requestBody = JSON.stringify(typedInput.body);
|
|
76
|
+
if (!headers['Content-Type']) {
|
|
77
|
+
headers['Content-Type'] = 'application/json';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Create abort controller for timeout
|
|
82
|
+
const abortController = new AbortController();
|
|
83
|
+
const timeoutId = setTimeout(()=>abortController.abort(), timeout);
|
|
84
|
+
// Retry logic
|
|
85
|
+
const maxRetries = Math.min(Math.max(typedInput.retries || 0, 0), 5);
|
|
86
|
+
const retryDelay = Math.max(typedInput.retryDelay || 1000, 100);
|
|
87
|
+
let lastError = null;
|
|
88
|
+
for(let attempt = 0; attempt <= maxRetries; attempt++){
|
|
89
|
+
try {
|
|
90
|
+
// Add delay for retry attempts
|
|
91
|
+
if (attempt > 0) {
|
|
92
|
+
req?.payload?.logger?.info({
|
|
93
|
+
attempt: attempt + 1,
|
|
94
|
+
maxRetries: maxRetries + 1,
|
|
95
|
+
url: typedInput.url,
|
|
96
|
+
delay: retryDelay
|
|
97
|
+
}, 'HTTP request retry attempt');
|
|
98
|
+
await new Promise((resolve)=>setTimeout(resolve, retryDelay));
|
|
99
|
+
}
|
|
100
|
+
const response = await fetch(typedInput.url, {
|
|
101
|
+
method,
|
|
102
|
+
headers,
|
|
103
|
+
body: requestBody,
|
|
104
|
+
signal: abortController.signal
|
|
105
|
+
});
|
|
106
|
+
clearTimeout(timeoutId);
|
|
107
|
+
const duration = Date.now() - startTime;
|
|
108
|
+
// Parse response
|
|
109
|
+
const responseText = await response.text();
|
|
110
|
+
let parsedData = null;
|
|
111
|
+
try {
|
|
112
|
+
const contentType = response.headers.get('content-type') || '';
|
|
113
|
+
if (contentType.includes('application/json') || contentType.includes('text/json')) {
|
|
114
|
+
parsedData = JSON.parse(responseText);
|
|
115
|
+
}
|
|
116
|
+
} catch (parseError) {
|
|
117
|
+
// Not JSON, that's fine
|
|
118
|
+
}
|
|
119
|
+
// Convert headers to plain object
|
|
120
|
+
const responseHeaders = {};
|
|
121
|
+
response.headers.forEach((value, key)=>{
|
|
122
|
+
responseHeaders[key] = value;
|
|
123
|
+
});
|
|
124
|
+
const output = {
|
|
125
|
+
status: response.status,
|
|
126
|
+
statusText: response.statusText,
|
|
127
|
+
headers: responseHeaders,
|
|
128
|
+
body: responseText,
|
|
129
|
+
data: parsedData,
|
|
130
|
+
duration
|
|
131
|
+
};
|
|
132
|
+
req?.payload?.logger?.info({
|
|
133
|
+
url: typedInput.url,
|
|
134
|
+
method,
|
|
135
|
+
status: response.status,
|
|
136
|
+
duration,
|
|
137
|
+
attempt: attempt + 1
|
|
138
|
+
}, 'HTTP request completed');
|
|
139
|
+
return {
|
|
140
|
+
output,
|
|
141
|
+
// Always return 'succeeded' for completed HTTP requests, even with error status codes (4xx/5xx).
|
|
142
|
+
// This preserves error information in the output for workflow conditional logic.
|
|
143
|
+
// Only network errors, timeouts, and connection failures should result in 'failed' state.
|
|
144
|
+
// This design allows workflows to handle HTTP errors gracefully rather than failing completely.
|
|
145
|
+
state: 'succeeded'
|
|
146
|
+
};
|
|
147
|
+
} catch (error) {
|
|
148
|
+
lastError = error instanceof Error ? error : new Error('Unknown error');
|
|
149
|
+
// Handle specific error types
|
|
150
|
+
if (error instanceof Error) {
|
|
151
|
+
if (error.name === 'AbortError') {
|
|
152
|
+
lastError = new Error(`Request timeout after ${timeout}ms`);
|
|
153
|
+
} else if (error.message.includes('fetch')) {
|
|
154
|
+
lastError = new Error(`Network error: ${error.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
req?.payload?.logger?.warn({
|
|
158
|
+
url: typedInput.url,
|
|
159
|
+
method,
|
|
160
|
+
attempt: attempt + 1,
|
|
161
|
+
maxRetries: maxRetries + 1,
|
|
162
|
+
error: lastError.message
|
|
163
|
+
}, 'HTTP request attempt failed');
|
|
164
|
+
// Don't retry on certain errors
|
|
165
|
+
if (lastError.message.includes('Invalid URL') || lastError.message.includes('TypeError') || attempt >= maxRetries) {
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
clearTimeout(timeoutId);
|
|
171
|
+
const duration = Date.now() - startTime;
|
|
172
|
+
// All retries exhausted
|
|
173
|
+
const finalError = lastError || new Error('HTTP request failed');
|
|
174
|
+
req?.payload?.logger?.error({
|
|
175
|
+
url: typedInput.url,
|
|
176
|
+
method,
|
|
177
|
+
totalAttempts: maxRetries + 1,
|
|
178
|
+
duration,
|
|
179
|
+
error: finalError.message
|
|
180
|
+
}, 'HTTP request failed after all retries');
|
|
181
|
+
// Include detailed error information in the output
|
|
182
|
+
// Even though PayloadCMS will discard this for failed tasks,
|
|
183
|
+
// we include it here for potential future PayloadCMS improvements
|
|
184
|
+
const errorDetails = {
|
|
185
|
+
errorType: finalError.message.includes('timeout') ? 'timeout' : finalError.message.includes('ENOTFOUND') ? 'dns' : finalError.message.includes('ECONNREFUSED') ? 'connection' : 'network',
|
|
186
|
+
duration,
|
|
187
|
+
attempts: maxRetries + 1,
|
|
188
|
+
finalError: finalError.message,
|
|
189
|
+
context: {
|
|
190
|
+
url: typedInput.url,
|
|
191
|
+
method,
|
|
192
|
+
timeout: typedInput.timeout,
|
|
193
|
+
headers: typedInput.headers
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
// Return comprehensive output (PayloadCMS will discard it for failed state, but we try anyway)
|
|
197
|
+
return {
|
|
198
|
+
output: {
|
|
199
|
+
status: 0,
|
|
200
|
+
statusText: 'Request Failed',
|
|
201
|
+
headers: {},
|
|
202
|
+
body: '',
|
|
203
|
+
data: null,
|
|
204
|
+
duration,
|
|
205
|
+
error: finalError.message,
|
|
206
|
+
errorDetails
|
|
207
|
+
},
|
|
208
|
+
state: 'failed'
|
|
209
|
+
};
|
|
210
|
+
} catch (unexpectedError) {
|
|
211
|
+
// Handle any unexpected errors that weren't caught above
|
|
212
|
+
const error = unexpectedError instanceof Error ? unexpectedError : new Error('Unexpected error');
|
|
213
|
+
req?.payload?.logger?.error({
|
|
214
|
+
error: error.message,
|
|
215
|
+
stack: error.stack,
|
|
216
|
+
input: input?.url || 'unknown'
|
|
217
|
+
}, 'Unexpected error in HTTP request handler');
|
|
218
|
+
return {
|
|
219
|
+
output: {
|
|
220
|
+
status: 0,
|
|
221
|
+
statusText: 'Handler Error',
|
|
222
|
+
headers: {},
|
|
223
|
+
body: '',
|
|
224
|
+
data: null,
|
|
225
|
+
duration: Date.now() - startTime,
|
|
226
|
+
error: `HTTP request handler error: ${error.message}`
|
|
227
|
+
},
|
|
228
|
+
state: 'failed'
|
|
229
|
+
};
|
|
4
230
|
}
|
|
5
|
-
const response = await fetch(input.url);
|
|
6
|
-
return {
|
|
7
|
-
output: {
|
|
8
|
-
response: await response.text()
|
|
9
|
-
},
|
|
10
|
-
state: response.ok ? 'succeeded' : undefined
|
|
11
|
-
};
|
|
12
231
|
};
|
|
13
232
|
|
|
14
233
|
//# sourceMappingURL=http-request-handler.js.map
|