@xtr-dev/payload-automation 0.0.52 → 0.0.54
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 +194 -56
- package/dist/collections/Workflow.js +12 -4
- package/dist/collections/Workflow.js.map +1 -1
- package/dist/core/workflow-executor.d.ts +5 -2
- package/dist/core/workflow-executor.js +27 -11
- package/dist/core/workflow-executor.js.map +1 -1
- package/dist/plugin/config-types.d.ts +1 -0
- package/dist/plugin/config-types.js.map +1 -1
- package/dist/plugin/index.js +5 -1
- package/dist/plugin/index.js.map +1 -1
- package/dist/steps/index.d.ts +0 -2
- package/dist/steps/index.js +0 -2
- package/dist/steps/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/steps/create-step.d.ts +0 -66
- package/dist/steps/create-step.js +0 -59
- package/dist/steps/create-step.js.map +0 -1
package/README.md
CHANGED
|
@@ -8,15 +8,13 @@ A workflow automation plugin for PayloadCMS 3.x. Build visual workflows triggere
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- **Custom Steps** - Create your own step types with the step factory
|
|
19
|
-
- **JSONata Expressions** - Powerful data transformation between steps
|
|
11
|
+
- 🔄 Visual workflow builder in PayloadCMS admin
|
|
12
|
+
- ⚡ Run workflows when documents are created/updated/deleted
|
|
13
|
+
- 🎯 Trigger workflows via webhooks
|
|
14
|
+
- 📊 Track workflow execution history
|
|
15
|
+
- 🔧 HTTP requests, document operations, email sending
|
|
16
|
+
- 🔗 Use data from previous steps in templates
|
|
17
|
+
- ⚙️ Step dependencies with parallel and sequential execution
|
|
20
18
|
|
|
21
19
|
## Installation
|
|
22
20
|
|
|
@@ -30,20 +28,20 @@ npm install @xtr-dev/payload-automation
|
|
|
30
28
|
|
|
31
29
|
```typescript
|
|
32
30
|
import { buildConfig } from 'payload'
|
|
33
|
-
import { workflowsPlugin } from '@xtr-dev/payload-automation'
|
|
31
|
+
import { workflowsPlugin } from '@xtr-dev/payload-automation/server'
|
|
34
32
|
|
|
35
33
|
export default buildConfig({
|
|
34
|
+
// ... your config
|
|
36
35
|
plugins: [
|
|
37
36
|
workflowsPlugin({
|
|
38
|
-
enabled: true,
|
|
39
37
|
collectionTriggers: {
|
|
40
|
-
|
|
41
|
-
users: {
|
|
42
|
-
|
|
38
|
+
posts: true, // Enable all CRUD triggers for posts
|
|
39
|
+
users: {
|
|
40
|
+
create: true, // Only enable create trigger for users
|
|
41
|
+
update: true
|
|
43
42
|
}
|
|
44
43
|
},
|
|
45
|
-
|
|
46
|
-
steps: [myCustomStep],
|
|
44
|
+
enabled: true,
|
|
47
45
|
}),
|
|
48
46
|
],
|
|
49
47
|
})
|
|
@@ -52,10 +50,10 @@ export default buildConfig({
|
|
|
52
50
|
## Imports
|
|
53
51
|
|
|
54
52
|
```typescript
|
|
55
|
-
//
|
|
56
|
-
import { workflowsPlugin } from '@xtr-dev/payload-automation'
|
|
53
|
+
// Server plugin
|
|
54
|
+
import { workflowsPlugin } from '@xtr-dev/payload-automation/server'
|
|
57
55
|
|
|
58
|
-
// Client components
|
|
56
|
+
// Client components
|
|
59
57
|
import { StatusCell, ErrorDisplay } from '@xtr-dev/payload-automation/client'
|
|
60
58
|
|
|
61
59
|
// Types
|
|
@@ -89,13 +87,84 @@ const exampleWorkflows: SeedWorkflow[] = [
|
|
|
89
87
|
name: 'Send Email',
|
|
90
88
|
type: 'send-email',
|
|
91
89
|
input: {
|
|
92
|
-
to: '
|
|
90
|
+
to: '{{trigger.doc.email}}',
|
|
93
91
|
subject: 'Welcome!',
|
|
94
92
|
text: 'Thanks for joining us!',
|
|
95
93
|
},
|
|
96
94
|
},
|
|
97
95
|
],
|
|
98
96
|
},
|
|
97
|
+
{
|
|
98
|
+
slug: 'example-order-processing',
|
|
99
|
+
name: 'Example: Order Processing Pipeline',
|
|
100
|
+
description: 'Process order with validation, inventory check, and notifications',
|
|
101
|
+
triggers: [
|
|
102
|
+
{
|
|
103
|
+
type: 'collection-hook',
|
|
104
|
+
parameters: {
|
|
105
|
+
collectionSlug: 'orders',
|
|
106
|
+
hook: 'afterChange',
|
|
107
|
+
},
|
|
108
|
+
condition: 'trigger.operation = "create"',
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
steps: [
|
|
112
|
+
{
|
|
113
|
+
name: 'Validate Order',
|
|
114
|
+
slug: 'validate-order', // Unique identifier for this step
|
|
115
|
+
type: 'http-request-step',
|
|
116
|
+
input: {
|
|
117
|
+
url: 'https://api.example.com/validate',
|
|
118
|
+
method: 'POST',
|
|
119
|
+
body: {
|
|
120
|
+
orderId: '{{trigger.doc.id}}',
|
|
121
|
+
items: '{{trigger.doc.items}}',
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'Check Inventory',
|
|
127
|
+
slug: 'check-inventory',
|
|
128
|
+
type: 'http-request-step',
|
|
129
|
+
input: {
|
|
130
|
+
url: 'https://api.example.com/inventory/check',
|
|
131
|
+
method: 'POST',
|
|
132
|
+
body: {
|
|
133
|
+
items: '{{trigger.doc.items}}',
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
// Dependencies reference other steps by slug
|
|
137
|
+
dependencies: ['validate-order'],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'Create Shipment',
|
|
141
|
+
slug: 'create-shipment',
|
|
142
|
+
type: 'create-document',
|
|
143
|
+
input: {
|
|
144
|
+
collection: 'shipments',
|
|
145
|
+
data: {
|
|
146
|
+
orderId: '{{trigger.doc.id}}',
|
|
147
|
+
status: 'pending',
|
|
148
|
+
items: '{{trigger.doc.items}}',
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
// This step waits for both validation and inventory check
|
|
152
|
+
dependencies: ['validate-order', 'check-inventory'],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'Send Confirmation Email',
|
|
156
|
+
slug: 'send-email',
|
|
157
|
+
type: 'send-email',
|
|
158
|
+
input: {
|
|
159
|
+
to: '{{trigger.doc.customer.email}}',
|
|
160
|
+
subject: 'Order Confirmed',
|
|
161
|
+
text: 'Your order {{trigger.doc.id}} has been confirmed!',
|
|
162
|
+
},
|
|
163
|
+
// Dependencies reference step slugs
|
|
164
|
+
dependencies: ['create-shipment'],
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
99
168
|
]
|
|
100
169
|
|
|
101
170
|
workflowsPlugin({
|
|
@@ -114,8 +183,78 @@ Seeded workflows:
|
|
|
114
183
|
|
|
115
184
|
See [docs/SEEDING_WORKFLOWS.md](./docs/SEEDING_WORKFLOWS.md) for detailed documentation.
|
|
116
185
|
|
|
186
|
+
## Step Dependencies
|
|
187
|
+
|
|
188
|
+
Steps can declare dependencies on other steps to control execution order. Dependencies reference steps by their **slug** (not by name or index), making them stable across renames and reordering.
|
|
189
|
+
|
|
190
|
+
### How Dependencies Work
|
|
191
|
+
|
|
192
|
+
- **Parallel Execution**: Steps without dependencies run in parallel
|
|
193
|
+
- **Sequential Execution**: Steps with dependencies wait for their dependencies to complete successfully
|
|
194
|
+
- **Multiple Dependencies**: A step can depend on multiple other steps (all must succeed)
|
|
195
|
+
- **Failure Handling**: If a dependency fails, the dependent step is skipped
|
|
196
|
+
- **Slug-based**: Dependencies reference step `slug` fields, not names or positions
|
|
197
|
+
|
|
198
|
+
### Example: Parallel and Sequential Steps
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
steps: [
|
|
202
|
+
{
|
|
203
|
+
name: 'Fetch User Data',
|
|
204
|
+
slug: 'fetch-user',
|
|
205
|
+
type: 'http-request-step',
|
|
206
|
+
// No dependencies - runs immediately
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'Fetch Order Data',
|
|
210
|
+
slug: 'fetch-orders',
|
|
211
|
+
type: 'http-request-step',
|
|
212
|
+
// No dependencies - runs in parallel with fetch-user
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: 'Generate Report',
|
|
216
|
+
slug: 'generate-report',
|
|
217
|
+
type: 'http-request-step',
|
|
218
|
+
dependencies: ['fetch-user', 'fetch-orders'], // Reference by slug
|
|
219
|
+
// Waits for both API calls to complete
|
|
220
|
+
input: {
|
|
221
|
+
url: 'https://api.example.com/reports',
|
|
222
|
+
body: {
|
|
223
|
+
user: '{{steps.FetchUserData.output.user}}',
|
|
224
|
+
orders: '{{steps.FetchOrderData.output.orders}}',
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Accessing Step Output
|
|
232
|
+
|
|
233
|
+
Use `{{steps.<stepName>.output.<field>}}` to reference data from completed steps:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
{
|
|
237
|
+
name: 'Process Result',
|
|
238
|
+
slug: 'process-result',
|
|
239
|
+
type: 'create-document',
|
|
240
|
+
dependencies: ['api-call'], // Reference by slug
|
|
241
|
+
input: {
|
|
242
|
+
collection: 'results',
|
|
243
|
+
data: {
|
|
244
|
+
// Access output from the "API Call" step
|
|
245
|
+
apiResponse: '{{steps.APICall.output.data}}',
|
|
246
|
+
status: '{{steps.APICall.output.status}}',
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
117
252
|
## Step Types
|
|
118
253
|
|
|
254
|
+
> **Note:** Steps are just regular [PayloadCMS tasks](https://payloadcms.com/docs/jobs/overview). This plugin uses Payload's built-in job queue system, so you can leverage all of Payload's task features including retries, scheduling, and monitoring. Any `TaskConfig` you create is a valid step.
|
|
255
|
+
|
|
256
|
+
The plugin comes with a few built-in step types found below.
|
|
257
|
+
|
|
119
258
|
### HTTP Request
|
|
120
259
|
Call external APIs with full configuration:
|
|
121
260
|
|
|
@@ -156,12 +295,13 @@ Send notifications via PayloadCMS email adapter:
|
|
|
156
295
|
|
|
157
296
|
## Custom Steps
|
|
158
297
|
|
|
159
|
-
|
|
298
|
+
Steps are standard PayloadCMS tasks, so creating custom steps is just defining a `TaskConfig`. No proprietary APIs to learn:
|
|
160
299
|
|
|
161
300
|
```typescript
|
|
162
|
-
import {
|
|
301
|
+
import type { TaskConfig } from 'payload'
|
|
163
302
|
|
|
164
|
-
|
|
303
|
+
// Define the step configuration
|
|
304
|
+
export const SlackNotificationStep: TaskConfig<'slack-notification'> = {
|
|
165
305
|
slug: 'slack-notification',
|
|
166
306
|
label: 'Send Slack Message',
|
|
167
307
|
|
|
@@ -175,42 +315,40 @@ export const SlackNotificationStep = createStep({
|
|
|
175
315
|
{ name: 'timestamp', type: 'text' },
|
|
176
316
|
],
|
|
177
317
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
318
|
+
handler: async ({ input, req }) => {
|
|
319
|
+
try {
|
|
320
|
+
const response = await fetch('https://slack.com/api/chat.postMessage', {
|
|
321
|
+
method: 'POST',
|
|
322
|
+
headers: {
|
|
323
|
+
'Authorization': `Bearer ${process.env.SLACK_TOKEN}`,
|
|
324
|
+
'Content-Type': 'application/json',
|
|
325
|
+
},
|
|
326
|
+
body: JSON.stringify({
|
|
327
|
+
channel: input.channel,
|
|
328
|
+
text: input.message,
|
|
329
|
+
}),
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
const data = await response.json()
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
output: {
|
|
336
|
+
messageId: data.message.ts,
|
|
337
|
+
timestamp: new Date().toISOString(),
|
|
338
|
+
},
|
|
339
|
+
state: 'succeeded'
|
|
340
|
+
}
|
|
341
|
+
} catch (error) {
|
|
342
|
+
return {
|
|
343
|
+
output: {},
|
|
344
|
+
state: 'failed',
|
|
345
|
+
errorMessage: error instanceof Error ? error.message : 'Unknown error'
|
|
346
|
+
}
|
|
206
347
|
}
|
|
207
348
|
},
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
Register custom steps in the plugin config:
|
|
349
|
+
}
|
|
212
350
|
|
|
213
|
-
|
|
351
|
+
// Register in plugin config
|
|
214
352
|
workflowsPlugin({
|
|
215
353
|
steps: [SlackNotificationStep],
|
|
216
354
|
})
|
|
@@ -116,6 +116,14 @@
|
|
|
116
116
|
relationTo: 'automation-steps',
|
|
117
117
|
required: true
|
|
118
118
|
},
|
|
119
|
+
{
|
|
120
|
+
name: 'slug',
|
|
121
|
+
type: 'text',
|
|
122
|
+
required: true,
|
|
123
|
+
admin: {
|
|
124
|
+
description: 'Unique identifier for this step within the workflow. Used for dependencies.'
|
|
125
|
+
}
|
|
126
|
+
},
|
|
119
127
|
{
|
|
120
128
|
name: 'stepName',
|
|
121
129
|
type: 'text',
|
|
@@ -143,14 +151,14 @@
|
|
|
143
151
|
name: 'dependencies',
|
|
144
152
|
type: 'array',
|
|
145
153
|
admin: {
|
|
146
|
-
description: 'Steps that must complete before this step can run'
|
|
154
|
+
description: 'Steps that must complete before this step can run. Reference steps by their slug.'
|
|
147
155
|
},
|
|
148
156
|
fields: [
|
|
149
157
|
{
|
|
150
|
-
name: '
|
|
151
|
-
type: '
|
|
158
|
+
name: 'slug',
|
|
159
|
+
type: 'text',
|
|
152
160
|
admin: {
|
|
153
|
-
description: '
|
|
161
|
+
description: 'Slug of the dependent step'
|
|
154
162
|
},
|
|
155
163
|
required: true
|
|
156
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/collections/Workflow.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\n/**\n * Creates the workflows collection.\n * Workflows reference triggers and steps via relationships for reusability.\n */\nexport const createWorkflowCollection = (): CollectionConfig => {\n return {\n slug: 'workflows',\n access: {\n create: () => true,\n delete: ({ req, data }) => {\n // Prevent deletion of read-only workflows\n if (data?.readOnly === true) {\n return false\n }\n return true\n },\n read: () => true,\n update: ({ req, data }) => {\n // Prevent updates to read-only workflows\n if (data?.readOnly === true) {\n return false\n }\n return true\n },\n },\n admin: {\n defaultColumns: ['name', 'slug', 'readOnly', 'enabled', 'updatedAt'],\n description: 'Create and manage automated workflows.',\n group: 'Automation',\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n admin: {\n description: 'Human-readable name for the workflow',\n },\n required: true,\n },\n {\n name: 'slug',\n type: 'text',\n admin: {\n description: 'URL-safe unique identifier for this workflow',\n position: 'sidebar',\n },\n index: true,\n unique: true,\n },\n {\n name: 'readOnly',\n type: 'checkbox',\n admin: {\n description: 'Read-only workflows cannot be edited or deleted. This is typically used for seeded template workflows.',\n position: 'sidebar',\n readOnly: true,\n },\n defaultValue: false,\n },\n {\n name: 'readOnlyBanner',\n type: 'ui',\n admin: {\n components: {\n Field: '@xtr-dev/payload-automation/client#ReadOnlyBanner',\n },\n condition: (data) => data?.readOnly === true,\n },\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'Optional description of what this workflow does',\n },\n },\n {\n name: 'enabled',\n type: 'checkbox',\n admin: {\n description: 'Enable or disable this workflow',\n position: 'sidebar',\n },\n defaultValue: true,\n },\n // Triggers - relationship to automation-triggers collection\n {\n name: 'triggers',\n type: 'relationship',\n admin: {\n description: 'Triggers that can start this workflow. Uses OR logic - workflow runs if ANY trigger fires.',\n },\n hasMany: true,\n relationTo: 'automation-triggers',\n },\n // Steps with workflow-specific configuration\n {\n name: 'steps',\n type: 'array',\n admin: {\n description: 'Steps to execute when this workflow runs. Steps execute in order based on dependencies.',\n },\n fields: [\n {\n name: 'step',\n type: 'relationship',\n admin: {\n description: 'Select a step from the step library',\n },\n relationTo: 'automation-steps',\n required: true,\n },\n {\n name: 'stepName',\n type: 'text',\n admin: {\n description: 'Override the step name for this workflow instance (optional)',\n },\n },\n {\n name: 'inputOverrides',\n type: 'json',\n admin: {\n description: 'Override step configuration values for this workflow. Merged with step defaults.',\n },\n defaultValue: {},\n },\n {\n name: 'condition',\n type: 'code',\n admin: {\n description: 'JSONata expression that must evaluate to true for this step to execute. Leave empty to always run. Example: trigger.operation = \"create\"',\n language: 'javascript',\n },\n },\n {\n name: 'dependencies',\n type: 'array',\n admin: {\n description: 'Steps that must complete before this step can run',\n },\n fields: [\n {\n name: 'stepIndex',\n type: 'number',\n admin: {\n description: 'Index of the dependent step (0-based)',\n },\n required: true,\n },\n ],\n },\n // Visual builder position\n {\n name: 'position',\n type: 'point',\n admin: {\n description: 'Position in the visual workflow builder',\n hidden: true,\n },\n },\n ],\n },\n // Global workflow settings\n {\n type: 'collapsible',\n label: 'Error Handling',\n admin: {\n initCollapsed: true,\n },\n fields: [\n {\n name: 'errorHandling',\n type: 'select',\n admin: {\n description: 'How to handle step failures',\n },\n defaultValue: 'stop',\n options: [\n { label: 'Stop workflow', value: 'stop' },\n { label: 'Continue to next step', value: 'continue' },\n { label: 'Retry failed step', value: 'retry' },\n ],\n },\n {\n name: 'maxRetries',\n type: 'number',\n admin: {\n condition: (_, siblingData) => siblingData?.errorHandling === 'retry',\n description: 'Maximum number of retry attempts',\n },\n defaultValue: 3,\n },\n {\n name: 'retryDelay',\n type: 'number',\n admin: {\n condition: (_, siblingData) => siblingData?.errorHandling === 'retry',\n description: 'Delay between retries in milliseconds',\n },\n defaultValue: 1000,\n },\n {\n name: 'timeout',\n type: 'number',\n admin: {\n description: 'Maximum execution time in milliseconds (0 for no timeout)',\n },\n defaultValue: 300000, // 5 minutes\n },\n ],\n },\n ],\n hooks: {\n afterChange: [\n // Update usage counts for triggers and steps\n async ({ doc, req }) => {\n const payload = req.payload\n\n // Update trigger usage counts\n if (doc.triggers && Array.isArray(doc.triggers)) {\n for (const triggerId of doc.triggers) {\n const id = typeof triggerId === 'object' ? triggerId.id : triggerId\n if (id) {\n try {\n // Count workflows using this trigger\n const count = await payload.count({\n collection: 'workflows',\n where: {\n triggers: { contains: id },\n },\n })\n await payload.update({\n collection: 'automation-triggers',\n id,\n data: { usageCount: count.totalDocs },\n })\n } catch {\n // Ignore errors - trigger might have been deleted\n }\n }\n }\n }\n\n // Update step usage counts\n if (doc.steps && Array.isArray(doc.steps)) {\n const stepIds = new Set<string>()\n for (const workflowStep of doc.steps) {\n const stepId = typeof workflowStep.step === 'object'\n ? workflowStep.step.id\n : workflowStep.step\n if (stepId) stepIds.add(stepId)\n }\n\n for (const stepId of stepIds) {\n try {\n // Count workflows using this step\n const count = await payload.count({\n collection: 'workflows',\n where: {\n 'steps.step': { equals: stepId },\n },\n })\n await payload.update({\n collection: 'automation-steps',\n id: stepId,\n data: { usageCount: count.totalDocs },\n })\n } catch {\n // Ignore errors - step might have been deleted\n }\n }\n }\n\n return doc\n },\n ],\n },\n versions: {\n drafts: {\n autosave: false,\n },\n maxPerDoc: 10,\n },\n }\n}\n"],"names":["createWorkflowCollection","slug","access","create","delete","req","data","readOnly","read","update","admin","defaultColumns","description","group","useAsTitle","fields","name","type","required","position","index","unique","defaultValue","components","Field","condition","hasMany","relationTo","language","hidden","label","initCollapsed","options","value","_","siblingData","errorHandling","hooks","afterChange","doc","payload","triggers","Array","isArray","triggerId","id","count","collection","where","contains","usageCount","totalDocs","steps","stepIds","Set","workflowStep","stepId","step","add","equals","versions","drafts","autosave","maxPerDoc"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/collections/Workflow.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\n/**\n * Creates the workflows collection.\n * Workflows reference triggers and steps via relationships for reusability.\n */\nexport const createWorkflowCollection = (): CollectionConfig => {\n return {\n slug: 'workflows',\n access: {\n create: () => true,\n delete: ({ req, data }) => {\n // Prevent deletion of read-only workflows\n if (data?.readOnly === true) {\n return false\n }\n return true\n },\n read: () => true,\n update: ({ req, data }) => {\n // Prevent updates to read-only workflows\n if (data?.readOnly === true) {\n return false\n }\n return true\n },\n },\n admin: {\n defaultColumns: ['name', 'slug', 'readOnly', 'enabled', 'updatedAt'],\n description: 'Create and manage automated workflows.',\n group: 'Automation',\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n admin: {\n description: 'Human-readable name for the workflow',\n },\n required: true,\n },\n {\n name: 'slug',\n type: 'text',\n admin: {\n description: 'URL-safe unique identifier for this workflow',\n position: 'sidebar',\n },\n index: true,\n unique: true,\n },\n {\n name: 'readOnly',\n type: 'checkbox',\n admin: {\n description: 'Read-only workflows cannot be edited or deleted. This is typically used for seeded template workflows.',\n position: 'sidebar',\n readOnly: true,\n },\n defaultValue: false,\n },\n {\n name: 'readOnlyBanner',\n type: 'ui',\n admin: {\n components: {\n Field: '@xtr-dev/payload-automation/client#ReadOnlyBanner',\n },\n condition: (data) => data?.readOnly === true,\n },\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'Optional description of what this workflow does',\n },\n },\n {\n name: 'enabled',\n type: 'checkbox',\n admin: {\n description: 'Enable or disable this workflow',\n position: 'sidebar',\n },\n defaultValue: true,\n },\n // Triggers - relationship to automation-triggers collection\n {\n name: 'triggers',\n type: 'relationship',\n admin: {\n description: 'Triggers that can start this workflow. Uses OR logic - workflow runs if ANY trigger fires.',\n },\n hasMany: true,\n relationTo: 'automation-triggers',\n },\n // Steps with workflow-specific configuration\n {\n name: 'steps',\n type: 'array',\n admin: {\n description: 'Steps to execute when this workflow runs. Steps execute in order based on dependencies.',\n },\n fields: [\n {\n name: 'step',\n type: 'relationship',\n admin: {\n description: 'Select a step from the step library',\n },\n relationTo: 'automation-steps',\n required: true,\n },\n {\n name: 'slug',\n type: 'text',\n required: true,\n admin: {\n description: 'Unique identifier for this step within the workflow. Used for dependencies.',\n },\n },\n {\n name: 'stepName',\n type: 'text',\n admin: {\n description: 'Override the step name for this workflow instance (optional)',\n },\n },\n {\n name: 'inputOverrides',\n type: 'json',\n admin: {\n description: 'Override step configuration values for this workflow. Merged with step defaults.',\n },\n defaultValue: {},\n },\n {\n name: 'condition',\n type: 'code',\n admin: {\n description: 'JSONata expression that must evaluate to true for this step to execute. Leave empty to always run. Example: trigger.operation = \"create\"',\n language: 'javascript',\n },\n },\n {\n name: 'dependencies',\n type: 'array',\n admin: {\n description: 'Steps that must complete before this step can run. Reference steps by their slug.',\n },\n fields: [\n {\n name: 'slug',\n type: 'text',\n admin: {\n description: 'Slug of the dependent step',\n },\n required: true,\n },\n ],\n },\n // Visual builder position\n {\n name: 'position',\n type: 'point',\n admin: {\n description: 'Position in the visual workflow builder',\n hidden: true,\n },\n },\n ],\n },\n // Global workflow settings\n {\n type: 'collapsible',\n label: 'Error Handling',\n admin: {\n initCollapsed: true,\n },\n fields: [\n {\n name: 'errorHandling',\n type: 'select',\n admin: {\n description: 'How to handle step failures',\n },\n defaultValue: 'stop',\n options: [\n { label: 'Stop workflow', value: 'stop' },\n { label: 'Continue to next step', value: 'continue' },\n { label: 'Retry failed step', value: 'retry' },\n ],\n },\n {\n name: 'maxRetries',\n type: 'number',\n admin: {\n condition: (_, siblingData) => siblingData?.errorHandling === 'retry',\n description: 'Maximum number of retry attempts',\n },\n defaultValue: 3,\n },\n {\n name: 'retryDelay',\n type: 'number',\n admin: {\n condition: (_, siblingData) => siblingData?.errorHandling === 'retry',\n description: 'Delay between retries in milliseconds',\n },\n defaultValue: 1000,\n },\n {\n name: 'timeout',\n type: 'number',\n admin: {\n description: 'Maximum execution time in milliseconds (0 for no timeout)',\n },\n defaultValue: 300000, // 5 minutes\n },\n ],\n },\n ],\n hooks: {\n afterChange: [\n // Update usage counts for triggers and steps\n async ({ doc, req }) => {\n const payload = req.payload\n\n // Update trigger usage counts\n if (doc.triggers && Array.isArray(doc.triggers)) {\n for (const triggerId of doc.triggers) {\n const id = typeof triggerId === 'object' ? triggerId.id : triggerId\n if (id) {\n try {\n // Count workflows using this trigger\n const count = await payload.count({\n collection: 'workflows',\n where: {\n triggers: { contains: id },\n },\n })\n await payload.update({\n collection: 'automation-triggers',\n id,\n data: { usageCount: count.totalDocs },\n })\n } catch {\n // Ignore errors - trigger might have been deleted\n }\n }\n }\n }\n\n // Update step usage counts\n if (doc.steps && Array.isArray(doc.steps)) {\n const stepIds = new Set<string>()\n for (const workflowStep of doc.steps) {\n const stepId = typeof workflowStep.step === 'object'\n ? workflowStep.step.id\n : workflowStep.step\n if (stepId) stepIds.add(stepId)\n }\n\n for (const stepId of stepIds) {\n try {\n // Count workflows using this step\n const count = await payload.count({\n collection: 'workflows',\n where: {\n 'steps.step': { equals: stepId },\n },\n })\n await payload.update({\n collection: 'automation-steps',\n id: stepId,\n data: { usageCount: count.totalDocs },\n })\n } catch {\n // Ignore errors - step might have been deleted\n }\n }\n }\n\n return doc\n },\n ],\n },\n versions: {\n drafts: {\n autosave: false,\n },\n maxPerDoc: 10,\n },\n }\n}\n"],"names":["createWorkflowCollection","slug","access","create","delete","req","data","readOnly","read","update","admin","defaultColumns","description","group","useAsTitle","fields","name","type","required","position","index","unique","defaultValue","components","Field","condition","hasMany","relationTo","language","hidden","label","initCollapsed","options","value","_","siblingData","errorHandling","hooks","afterChange","doc","payload","triggers","Array","isArray","triggerId","id","count","collection","where","contains","usageCount","totalDocs","steps","stepIds","Set","workflowStep","stepId","step","add","equals","versions","drafts","autosave","maxPerDoc"],"mappings":"AAEA;;;CAGC,GACD,OAAO,MAAMA,2BAA2B;IACtC,OAAO;QACLC,MAAM;QACNC,QAAQ;YACNC,QAAQ,IAAM;YACdC,QAAQ,CAAC,EAAEC,GAAG,EAAEC,IAAI,EAAE;gBACpB,0CAA0C;gBAC1C,IAAIA,MAAMC,aAAa,MAAM;oBAC3B,OAAO;gBACT;gBACA,OAAO;YACT;YACAC,MAAM,IAAM;YACZC,QAAQ,CAAC,EAAEJ,GAAG,EAAEC,IAAI,EAAE;gBACpB,yCAAyC;gBACzC,IAAIA,MAAMC,aAAa,MAAM;oBAC3B,OAAO;gBACT;gBACA,OAAO;YACT;QACF;QACAG,OAAO;YACLC,gBAAgB;gBAAC;gBAAQ;gBAAQ;gBAAY;gBAAW;aAAY;YACpEC,aAAa;YACbC,OAAO;YACPC,YAAY;QACd;QACAC,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;gBACf;gBACAM,UAAU;YACZ;YACA;gBACEF,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;oBACbO,UAAU;gBACZ;gBACAC,OAAO;gBACPC,QAAQ;YACV;YACA;gBACEL,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;oBACbO,UAAU;oBACVZ,UAAU;gBACZ;gBACAe,cAAc;YAChB;YACA;gBACEN,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLa,YAAY;wBACVC,OAAO;oBACT;oBACAC,WAAW,CAACnB,OAASA,MAAMC,aAAa;gBAC1C;YACF;YACA;gBACES,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;gBACf;YACF;YACA;gBACEI,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;oBACbO,UAAU;gBACZ;gBACAG,cAAc;YAChB;YACA,4DAA4D;YAC5D;gBACEN,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;gBACf;gBACAc,SAAS;gBACTC,YAAY;YACd;YACA,6CAA6C;YAC7C;gBACEX,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;gBACf;gBACAG,QAAQ;oBACN;wBACEC,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAe,YAAY;wBACZT,UAAU;oBACZ;oBACA;wBACEF,MAAM;wBACNC,MAAM;wBACNC,UAAU;wBACVR,OAAO;4BACLE,aAAa;wBACf;oBACF;oBACA;wBACEI,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;oBACF;oBACA;wBACEI,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAU,cAAc,CAAC;oBACjB;oBACA;wBACEN,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;4BACbgB,UAAU;wBACZ;oBACF;oBACA;wBACEZ,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAG,QAAQ;4BACN;gCACEC,MAAM;gCACNC,MAAM;gCACNP,OAAO;oCACLE,aAAa;gCACf;gCACAM,UAAU;4BACZ;yBACD;oBACH;oBACA,0BAA0B;oBAC1B;wBACEF,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;4BACbiB,QAAQ;wBACV;oBACF;iBACD;YACH;YACA,2BAA2B;YAC3B;gBACEZ,MAAM;gBACNa,OAAO;gBACPpB,OAAO;oBACLqB,eAAe;gBACjB;gBACAhB,QAAQ;oBACN;wBACEC,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAU,cAAc;wBACdU,SAAS;4BACP;gCAAEF,OAAO;gCAAiBG,OAAO;4BAAO;4BACxC;gCAAEH,OAAO;gCAAyBG,OAAO;4BAAW;4BACpD;gCAAEH,OAAO;gCAAqBG,OAAO;4BAAQ;yBAC9C;oBACH;oBACA;wBACEjB,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLe,WAAW,CAACS,GAAGC,cAAgBA,aAAaC,kBAAkB;4BAC9DxB,aAAa;wBACf;wBACAU,cAAc;oBAChB;oBACA;wBACEN,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLe,WAAW,CAACS,GAAGC,cAAgBA,aAAaC,kBAAkB;4BAC9DxB,aAAa;wBACf;wBACAU,cAAc;oBAChB;oBACA;wBACEN,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAU,cAAc;oBAChB;iBACD;YACH;SACD;QACDe,OAAO;YACLC,aAAa;gBACX,6CAA6C;gBAC7C,OAAO,EAAEC,GAAG,EAAElC,GAAG,EAAE;oBACjB,MAAMmC,UAAUnC,IAAImC,OAAO;oBAE3B,8BAA8B;oBAC9B,IAAID,IAAIE,QAAQ,IAAIC,MAAMC,OAAO,CAACJ,IAAIE,QAAQ,GAAG;wBAC/C,KAAK,MAAMG,aAAaL,IAAIE,QAAQ,CAAE;4BACpC,MAAMI,KAAK,OAAOD,cAAc,WAAWA,UAAUC,EAAE,GAAGD;4BAC1D,IAAIC,IAAI;gCACN,IAAI;oCACF,qCAAqC;oCACrC,MAAMC,QAAQ,MAAMN,QAAQM,KAAK,CAAC;wCAChCC,YAAY;wCACZC,OAAO;4CACLP,UAAU;gDAAEQ,UAAUJ;4CAAG;wCAC3B;oCACF;oCACA,MAAML,QAAQ/B,MAAM,CAAC;wCACnBsC,YAAY;wCACZF;wCACAvC,MAAM;4CAAE4C,YAAYJ,MAAMK,SAAS;wCAAC;oCACtC;gCACF,EAAE,OAAM;gCACN,kDAAkD;gCACpD;4BACF;wBACF;oBACF;oBAEA,2BAA2B;oBAC3B,IAAIZ,IAAIa,KAAK,IAAIV,MAAMC,OAAO,CAACJ,IAAIa,KAAK,GAAG;wBACzC,MAAMC,UAAU,IAAIC;wBACpB,KAAK,MAAMC,gBAAgBhB,IAAIa,KAAK,CAAE;4BACpC,MAAMI,SAAS,OAAOD,aAAaE,IAAI,KAAK,WACxCF,aAAaE,IAAI,CAACZ,EAAE,GACpBU,aAAaE,IAAI;4BACrB,IAAID,QAAQH,QAAQK,GAAG,CAACF;wBAC1B;wBAEA,KAAK,MAAMA,UAAUH,QAAS;4BAC5B,IAAI;gCACF,kCAAkC;gCAClC,MAAMP,QAAQ,MAAMN,QAAQM,KAAK,CAAC;oCAChCC,YAAY;oCACZC,OAAO;wCACL,cAAc;4CAAEW,QAAQH;wCAAO;oCACjC;gCACF;gCACA,MAAMhB,QAAQ/B,MAAM,CAAC;oCACnBsC,YAAY;oCACZF,IAAIW;oCACJlD,MAAM;wCAAE4C,YAAYJ,MAAMK,SAAS;oCAAC;gCACtC;4BACF,EAAE,OAAM;4BACN,+CAA+C;4BACjD;wBACF;oBACF;oBAEA,OAAOZ;gBACT;aACD;QACH;QACAqB,UAAU;YACRC,QAAQ;gBACNC,UAAU;YACZ;YACAC,WAAW;QACb;IACF;AACF,EAAC"}
|
|
@@ -11,11 +11,12 @@ export type PayloadWorkflow = {
|
|
|
11
11
|
steps?: Array<{
|
|
12
12
|
id?: string;
|
|
13
13
|
step: any;
|
|
14
|
+
slug: string;
|
|
14
15
|
stepName?: string | null;
|
|
15
16
|
inputOverrides?: Record<string, unknown> | null;
|
|
16
17
|
condition?: string | null;
|
|
17
18
|
dependencies?: Array<{
|
|
18
|
-
|
|
19
|
+
slug: string;
|
|
19
20
|
}> | null;
|
|
20
21
|
position?: {
|
|
21
22
|
x: number;
|
|
@@ -33,12 +34,13 @@ export type PayloadWorkflow = {
|
|
|
33
34
|
*/
|
|
34
35
|
export type ResolvedStep = {
|
|
35
36
|
stepIndex: number;
|
|
37
|
+
slug: string;
|
|
36
38
|
stepId: string | number;
|
|
37
39
|
stepName: string;
|
|
38
40
|
stepType: string;
|
|
39
41
|
config: Record<string, unknown>;
|
|
40
42
|
condition?: string | null;
|
|
41
|
-
dependencies:
|
|
43
|
+
dependencies: string[];
|
|
42
44
|
retryOnFailure?: boolean;
|
|
43
45
|
maxRetries?: number;
|
|
44
46
|
retryDelay?: number;
|
|
@@ -49,6 +51,7 @@ export interface ExecutionContext {
|
|
|
49
51
|
}
|
|
50
52
|
export interface StepResult {
|
|
51
53
|
step?: string | number;
|
|
54
|
+
slug: string;
|
|
52
55
|
stepName: string;
|
|
53
56
|
stepIndex: number;
|
|
54
57
|
status: 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped';
|
|
@@ -43,9 +43,10 @@ export class WorkflowExecutor {
|
|
|
43
43
|
...baseConfig,
|
|
44
44
|
...overrides
|
|
45
45
|
};
|
|
46
|
-
const dependencies = (workflowStep.dependencies || []).map((d)=>d.
|
|
46
|
+
const dependencies = (workflowStep.dependencies || []).map((d)=>d.slug);
|
|
47
47
|
resolvedSteps.push({
|
|
48
48
|
stepIndex: i,
|
|
49
|
+
slug: workflowStep.slug,
|
|
49
50
|
stepId: baseStep.id,
|
|
50
51
|
stepName: workflowStep.stepName || baseStep.name || `step-${i}`,
|
|
51
52
|
stepType: baseStep.type,
|
|
@@ -62,17 +63,30 @@ export class WorkflowExecutor {
|
|
|
62
63
|
/**
|
|
63
64
|
* Resolve step execution order based on dependencies
|
|
64
65
|
*/ resolveExecutionOrder(steps) {
|
|
66
|
+
// Create a map from slug to step for lookups
|
|
67
|
+
const stepBySlug = new Map();
|
|
68
|
+
for (const step of steps){
|
|
69
|
+
stepBySlug.set(step.slug, step);
|
|
70
|
+
}
|
|
71
|
+
// Validate all dependencies exist
|
|
72
|
+
for (const step of steps){
|
|
73
|
+
for (const depSlug of step.dependencies){
|
|
74
|
+
if (!stepBySlug.has(depSlug)) {
|
|
75
|
+
throw new Error(`Step "${step.slug}" depends on non-existent step "${depSlug}"`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
65
79
|
const indegree = new Map();
|
|
66
80
|
const dependents = new Map();
|
|
67
81
|
for (const step of steps){
|
|
68
|
-
indegree.set(step.
|
|
69
|
-
dependents.set(step.
|
|
82
|
+
indegree.set(step.slug, step.dependencies.length);
|
|
83
|
+
dependents.set(step.slug, []);
|
|
70
84
|
}
|
|
71
85
|
for (const step of steps){
|
|
72
|
-
for (const
|
|
73
|
-
const deps = dependents.get(
|
|
74
|
-
deps.push(step.
|
|
75
|
-
dependents.set(
|
|
86
|
+
for (const depSlug of step.dependencies){
|
|
87
|
+
const deps = dependents.get(depSlug) || [];
|
|
88
|
+
deps.push(step.slug);
|
|
89
|
+
dependents.set(depSlug, deps);
|
|
76
90
|
}
|
|
77
91
|
}
|
|
78
92
|
const executionBatches = [];
|
|
@@ -80,7 +94,7 @@ export class WorkflowExecutor {
|
|
|
80
94
|
while(processed.size < steps.length){
|
|
81
95
|
const currentBatch = [];
|
|
82
96
|
for (const step of steps){
|
|
83
|
-
if (!processed.has(step.
|
|
97
|
+
if (!processed.has(step.slug) && indegree.get(step.slug) === 0) {
|
|
84
98
|
currentBatch.push(step);
|
|
85
99
|
}
|
|
86
100
|
}
|
|
@@ -89,9 +103,9 @@ export class WorkflowExecutor {
|
|
|
89
103
|
}
|
|
90
104
|
executionBatches.push(currentBatch);
|
|
91
105
|
for (const step of currentBatch){
|
|
92
|
-
processed.add(step.
|
|
93
|
-
for (const
|
|
94
|
-
indegree.set(
|
|
106
|
+
processed.add(step.slug);
|
|
107
|
+
for (const depSlug of dependents.get(step.slug) || []){
|
|
108
|
+
indegree.set(depSlug, (indegree.get(depSlug) || 1) - 1);
|
|
95
109
|
}
|
|
96
110
|
}
|
|
97
111
|
}
|
|
@@ -102,6 +116,7 @@ export class WorkflowExecutor {
|
|
|
102
116
|
*/ async executeStep(step, context, req, stepResults, jobMeta) {
|
|
103
117
|
const result = {
|
|
104
118
|
step: step.stepId,
|
|
119
|
+
slug: step.slug,
|
|
105
120
|
stepName: step.stepName,
|
|
106
121
|
stepIndex: step.stepIndex,
|
|
107
122
|
status: 'running',
|
|
@@ -349,6 +364,7 @@ export class WorkflowExecutor {
|
|
|
349
364
|
for (const step of resolvedSteps){
|
|
350
365
|
stepResults.push({
|
|
351
366
|
step: step.stepId,
|
|
367
|
+
slug: step.slug,
|
|
352
368
|
stepName: step.stepName,
|
|
353
369
|
stepIndex: step.stepIndex,
|
|
354
370
|
status: 'pending'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/workflow-executor.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\n\nimport {\n evaluateCondition as evalCondition,\n resolveStepInput as resolveInput,\n type ExpressionContext\n} from './expression-engine.js'\nimport {getPluginConfig} from \"../plugin/get-plugin-config.js\";\nimport {WorkflowsPluginConfig} from \"../plugin/config-types.js\";\n\n/**\n * Type for workflow data from the refactored collection\n */\nexport type PayloadWorkflow = {\n id: number | string\n name: string\n description?: string | null\n enabled?: boolean\n triggers?: Array<any> | null\n steps?: Array<{\n id?: string\n step: any\n stepName?: string | null\n inputOverrides?: Record<string, unknown> | null\n condition?: string | null\n dependencies?: Array<{ stepIndex: number }> | null\n position?: { x: number; y: number } | null\n }> | null\n errorHandling?: 'stop' | 'continue' | 'retry' | null\n maxRetries?: number | null\n retryDelay?: number | null\n timeout?: number | null\n [key: string]: unknown\n}\n\n/**\n * Type for a resolved workflow step (with base step data merged)\n */\nexport type ResolvedStep = {\n stepIndex: number\n stepId: string | number\n stepName: string\n stepType: string\n config: Record<string, unknown>\n condition?: string | null\n dependencies: number[]\n retryOnFailure?: boolean\n maxRetries?: number\n retryDelay?: number\n}\n\nexport interface ExecutionContext {\n steps: Record<string, any>\n trigger: Record<string, any>\n}\n\nexport interface StepResult {\n step?: string | number\n stepName: string\n stepIndex: number\n status: 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped'\n startedAt?: string\n completedAt?: string\n duration?: number\n input?: Record<string, unknown>\n output?: Record<string, unknown>\n error?: string\n retryCount?: number\n}\n\n/**\n * Workflow context stored on jobs created by workflow execution.\n * Uses relationship IDs that link to the respective collections.\n */\nexport interface WorkflowJobMeta {\n automationWorkflowId: string | number\n automationWorkflowRunId: string | number\n automationTriggerId?: string | number\n}\n\nexport class WorkflowExecutor {\n private config: WorkflowsPluginConfig<string, string>;\n\n constructor(\n private payload: Payload,\n private logger: Payload['logger']\n ) {\n this.config = getPluginConfig(payload)\n }\n\n /**\n * Resolve workflow steps by loading base step configurations and merging with overrides\n */\n private async resolveWorkflowSteps(workflow: PayloadWorkflow): Promise<ResolvedStep[]> {\n const resolvedSteps: ResolvedStep[] = []\n\n if (!workflow.steps || workflow.steps.length === 0) {\n return resolvedSteps\n }\n\n for (let i = 0; i < workflow.steps.length; i++) {\n const workflowStep = workflow.steps[i]\n\n let baseStep: any\n if (typeof workflowStep.step === 'object' && workflowStep.step !== null) {\n baseStep = workflowStep.step\n } else {\n try {\n baseStep = await this.payload.findByID({\n collection: 'automation-steps',\n id: workflowStep.step,\n depth: 0\n })\n } catch (error) {\n this.logger.error({\n stepId: workflowStep.step,\n stepIndex: i,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to load step configuration')\n throw new Error(`Failed to load step ${workflowStep.step}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n const baseConfig = (baseStep.config as Record<string, unknown>) || {}\n const overrides = (workflowStep.inputOverrides as Record<string, unknown>) || {}\n const mergedConfig = { ...baseConfig, ...overrides }\n\n const dependencies = (workflowStep.dependencies || []).map(d => d.stepIndex)\n\n resolvedSteps.push({\n stepIndex: i,\n stepId: baseStep.id,\n stepName: workflowStep.stepName || baseStep.name || `step-${i}`,\n stepType: baseStep.type as string,\n config: mergedConfig,\n condition: workflowStep.condition,\n dependencies,\n retryOnFailure: baseStep.retryOnFailure,\n maxRetries: baseStep.maxRetries || workflow.maxRetries || 3,\n retryDelay: baseStep.retryDelay || workflow.retryDelay || 1000\n })\n }\n\n return resolvedSteps\n }\n\n /**\n * Resolve step execution order based on dependencies\n */\n private resolveExecutionOrder(steps: ResolvedStep[]): ResolvedStep[][] {\n const indegree = new Map<number, number>()\n const dependents = new Map<number, number[]>()\n\n for (const step of steps) {\n indegree.set(step.stepIndex, step.dependencies.length)\n dependents.set(step.stepIndex, [])\n }\n\n for (const step of steps) {\n for (const depIndex of step.dependencies) {\n const deps = dependents.get(depIndex) || []\n deps.push(step.stepIndex)\n dependents.set(depIndex, deps)\n }\n }\n\n const executionBatches: ResolvedStep[][] = []\n const processed = new Set<number>()\n\n while (processed.size < steps.length) {\n const currentBatch: ResolvedStep[] = []\n\n for (const step of steps) {\n if (!processed.has(step.stepIndex) && indegree.get(step.stepIndex) === 0) {\n currentBatch.push(step)\n }\n }\n\n if (currentBatch.length === 0) {\n throw new Error('Circular dependency detected in workflow steps')\n }\n\n executionBatches.push(currentBatch)\n\n for (const step of currentBatch) {\n processed.add(step.stepIndex)\n for (const depIndex of dependents.get(step.stepIndex) || []) {\n indegree.set(depIndex, (indegree.get(depIndex) || 1) - 1)\n }\n }\n }\n\n return executionBatches\n }\n\n /**\n * Execute a single workflow step\n */\n private async executeStep(\n step: ResolvedStep,\n context: ExecutionContext,\n req: PayloadRequest,\n stepResults: StepResult[],\n jobMeta: WorkflowJobMeta\n ): Promise<StepResult> {\n const result: StepResult = {\n step: step.stepId,\n stepName: step.stepName,\n stepIndex: step.stepIndex,\n status: 'running',\n startedAt: new Date().toISOString(),\n retryCount: 0\n }\n\n this.logger.info({\n stepName: step.stepName,\n stepType: step.stepType,\n stepIndex: step.stepIndex\n }, 'Executing step')\n\n // Check step condition if present\n if (step.condition) {\n const conditionMet = await this.evaluateCondition(step.condition, context)\n if (!conditionMet) {\n this.logger.info({\n stepName: step.stepName,\n condition: step.condition\n }, 'Step condition not met, skipping')\n\n result.status = 'skipped'\n result.completedAt = new Date().toISOString()\n result.output = { reason: 'Condition not met', skipped: true }\n\n context.steps[step.stepName] = {\n state: 'skipped',\n output: result.output\n }\n\n return result\n }\n }\n\n // Resolve input using JSONata expressions\n const resolvedInput = await this.resolveStepInput(step.config, context)\n result.input = resolvedInput\n\n context.steps[step.stepName] = {\n state: 'running',\n input: resolvedInput\n }\n\n try {\n const job = await this.payload.jobs.queue({\n input: resolvedInput,\n req,\n task: step.stepType,\n })\n\n if (this.config.debug) {\n this.logger.info(job, `Queued job for step '${step.stepName}'`)\n }\n\n // Update the job with automation context fields\n // This allows tracking which workflow run triggered this job\n await this.payload.update({\n collection: 'payload-jobs',\n id: job.id,\n data: {\n automationWorkflow: jobMeta.automationWorkflowId,\n automationWorkflowRun: jobMeta.automationWorkflowRunId,\n automationTrigger: jobMeta.automationTriggerId,\n automationStepName: step.stepName,\n },\n req,\n })\n\n // Run the job and capture the result directly from runByID\n // This is important because PayloadCMS may delete jobs on completion (deleteJobOnComplete: true by default)\n const runResult = await this.payload.jobs.runByID({\n id: job.id,\n req\n })\n\n if (this.config.debug) {\n this.logger.info(runResult, `Run result for step '${step.stepName}'`)\n }\n\n // Check the job status from the run result\n // runByID returns { jobStatus: { [jobId]: { status: 'success' | 'error' | ... } }, ... }\n const jobStatus = (runResult as any)?.jobStatus?.[job.id]\n const jobSucceeded = jobStatus?.status === 'success'\n\n if (jobSucceeded) {\n // Job completed successfully - try to get output from the job if it still exists\n // Note: Job may have been deleted if deleteJobOnComplete is true\n let output: Record<string, unknown> = {}\n try {\n const completedJob = await this.payload.findByID({\n id: job.id,\n collection: 'payload-jobs',\n req\n })\n const taskStatus = completedJob.taskStatus?.[completedJob.taskSlug]?.[completedJob.totalTried]\n output = taskStatus?.output || {}\n } catch {\n // Job was deleted after completion - this is expected behavior with deleteJobOnComplete: true\n // The job succeeded, so we proceed without the output\n this.logger.debug({ stepName: step.stepName }, 'Job was deleted after successful completion (deleteJobOnComplete)')\n }\n\n result.status = 'succeeded'\n result.output = output\n result.completedAt = new Date().toISOString()\n result.duration = new Date(result.completedAt).getTime() - new Date(result.startedAt!).getTime()\n } else {\n // Job failed - try to get error details from the job\n let errorMessage = 'Task failed'\n try {\n const completedJob = await this.payload.findByID({\n id: job.id,\n collection: 'payload-jobs',\n req\n })\n const taskStatus = completedJob.taskStatus?.[completedJob.taskSlug]?.[completedJob.totalTried]\n if (completedJob.log && completedJob.log.length > 0) {\n const latestLog = completedJob.log[completedJob.log.length - 1]\n errorMessage = latestLog.error?.message || latestLog.error || errorMessage\n }\n if (taskStatus?.output?.errorMessage) {\n errorMessage = taskStatus.output.errorMessage\n }\n } catch {\n // Job may have been deleted - use the job status from run result\n errorMessage = `Task failed with status: ${jobStatus?.status || 'unknown'}`\n }\n throw new Error(errorMessage)\n }\n\n context.steps[step.stepName] = {\n state: 'succeeded',\n input: resolvedInput,\n output: result.output\n }\n\n this.logger.info({\n stepName: step.stepName,\n duration: result.duration\n }, 'Step completed successfully')\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n result.status = 'failed'\n result.error = errorMessage\n result.completedAt = new Date().toISOString()\n result.duration = new Date(result.completedAt).getTime() - new Date(result.startedAt!).getTime()\n\n context.steps[step.stepName] = {\n state: 'failed',\n input: resolvedInput,\n error: errorMessage\n }\n\n this.logger.error({\n stepName: step.stepName,\n error: errorMessage\n }, 'Step execution failed')\n\n throw error\n }\n\n return result\n }\n\n /**\n * Resolve step input using JSONata expressions\n */\n private async resolveStepInput(\n config: Record<string, unknown>,\n context: ExecutionContext\n ): Promise<Record<string, unknown>> {\n try {\n return await resolveInput(config, context as ExpressionContext, {\n timeout: 5000,\n debug: this.config.debug,\n logger: this.logger\n })\n } catch (error) {\n this.logger.warn({\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to resolve step input, using raw config')\n return config\n }\n }\n\n /**\n * Evaluate a condition using JSONata\n */\n public async evaluateCondition(condition: string, context: ExecutionContext): Promise<boolean> {\n try {\n return await evalCondition(condition, context as ExpressionContext, { timeout: 5000 })\n } catch (error) {\n this.logger.warn({\n condition,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to evaluate condition')\n return false\n }\n }\n\n /**\n * Safely serialize an object for storage\n */\n private safeSerialize(obj: unknown): unknown {\n const seen = new WeakSet()\n\n // Keys to completely exclude from serialization\n const excludeKeys = new Set([\n 'table',\n 'schema',\n '_',\n '__',\n 'payload', // Exclude payload instance (contains entire config)\n 'res', // Exclude response object\n 'transactionID',\n 'i18n',\n 'fallbackLocale',\n ])\n\n // For req object, only keep these useful debugging properties\n const reqAllowedKeys = new Set([\n 'payloadAPI', // 'local', 'REST', or 'GraphQL'\n 'locale',\n 'user', // authenticated user\n 'method', // HTTP method\n 'url', // request URL\n ])\n\n const serialize = (value: unknown, parentKey?: string): unknown => {\n if (value === null || typeof value !== 'object') {\n return value\n }\n if (seen.has(value)) {\n return '[Circular Reference]'\n }\n seen.add(value)\n\n if (Array.isArray(value)) {\n return value.map((v) => serialize(v))\n }\n\n const result: Record<string, unknown> = {}\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n try {\n if (excludeKeys.has(key)) {\n continue\n }\n // Special handling for req object - only include allowed keys\n if (parentKey === 'req' && !reqAllowedKeys.has(key)) {\n continue\n }\n result[key] = serialize(val, key)\n } catch {\n result[key] = '[Non-serializable]'\n }\n }\n return result\n }\n\n return serialize(obj)\n }\n\n /**\n * Execute a workflow with the given context\n */\n async execute(\n workflow: PayloadWorkflow,\n context: ExecutionContext,\n req: PayloadRequest,\n firedTrigger?: any\n ): Promise<void> {\n this.logger.info({\n workflowId: workflow.id,\n workflowName: workflow.name,\n triggerId: firedTrigger?.id,\n triggerName: firedTrigger?.name\n }, 'Starting workflow execution')\n\n const resolvedSteps = await this.resolveWorkflowSteps(workflow)\n const stepResults: StepResult[] = []\n\n for (const step of resolvedSteps) {\n stepResults.push({\n step: step.stepId,\n stepName: step.stepName,\n stepIndex: step.stepIndex,\n status: 'pending'\n })\n }\n\n const workflowRun = await this.payload.create({\n collection: 'workflow-runs',\n data: {\n workflow: workflow.id,\n workflowVersion: 1,\n firedTrigger: firedTrigger?.id,\n triggerData: this.safeSerialize(context.trigger),\n status: 'running',\n startedAt: new Date().toISOString(),\n triggeredBy: context.trigger.req?.user?.email || 'system',\n stepResults,\n context: this.safeSerialize(context),\n inputs: this.safeSerialize(context.trigger),\n logs: [{\n timestamp: new Date().toISOString(),\n level: 'info',\n message: 'Workflow execution started'\n }]\n },\n req\n })\n\n this.logger.info({\n workflowRunId: workflowRun.id,\n workflowId: workflow.id\n }, 'Workflow run record created')\n\n // Create job metadata for tracking workflow context in payload-jobs\n const jobMeta: WorkflowJobMeta = {\n automationWorkflowId: workflow.id,\n automationWorkflowRunId: workflowRun.id,\n automationTriggerId: firedTrigger?.id,\n }\n\n try {\n const executionBatches = this.resolveExecutionOrder(resolvedSteps)\n\n this.logger.info({\n batchCount: executionBatches.length,\n batchSizes: executionBatches.map(b => b.length)\n }, 'Resolved step execution order')\n\n for (let batchIndex = 0; batchIndex < executionBatches.length; batchIndex++) {\n const batch = executionBatches[batchIndex]\n\n this.logger.info({\n batchIndex,\n stepCount: batch.length,\n stepNames: batch.map(s => s.stepName)\n }, 'Executing batch')\n\n const batchPromises = batch.map(async (step) => {\n try {\n const result = await this.executeStep(step, context, req, stepResults, jobMeta)\n const idx = stepResults.findIndex(r => r.stepIndex === step.stepIndex)\n if (idx !== -1) {\n stepResults[idx] = result\n }\n return result\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n const idx = stepResults.findIndex(r => r.stepIndex === step.stepIndex)\n if (idx !== -1) {\n stepResults[idx] = {\n ...stepResults[idx],\n status: 'failed',\n error: errorMessage,\n completedAt: new Date().toISOString()\n }\n }\n\n if (workflow.errorHandling === 'stop') {\n throw error\n }\n this.logger.warn({\n stepName: step.stepName,\n error: errorMessage\n }, 'Step failed but continuing due to error handling setting')\n }\n })\n\n await Promise.all(batchPromises)\n\n await this.payload.update({\n id: workflowRun.id,\n collection: 'workflow-runs',\n data: {\n stepResults,\n context: this.safeSerialize(context)\n },\n req\n })\n }\n\n const outputs: Record<string, unknown> = {}\n for (const result of stepResults) {\n if (result.status === 'succeeded' && result.output) {\n outputs[result.stepName] = result.output\n }\n }\n\n await this.payload.update({\n id: workflowRun.id,\n collection: 'workflow-runs',\n data: {\n status: 'completed',\n completedAt: new Date().toISOString(),\n stepResults,\n context: this.safeSerialize(context),\n outputs,\n logs: [\n ...(workflowRun.logs || []),\n {\n timestamp: new Date().toISOString(),\n level: 'info',\n message: 'Workflow execution completed successfully'\n }\n ]\n },\n req\n })\n\n this.logger.info({\n workflowRunId: workflowRun.id,\n workflowId: workflow.id\n }, 'Workflow execution completed')\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\n await this.payload.update({\n id: workflowRun.id,\n collection: 'workflow-runs',\n data: {\n status: 'failed',\n completedAt: new Date().toISOString(),\n stepResults,\n context: this.safeSerialize(context),\n error: errorMessage,\n logs: [\n ...(workflowRun.logs || []),\n {\n timestamp: new Date().toISOString(),\n level: 'error',\n message: `Workflow execution failed: ${errorMessage}`\n }\n ]\n },\n req\n })\n\n this.logger.error({\n workflowRunId: workflowRun.id,\n workflowId: workflow.id,\n error: errorMessage\n }, 'Workflow execution failed')\n\n throw error\n }\n }\n}\n"],"names":["evaluateCondition","evalCondition","resolveStepInput","resolveInput","getPluginConfig","WorkflowExecutor","config","payload","logger","resolveWorkflowSteps","workflow","resolvedSteps","steps","length","i","workflowStep","baseStep","step","findByID","collection","id","depth","error","stepId","stepIndex","Error","message","baseConfig","overrides","inputOverrides","mergedConfig","dependencies","map","d","push","stepName","name","stepType","type","condition","retryOnFailure","maxRetries","retryDelay","resolveExecutionOrder","indegree","Map","dependents","set","depIndex","deps","get","executionBatches","processed","Set","size","currentBatch","has","add","executeStep","context","req","stepResults","jobMeta","result","status","startedAt","Date","toISOString","retryCount","info","conditionMet","completedAt","output","reason","skipped","state","resolvedInput","input","job","jobs","queue","task","debug","update","data","automationWorkflow","automationWorkflowId","automationWorkflowRun","automationWorkflowRunId","automationTrigger","automationTriggerId","automationStepName","runResult","runByID","jobStatus","jobSucceeded","completedJob","taskStatus","taskSlug","totalTried","duration","getTime","errorMessage","log","latestLog","timeout","warn","safeSerialize","obj","seen","WeakSet","excludeKeys","reqAllowedKeys","serialize","value","parentKey","Array","isArray","v","key","val","Object","entries","execute","firedTrigger","workflowId","workflowName","triggerId","triggerName","workflowRun","create","workflowVersion","triggerData","trigger","triggeredBy","user","email","inputs","logs","timestamp","level","workflowRunId","batchCount","batchSizes","b","batchIndex","batch","stepCount","stepNames","s","batchPromises","idx","findIndex","r","errorHandling","Promise","all","outputs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/workflow-executor.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\n\nimport {\n evaluateCondition as evalCondition,\n resolveStepInput as resolveInput,\n type ExpressionContext\n} from './expression-engine.js'\nimport {getPluginConfig} from \"../plugin/get-plugin-config.js\";\nimport {WorkflowsPluginConfig} from \"../plugin/config-types.js\";\n\n/**\n * Type for workflow data from the refactored collection\n */\nexport type PayloadWorkflow = {\n id: number | string\n name: string\n description?: string | null\n enabled?: boolean\n triggers?: Array<any> | null\n steps?: Array<{\n id?: string\n step: any\n slug: string\n stepName?: string | null\n inputOverrides?: Record<string, unknown> | null\n condition?: string | null\n dependencies?: Array<{ slug: string }> | null\n position?: { x: number; y: number } | null\n }> | null\n errorHandling?: 'stop' | 'continue' | 'retry' | null\n maxRetries?: number | null\n retryDelay?: number | null\n timeout?: number | null\n [key: string]: unknown\n}\n\n/**\n * Type for a resolved workflow step (with base step data merged)\n */\nexport type ResolvedStep = {\n stepIndex: number\n slug: string\n stepId: string | number\n stepName: string\n stepType: string\n config: Record<string, unknown>\n condition?: string | null\n dependencies: string[]\n retryOnFailure?: boolean\n maxRetries?: number\n retryDelay?: number\n}\n\nexport interface ExecutionContext {\n steps: Record<string, any>\n trigger: Record<string, any>\n}\n\nexport interface StepResult {\n step?: string | number\n slug: string\n stepName: string\n stepIndex: number\n status: 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped'\n startedAt?: string\n completedAt?: string\n duration?: number\n input?: Record<string, unknown>\n output?: Record<string, unknown>\n error?: string\n retryCount?: number\n}\n\n/**\n * Workflow context stored on jobs created by workflow execution.\n * Uses relationship IDs that link to the respective collections.\n */\nexport interface WorkflowJobMeta {\n automationWorkflowId: string | number\n automationWorkflowRunId: string | number\n automationTriggerId?: string | number\n}\n\nexport class WorkflowExecutor {\n private config: WorkflowsPluginConfig<string, string>;\n\n constructor(\n private payload: Payload,\n private logger: Payload['logger']\n ) {\n this.config = getPluginConfig(payload)\n }\n\n /**\n * Resolve workflow steps by loading base step configurations and merging with overrides\n */\n private async resolveWorkflowSteps(workflow: PayloadWorkflow): Promise<ResolvedStep[]> {\n const resolvedSteps: ResolvedStep[] = []\n\n if (!workflow.steps || workflow.steps.length === 0) {\n return resolvedSteps\n }\n\n for (let i = 0; i < workflow.steps.length; i++) {\n const workflowStep = workflow.steps[i]\n\n let baseStep: any\n if (typeof workflowStep.step === 'object' && workflowStep.step !== null) {\n baseStep = workflowStep.step\n } else {\n try {\n baseStep = await this.payload.findByID({\n collection: 'automation-steps',\n id: workflowStep.step,\n depth: 0\n })\n } catch (error) {\n this.logger.error({\n stepId: workflowStep.step,\n stepIndex: i,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to load step configuration')\n throw new Error(`Failed to load step ${workflowStep.step}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n const baseConfig = (baseStep.config as Record<string, unknown>) || {}\n const overrides = (workflowStep.inputOverrides as Record<string, unknown>) || {}\n const mergedConfig = { ...baseConfig, ...overrides }\n\n const dependencies = (workflowStep.dependencies || []).map(d => d.slug)\n\n resolvedSteps.push({\n stepIndex: i,\n slug: workflowStep.slug,\n stepId: baseStep.id,\n stepName: workflowStep.stepName || baseStep.name || `step-${i}`,\n stepType: baseStep.type as string,\n config: mergedConfig,\n condition: workflowStep.condition,\n dependencies,\n retryOnFailure: baseStep.retryOnFailure,\n maxRetries: baseStep.maxRetries || workflow.maxRetries || 3,\n retryDelay: baseStep.retryDelay || workflow.retryDelay || 1000\n })\n }\n\n return resolvedSteps\n }\n\n /**\n * Resolve step execution order based on dependencies\n */\n private resolveExecutionOrder(steps: ResolvedStep[]): ResolvedStep[][] {\n // Create a map from slug to step for lookups\n const stepBySlug = new Map<string, ResolvedStep>()\n for (const step of steps) {\n stepBySlug.set(step.slug, step)\n }\n\n // Validate all dependencies exist\n for (const step of steps) {\n for (const depSlug of step.dependencies) {\n if (!stepBySlug.has(depSlug)) {\n throw new Error(`Step \"${step.slug}\" depends on non-existent step \"${depSlug}\"`)\n }\n }\n }\n\n const indegree = new Map<string, number>()\n const dependents = new Map<string, string[]>()\n\n for (const step of steps) {\n indegree.set(step.slug, step.dependencies.length)\n dependents.set(step.slug, [])\n }\n\n for (const step of steps) {\n for (const depSlug of step.dependencies) {\n const deps = dependents.get(depSlug) || []\n deps.push(step.slug)\n dependents.set(depSlug, deps)\n }\n }\n\n const executionBatches: ResolvedStep[][] = []\n const processed = new Set<string>()\n\n while (processed.size < steps.length) {\n const currentBatch: ResolvedStep[] = []\n\n for (const step of steps) {\n if (!processed.has(step.slug) && indegree.get(step.slug) === 0) {\n currentBatch.push(step)\n }\n }\n\n if (currentBatch.length === 0) {\n throw new Error('Circular dependency detected in workflow steps')\n }\n\n executionBatches.push(currentBatch)\n\n for (const step of currentBatch) {\n processed.add(step.slug)\n for (const depSlug of dependents.get(step.slug) || []) {\n indegree.set(depSlug, (indegree.get(depSlug) || 1) - 1)\n }\n }\n }\n\n return executionBatches\n }\n\n /**\n * Execute a single workflow step\n */\n private async executeStep(\n step: ResolvedStep,\n context: ExecutionContext,\n req: PayloadRequest,\n stepResults: StepResult[],\n jobMeta: WorkflowJobMeta\n ): Promise<StepResult> {\n const result: StepResult = {\n step: step.stepId,\n slug: step.slug,\n stepName: step.stepName,\n stepIndex: step.stepIndex,\n status: 'running',\n startedAt: new Date().toISOString(),\n retryCount: 0\n }\n\n this.logger.info({\n stepName: step.stepName,\n stepType: step.stepType,\n stepIndex: step.stepIndex\n }, 'Executing step')\n\n // Check step condition if present\n if (step.condition) {\n const conditionMet = await this.evaluateCondition(step.condition, context)\n if (!conditionMet) {\n this.logger.info({\n stepName: step.stepName,\n condition: step.condition\n }, 'Step condition not met, skipping')\n\n result.status = 'skipped'\n result.completedAt = new Date().toISOString()\n result.output = { reason: 'Condition not met', skipped: true }\n\n context.steps[step.stepName] = {\n state: 'skipped',\n output: result.output\n }\n\n return result\n }\n }\n\n // Resolve input using JSONata expressions\n const resolvedInput = await this.resolveStepInput(step.config, context)\n result.input = resolvedInput\n\n context.steps[step.stepName] = {\n state: 'running',\n input: resolvedInput\n }\n\n try {\n const job = await this.payload.jobs.queue({\n input: resolvedInput,\n req,\n task: step.stepType,\n })\n\n if (this.config.debug) {\n this.logger.info(job, `Queued job for step '${step.stepName}'`)\n }\n\n // Update the job with automation context fields\n // This allows tracking which workflow run triggered this job\n await this.payload.update({\n collection: 'payload-jobs',\n id: job.id,\n data: {\n automationWorkflow: jobMeta.automationWorkflowId,\n automationWorkflowRun: jobMeta.automationWorkflowRunId,\n automationTrigger: jobMeta.automationTriggerId,\n automationStepName: step.stepName,\n },\n req,\n })\n\n // Run the job and capture the result directly from runByID\n // This is important because PayloadCMS may delete jobs on completion (deleteJobOnComplete: true by default)\n const runResult = await this.payload.jobs.runByID({\n id: job.id,\n req\n })\n\n if (this.config.debug) {\n this.logger.info(runResult, `Run result for step '${step.stepName}'`)\n }\n\n // Check the job status from the run result\n // runByID returns { jobStatus: { [jobId]: { status: 'success' | 'error' | ... } }, ... }\n const jobStatus = (runResult as any)?.jobStatus?.[job.id]\n const jobSucceeded = jobStatus?.status === 'success'\n\n if (jobSucceeded) {\n // Job completed successfully - try to get output from the job if it still exists\n // Note: Job may have been deleted if deleteJobOnComplete is true\n let output: Record<string, unknown> = {}\n try {\n const completedJob = await this.payload.findByID({\n id: job.id,\n collection: 'payload-jobs',\n req\n })\n const taskStatus = completedJob.taskStatus?.[completedJob.taskSlug]?.[completedJob.totalTried]\n output = taskStatus?.output || {}\n } catch {\n // Job was deleted after completion - this is expected behavior with deleteJobOnComplete: true\n // The job succeeded, so we proceed without the output\n this.logger.debug({ stepName: step.stepName }, 'Job was deleted after successful completion (deleteJobOnComplete)')\n }\n\n result.status = 'succeeded'\n result.output = output\n result.completedAt = new Date().toISOString()\n result.duration = new Date(result.completedAt).getTime() - new Date(result.startedAt!).getTime()\n } else {\n // Job failed - try to get error details from the job\n let errorMessage = 'Task failed'\n try {\n const completedJob = await this.payload.findByID({\n id: job.id,\n collection: 'payload-jobs',\n req\n })\n const taskStatus = completedJob.taskStatus?.[completedJob.taskSlug]?.[completedJob.totalTried]\n if (completedJob.log && completedJob.log.length > 0) {\n const latestLog = completedJob.log[completedJob.log.length - 1]\n errorMessage = latestLog.error?.message || latestLog.error || errorMessage\n }\n if (taskStatus?.output?.errorMessage) {\n errorMessage = taskStatus.output.errorMessage\n }\n } catch {\n // Job may have been deleted - use the job status from run result\n errorMessage = `Task failed with status: ${jobStatus?.status || 'unknown'}`\n }\n throw new Error(errorMessage)\n }\n\n context.steps[step.stepName] = {\n state: 'succeeded',\n input: resolvedInput,\n output: result.output\n }\n\n this.logger.info({\n stepName: step.stepName,\n duration: result.duration\n }, 'Step completed successfully')\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n result.status = 'failed'\n result.error = errorMessage\n result.completedAt = new Date().toISOString()\n result.duration = new Date(result.completedAt).getTime() - new Date(result.startedAt!).getTime()\n\n context.steps[step.stepName] = {\n state: 'failed',\n input: resolvedInput,\n error: errorMessage\n }\n\n this.logger.error({\n stepName: step.stepName,\n error: errorMessage\n }, 'Step execution failed')\n\n throw error\n }\n\n return result\n }\n\n /**\n * Resolve step input using JSONata expressions\n */\n private async resolveStepInput(\n config: Record<string, unknown>,\n context: ExecutionContext\n ): Promise<Record<string, unknown>> {\n try {\n return await resolveInput(config, context as ExpressionContext, {\n timeout: 5000,\n debug: this.config.debug,\n logger: this.logger\n })\n } catch (error) {\n this.logger.warn({\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to resolve step input, using raw config')\n return config\n }\n }\n\n /**\n * Evaluate a condition using JSONata\n */\n public async evaluateCondition(condition: string, context: ExecutionContext): Promise<boolean> {\n try {\n return await evalCondition(condition, context as ExpressionContext, { timeout: 5000 })\n } catch (error) {\n this.logger.warn({\n condition,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to evaluate condition')\n return false\n }\n }\n\n /**\n * Safely serialize an object for storage\n */\n private safeSerialize(obj: unknown): unknown {\n const seen = new WeakSet()\n\n // Keys to completely exclude from serialization\n const excludeKeys = new Set([\n 'table',\n 'schema',\n '_',\n '__',\n 'payload', // Exclude payload instance (contains entire config)\n 'res', // Exclude response object\n 'transactionID',\n 'i18n',\n 'fallbackLocale',\n ])\n\n // For req object, only keep these useful debugging properties\n const reqAllowedKeys = new Set([\n 'payloadAPI', // 'local', 'REST', or 'GraphQL'\n 'locale',\n 'user', // authenticated user\n 'method', // HTTP method\n 'url', // request URL\n ])\n\n const serialize = (value: unknown, parentKey?: string): unknown => {\n if (value === null || typeof value !== 'object') {\n return value\n }\n if (seen.has(value)) {\n return '[Circular Reference]'\n }\n seen.add(value)\n\n if (Array.isArray(value)) {\n return value.map((v) => serialize(v))\n }\n\n const result: Record<string, unknown> = {}\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n try {\n if (excludeKeys.has(key)) {\n continue\n }\n // Special handling for req object - only include allowed keys\n if (parentKey === 'req' && !reqAllowedKeys.has(key)) {\n continue\n }\n result[key] = serialize(val, key)\n } catch {\n result[key] = '[Non-serializable]'\n }\n }\n return result\n }\n\n return serialize(obj)\n }\n\n /**\n * Execute a workflow with the given context\n */\n async execute(\n workflow: PayloadWorkflow,\n context: ExecutionContext,\n req: PayloadRequest,\n firedTrigger?: any\n ): Promise<void> {\n this.logger.info({\n workflowId: workflow.id,\n workflowName: workflow.name,\n triggerId: firedTrigger?.id,\n triggerName: firedTrigger?.name\n }, 'Starting workflow execution')\n\n const resolvedSteps = await this.resolveWorkflowSteps(workflow)\n const stepResults: StepResult[] = []\n\n for (const step of resolvedSteps) {\n stepResults.push({\n step: step.stepId,\n slug: step.slug,\n stepName: step.stepName,\n stepIndex: step.stepIndex,\n status: 'pending'\n })\n }\n\n const workflowRun = await this.payload.create({\n collection: 'workflow-runs',\n data: {\n workflow: workflow.id,\n workflowVersion: 1,\n firedTrigger: firedTrigger?.id,\n triggerData: this.safeSerialize(context.trigger),\n status: 'running',\n startedAt: new Date().toISOString(),\n triggeredBy: context.trigger.req?.user?.email || 'system',\n stepResults,\n context: this.safeSerialize(context),\n inputs: this.safeSerialize(context.trigger),\n logs: [{\n timestamp: new Date().toISOString(),\n level: 'info',\n message: 'Workflow execution started'\n }]\n },\n req\n })\n\n this.logger.info({\n workflowRunId: workflowRun.id,\n workflowId: workflow.id\n }, 'Workflow run record created')\n\n // Create job metadata for tracking workflow context in payload-jobs\n const jobMeta: WorkflowJobMeta = {\n automationWorkflowId: workflow.id,\n automationWorkflowRunId: workflowRun.id,\n automationTriggerId: firedTrigger?.id,\n }\n\n try {\n const executionBatches = this.resolveExecutionOrder(resolvedSteps)\n\n this.logger.info({\n batchCount: executionBatches.length,\n batchSizes: executionBatches.map(b => b.length)\n }, 'Resolved step execution order')\n\n for (let batchIndex = 0; batchIndex < executionBatches.length; batchIndex++) {\n const batch = executionBatches[batchIndex]\n\n this.logger.info({\n batchIndex,\n stepCount: batch.length,\n stepNames: batch.map(s => s.stepName)\n }, 'Executing batch')\n\n const batchPromises = batch.map(async (step) => {\n try {\n const result = await this.executeStep(step, context, req, stepResults, jobMeta)\n const idx = stepResults.findIndex(r => r.stepIndex === step.stepIndex)\n if (idx !== -1) {\n stepResults[idx] = result\n }\n return result\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n const idx = stepResults.findIndex(r => r.stepIndex === step.stepIndex)\n if (idx !== -1) {\n stepResults[idx] = {\n ...stepResults[idx],\n status: 'failed',\n error: errorMessage,\n completedAt: new Date().toISOString()\n }\n }\n\n if (workflow.errorHandling === 'stop') {\n throw error\n }\n this.logger.warn({\n stepName: step.stepName,\n error: errorMessage\n }, 'Step failed but continuing due to error handling setting')\n }\n })\n\n await Promise.all(batchPromises)\n\n await this.payload.update({\n id: workflowRun.id,\n collection: 'workflow-runs',\n data: {\n stepResults,\n context: this.safeSerialize(context)\n },\n req\n })\n }\n\n const outputs: Record<string, unknown> = {}\n for (const result of stepResults) {\n if (result.status === 'succeeded' && result.output) {\n outputs[result.stepName] = result.output\n }\n }\n\n await this.payload.update({\n id: workflowRun.id,\n collection: 'workflow-runs',\n data: {\n status: 'completed',\n completedAt: new Date().toISOString(),\n stepResults,\n context: this.safeSerialize(context),\n outputs,\n logs: [\n ...(workflowRun.logs || []),\n {\n timestamp: new Date().toISOString(),\n level: 'info',\n message: 'Workflow execution completed successfully'\n }\n ]\n },\n req\n })\n\n this.logger.info({\n workflowRunId: workflowRun.id,\n workflowId: workflow.id\n }, 'Workflow execution completed')\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\n await this.payload.update({\n id: workflowRun.id,\n collection: 'workflow-runs',\n data: {\n status: 'failed',\n completedAt: new Date().toISOString(),\n stepResults,\n context: this.safeSerialize(context),\n error: errorMessage,\n logs: [\n ...(workflowRun.logs || []),\n {\n timestamp: new Date().toISOString(),\n level: 'error',\n message: `Workflow execution failed: ${errorMessage}`\n }\n ]\n },\n req\n })\n\n this.logger.error({\n workflowRunId: workflowRun.id,\n workflowId: workflow.id,\n error: errorMessage\n }, 'Workflow execution failed')\n\n throw error\n }\n }\n}\n"],"names":["evaluateCondition","evalCondition","resolveStepInput","resolveInput","getPluginConfig","WorkflowExecutor","config","payload","logger","resolveWorkflowSteps","workflow","resolvedSteps","steps","length","i","workflowStep","baseStep","step","findByID","collection","id","depth","error","stepId","stepIndex","Error","message","baseConfig","overrides","inputOverrides","mergedConfig","dependencies","map","d","slug","push","stepName","name","stepType","type","condition","retryOnFailure","maxRetries","retryDelay","resolveExecutionOrder","stepBySlug","Map","set","depSlug","has","indegree","dependents","deps","get","executionBatches","processed","Set","size","currentBatch","add","executeStep","context","req","stepResults","jobMeta","result","status","startedAt","Date","toISOString","retryCount","info","conditionMet","completedAt","output","reason","skipped","state","resolvedInput","input","job","jobs","queue","task","debug","update","data","automationWorkflow","automationWorkflowId","automationWorkflowRun","automationWorkflowRunId","automationTrigger","automationTriggerId","automationStepName","runResult","runByID","jobStatus","jobSucceeded","completedJob","taskStatus","taskSlug","totalTried","duration","getTime","errorMessage","log","latestLog","timeout","warn","safeSerialize","obj","seen","WeakSet","excludeKeys","reqAllowedKeys","serialize","value","parentKey","Array","isArray","v","key","val","Object","entries","execute","firedTrigger","workflowId","workflowName","triggerId","triggerName","workflowRun","create","workflowVersion","triggerData","trigger","triggeredBy","user","email","inputs","logs","timestamp","level","workflowRunId","batchCount","batchSizes","b","batchIndex","batch","stepCount","stepNames","s","batchPromises","idx","findIndex","r","errorHandling","Promise","all","outputs"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugin/config-types.ts"],"sourcesContent":["import type {CollectionConfig, GlobalConfig, TaskConfig} from \"payload\"\n\n/**\n * Trigger definition for custom trigger configurations.\n */\nexport interface Trigger {\n slug: string\n label?: string\n parameters?: Array<{\n name: string\n type: string\n required?: boolean\n }>\n}\n\nexport type TriggerConfig = (config: WorkflowsPluginConfig) => Trigger\n\nexport type SeedWorkflow = {\n slug: string\n name: string\n description?: string\n triggers: Array<{\n type: string\n parameters?: Record<string, any>\n condition?: string\n }>\n steps: Array<{\n name: string\n type: string\n input?: Record<string, any>\n dependencies?: string[]\n condition?: string\n }>\n}\n\n/**\n * Plugin configuration for the workflows automation plugin.\n */\nexport type WorkflowsPluginConfig<\n TCollection extends string = string,\n TGlobal extends string = string\n> = {\n /**\n * Whether the plugin is enabled. Defaults to true.\n */\n enabled?: boolean\n\n /**\n * Collection triggers configuration.\n * Keys are collection slugs, values configure which hooks to listen to.\n * Set to `true` to enable all default hooks (afterChange, afterDelete, afterRead).\n */\n collectionTriggers?: {\n [key in TCollection]?: {\n [key in keyof CollectionConfig['hooks']]?: true\n } | true\n }\n\n /**\n * Global triggers configuration.\n * Keys are global slugs, values configure which hooks to listen to.\n * Set to `true` to enable all default hooks (afterChange, afterRead).\n */\n globalTriggers?: {\n [key in TGlobal]?: {\n [key in keyof GlobalConfig['hooks']]?: true\n } | true\n }\n\n /**\n * Step task configurations.\n * These are the step types available for use in workflows.\n */\n steps: TaskConfig<string>[]\n\n /**\n * Seed workflows to create on plugin initialization.\n * These workflows are read-only and serve as templates.\n */\n seedWorkflows?: SeedWorkflow[]\n\n /**\n * Custom trigger configurations.\n */\n triggers?: TriggerConfig[]\n\n /**\n * Logging configuration.\n * Set to true to enable debug logging.\n */\n debug?: boolean\n}"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/config-types.ts"],"sourcesContent":["import type {CollectionConfig, GlobalConfig, TaskConfig} from \"payload\"\n\n/**\n * Trigger definition for custom trigger configurations.\n */\nexport interface Trigger {\n slug: string\n label?: string\n parameters?: Array<{\n name: string\n type: string\n required?: boolean\n }>\n}\n\nexport type TriggerConfig = (config: WorkflowsPluginConfig) => Trigger\n\nexport type SeedWorkflow = {\n slug: string\n name: string\n description?: string\n triggers: Array<{\n type: string\n parameters?: Record<string, any>\n condition?: string\n }>\n steps: Array<{\n name: string\n slug?: string // Optional: auto-generated from name if not provided\n type: string\n input?: Record<string, any>\n dependencies?: string[] // Array of step slugs\n condition?: string\n }>\n}\n\n/**\n * Plugin configuration for the workflows automation plugin.\n */\nexport type WorkflowsPluginConfig<\n TCollection extends string = string,\n TGlobal extends string = string\n> = {\n /**\n * Whether the plugin is enabled. Defaults to true.\n */\n enabled?: boolean\n\n /**\n * Collection triggers configuration.\n * Keys are collection slugs, values configure which hooks to listen to.\n * Set to `true` to enable all default hooks (afterChange, afterDelete, afterRead).\n */\n collectionTriggers?: {\n [key in TCollection]?: {\n [key in keyof CollectionConfig['hooks']]?: true\n } | true\n }\n\n /**\n * Global triggers configuration.\n * Keys are global slugs, values configure which hooks to listen to.\n * Set to `true` to enable all default hooks (afterChange, afterRead).\n */\n globalTriggers?: {\n [key in TGlobal]?: {\n [key in keyof GlobalConfig['hooks']]?: true\n } | true\n }\n\n /**\n * Step task configurations.\n * These are the step types available for use in workflows.\n */\n steps: TaskConfig<string>[]\n\n /**\n * Seed workflows to create on plugin initialization.\n * These workflows are read-only and serve as templates.\n */\n seedWorkflows?: SeedWorkflow[]\n\n /**\n * Custom trigger configurations.\n */\n triggers?: TriggerConfig[]\n\n /**\n * Logging configuration.\n * Set to true to enable debug logging.\n */\n debug?: boolean\n}"],"names":[],"mappings":"AAoCA;;CAEC,GACD,WAqDC"}
|
package/dist/plugin/index.js
CHANGED
|
@@ -243,10 +243,13 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
|
|
|
243
243
|
triggerIds.push(trigger.id);
|
|
244
244
|
logger.debug(`Created trigger: ${triggerName}`);
|
|
245
245
|
}
|
|
246
|
+
// Helper to generate slug from name
|
|
247
|
+
const slugify = (str)=>str.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
246
248
|
// Create steps in automation-steps collection and build workflow steps array
|
|
247
249
|
const workflowSteps = [];
|
|
248
250
|
for (const stepDef of seedWorkflow.steps){
|
|
249
251
|
const stepName = `${seedWorkflow.name} - ${stepDef.name}`;
|
|
252
|
+
const stepSlug = stepDef.slug || slugify(stepDef.name);
|
|
250
253
|
// Create step in automation-steps collection
|
|
251
254
|
const step = await payload.create({
|
|
252
255
|
collection: 'automation-steps',
|
|
@@ -260,11 +263,12 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
|
|
|
260
263
|
// Add to workflow steps with relationship ID
|
|
261
264
|
workflowSteps.push({
|
|
262
265
|
step: step.id,
|
|
266
|
+
slug: stepSlug,
|
|
263
267
|
stepName: stepDef.name,
|
|
264
268
|
inputOverrides: stepDef.input || {},
|
|
265
269
|
condition: stepDef.condition,
|
|
266
270
|
dependencies: stepDef.dependencies?.map((dep)=>({
|
|
267
|
-
|
|
271
|
+
slug: dep
|
|
268
272
|
}))
|
|
269
273
|
});
|
|
270
274
|
}
|
package/dist/plugin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugin/index.ts"],"sourcesContent":["import type { CollectionConfig, Config } from 'payload'\n\nimport type { WorkflowsPluginConfig } from './config-types.js'\n\nimport { createTriggersCollection } from '../collections/Triggers.js'\nimport { createStepsCollection } from '../collections/Steps.js'\nimport { createWorkflowCollection } from '../collections/Workflow.js'\nimport { WorkflowRunsCollection } from '../collections/WorkflowRuns.js'\nimport { getConfigLogger, initializeLogger } from './logger.js'\nimport { createCollectionTriggerHook, createGlobalTriggerHook } from './trigger-hook.js'\n\nexport { getLogger } from './logger.js'\n\nconst applyCollectionsConfig = <T extends string>(\n pluginOptions: WorkflowsPluginConfig<T>,\n config: Config\n) => {\n if (!config.collections) {\n config.collections = []\n }\n\n // Add all automation collections\n config.collections.push(\n createTriggersCollection(pluginOptions),\n createStepsCollection(pluginOptions.steps),\n createWorkflowCollection(),\n WorkflowRunsCollection\n )\n}\n\ntype AnyHook =\n CollectionConfig['hooks'] extends infer H\n ? H extends Record<string, unknown>\n ? NonNullable<H[keyof H]> extends (infer U)[]\n ? U\n : never\n : never\n : never\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 const logger = getConfigLogger()\n\n // Register collection hooks\n if (config.collections && pluginOptions.collectionTriggers) {\n for (const [collectionSlug, triggerConfig] of Object.entries(pluginOptions.collectionTriggers)) {\n if (!triggerConfig) {\n continue\n }\n\n const collectionIndex = config.collections.findIndex(c => c.slug === collectionSlug)\n if (collectionIndex === -1) {\n logger.warn(`Collection '${collectionSlug}' not found in config.collections`)\n continue\n }\n\n const collection = config.collections[collectionIndex]\n\n if (!collection.hooks) {\n collection.hooks = {}\n }\n\n const hooksToRegister = triggerConfig === true\n ? { afterChange: true, afterDelete: true, afterRead: true }\n : triggerConfig\n\n Object.entries(hooksToRegister).forEach(([hookName, enabled]) => {\n if (!enabled) {\n return\n }\n\n const hookKey = hookName as keyof typeof collection.hooks\n\n if (!collection.hooks![hookKey]) {\n collection.hooks![hookKey] = []\n }\n\n const automationHook = createCollectionTriggerHook(collectionSlug, hookKey)\n\n Object.defineProperty(automationHook, '__isAutomationHook', {\n value: true,\n enumerable: false\n })\n Object.defineProperty(automationHook, '__hookType', {\n value: hookKey,\n enumerable: false\n })\n\n ;(collection.hooks![hookKey] as Array<unknown>).push(automationHook)\n\n logger.debug(`Registered ${hookKey} hook for collection '${collectionSlug}'`)\n })\n }\n }\n\n // Register global hooks\n if (config.globals && pluginOptions.globalTriggers) {\n for (const [globalSlug, triggerConfig] of Object.entries(pluginOptions.globalTriggers)) {\n if (!triggerConfig) {\n continue\n }\n\n const globalIndex = config.globals.findIndex(g => g.slug === globalSlug)\n if (globalIndex === -1) {\n logger.warn(`Global '${globalSlug}' not found in config.globals`)\n continue\n }\n\n const global = config.globals[globalIndex]\n\n if (!global.hooks) {\n global.hooks = {}\n }\n\n const hooksToRegister = triggerConfig === true\n ? { afterChange: true, afterRead: true }\n : triggerConfig\n\n Object.entries(hooksToRegister).forEach(([hookName, enabled]) => {\n if (!enabled) {\n return\n }\n\n const hookKey = hookName as keyof typeof global.hooks\n\n if (!global.hooks![hookKey]) {\n global.hooks![hookKey] = []\n }\n\n const automationHook = createGlobalTriggerHook(globalSlug, hookKey)\n\n Object.defineProperty(automationHook, '__isAutomationHook', {\n value: true,\n enumerable: false\n })\n Object.defineProperty(automationHook, '__hookType', {\n value: hookKey,\n enumerable: false\n })\n\n ;(global.hooks![hookKey] as Array<unknown>).push(automationHook)\n\n logger.debug(`Registered ${hookKey} hook for global '${globalSlug}'`)\n })\n }\n }\n\n // Register step tasks\n if (!config.jobs) {\n config.jobs = { tasks: [] }\n }\n\n for (const step of pluginOptions.steps) {\n if (!config.jobs?.tasks?.find(task => task.slug === step.slug)) {\n config.jobs?.tasks?.push(step)\n }\n }\n\n // Extend payload-jobs collection with automation context fields\n const existingJobsOverrides = config.jobs.jobsCollectionOverrides\n config.jobs.jobsCollectionOverrides = ({ defaultJobsCollection }) => {\n // Apply any existing overrides first\n const collection = existingJobsOverrides\n ? existingJobsOverrides({ defaultJobsCollection })\n : defaultJobsCollection\n\n return {\n ...collection,\n fields: [\n ...collection.fields,\n // Structured automation context fields for admin UI integration\n {\n name: 'automationWorkflow',\n type: 'relationship',\n relationTo: 'workflows',\n admin: {\n position: 'sidebar',\n readOnly: true,\n description: 'Workflow that created this job',\n },\n },\n {\n name: 'automationWorkflowRun',\n type: 'relationship',\n relationTo: 'workflow-runs',\n admin: {\n position: 'sidebar',\n readOnly: true,\n description: 'Workflow run that created this job',\n },\n },\n {\n name: 'automationTrigger',\n type: 'relationship',\n relationTo: 'automation-triggers',\n admin: {\n position: 'sidebar',\n readOnly: true,\n description: 'Trigger that initiated the workflow',\n },\n },\n {\n name: 'automationStepName',\n type: 'text',\n admin: {\n position: 'sidebar',\n readOnly: true,\n description: 'Name of the workflow step that created this job',\n },\n },\n ],\n admin: {\n ...collection.admin,\n listSearchableFields: [\n ...(collection.admin?.listSearchableFields || []),\n ],\n defaultColumns: [\n ...(collection.admin?.defaultColumns || ['taskSlug', 'queue', 'processing', 'completedAt']),\n ],\n },\n }\n }\n\n // Set up onInit\n const incomingOnInit = config.onInit\n config.onInit = async (payload) => {\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n\n const logger = initializeLogger(payload)\n logger.info('Automation plugin initialized')\n\n const collectionCount = Object.keys(pluginOptions.collectionTriggers || {}).length\n const globalCount = Object.keys(pluginOptions.globalTriggers || {}).length\n const stepCount = pluginOptions.steps?.length || 0\n\n // Seed workflows if configured\n if (pluginOptions.seedWorkflows && pluginOptions.seedWorkflows.length > 0) {\n logger.info(`Seeding ${pluginOptions.seedWorkflows.length} workflows...`)\n\n for (const seedWorkflow of pluginOptions.seedWorkflows) {\n try {\n // Check if workflow already exists by slug\n const existingWorkflow = await payload.find({\n collection: 'workflows',\n where: {\n slug: {\n equals: seedWorkflow.slug,\n },\n },\n limit: 1,\n })\n\n if (existingWorkflow.docs.length > 0) {\n logger.debug(`Workflow '${seedWorkflow.slug}' already exists, skipping seed`)\n continue\n }\n\n // Create triggers in automation-triggers collection\n const triggerIds: (string | number)[] = []\n for (let i = 0; i < seedWorkflow.triggers.length; i++) {\n const triggerDef = seedWorkflow.triggers[i]\n const triggerName = `${seedWorkflow.name} - Trigger ${i + 1}`\n\n // Build trigger data based on type\n const triggerData: Record<string, unknown> = {\n name: triggerName,\n type: triggerDef.type,\n condition: triggerDef.condition,\n }\n\n // Map parameters to trigger fields based on type\n if (triggerDef.parameters) {\n if (triggerDef.type === 'collection-hook') {\n triggerData.collectionSlug = triggerDef.parameters.collectionSlug\n triggerData.hook = triggerDef.parameters.hook\n } else if (triggerDef.type === 'global-hook') {\n triggerData.globalSlug = triggerDef.parameters.globalSlug\n triggerData.hook = triggerDef.parameters.hook\n } else if (triggerDef.type === 'scheduled') {\n triggerData.schedule = triggerDef.parameters.schedule\n } else if (triggerDef.type === 'webhook') {\n triggerData.webhookPath = triggerDef.parameters.webhookPath\n }\n }\n\n const trigger = await payload.create({\n collection: 'automation-triggers',\n data: triggerData,\n })\n triggerIds.push(trigger.id)\n logger.debug(`Created trigger: ${triggerName}`)\n }\n\n // Create steps in automation-steps collection and build workflow steps array\n const workflowSteps: Array<{\n step: string | number\n stepName: string\n inputOverrides: Record<string, unknown>\n condition?: string\n dependencies?: Array<{ stepName: string }>\n }> = []\n\n for (const stepDef of seedWorkflow.steps) {\n const stepName = `${seedWorkflow.name} - ${stepDef.name}`\n\n // Create step in automation-steps collection\n const step = await payload.create({\n collection: 'automation-steps',\n data: {\n name: stepName,\n type: stepDef.type,\n config: stepDef.input || {},\n },\n })\n logger.debug(`Created step: ${stepName}`)\n\n // Add to workflow steps with relationship ID\n workflowSteps.push({\n step: step.id,\n stepName: stepDef.name,\n inputOverrides: stepDef.input || {},\n condition: stepDef.condition,\n dependencies: stepDef.dependencies?.map(dep => ({ stepName: dep })),\n })\n }\n\n // Create the workflow with relationship IDs\n await payload.create({\n collection: 'workflows',\n data: {\n slug: seedWorkflow.slug,\n name: seedWorkflow.name,\n description: seedWorkflow.description,\n triggers: triggerIds,\n steps: workflowSteps,\n readOnly: true,\n },\n })\n\n logger.info(`Seeded workflow: ${seedWorkflow.name}`)\n } catch (error) {\n logger.error(`Failed to seed workflow '${seedWorkflow.name}':`, error)\n }\n }\n }\n\n logger.info(`Plugin configuration: ${collectionCount} collection triggers, ${globalCount} global triggers, ${stepCount} steps`\n )\n }\n\n if (!config.custom) {\n config.custom = {}\n }\n if (!config.custom.pluginConfigs) {\n config.custom.pluginConfigs = {}\n }\n config.custom.pluginConfigs['@xtr-dev/payload-automation'] = pluginOptions\n\n return config\n }\n"],"names":["createTriggersCollection","createStepsCollection","createWorkflowCollection","WorkflowRunsCollection","getConfigLogger","initializeLogger","createCollectionTriggerHook","createGlobalTriggerHook","getLogger","applyCollectionsConfig","pluginOptions","config","collections","push","steps","workflowsPlugin","enabled","logger","collectionTriggers","collectionSlug","triggerConfig","Object","entries","collectionIndex","findIndex","c","slug","warn","collection","hooks","hooksToRegister","afterChange","afterDelete","afterRead","forEach","hookName","hookKey","automationHook","defineProperty","value","enumerable","debug","globals","globalTriggers","globalSlug","globalIndex","g","global","jobs","tasks","step","find","task","existingJobsOverrides","jobsCollectionOverrides","defaultJobsCollection","fields","name","type","relationTo","admin","position","readOnly","description","listSearchableFields","defaultColumns","incomingOnInit","onInit","payload","info","collectionCount","keys","length","globalCount","stepCount","seedWorkflows","seedWorkflow","existingWorkflow","where","equals","limit","docs","triggerIds","i","triggers","triggerDef","triggerName","triggerData","condition","parameters","hook","schedule","webhookPath","trigger","create","data","id","workflowSteps","stepDef","stepName","input","inputOverrides","dependencies","map","dep","error","custom","pluginConfigs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/index.ts"],"sourcesContent":["import type { CollectionConfig, Config } from 'payload'\n\nimport type { WorkflowsPluginConfig } from './config-types.js'\n\nimport { createTriggersCollection } from '../collections/Triggers.js'\nimport { createStepsCollection } from '../collections/Steps.js'\nimport { createWorkflowCollection } from '../collections/Workflow.js'\nimport { WorkflowRunsCollection } from '../collections/WorkflowRuns.js'\nimport { getConfigLogger, initializeLogger } from './logger.js'\nimport { createCollectionTriggerHook, createGlobalTriggerHook } from './trigger-hook.js'\n\nexport { getLogger } from './logger.js'\n\nconst applyCollectionsConfig = <T extends string>(\n pluginOptions: WorkflowsPluginConfig<T>,\n config: Config\n) => {\n if (!config.collections) {\n config.collections = []\n }\n\n // Add all automation collections\n config.collections.push(\n createTriggersCollection(pluginOptions),\n createStepsCollection(pluginOptions.steps),\n createWorkflowCollection(),\n WorkflowRunsCollection\n )\n}\n\ntype AnyHook =\n CollectionConfig['hooks'] extends infer H\n ? H extends Record<string, unknown>\n ? NonNullable<H[keyof H]> extends (infer U)[]\n ? U\n : never\n : never\n : never\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 const logger = getConfigLogger()\n\n // Register collection hooks\n if (config.collections && pluginOptions.collectionTriggers) {\n for (const [collectionSlug, triggerConfig] of Object.entries(pluginOptions.collectionTriggers)) {\n if (!triggerConfig) {\n continue\n }\n\n const collectionIndex = config.collections.findIndex(c => c.slug === collectionSlug)\n if (collectionIndex === -1) {\n logger.warn(`Collection '${collectionSlug}' not found in config.collections`)\n continue\n }\n\n const collection = config.collections[collectionIndex]\n\n if (!collection.hooks) {\n collection.hooks = {}\n }\n\n const hooksToRegister = triggerConfig === true\n ? { afterChange: true, afterDelete: true, afterRead: true }\n : triggerConfig\n\n Object.entries(hooksToRegister).forEach(([hookName, enabled]) => {\n if (!enabled) {\n return\n }\n\n const hookKey = hookName as keyof typeof collection.hooks\n\n if (!collection.hooks![hookKey]) {\n collection.hooks![hookKey] = []\n }\n\n const automationHook = createCollectionTriggerHook(collectionSlug, hookKey)\n\n Object.defineProperty(automationHook, '__isAutomationHook', {\n value: true,\n enumerable: false\n })\n Object.defineProperty(automationHook, '__hookType', {\n value: hookKey,\n enumerable: false\n })\n\n ;(collection.hooks![hookKey] as Array<unknown>).push(automationHook)\n\n logger.debug(`Registered ${hookKey} hook for collection '${collectionSlug}'`)\n })\n }\n }\n\n // Register global hooks\n if (config.globals && pluginOptions.globalTriggers) {\n for (const [globalSlug, triggerConfig] of Object.entries(pluginOptions.globalTriggers)) {\n if (!triggerConfig) {\n continue\n }\n\n const globalIndex = config.globals.findIndex(g => g.slug === globalSlug)\n if (globalIndex === -1) {\n logger.warn(`Global '${globalSlug}' not found in config.globals`)\n continue\n }\n\n const global = config.globals[globalIndex]\n\n if (!global.hooks) {\n global.hooks = {}\n }\n\n const hooksToRegister = triggerConfig === true\n ? { afterChange: true, afterRead: true }\n : triggerConfig\n\n Object.entries(hooksToRegister).forEach(([hookName, enabled]) => {\n if (!enabled) {\n return\n }\n\n const hookKey = hookName as keyof typeof global.hooks\n\n if (!global.hooks![hookKey]) {\n global.hooks![hookKey] = []\n }\n\n const automationHook = createGlobalTriggerHook(globalSlug, hookKey)\n\n Object.defineProperty(automationHook, '__isAutomationHook', {\n value: true,\n enumerable: false\n })\n Object.defineProperty(automationHook, '__hookType', {\n value: hookKey,\n enumerable: false\n })\n\n ;(global.hooks![hookKey] as Array<unknown>).push(automationHook)\n\n logger.debug(`Registered ${hookKey} hook for global '${globalSlug}'`)\n })\n }\n }\n\n // Register step tasks\n if (!config.jobs) {\n config.jobs = { tasks: [] }\n }\n\n for (const step of pluginOptions.steps) {\n if (!config.jobs?.tasks?.find(task => task.slug === step.slug)) {\n config.jobs?.tasks?.push(step)\n }\n }\n\n // Extend payload-jobs collection with automation context fields\n const existingJobsOverrides = config.jobs.jobsCollectionOverrides\n config.jobs.jobsCollectionOverrides = ({ defaultJobsCollection }) => {\n // Apply any existing overrides first\n const collection = existingJobsOverrides\n ? existingJobsOverrides({ defaultJobsCollection })\n : defaultJobsCollection\n\n return {\n ...collection,\n fields: [\n ...collection.fields,\n // Structured automation context fields for admin UI integration\n {\n name: 'automationWorkflow',\n type: 'relationship',\n relationTo: 'workflows',\n admin: {\n position: 'sidebar',\n readOnly: true,\n description: 'Workflow that created this job',\n },\n },\n {\n name: 'automationWorkflowRun',\n type: 'relationship',\n relationTo: 'workflow-runs',\n admin: {\n position: 'sidebar',\n readOnly: true,\n description: 'Workflow run that created this job',\n },\n },\n {\n name: 'automationTrigger',\n type: 'relationship',\n relationTo: 'automation-triggers',\n admin: {\n position: 'sidebar',\n readOnly: true,\n description: 'Trigger that initiated the workflow',\n },\n },\n {\n name: 'automationStepName',\n type: 'text',\n admin: {\n position: 'sidebar',\n readOnly: true,\n description: 'Name of the workflow step that created this job',\n },\n },\n ],\n admin: {\n ...collection.admin,\n listSearchableFields: [\n ...(collection.admin?.listSearchableFields || []),\n ],\n defaultColumns: [\n ...(collection.admin?.defaultColumns || ['taskSlug', 'queue', 'processing', 'completedAt']),\n ],\n },\n }\n }\n\n // Set up onInit\n const incomingOnInit = config.onInit\n config.onInit = async (payload) => {\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n\n const logger = initializeLogger(payload)\n logger.info('Automation plugin initialized')\n\n const collectionCount = Object.keys(pluginOptions.collectionTriggers || {}).length\n const globalCount = Object.keys(pluginOptions.globalTriggers || {}).length\n const stepCount = pluginOptions.steps?.length || 0\n\n // Seed workflows if configured\n if (pluginOptions.seedWorkflows && pluginOptions.seedWorkflows.length > 0) {\n logger.info(`Seeding ${pluginOptions.seedWorkflows.length} workflows...`)\n\n for (const seedWorkflow of pluginOptions.seedWorkflows) {\n try {\n // Check if workflow already exists by slug\n const existingWorkflow = await payload.find({\n collection: 'workflows',\n where: {\n slug: {\n equals: seedWorkflow.slug,\n },\n },\n limit: 1,\n })\n\n if (existingWorkflow.docs.length > 0) {\n logger.debug(`Workflow '${seedWorkflow.slug}' already exists, skipping seed`)\n continue\n }\n\n // Create triggers in automation-triggers collection\n const triggerIds: (string | number)[] = []\n for (let i = 0; i < seedWorkflow.triggers.length; i++) {\n const triggerDef = seedWorkflow.triggers[i]\n const triggerName = `${seedWorkflow.name} - Trigger ${i + 1}`\n\n // Build trigger data based on type\n const triggerData: Record<string, unknown> = {\n name: triggerName,\n type: triggerDef.type,\n condition: triggerDef.condition,\n }\n\n // Map parameters to trigger fields based on type\n if (triggerDef.parameters) {\n if (triggerDef.type === 'collection-hook') {\n triggerData.collectionSlug = triggerDef.parameters.collectionSlug\n triggerData.hook = triggerDef.parameters.hook\n } else if (triggerDef.type === 'global-hook') {\n triggerData.globalSlug = triggerDef.parameters.globalSlug\n triggerData.hook = triggerDef.parameters.hook\n } else if (triggerDef.type === 'scheduled') {\n triggerData.schedule = triggerDef.parameters.schedule\n } else if (triggerDef.type === 'webhook') {\n triggerData.webhookPath = triggerDef.parameters.webhookPath\n }\n }\n\n const trigger = await payload.create({\n collection: 'automation-triggers',\n data: triggerData,\n })\n triggerIds.push(trigger.id)\n logger.debug(`Created trigger: ${triggerName}`)\n }\n\n // Helper to generate slug from name\n const slugify = (str: string): string =>\n str.toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n\n // Create steps in automation-steps collection and build workflow steps array\n const workflowSteps: Array<{\n step: string | number\n slug: string\n stepName: string\n inputOverrides: Record<string, unknown>\n condition?: string\n dependencies?: Array<{ slug: string }>\n }> = []\n\n for (const stepDef of seedWorkflow.steps) {\n const stepName = `${seedWorkflow.name} - ${stepDef.name}`\n const stepSlug = stepDef.slug || slugify(stepDef.name)\n\n // Create step in automation-steps collection\n const step = await payload.create({\n collection: 'automation-steps',\n data: {\n name: stepName,\n type: stepDef.type,\n config: stepDef.input || {},\n },\n })\n logger.debug(`Created step: ${stepName}`)\n\n // Add to workflow steps with relationship ID\n workflowSteps.push({\n step: step.id,\n slug: stepSlug,\n stepName: stepDef.name,\n inputOverrides: stepDef.input || {},\n condition: stepDef.condition,\n dependencies: stepDef.dependencies?.map(dep => ({ slug: dep })),\n })\n }\n\n // Create the workflow with relationship IDs\n await payload.create({\n collection: 'workflows',\n data: {\n slug: seedWorkflow.slug,\n name: seedWorkflow.name,\n description: seedWorkflow.description,\n triggers: triggerIds,\n steps: workflowSteps,\n readOnly: true,\n },\n })\n\n logger.info(`Seeded workflow: ${seedWorkflow.name}`)\n } catch (error) {\n logger.error(`Failed to seed workflow '${seedWorkflow.name}':`, error)\n }\n }\n }\n\n logger.info(`Plugin configuration: ${collectionCount} collection triggers, ${globalCount} global triggers, ${stepCount} steps`\n )\n }\n\n if (!config.custom) {\n config.custom = {}\n }\n if (!config.custom.pluginConfigs) {\n config.custom.pluginConfigs = {}\n }\n config.custom.pluginConfigs['@xtr-dev/payload-automation'] = pluginOptions\n\n return config\n }\n"],"names":["createTriggersCollection","createStepsCollection","createWorkflowCollection","WorkflowRunsCollection","getConfigLogger","initializeLogger","createCollectionTriggerHook","createGlobalTriggerHook","getLogger","applyCollectionsConfig","pluginOptions","config","collections","push","steps","workflowsPlugin","enabled","logger","collectionTriggers","collectionSlug","triggerConfig","Object","entries","collectionIndex","findIndex","c","slug","warn","collection","hooks","hooksToRegister","afterChange","afterDelete","afterRead","forEach","hookName","hookKey","automationHook","defineProperty","value","enumerable","debug","globals","globalTriggers","globalSlug","globalIndex","g","global","jobs","tasks","step","find","task","existingJobsOverrides","jobsCollectionOverrides","defaultJobsCollection","fields","name","type","relationTo","admin","position","readOnly","description","listSearchableFields","defaultColumns","incomingOnInit","onInit","payload","info","collectionCount","keys","length","globalCount","stepCount","seedWorkflows","seedWorkflow","existingWorkflow","where","equals","limit","docs","triggerIds","i","triggers","triggerDef","triggerName","triggerData","condition","parameters","hook","schedule","webhookPath","trigger","create","data","id","slugify","str","toLowerCase","replace","workflowSteps","stepDef","stepName","stepSlug","input","inputOverrides","dependencies","map","dep","error","custom","pluginConfigs"],"mappings":"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"}
|
package/dist/steps/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export { createStep } from './create-step.js';
|
|
2
|
-
export type { StepDefinition, StepTask } from './create-step.js';
|
|
3
1
|
export { CreateDocumentStepTask } from './create-document.js';
|
|
4
2
|
export { createDocumentHandler } from './create-document-handler.js';
|
|
5
3
|
export { DeleteDocumentStepTask } from './delete-document.js';
|
package/dist/steps/index.js
CHANGED
package/dist/steps/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/steps/index.ts"],"sourcesContent":["//
|
|
1
|
+
{"version":3,"sources":["../../src/steps/index.ts"],"sourcesContent":["// Built-in steps\nexport { CreateDocumentStepTask } from './create-document.js'\nexport { createDocumentHandler } from './create-document-handler.js'\nexport { DeleteDocumentStepTask } from './delete-document.js'\nexport { deleteDocumentHandler } from './delete-document-handler.js'\nexport { HttpRequestStepTask } from './http-request.js'\nexport { httpStepHandler } from './http-request-handler.js'\n\nexport { ReadDocumentStepTask } from './read-document.js'\nexport { readDocumentHandler } from './read-document-handler.js'\nexport { SendEmailStepTask } from './send-email.js'\nexport { sendEmailHandler } from './send-email-handler.js'\nexport { UpdateDocumentStepTask } from './update-document.js'\nexport { updateDocumentHandler } from './update-document-handler.js'\n"],"names":["CreateDocumentStepTask","createDocumentHandler","DeleteDocumentStepTask","deleteDocumentHandler","HttpRequestStepTask","httpStepHandler","ReadDocumentStepTask","readDocumentHandler","SendEmailStepTask","sendEmailHandler","UpdateDocumentStepTask","updateDocumentHandler"],"mappings":"AAAA,iBAAiB;AACjB,SAASA,sBAAsB,QAAQ,uBAAsB;AAC7D,SAASC,qBAAqB,QAAQ,+BAA8B;AACpE,SAASC,sBAAsB,QAAQ,uBAAsB;AAC7D,SAASC,qBAAqB,QAAQ,+BAA8B;AACpE,SAASC,mBAAmB,QAAQ,oBAAmB;AACvD,SAASC,eAAe,QAAQ,4BAA2B;AAE3D,SAASC,oBAAoB,QAAQ,qBAAoB;AACzD,SAASC,mBAAmB,QAAQ,6BAA4B;AAChE,SAASC,iBAAiB,QAAQ,kBAAiB;AACnD,SAASC,gBAAgB,QAAQ,0BAAyB;AAC1D,SAASC,sBAAsB,QAAQ,uBAAsB;AAC7D,SAASC,qBAAqB,QAAQ,+BAA8B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xtr-dev/payload-automation",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.54",
|
|
4
4
|
"description": "PayloadCMS Automation Plugin - Comprehensive workflow automation system with visual workflow building, execution tracking, and step types",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { Field, JsonObject, PayloadRequest, TaskConfig } from 'payload';
|
|
2
|
-
/**
|
|
3
|
-
* Configuration for creating a step with the factory.
|
|
4
|
-
*/
|
|
5
|
-
export interface StepDefinition<TSlug extends string> {
|
|
6
|
-
/** Unique identifier for the step */
|
|
7
|
-
slug: TSlug;
|
|
8
|
-
/** Human-readable label for the step (optional, defaults to slug) */
|
|
9
|
-
label?: string;
|
|
10
|
-
/** Input fields schema */
|
|
11
|
-
inputSchema: Field[];
|
|
12
|
-
/** Output fields schema */
|
|
13
|
-
outputSchema: Field[];
|
|
14
|
-
/**
|
|
15
|
-
* Optional validation function. Throw an error if validation fails.
|
|
16
|
-
* Runs before the execute function.
|
|
17
|
-
*/
|
|
18
|
-
validate?: (input: JsonObject) => void;
|
|
19
|
-
/**
|
|
20
|
-
* The main execution function for the step.
|
|
21
|
-
* Should return the output data on success, or throw an error on failure.
|
|
22
|
-
*/
|
|
23
|
-
execute: (input: JsonObject, req: PayloadRequest) => Promise<JsonObject>;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* The result type returned by createStep.
|
|
27
|
-
* Combines TaskConfig with the handler for convenience.
|
|
28
|
-
*/
|
|
29
|
-
export type StepTask<TSlug extends string> = TaskConfig<TSlug>;
|
|
30
|
-
/**
|
|
31
|
-
* Creates a step definition that combines TaskConfig and handler in one place.
|
|
32
|
-
*
|
|
33
|
-
* This factory eliminates the need for separate `{step}.ts` and `{step}-handler.ts` files
|
|
34
|
-
* by providing a single unified definition.
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* ```typescript
|
|
38
|
-
* export const myStep = createStep({
|
|
39
|
-
* slug: 'my-step',
|
|
40
|
-
* inputSchema: [
|
|
41
|
-
* { name: 'url', type: 'text', required: true }
|
|
42
|
-
* ],
|
|
43
|
-
* outputSchema: [
|
|
44
|
-
* { name: 'result', type: 'json' }
|
|
45
|
-
* ],
|
|
46
|
-
* validate: (input) => {
|
|
47
|
-
* if (!input.url) throw new Error('URL is required')
|
|
48
|
-
* },
|
|
49
|
-
* execute: async (input, req) => {
|
|
50
|
-
* const response = await fetch(input.url)
|
|
51
|
-
* return { result: await response.json() }
|
|
52
|
-
* }
|
|
53
|
-
* })
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
export declare function createStep<TSlug extends string>(definition: StepDefinition<TSlug>): StepTask<TSlug>;
|
|
57
|
-
/**
|
|
58
|
-
* Helper type to extract input type from a step's inputSchema.
|
|
59
|
-
* Note: This provides a basic type based on field names, not full type inference.
|
|
60
|
-
*/
|
|
61
|
-
export type StepInput<T extends StepTask<string>> = T extends StepTask<infer _> ? Record<string, unknown> : never;
|
|
62
|
-
/**
|
|
63
|
-
* Helper type to extract output type from a step's outputSchema.
|
|
64
|
-
* Note: This provides a basic type based on field names, not full type inference.
|
|
65
|
-
*/
|
|
66
|
-
export type StepOutput<T extends StepTask<string>> = T extends StepTask<infer _> ? Record<string, unknown> : never;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a step definition that combines TaskConfig and handler in one place.
|
|
3
|
-
*
|
|
4
|
-
* This factory eliminates the need for separate `{step}.ts` and `{step}-handler.ts` files
|
|
5
|
-
* by providing a single unified definition.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* export const myStep = createStep({
|
|
10
|
-
* slug: 'my-step',
|
|
11
|
-
* inputSchema: [
|
|
12
|
-
* { name: 'url', type: 'text', required: true }
|
|
13
|
-
* ],
|
|
14
|
-
* outputSchema: [
|
|
15
|
-
* { name: 'result', type: 'json' }
|
|
16
|
-
* ],
|
|
17
|
-
* validate: (input) => {
|
|
18
|
-
* if (!input.url) throw new Error('URL is required')
|
|
19
|
-
* },
|
|
20
|
-
* execute: async (input, req) => {
|
|
21
|
-
* const response = await fetch(input.url)
|
|
22
|
-
* return { result: await response.json() }
|
|
23
|
-
* }
|
|
24
|
-
* })
|
|
25
|
-
* ```
|
|
26
|
-
*/ export function createStep(definition) {
|
|
27
|
-
const { slug, label, inputSchema, outputSchema, validate, execute } = definition;
|
|
28
|
-
// Create the handler that wraps validation and execution
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
-
const handler = async ({ input, req })=>{
|
|
31
|
-
try {
|
|
32
|
-
const jsonInput = input ?? {};
|
|
33
|
-
// Run validation if provided
|
|
34
|
-
if (validate) {
|
|
35
|
-
validate(jsonInput);
|
|
36
|
-
}
|
|
37
|
-
// Execute the step
|
|
38
|
-
const output = await execute(jsonInput, req);
|
|
39
|
-
return {
|
|
40
|
-
output,
|
|
41
|
-
state: 'succeeded'
|
|
42
|
-
};
|
|
43
|
-
} catch (error) {
|
|
44
|
-
return {
|
|
45
|
-
errorMessage: error instanceof Error ? error.message : 'Unknown error',
|
|
46
|
-
state: 'failed'
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
return {
|
|
51
|
-
slug,
|
|
52
|
-
label,
|
|
53
|
-
handler,
|
|
54
|
-
inputSchema,
|
|
55
|
-
outputSchema
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
//# sourceMappingURL=create-step.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/steps/create-step.ts"],"sourcesContent":["import type { Field, JsonObject, PayloadRequest, TaskConfig, TaskHandler } from 'payload'\n\n/**\n * Configuration for creating a step with the factory.\n */\nexport interface StepDefinition<TSlug extends string> {\n /** Unique identifier for the step */\n slug: TSlug\n /** Human-readable label for the step (optional, defaults to slug) */\n label?: string\n /** Input fields schema */\n inputSchema: Field[]\n /** Output fields schema */\n outputSchema: Field[]\n /**\n * Optional validation function. Throw an error if validation fails.\n * Runs before the execute function.\n */\n validate?: (input: JsonObject) => void\n /**\n * The main execution function for the step.\n * Should return the output data on success, or throw an error on failure.\n */\n execute: (input: JsonObject, req: PayloadRequest) => Promise<JsonObject>\n}\n\n/**\n * The result type returned by createStep.\n * Combines TaskConfig with the handler for convenience.\n */\nexport type StepTask<TSlug extends string> = TaskConfig<TSlug>\n\n/**\n * Creates a step definition that combines TaskConfig and handler in one place.\n *\n * This factory eliminates the need for separate `{step}.ts` and `{step}-handler.ts` files\n * by providing a single unified definition.\n *\n * @example\n * ```typescript\n * export const myStep = createStep({\n * slug: 'my-step',\n * inputSchema: [\n * { name: 'url', type: 'text', required: true }\n * ],\n * outputSchema: [\n * { name: 'result', type: 'json' }\n * ],\n * validate: (input) => {\n * if (!input.url) throw new Error('URL is required')\n * },\n * execute: async (input, req) => {\n * const response = await fetch(input.url)\n * return { result: await response.json() }\n * }\n * })\n * ```\n */\nexport function createStep<TSlug extends string>(\n definition: StepDefinition<TSlug>\n): StepTask<TSlug> {\n const { slug, label, inputSchema, outputSchema, validate, execute } = definition\n\n // Create the handler that wraps validation and execution\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const handler = async ({ input, req }: any) => {\n try {\n const jsonInput = (input ?? {}) as JsonObject\n\n // Run validation if provided\n if (validate) {\n validate(jsonInput)\n }\n\n // Execute the step\n const output = await execute(jsonInput, req)\n return {\n output,\n state: 'succeeded'\n }\n } catch (error) {\n return {\n errorMessage: error instanceof Error ? error.message : 'Unknown error',\n state: 'failed'\n }\n }\n }\n\n return {\n slug,\n label,\n handler,\n inputSchema,\n outputSchema\n } as StepTask<TSlug>\n}\n\n/**\n * Helper type to extract input type from a step's inputSchema.\n * Note: This provides a basic type based on field names, not full type inference.\n */\nexport type StepInput<T extends StepTask<string>> = T extends StepTask<infer _>\n ? Record<string, unknown>\n : never\n\n/**\n * Helper type to extract output type from a step's outputSchema.\n * Note: This provides a basic type based on field names, not full type inference.\n */\nexport type StepOutput<T extends StepTask<string>> = T extends StepTask<infer _>\n ? Record<string, unknown>\n : never\n"],"names":["createStep","definition","slug","label","inputSchema","outputSchema","validate","execute","handler","input","req","jsonInput","output","state","error","errorMessage","Error","message"],"mappings":"AAgCA;;;;;;;;;;;;;;;;;;;;;;;;;CAyBC,GACD,OAAO,SAASA,WACdC,UAAiC;IAEjC,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAEC,WAAW,EAAEC,YAAY,EAAEC,QAAQ,EAAEC,OAAO,EAAE,GAAGN;IAEtE,yDAAyD;IACzD,8DAA8D;IAC9D,MAAMO,UAAU,OAAO,EAAEC,KAAK,EAAEC,GAAG,EAAO;QACxC,IAAI;YACF,MAAMC,YAAaF,SAAS,CAAC;YAE7B,6BAA6B;YAC7B,IAAIH,UAAU;gBACZA,SAASK;YACX;YAEA,mBAAmB;YACnB,MAAMC,SAAS,MAAML,QAAQI,WAAWD;YACxC,OAAO;gBACLE;gBACAC,OAAO;YACT;QACF,EAAE,OAAOC,OAAO;YACd,OAAO;gBACLC,cAAcD,iBAAiBE,QAAQF,MAAMG,OAAO,GAAG;gBACvDJ,OAAO;YACT;QACF;IACF;IAEA,OAAO;QACLX;QACAC;QACAK;QACAJ;QACAC;IACF;AACF"}
|