@xtr-dev/payload-automation 0.0.22 → 0.0.24
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 +187 -18
- 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 +42 -2
- package/dist/core/workflow-executor.js +169 -14
- 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/exports/helpers.d.ts +26 -0
- package/dist/exports/helpers.js +30 -0
- package/dist/exports/helpers.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin/cron-scheduler.js +27 -27
- package/dist/plugin/cron-scheduler.js.map +1 -1
- package/dist/plugin/index.js +134 -43
- 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/plugin/init-webhook.js +1 -1
- package/dist/plugin/init-webhook.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/dist/utils/trigger-helpers.d.ts +46 -0
- package/dist/utils/trigger-helpers.js +100 -0
- package/dist/utils/trigger-helpers.js.map +1 -0
- package/dist/utils/trigger-presets.d.ts +60 -0
- package/dist/utils/trigger-presets.js +172 -0
- package/dist/utils/trigger-presets.js.map +1 -0
- package/package.json +9 -1
- package/dist/test/basic.test.d.ts +0 -1
|
@@ -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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/steps/http-request-handler.ts"],"sourcesContent":["import type {TaskHandler} from \"payload\"\n\nexport const httpStepHandler: TaskHandler<'http-request-step'> = async ({input}) => {\n if (!input) {\n throw new Error('No input provided')\n }\n const response = await fetch(input.url)\n return {\n output: {\n response: await response.text()\n },\n state: response.ok ? 'succeeded' : undefined\n }\n}\n"],"names":["httpStepHandler","input","Error","response","fetch","url","output","text","state","ok","undefined"],"mappings":"AAEA,OAAO,MAAMA,kBAAoD,OAAO,EAACC,KAAK,EAAC;IAC7E,IAAI,CAACA,OAAO;QACV,MAAM,IAAIC,MAAM;IAClB;IACA,MAAMC,WAAW,MAAMC,MAAMH,MAAMI,GAAG;IACtC,OAAO;QACLC,QAAQ;YACNH,UAAU,MAAMA,SAASI,IAAI;QAC/B;QACAC,OAAOL,SAASM,EAAE,GAAG,cAAcC;IACrC;AACF,EAAC"}
|
|
1
|
+
{"version":3,"sources":["../../src/steps/http-request-handler.ts"],"sourcesContent":["import type {TaskHandler} from \"payload\"\n\ninterface HttpRequestInput {\n url: string\n method?: string\n headers?: Record<string, string>\n body?: any\n timeout?: number\n authentication?: {\n type?: 'none' | 'bearer' | 'basic' | 'apikey'\n token?: string\n username?: string\n password?: string\n headerName?: string\n headerValue?: string\n }\n retries?: number\n retryDelay?: number\n}\n\nexport const httpStepHandler: TaskHandler<'http-request-step'> = async ({input, req}) => {\n const startTime = Date.now() // Move startTime to outer scope\n \n try {\n if (!input || !input.url) {\n return {\n output: {\n status: 0,\n statusText: 'Invalid Input',\n headers: {},\n body: '',\n data: null,\n duration: 0,\n error: 'URL is required for HTTP request'\n },\n state: 'failed'\n }\n }\n\n const typedInput = input as HttpRequestInput\n \n // Validate URL\n try {\n new URL(typedInput.url)\n } catch (error) {\n return {\n output: {\n status: 0,\n statusText: 'Invalid URL',\n headers: {},\n body: '',\n data: null,\n duration: 0,\n error: `Invalid URL: ${typedInput.url}`\n },\n state: 'failed'\n }\n }\n\n // Prepare request options\n const method = (typedInput.method || 'GET').toUpperCase()\n const timeout = typedInput.timeout || 30000\n const headers: Record<string, string> = {\n 'User-Agent': 'PayloadCMS-Automation/1.0',\n ...typedInput.headers\n }\n\n // Handle authentication\n if (typedInput.authentication) {\n switch (typedInput.authentication.type) {\n case 'bearer':\n if (typedInput.authentication.token) {\n headers['Authorization'] = `Bearer ${typedInput.authentication.token}`\n }\n break\n case 'basic':\n if (typedInput.authentication.username && typedInput.authentication.password) {\n const credentials = btoa(`${typedInput.authentication.username}:${typedInput.authentication.password}`)\n headers['Authorization'] = `Basic ${credentials}`\n }\n break\n case 'apikey':\n if (typedInput.authentication.headerName && typedInput.authentication.headerValue) {\n headers[typedInput.authentication.headerName] = typedInput.authentication.headerValue\n }\n break\n }\n }\n\n // Prepare request body\n let requestBody: string | undefined\n if (['POST', 'PUT', 'PATCH'].includes(method) && typedInput.body) {\n if (typeof typedInput.body === 'string') {\n requestBody = typedInput.body\n } else {\n requestBody = JSON.stringify(typedInput.body)\n if (!headers['Content-Type']) {\n headers['Content-Type'] = 'application/json'\n }\n }\n }\n\n // Create abort controller for timeout\n const abortController = new AbortController()\n const timeoutId = setTimeout(() => abortController.abort(), timeout)\n\n // Retry logic\n const maxRetries = Math.min(Math.max(typedInput.retries || 0, 0), 5)\n const retryDelay = Math.max(typedInput.retryDelay || 1000, 100)\n\n let lastError: Error | null = null\n \n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n // Add delay for retry attempts\n if (attempt > 0) {\n req?.payload?.logger?.info({\n attempt: attempt + 1,\n maxRetries: maxRetries + 1,\n url: typedInput.url,\n delay: retryDelay\n }, 'HTTP request retry attempt')\n \n await new Promise(resolve => setTimeout(resolve, retryDelay))\n }\n\n const response = await fetch(typedInput.url, {\n method,\n headers,\n body: requestBody,\n signal: abortController.signal\n })\n\n clearTimeout(timeoutId)\n const duration = Date.now() - startTime\n\n // Parse response\n const responseText = await response.text()\n let parsedData: any = null\n\n try {\n const contentType = response.headers.get('content-type') || ''\n if (contentType.includes('application/json') || contentType.includes('text/json')) {\n parsedData = JSON.parse(responseText)\n }\n } catch (parseError) {\n // Not JSON, that's fine\n }\n\n // Convert headers to plain object\n const responseHeaders: Record<string, string> = {}\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value\n })\n\n const output = {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n body: responseText,\n data: parsedData,\n duration\n }\n\n req?.payload?.logger?.info({\n url: typedInput.url,\n method,\n status: response.status,\n duration,\n attempt: attempt + 1\n }, 'HTTP request completed')\n\n return {\n output,\n // Always return 'succeeded' for completed HTTP requests, even with error status codes (4xx/5xx).\n // This preserves error information in the output for workflow conditional logic.\n // Only network errors, timeouts, and connection failures should result in 'failed' state.\n // This design allows workflows to handle HTTP errors gracefully rather than failing completely.\n state: 'succeeded'\n }\n\n } catch (error) {\n lastError = error instanceof Error ? error : new Error('Unknown error')\n \n // Handle specific error types\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n lastError = new Error(`Request timeout after ${timeout}ms`)\n } else if (error.message.includes('fetch')) {\n lastError = new Error(`Network error: ${error.message}`)\n }\n }\n\n req?.payload?.logger?.warn({\n url: typedInput.url,\n method,\n attempt: attempt + 1,\n maxRetries: maxRetries + 1,\n error: lastError.message\n }, 'HTTP request attempt failed')\n\n // Don't retry on certain errors\n if (lastError.message.includes('Invalid URL') || \n lastError.message.includes('TypeError') ||\n attempt >= maxRetries) {\n break\n }\n }\n }\n\n clearTimeout(timeoutId)\n const duration = Date.now() - startTime\n\n // All retries exhausted\n const finalError = lastError || new Error('HTTP request failed')\n \n req?.payload?.logger?.error({\n url: typedInput.url,\n method,\n totalAttempts: maxRetries + 1,\n duration,\n error: finalError.message\n }, 'HTTP request failed after all retries')\n\n // Include detailed error information in the output\n // Even though PayloadCMS will discard this for failed tasks,\n // we include it here for potential future PayloadCMS improvements\n const errorDetails = {\n errorType: finalError.message.includes('timeout') ? 'timeout' : \n finalError.message.includes('ENOTFOUND') ? 'dns' :\n finalError.message.includes('ECONNREFUSED') ? 'connection' : 'network',\n duration,\n attempts: maxRetries + 1,\n finalError: finalError.message,\n context: {\n url: typedInput.url,\n method,\n timeout: typedInput.timeout,\n headers: typedInput.headers\n }\n }\n\n // Return comprehensive output (PayloadCMS will discard it for failed state, but we try anyway)\n return {\n output: {\n status: 0,\n statusText: 'Request Failed',\n headers: {},\n body: '',\n data: null,\n duration,\n error: finalError.message,\n errorDetails // Include detailed error info (will be discarded by PayloadCMS)\n },\n state: 'failed'\n }\n } catch (unexpectedError) {\n // Handle any unexpected errors that weren't caught above\n const error = unexpectedError instanceof Error ? unexpectedError : new Error('Unexpected error')\n \n req?.payload?.logger?.error({\n error: error.message,\n stack: error.stack,\n input: (input as any)?.url || 'unknown'\n }, 'Unexpected error in HTTP request handler')\n\n return {\n output: {\n status: 0,\n statusText: 'Handler Error',\n headers: {},\n body: '',\n data: null,\n duration: Date.now() - startTime,\n error: `HTTP request handler error: ${error.message}`\n },\n state: 'failed'\n }\n }\n}\n"],"names":["httpStepHandler","input","req","startTime","Date","now","url","output","status","statusText","headers","body","data","duration","error","state","typedInput","URL","method","toUpperCase","timeout","authentication","type","token","username","password","credentials","btoa","headerName","headerValue","requestBody","includes","JSON","stringify","abortController","AbortController","timeoutId","setTimeout","abort","maxRetries","Math","min","max","retries","retryDelay","lastError","attempt","payload","logger","info","delay","Promise","resolve","response","fetch","signal","clearTimeout","responseText","text","parsedData","contentType","get","parse","parseError","responseHeaders","forEach","value","key","Error","name","message","warn","finalError","totalAttempts","errorDetails","errorType","attempts","context","unexpectedError","stack"],"mappings":"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"}
|
|
@@ -1,12 +1,155 @@
|
|
|
1
1
|
export declare const HttpRequestStepTask: {
|
|
2
2
|
slug: "http-request-step";
|
|
3
3
|
handler: import("payload").TaskHandler<"http-request-step">;
|
|
4
|
-
inputSchema: {
|
|
4
|
+
inputSchema: ({
|
|
5
5
|
name: string;
|
|
6
6
|
type: "text";
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
admin: {
|
|
8
|
+
description: string;
|
|
9
|
+
condition?: undefined;
|
|
10
|
+
};
|
|
11
|
+
required: true;
|
|
12
|
+
options?: undefined;
|
|
13
|
+
defaultValue?: undefined;
|
|
14
|
+
fields?: undefined;
|
|
15
|
+
min?: undefined;
|
|
16
|
+
max?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
name: string;
|
|
19
|
+
type: "select";
|
|
20
|
+
options: {
|
|
21
|
+
label: string;
|
|
22
|
+
value: string;
|
|
23
|
+
}[];
|
|
24
|
+
defaultValue: string;
|
|
25
|
+
admin: {
|
|
26
|
+
description: string;
|
|
27
|
+
condition?: undefined;
|
|
28
|
+
};
|
|
29
|
+
required?: undefined;
|
|
30
|
+
fields?: undefined;
|
|
31
|
+
min?: undefined;
|
|
32
|
+
max?: undefined;
|
|
33
|
+
} | {
|
|
34
|
+
name: string;
|
|
35
|
+
type: "json";
|
|
36
|
+
admin: {
|
|
37
|
+
description: string;
|
|
38
|
+
condition?: undefined;
|
|
39
|
+
};
|
|
40
|
+
required?: undefined;
|
|
41
|
+
options?: undefined;
|
|
42
|
+
defaultValue?: undefined;
|
|
43
|
+
fields?: undefined;
|
|
44
|
+
min?: undefined;
|
|
45
|
+
max?: undefined;
|
|
46
|
+
} | {
|
|
47
|
+
name: string;
|
|
48
|
+
type: "json";
|
|
49
|
+
admin: {
|
|
50
|
+
condition: (_: Partial<any>, siblingData: Partial<any>) => boolean;
|
|
51
|
+
description: string;
|
|
52
|
+
};
|
|
53
|
+
required?: undefined;
|
|
54
|
+
options?: undefined;
|
|
55
|
+
defaultValue?: undefined;
|
|
56
|
+
fields?: undefined;
|
|
57
|
+
min?: undefined;
|
|
58
|
+
max?: undefined;
|
|
59
|
+
} | {
|
|
60
|
+
name: string;
|
|
61
|
+
type: "number";
|
|
62
|
+
defaultValue: number;
|
|
63
|
+
admin: {
|
|
64
|
+
description: string;
|
|
65
|
+
condition?: undefined;
|
|
66
|
+
};
|
|
67
|
+
required?: undefined;
|
|
68
|
+
options?: undefined;
|
|
69
|
+
fields?: undefined;
|
|
70
|
+
min?: undefined;
|
|
71
|
+
max?: undefined;
|
|
72
|
+
} | {
|
|
73
|
+
name: string;
|
|
74
|
+
type: "group";
|
|
75
|
+
fields: ({
|
|
76
|
+
name: string;
|
|
77
|
+
type: "select";
|
|
78
|
+
options: {
|
|
79
|
+
label: string;
|
|
80
|
+
value: string;
|
|
81
|
+
}[];
|
|
82
|
+
defaultValue: string;
|
|
83
|
+
admin: {
|
|
84
|
+
description: string;
|
|
85
|
+
condition?: undefined;
|
|
86
|
+
};
|
|
87
|
+
} | {
|
|
88
|
+
name: string;
|
|
89
|
+
type: "text";
|
|
90
|
+
admin: {
|
|
91
|
+
condition: (_: Partial<any>, siblingData: Partial<any>) => boolean;
|
|
92
|
+
description: string;
|
|
93
|
+
};
|
|
94
|
+
options?: undefined;
|
|
95
|
+
defaultValue?: undefined;
|
|
96
|
+
})[];
|
|
97
|
+
admin?: undefined;
|
|
98
|
+
required?: undefined;
|
|
99
|
+
options?: undefined;
|
|
100
|
+
defaultValue?: undefined;
|
|
101
|
+
min?: undefined;
|
|
102
|
+
max?: undefined;
|
|
103
|
+
} | {
|
|
104
|
+
name: string;
|
|
105
|
+
type: "number";
|
|
106
|
+
defaultValue: number;
|
|
107
|
+
min: number;
|
|
108
|
+
max: number;
|
|
109
|
+
admin: {
|
|
110
|
+
description: string;
|
|
111
|
+
condition?: undefined;
|
|
112
|
+
};
|
|
113
|
+
required?: undefined;
|
|
114
|
+
options?: undefined;
|
|
115
|
+
fields?: undefined;
|
|
116
|
+
} | {
|
|
117
|
+
name: string;
|
|
118
|
+
type: "number";
|
|
119
|
+
defaultValue: number;
|
|
120
|
+
admin: {
|
|
121
|
+
condition: (_: Partial<any>, siblingData: Partial<any>) => boolean;
|
|
122
|
+
description: string;
|
|
123
|
+
};
|
|
124
|
+
required?: undefined;
|
|
125
|
+
options?: undefined;
|
|
126
|
+
fields?: undefined;
|
|
127
|
+
min?: undefined;
|
|
128
|
+
max?: undefined;
|
|
129
|
+
})[];
|
|
130
|
+
outputSchema: ({
|
|
131
|
+
name: string;
|
|
132
|
+
type: "number";
|
|
133
|
+
admin: {
|
|
134
|
+
description: string;
|
|
135
|
+
};
|
|
136
|
+
} | {
|
|
137
|
+
name: string;
|
|
138
|
+
type: "text";
|
|
139
|
+
admin: {
|
|
140
|
+
description: string;
|
|
141
|
+
};
|
|
142
|
+
} | {
|
|
143
|
+
name: string;
|
|
144
|
+
type: "json";
|
|
145
|
+
admin: {
|
|
146
|
+
description: string;
|
|
147
|
+
};
|
|
148
|
+
} | {
|
|
9
149
|
name: string;
|
|
10
150
|
type: "textarea";
|
|
11
|
-
|
|
151
|
+
admin: {
|
|
152
|
+
description: string;
|
|
153
|
+
};
|
|
154
|
+
})[];
|
|
12
155
|
};
|
|
@@ -5,13 +5,199 @@ export const HttpRequestStepTask = {
|
|
|
5
5
|
inputSchema: [
|
|
6
6
|
{
|
|
7
7
|
name: 'url',
|
|
8
|
-
type: 'text'
|
|
8
|
+
type: 'text',
|
|
9
|
+
admin: {
|
|
10
|
+
description: 'The URL to make the HTTP request to'
|
|
11
|
+
},
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'method',
|
|
16
|
+
type: 'select',
|
|
17
|
+
options: [
|
|
18
|
+
{
|
|
19
|
+
label: 'GET',
|
|
20
|
+
value: 'GET'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
label: 'POST',
|
|
24
|
+
value: 'POST'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: 'PUT',
|
|
28
|
+
value: 'PUT'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
label: 'DELETE',
|
|
32
|
+
value: 'DELETE'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
label: 'PATCH',
|
|
36
|
+
value: 'PATCH'
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
defaultValue: 'GET',
|
|
40
|
+
admin: {
|
|
41
|
+
description: 'HTTP method to use'
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'headers',
|
|
46
|
+
type: 'json',
|
|
47
|
+
admin: {
|
|
48
|
+
description: 'HTTP headers as JSON object (e.g., {"Content-Type": "application/json"})'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'body',
|
|
53
|
+
type: 'json',
|
|
54
|
+
admin: {
|
|
55
|
+
condition: (_, siblingData)=>siblingData?.method !== 'GET' && siblingData?.method !== 'DELETE',
|
|
56
|
+
description: 'Request body data. Use JSONPath to reference values (e.g., {"postId": "$.trigger.doc.id", "title": "$.trigger.doc.title"})'
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'timeout',
|
|
61
|
+
type: 'number',
|
|
62
|
+
defaultValue: 30000,
|
|
63
|
+
admin: {
|
|
64
|
+
description: 'Request timeout in milliseconds (default: 30000)'
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'authentication',
|
|
69
|
+
type: 'group',
|
|
70
|
+
fields: [
|
|
71
|
+
{
|
|
72
|
+
name: 'type',
|
|
73
|
+
type: 'select',
|
|
74
|
+
options: [
|
|
75
|
+
{
|
|
76
|
+
label: 'None',
|
|
77
|
+
value: 'none'
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: 'Bearer Token',
|
|
81
|
+
value: 'bearer'
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
label: 'Basic Auth',
|
|
85
|
+
value: 'basic'
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
label: 'API Key Header',
|
|
89
|
+
value: 'apikey'
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
defaultValue: 'none',
|
|
93
|
+
admin: {
|
|
94
|
+
description: 'Authentication method'
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'token',
|
|
99
|
+
type: 'text',
|
|
100
|
+
admin: {
|
|
101
|
+
condition: (_, siblingData)=>siblingData?.type === 'bearer',
|
|
102
|
+
description: 'Bearer token value'
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'username',
|
|
107
|
+
type: 'text',
|
|
108
|
+
admin: {
|
|
109
|
+
condition: (_, siblingData)=>siblingData?.type === 'basic',
|
|
110
|
+
description: 'Basic auth username'
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'password',
|
|
115
|
+
type: 'text',
|
|
116
|
+
admin: {
|
|
117
|
+
condition: (_, siblingData)=>siblingData?.type === 'basic',
|
|
118
|
+
description: 'Basic auth password'
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'headerName',
|
|
123
|
+
type: 'text',
|
|
124
|
+
admin: {
|
|
125
|
+
condition: (_, siblingData)=>siblingData?.type === 'apikey',
|
|
126
|
+
description: 'API key header name (e.g., "X-API-Key")'
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'headerValue',
|
|
131
|
+
type: 'text',
|
|
132
|
+
admin: {
|
|
133
|
+
condition: (_, siblingData)=>siblingData?.type === 'apikey',
|
|
134
|
+
description: 'API key value'
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'retries',
|
|
141
|
+
type: 'number',
|
|
142
|
+
defaultValue: 0,
|
|
143
|
+
min: 0,
|
|
144
|
+
max: 5,
|
|
145
|
+
admin: {
|
|
146
|
+
description: 'Number of retry attempts on failure (max: 5)'
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'retryDelay',
|
|
151
|
+
type: 'number',
|
|
152
|
+
defaultValue: 1000,
|
|
153
|
+
admin: {
|
|
154
|
+
condition: (_, siblingData)=>(siblingData?.retries || 0) > 0,
|
|
155
|
+
description: 'Delay between retries in milliseconds'
|
|
156
|
+
}
|
|
9
157
|
}
|
|
10
158
|
],
|
|
11
159
|
outputSchema: [
|
|
12
160
|
{
|
|
13
|
-
name: '
|
|
14
|
-
type: '
|
|
161
|
+
name: 'status',
|
|
162
|
+
type: 'number',
|
|
163
|
+
admin: {
|
|
164
|
+
description: 'HTTP status code'
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'statusText',
|
|
169
|
+
type: 'text',
|
|
170
|
+
admin: {
|
|
171
|
+
description: 'HTTP status text'
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'headers',
|
|
176
|
+
type: 'json',
|
|
177
|
+
admin: {
|
|
178
|
+
description: 'Response headers'
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: 'body',
|
|
183
|
+
type: 'textarea',
|
|
184
|
+
admin: {
|
|
185
|
+
description: 'Response body'
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: 'data',
|
|
190
|
+
type: 'json',
|
|
191
|
+
admin: {
|
|
192
|
+
description: 'Parsed response data (if JSON)'
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: 'duration',
|
|
197
|
+
type: 'number',
|
|
198
|
+
admin: {
|
|
199
|
+
description: 'Request duration in milliseconds'
|
|
200
|
+
}
|
|
15
201
|
}
|
|
16
202
|
]
|
|
17
203
|
};
|