@xtr-dev/payload-automation 0.0.52 → 0.0.53
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 +185 -56
- 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,80 @@ 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
|
+
type: 'http-request-step',
|
|
115
|
+
input: {
|
|
116
|
+
url: 'https://api.example.com/validate',
|
|
117
|
+
method: 'POST',
|
|
118
|
+
body: {
|
|
119
|
+
orderId: '{{trigger.doc.id}}',
|
|
120
|
+
items: '{{trigger.doc.items}}',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'Check Inventory',
|
|
126
|
+
type: 'http-request-step',
|
|
127
|
+
input: {
|
|
128
|
+
url: 'https://api.example.com/inventory/check',
|
|
129
|
+
method: 'POST',
|
|
130
|
+
body: {
|
|
131
|
+
items: '{{trigger.doc.items}}',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
// This step runs only after Validate Order succeeds
|
|
135
|
+
dependencies: ['Validate Order'],
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'Create Shipment',
|
|
139
|
+
type: 'create-document',
|
|
140
|
+
input: {
|
|
141
|
+
collection: 'shipments',
|
|
142
|
+
data: {
|
|
143
|
+
orderId: '{{trigger.doc.id}}',
|
|
144
|
+
status: 'pending',
|
|
145
|
+
items: '{{trigger.doc.items}}',
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
// This step waits for both validation and inventory check
|
|
149
|
+
dependencies: ['Validate Order', 'Check Inventory'],
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'Send Confirmation Email',
|
|
153
|
+
type: 'send-email',
|
|
154
|
+
input: {
|
|
155
|
+
to: '{{trigger.doc.customer.email}}',
|
|
156
|
+
subject: 'Order Confirmed',
|
|
157
|
+
text: 'Your order {{trigger.doc.id}} has been confirmed!',
|
|
158
|
+
},
|
|
159
|
+
// Only send email after shipment is created
|
|
160
|
+
dependencies: ['Create Shipment'],
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
},
|
|
99
164
|
]
|
|
100
165
|
|
|
101
166
|
workflowsPlugin({
|
|
@@ -114,8 +179,73 @@ Seeded workflows:
|
|
|
114
179
|
|
|
115
180
|
See [docs/SEEDING_WORKFLOWS.md](./docs/SEEDING_WORKFLOWS.md) for detailed documentation.
|
|
116
181
|
|
|
182
|
+
## Step Dependencies
|
|
183
|
+
|
|
184
|
+
Steps can declare dependencies on other steps to control execution order. The workflow executor uses topological sorting to determine the optimal execution order.
|
|
185
|
+
|
|
186
|
+
### How Dependencies Work
|
|
187
|
+
|
|
188
|
+
- **Parallel Execution**: Steps without dependencies run in parallel
|
|
189
|
+
- **Sequential Execution**: Steps with dependencies wait for their dependencies to complete successfully
|
|
190
|
+
- **Multiple Dependencies**: A step can depend on multiple other steps (all must succeed)
|
|
191
|
+
- **Failure Handling**: If a dependency fails, the dependent step is skipped
|
|
192
|
+
|
|
193
|
+
### Example: Parallel and Sequential Steps
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
steps: [
|
|
197
|
+
{
|
|
198
|
+
name: 'Fetch User Data',
|
|
199
|
+
type: 'http-request-step',
|
|
200
|
+
// No dependencies - runs immediately
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'Fetch Order Data',
|
|
204
|
+
type: 'http-request-step',
|
|
205
|
+
// No dependencies - runs in parallel with Fetch User Data
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'Generate Report',
|
|
209
|
+
type: 'http-request-step',
|
|
210
|
+
dependencies: ['Fetch User Data', 'Fetch Order Data'],
|
|
211
|
+
// Waits for both API calls to complete
|
|
212
|
+
input: {
|
|
213
|
+
url: 'https://api.example.com/reports',
|
|
214
|
+
body: {
|
|
215
|
+
user: '{{steps.FetchUserData.output.user}}',
|
|
216
|
+
orders: '{{steps.FetchOrderData.output.orders}}',
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Accessing Step Output
|
|
224
|
+
|
|
225
|
+
Use `{{steps.<stepName>.output.<field>}}` to reference data from completed steps:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
{
|
|
229
|
+
name: 'Process Result',
|
|
230
|
+
type: 'create-document',
|
|
231
|
+
dependencies: ['API Call'],
|
|
232
|
+
input: {
|
|
233
|
+
collection: 'results',
|
|
234
|
+
data: {
|
|
235
|
+
// Access output from the "API Call" step
|
|
236
|
+
apiResponse: '{{steps.APICall.output.data}}',
|
|
237
|
+
status: '{{steps.APICall.output.status}}',
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
117
243
|
## Step Types
|
|
118
244
|
|
|
245
|
+
> **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.
|
|
246
|
+
|
|
247
|
+
The plugin comes with a few built-in step types found below.
|
|
248
|
+
|
|
119
249
|
### HTTP Request
|
|
120
250
|
Call external APIs with full configuration:
|
|
121
251
|
|
|
@@ -156,12 +286,13 @@ Send notifications via PayloadCMS email adapter:
|
|
|
156
286
|
|
|
157
287
|
## Custom Steps
|
|
158
288
|
|
|
159
|
-
|
|
289
|
+
Steps are standard PayloadCMS tasks, so creating custom steps is just defining a `TaskConfig`. No proprietary APIs to learn:
|
|
160
290
|
|
|
161
291
|
```typescript
|
|
162
|
-
import {
|
|
292
|
+
import type { TaskConfig } from 'payload'
|
|
163
293
|
|
|
164
|
-
|
|
294
|
+
// Define the step configuration
|
|
295
|
+
export const SlackNotificationStep: TaskConfig<'slack-notification'> = {
|
|
165
296
|
slug: 'slack-notification',
|
|
166
297
|
label: 'Send Slack Message',
|
|
167
298
|
|
|
@@ -175,42 +306,40 @@ export const SlackNotificationStep = createStep({
|
|
|
175
306
|
{ name: 'timestamp', type: 'text' },
|
|
176
307
|
],
|
|
177
308
|
|
|
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
|
-
|
|
309
|
+
handler: async ({ input, req }) => {
|
|
310
|
+
try {
|
|
311
|
+
const response = await fetch('https://slack.com/api/chat.postMessage', {
|
|
312
|
+
method: 'POST',
|
|
313
|
+
headers: {
|
|
314
|
+
'Authorization': `Bearer ${process.env.SLACK_TOKEN}`,
|
|
315
|
+
'Content-Type': 'application/json',
|
|
316
|
+
},
|
|
317
|
+
body: JSON.stringify({
|
|
318
|
+
channel: input.channel,
|
|
319
|
+
text: input.message,
|
|
320
|
+
}),
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
const data = await response.json()
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
output: {
|
|
327
|
+
messageId: data.message.ts,
|
|
328
|
+
timestamp: new Date().toISOString(),
|
|
329
|
+
},
|
|
330
|
+
state: 'succeeded'
|
|
331
|
+
}
|
|
332
|
+
} catch (error) {
|
|
333
|
+
return {
|
|
334
|
+
output: {},
|
|
335
|
+
state: 'failed',
|
|
336
|
+
errorMessage: error instanceof Error ? error.message : 'Unknown error'
|
|
337
|
+
}
|
|
206
338
|
}
|
|
207
339
|
},
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
Register custom steps in the plugin config:
|
|
340
|
+
}
|
|
212
341
|
|
|
213
|
-
|
|
342
|
+
// Register in plugin config
|
|
214
343
|
workflowsPlugin({
|
|
215
344
|
steps: [SlackNotificationStep],
|
|
216
345
|
})
|
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.53",
|
|
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"}
|