@xtr-dev/payload-automation 0.0.42 → 0.0.45

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.
Files changed (76) hide show
  1. package/README.md +221 -49
  2. package/dist/collections/Steps.d.ts +6 -0
  3. package/dist/collections/Steps.js +166 -0
  4. package/dist/collections/Steps.js.map +1 -0
  5. package/dist/collections/Triggers.d.ts +7 -0
  6. package/dist/collections/Triggers.js +224 -0
  7. package/dist/collections/Triggers.js.map +1 -0
  8. package/dist/collections/Workflow.d.ts +5 -2
  9. package/dist/collections/Workflow.js +179 -39
  10. package/dist/collections/Workflow.js.map +1 -1
  11. package/dist/collections/WorkflowRuns.d.ts +4 -0
  12. package/dist/collections/WorkflowRuns.js +219 -24
  13. package/dist/collections/WorkflowRuns.js.map +1 -1
  14. package/dist/components/WorkflowBuilder/WorkflowBuilder.js.map +1 -1
  15. package/dist/core/expression-engine.d.ts +58 -0
  16. package/dist/core/expression-engine.js +191 -0
  17. package/dist/core/expression-engine.js.map +1 -0
  18. package/dist/core/workflow-executor.d.ts +70 -56
  19. package/dist/core/workflow-executor.js +354 -677
  20. package/dist/core/workflow-executor.js.map +1 -1
  21. package/dist/exports/client.js +1 -3
  22. package/dist/exports/client.js.map +1 -1
  23. package/dist/exports/views.js +2 -4
  24. package/dist/exports/views.js.map +1 -1
  25. package/dist/fields/parameter.js +8 -3
  26. package/dist/fields/parameter.js.map +1 -1
  27. package/dist/index.d.ts +3 -2
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/plugin/config-types.d.ts +43 -5
  31. package/dist/plugin/config-types.js +3 -1
  32. package/dist/plugin/config-types.js.map +1 -1
  33. package/dist/plugin/index.d.ts +1 -1
  34. package/dist/plugin/index.js +82 -28
  35. package/dist/plugin/index.js.map +1 -1
  36. package/dist/plugin/trigger-hook.d.ts +13 -0
  37. package/dist/plugin/trigger-hook.js +184 -0
  38. package/dist/plugin/trigger-hook.js.map +1 -0
  39. package/dist/steps/create-step.d.ts +66 -0
  40. package/dist/steps/create-step.js +59 -0
  41. package/dist/steps/create-step.js.map +1 -0
  42. package/dist/steps/index.d.ts +2 -0
  43. package/dist/steps/index.js +3 -0
  44. package/dist/steps/index.js.map +1 -1
  45. package/dist/steps/read-document-handler.js +1 -1
  46. package/dist/steps/read-document-handler.js.map +1 -1
  47. package/dist/steps/update-document-handler.js +1 -1
  48. package/dist/steps/update-document-handler.js.map +1 -1
  49. package/dist/triggers/hook-options.d.ts +34 -0
  50. package/dist/triggers/hook-options.js +158 -0
  51. package/dist/triggers/hook-options.js.map +1 -0
  52. package/dist/triggers/index.d.ts +2 -2
  53. package/dist/triggers/index.js +1 -2
  54. package/dist/triggers/index.js.map +1 -1
  55. package/dist/types/index.d.ts +8 -0
  56. package/dist/types/index.js +4 -5
  57. package/dist/types/index.js.map +1 -1
  58. package/dist/utils/validation.d.ts +64 -0
  59. package/dist/utils/validation.js +107 -0
  60. package/dist/utils/validation.js.map +1 -0
  61. package/package.json +2 -1
  62. package/dist/plugin/collection-hook.d.ts +0 -1
  63. package/dist/plugin/collection-hook.js +0 -92
  64. package/dist/plugin/collection-hook.js.map +0 -1
  65. package/dist/plugin/global-hook.d.ts +0 -1
  66. package/dist/plugin/global-hook.js +0 -83
  67. package/dist/plugin/global-hook.js.map +0 -1
  68. package/dist/triggers/collection-trigger.d.ts +0 -2
  69. package/dist/triggers/collection-trigger.js +0 -36
  70. package/dist/triggers/collection-trigger.js.map +0 -1
  71. package/dist/triggers/global-trigger.d.ts +0 -2
  72. package/dist/triggers/global-trigger.js +0 -29
  73. package/dist/triggers/global-trigger.js.map +0 -1
  74. package/dist/triggers/types.d.ts +0 -5
  75. package/dist/triggers/types.js +0 -3
  76. package/dist/triggers/types.js.map +0 -1
@@ -1,15 +1,16 @@
1
+ import { createTriggersCollection } from '../collections/Triggers.js';
2
+ import { createStepsCollection } from '../collections/Steps.js';
1
3
  import { createWorkflowCollection } from '../collections/Workflow.js';
2
4
  import { WorkflowRunsCollection } from '../collections/WorkflowRuns.js';
3
5
  import { getConfigLogger, initializeLogger } from './logger.js';
4
- import { createCollectionTriggerHook } from "./collection-hook.js";
5
- import { createGlobalTriggerHook } from "./global-hook.js";
6
+ import { createCollectionTriggerHook, createGlobalTriggerHook } from './trigger-hook.js';
6
7
  export { getLogger } from './logger.js';
7
8
  const applyCollectionsConfig = (pluginOptions, config)=>{
8
- // Add workflow collections
9
9
  if (!config.collections) {
10
10
  config.collections = [];
11
11
  }
12
- config.collections.push(createWorkflowCollection(pluginOptions), WorkflowRunsCollection);
12
+ // Add all automation collections
13
+ config.collections.push(createTriggersCollection(pluginOptions), createStepsCollection(pluginOptions.steps), createWorkflowCollection(), WorkflowRunsCollection);
13
14
  };
14
15
  export const workflowsPlugin = (pluginOptions)=>(config)=>{
15
16
  // If the plugin is disabled, return config unchanged
@@ -17,44 +18,36 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
17
18
  return config;
18
19
  }
19
20
  applyCollectionsConfig(pluginOptions, config);
20
- // CRITICAL: Modify existing collection configs BEFORE PayloadCMS processes them
21
- // This is the ONLY time we can add hooks that will actually work
22
21
  const logger = getConfigLogger();
22
+ // Register collection hooks
23
23
  if (config.collections && pluginOptions.collectionTriggers) {
24
24
  for (const [collectionSlug, triggerConfig] of Object.entries(pluginOptions.collectionTriggers)){
25
25
  if (!triggerConfig) {
26
26
  continue;
27
27
  }
28
- // Find the collection config that matches
29
28
  const collectionIndex = config.collections.findIndex((c)=>c.slug === collectionSlug);
30
29
  if (collectionIndex === -1) {
31
30
  logger.warn(`Collection '${collectionSlug}' not found in config.collections`);
32
31
  continue;
33
32
  }
34
33
  const collection = config.collections[collectionIndex];
35
- // Initialize hooks if needed
36
34
  if (!collection.hooks) {
37
35
  collection.hooks = {};
38
36
  }
39
- // Determine which hooks to register based on config
40
37
  const hooksToRegister = triggerConfig === true ? {
41
38
  afterChange: true,
42
39
  afterDelete: true,
43
40
  afterRead: true
44
41
  } : triggerConfig;
45
- // Register each configured hook
46
42
  Object.entries(hooksToRegister).forEach(([hookName, enabled])=>{
47
43
  if (!enabled) {
48
44
  return;
49
45
  }
50
46
  const hookKey = hookName;
51
- // Initialize the hook array if needed
52
47
  if (!collection.hooks[hookKey]) {
53
48
  collection.hooks[hookKey] = [];
54
49
  }
55
- // Create the automation hook for this specific collection and hook type
56
50
  const automationHook = createCollectionTriggerHook(collectionSlug, hookKey);
57
- // Mark it for debugging
58
51
  Object.defineProperty(automationHook, '__isAutomationHook', {
59
52
  value: true,
60
53
  enumerable: false
@@ -68,41 +61,34 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
68
61
  });
69
62
  }
70
63
  }
71
- // Handle global triggers similarly to collection triggers
64
+ // Register global hooks
72
65
  if (config.globals && pluginOptions.globalTriggers) {
73
66
  for (const [globalSlug, triggerConfig] of Object.entries(pluginOptions.globalTriggers)){
74
67
  if (!triggerConfig) {
75
68
  continue;
76
69
  }
77
- // Find the global config that matches
78
70
  const globalIndex = config.globals.findIndex((g)=>g.slug === globalSlug);
79
71
  if (globalIndex === -1) {
80
72
  logger.warn(`Global '${globalSlug}' not found in config.globals`);
81
73
  continue;
82
74
  }
83
75
  const global = config.globals[globalIndex];
84
- // Initialize hooks if needed
85
76
  if (!global.hooks) {
86
77
  global.hooks = {};
87
78
  }
88
- // Determine which hooks to register based on config
89
79
  const hooksToRegister = triggerConfig === true ? {
90
80
  afterChange: true,
91
81
  afterRead: true
92
82
  } : triggerConfig;
93
- // Register each configured hook
94
83
  Object.entries(hooksToRegister).forEach(([hookName, enabled])=>{
95
84
  if (!enabled) {
96
85
  return;
97
86
  }
98
87
  const hookKey = hookName;
99
- // Initialize the hook array if needed
100
88
  if (!global.hooks[hookKey]) {
101
89
  global.hooks[hookKey] = [];
102
90
  }
103
- // Create the automation hook for this specific global and hook type
104
91
  const automationHook = createGlobalTriggerHook(globalSlug, hookKey);
105
- // Mark it for debugging
106
92
  Object.defineProperty(automationHook, '__isAutomationHook', {
107
93
  value: true,
108
94
  enumerable: false
@@ -116,6 +102,7 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
116
102
  });
117
103
  }
118
104
  }
105
+ // Register step tasks
119
106
  if (!config.jobs) {
120
107
  config.jobs = {
121
108
  tasks: []
@@ -126,18 +113,85 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
126
113
  config.jobs?.tasks?.push(step);
127
114
  }
128
115
  }
129
- // Set up onInit to initialize features
116
+ // Extend payload-jobs collection with automation context fields
117
+ const existingJobsOverrides = config.jobs.jobsCollectionOverrides;
118
+ config.jobs.jobsCollectionOverrides = ({ defaultJobsCollection })=>{
119
+ // Apply any existing overrides first
120
+ const collection = existingJobsOverrides ? existingJobsOverrides({
121
+ defaultJobsCollection
122
+ }) : defaultJobsCollection;
123
+ return {
124
+ ...collection,
125
+ fields: [
126
+ ...collection.fields,
127
+ // Structured automation context fields for admin UI integration
128
+ {
129
+ name: 'automationWorkflow',
130
+ type: 'relationship',
131
+ relationTo: 'workflows',
132
+ admin: {
133
+ position: 'sidebar',
134
+ readOnly: true,
135
+ description: 'Workflow that created this job'
136
+ }
137
+ },
138
+ {
139
+ name: 'automationWorkflowRun',
140
+ type: 'relationship',
141
+ relationTo: 'workflow-runs',
142
+ admin: {
143
+ position: 'sidebar',
144
+ readOnly: true,
145
+ description: 'Workflow run that created this job'
146
+ }
147
+ },
148
+ {
149
+ name: 'automationTrigger',
150
+ type: 'relationship',
151
+ relationTo: 'automation-triggers',
152
+ admin: {
153
+ position: 'sidebar',
154
+ readOnly: true,
155
+ description: 'Trigger that initiated the workflow'
156
+ }
157
+ },
158
+ {
159
+ name: 'automationStepName',
160
+ type: 'text',
161
+ admin: {
162
+ position: 'sidebar',
163
+ readOnly: true,
164
+ description: 'Name of the workflow step that created this job'
165
+ }
166
+ }
167
+ ],
168
+ admin: {
169
+ ...collection.admin,
170
+ listSearchableFields: [
171
+ ...collection.admin?.listSearchableFields || []
172
+ ],
173
+ defaultColumns: [
174
+ ...collection.admin?.defaultColumns || [
175
+ 'taskSlug',
176
+ 'queue',
177
+ 'processing',
178
+ 'completedAt'
179
+ ]
180
+ ]
181
+ }
182
+ };
183
+ };
184
+ // Set up onInit
130
185
  const incomingOnInit = config.onInit;
131
186
  config.onInit = async (payload)=>{
132
- // Execute any existing onInit functions first
133
187
  if (incomingOnInit) {
134
188
  await incomingOnInit(payload);
135
189
  }
136
- // Initialize the logger with the payload instance
137
190
  const logger = initializeLogger(payload);
138
- logger.info('Logger initialized with payload instance');
139
- // Log trigger configuration
140
- logger.info(`Plugin configuration: ${Object.keys(pluginOptions.collectionTriggers || {}).length} collection triggers, ${Object.keys(pluginOptions.globalTriggers || {}).length} global triggers, ${pluginOptions.steps?.length || 0} steps`);
191
+ logger.info('Automation plugin initialized');
192
+ const collectionCount = Object.keys(pluginOptions.collectionTriggers || {}).length;
193
+ const globalCount = Object.keys(pluginOptions.globalTriggers || {}).length;
194
+ const stepCount = pluginOptions.steps?.length || 0;
141
195
  // Seed workflows if configured
142
196
  if (pluginOptions.seedWorkflows && pluginOptions.seedWorkflows.length > 0) {
143
197
  logger.info(`Seeding ${pluginOptions.seedWorkflows.length} workflows...`);
@@ -191,7 +245,7 @@ export const workflowsPlugin = (pluginOptions)=>(config)=>{
191
245
  }
192
246
  }
193
247
  }
194
- logger.info('Plugin initialized successfully - all hooks registered');
248
+ logger.info(`Plugin configuration: ${collectionCount} collection triggers, ${globalCount} global triggers, ${stepCount} steps`);
195
249
  };
196
250
  return config;
197
251
  };
@@ -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 {createWorkflowCollection} from '../collections/Workflow.js'\nimport {WorkflowRunsCollection} from '../collections/WorkflowRuns.js'\nimport {WorkflowExecutor} from '../core/workflow-executor.js'\nimport {getConfigLogger, initializeLogger} from './logger.js'\nimport {createCollectionTriggerHook} from \"./collection-hook.js\"\nimport {createGlobalTriggerHook} from \"./global-hook.js\"\n\nexport {getLogger} from './logger.js'\n\nconst applyCollectionsConfig = <T extends string>(pluginOptions: WorkflowsPluginConfig<T>, config: Config) => {\n // Add workflow collections\n if (!config.collections) {\n config.collections = []\n }\n\n config.collections.push(\n createWorkflowCollection(pluginOptions),\n WorkflowRunsCollection\n )\n}\n\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\ntype HookArgs = Parameters<AnyHook>[0]\n\nexport const workflowsPlugin =\n <TSlug extends string>(pluginOptions: WorkflowsPluginConfig<TSlug>) =>\n (config: Config): Config => {\n // If the plugin is disabled, return config unchanged\n if (pluginOptions.enabled === false) {\n return config\n }\n\n applyCollectionsConfig<TSlug>(pluginOptions, config)\n\n // CRITICAL: Modify existing collection configs BEFORE PayloadCMS processes them\n // This is the ONLY time we can add hooks that will actually work\n const logger = getConfigLogger()\n\n if (config.collections && pluginOptions.collectionTriggers) {\n for (const [collectionSlug, triggerConfig] of Object.entries(pluginOptions.collectionTriggers)) {\n if (!triggerConfig) {\n continue\n }\n\n // Find the collection config that matches\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 // Initialize hooks if needed\n if (!collection.hooks) {\n collection.hooks = {}\n }\n\n // Determine which hooks to register based on config\n const hooksToRegister = triggerConfig === true\n ? {\n afterChange: true,\n afterDelete: true,\n afterRead: true,\n }\n : triggerConfig\n\n // Register each configured hook\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 // Initialize the hook array if needed\n if (!collection.hooks![hookKey]) {\n collection.hooks![hookKey] = []\n }\n\n // Create the automation hook for this specific collection and hook type\n const automationHook = createCollectionTriggerHook(collectionSlug, hookKey)\n\n // Mark it for debugging\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 // Add the hook to the collection\n ;(collection.hooks![hookKey] as Array<unknown>).push(automationHook)\n\n logger.debug(`Registered ${hookKey} hook for collection '${collectionSlug}'`)\n })\n }\n }\n\n // Handle global triggers similarly to collection triggers\n if (config.globals && pluginOptions.globalTriggers) {\n for (const [globalSlug, triggerConfig] of Object.entries(pluginOptions.globalTriggers)) {\n if (!triggerConfig) {\n continue\n }\n\n // Find the global config that matches\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 // Initialize hooks if needed\n if (!global.hooks) {\n global.hooks = {}\n }\n\n // Determine which hooks to register based on config\n const hooksToRegister = triggerConfig === true\n ? {\n afterChange: true,\n afterRead: true,\n }\n : triggerConfig\n\n // Register each configured hook\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 // Initialize the hook array if needed\n if (!global.hooks![hookKey]) {\n global.hooks![hookKey] = []\n }\n\n // Create the automation hook for this specific global and hook type\n const automationHook = createGlobalTriggerHook(globalSlug, hookKey)\n\n // Mark it for debugging\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 // Add the hook to the global\n ;(global.hooks![hookKey] as Array<unknown>).push(automationHook)\n\n logger.debug(`Registered ${hookKey} hook for global '${globalSlug}'`)\n })\n }\n }\n\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\n // Set up onInit to initialize features\n const incomingOnInit = config.onInit\n config.onInit = async (payload) => {\n // Execute any existing onInit functions first\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n\n // Initialize the logger with the payload instance\n const logger = initializeLogger(payload)\n logger.info('Logger initialized with payload instance')\n\n // Log trigger configuration\n logger.info(`Plugin configuration: ${Object.keys(pluginOptions.collectionTriggers || {}).length} collection triggers, ${Object.keys(pluginOptions.globalTriggers || {}).length} global triggers, ${pluginOptions.steps?.length || 0} steps`)\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 const existing = existingWorkflow.docs[0]\n\n // Detect changes by comparing workflow definition\n const stepsChanged = JSON.stringify(existing.steps) !== JSON.stringify(seedWorkflow.steps)\n const triggersChanged = JSON.stringify(existing.triggers) !== JSON.stringify(seedWorkflow.triggers)\n const nameChanged = existing.name !== seedWorkflow.name\n const descriptionChanged = existing.description !== seedWorkflow.description\n\n const hasChanges = stepsChanged || triggersChanged || nameChanged || descriptionChanged\n\n if (hasChanges) {\n logger.info(`Updating seeded workflow '${seedWorkflow.slug}': ${seedWorkflow.name}`)\n\n await payload.update({\n collection: 'workflows',\n id: existing.id,\n data: {\n ...seedWorkflow,\n readOnly: true,\n },\n })\n\n logger.info(`Updated workflow: ${seedWorkflow.name}`)\n } else {\n logger.debug(`Workflow '${seedWorkflow.slug}' is up to date, skipping`)\n }\n } else {\n // Create the workflow as read-only\n await payload.create({\n collection: 'workflows',\n data: {\n ...seedWorkflow,\n readOnly: true,\n },\n })\n\n logger.info(`Seeded workflow: ${seedWorkflow.name}`)\n }\n } catch (error) {\n logger.error(`Failed to seed workflow '${seedWorkflow.name}':`, error)\n }\n }\n }\n\n logger.info('Plugin initialized successfully - all hooks registered')\n }\n\n return config\n }\n"],"names":["createWorkflowCollection","WorkflowRunsCollection","getConfigLogger","initializeLogger","createCollectionTriggerHook","createGlobalTriggerHook","getLogger","applyCollectionsConfig","pluginOptions","config","collections","push","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","steps","find","task","incomingOnInit","onInit","payload","info","keys","length","seedWorkflows","seedWorkflow","existingWorkflow","where","equals","limit","docs","existing","stepsChanged","JSON","stringify","triggersChanged","triggers","nameChanged","name","descriptionChanged","description","hasChanges","update","id","data","readOnly","create","error"],"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 const existing = existingWorkflow.docs[0]\n\n // Detect changes by comparing workflow definition\n const stepsChanged = JSON.stringify(existing.steps) !== JSON.stringify(seedWorkflow.steps)\n const triggersChanged = JSON.stringify(existing.triggers) !== JSON.stringify(seedWorkflow.triggers)\n const nameChanged = existing.name !== seedWorkflow.name\n const descriptionChanged = existing.description !== seedWorkflow.description\n\n const hasChanges = stepsChanged || triggersChanged || nameChanged || descriptionChanged\n\n if (hasChanges) {\n logger.info(`Updating seeded workflow '${seedWorkflow.slug}': ${seedWorkflow.name}`)\n\n await payload.update({\n collection: 'workflows',\n id: existing.id,\n data: {\n ...seedWorkflow,\n readOnly: true,\n },\n })\n\n logger.info(`Updated workflow: ${seedWorkflow.name}`)\n } else {\n logger.debug(`Workflow '${seedWorkflow.slug}' is up to date, skipping`)\n }\n } else {\n // Create the workflow as read-only\n await payload.create({\n collection: 'workflows',\n data: {\n ...seedWorkflow,\n readOnly: true,\n },\n })\n\n logger.info(`Seeded workflow: ${seedWorkflow.name}`)\n }\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 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","existing","stepsChanged","JSON","stringify","triggersChanged","triggers","nameChanged","descriptionChanged","hasChanges","update","id","data","create","error"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export type TriggerType = 'collection' | 'global';
2
+ export interface TriggerConfig {
3
+ type: TriggerType;
4
+ slug: string;
5
+ hookType: string;
6
+ }
7
+ /**
8
+ * Creates a unified hook handler for both collection and global triggers.
9
+ * Works with the new relationship-based data model where triggers are a separate collection.
10
+ */
11
+ export declare const createTriggerHook: (config: TriggerConfig) => (args: any) => Promise<void>;
12
+ export declare const createCollectionTriggerHook: (collectionSlug: string, hookType: string) => (args: any) => Promise<void>;
13
+ export declare const createGlobalTriggerHook: (globalSlug: string, hookType: string) => (args: any) => Promise<void>;
@@ -0,0 +1,184 @@
1
+ import { WorkflowExecutor } from '../core/workflow-executor.js';
2
+ /**
3
+ * Creates a unified hook handler for both collection and global triggers.
4
+ * Works with the new relationship-based data model where triggers are a separate collection.
5
+ */ export const createTriggerHook = (config)=>{
6
+ const { type, slug, hookType } = config;
7
+ // Build context based on trigger type
8
+ const buildContext = (args, firedTrigger)=>({
9
+ steps: {},
10
+ trigger: {
11
+ ...args,
12
+ type,
13
+ firedTrigger,
14
+ ...type === 'collection' ? {
15
+ collection: slug
16
+ } : {
17
+ global: slug,
18
+ operation: hookType
19
+ }
20
+ }
21
+ });
22
+ return async function automationTriggerHook(args) {
23
+ const req = 'req' in args ? args.req : 'args' in args ? args.args.req : undefined;
24
+ if (!req) {
25
+ throw new Error(`No request object found in ${type} hook arguments`);
26
+ }
27
+ const payload = req.payload;
28
+ const logger = payload.logger;
29
+ try {
30
+ logger.info({
31
+ triggerType: type,
32
+ slug,
33
+ hookType
34
+ }, `${type} automation hook triggered`);
35
+ const executor = new WorkflowExecutor(payload, logger);
36
+ // Step 1: Find all triggers that match this hook event
37
+ const triggerQuery = type === 'collection' ? {
38
+ type: {
39
+ equals: 'collection-hook'
40
+ },
41
+ collectionSlug: {
42
+ equals: slug
43
+ },
44
+ hook: {
45
+ equals: hookType
46
+ }
47
+ } : {
48
+ type: {
49
+ equals: 'global-hook'
50
+ },
51
+ globalSlug: {
52
+ equals: slug
53
+ },
54
+ hook: {
55
+ equals: hookType
56
+ }
57
+ };
58
+ const { docs: matchingTriggers } = await payload.find({
59
+ collection: 'automation-triggers',
60
+ depth: 0,
61
+ limit: 100,
62
+ where: triggerQuery
63
+ });
64
+ if (matchingTriggers.length === 0) {
65
+ logger.debug({
66
+ triggerType: type,
67
+ slug,
68
+ hookType
69
+ }, 'No matching triggers found');
70
+ return;
71
+ }
72
+ const triggerIds = matchingTriggers.map((t)=>t.id);
73
+ // Step 2: Find all enabled workflows that reference any of these triggers
74
+ const { docs: workflows } = await payload.find({
75
+ collection: 'workflows',
76
+ depth: 2,
77
+ limit: 100,
78
+ where: {
79
+ enabled: {
80
+ equals: true
81
+ },
82
+ triggers: {
83
+ in: triggerIds
84
+ }
85
+ }
86
+ });
87
+ if (workflows.length === 0) {
88
+ logger.debug({
89
+ triggerType: type,
90
+ slug,
91
+ hookType,
92
+ triggerIds
93
+ }, 'No enabled workflows found for matching triggers');
94
+ return;
95
+ }
96
+ // Step 3: Execute each matching workflow
97
+ for (const workflow of workflows){
98
+ // Find which trigger actually fired (for tracking in WorkflowRuns)
99
+ const firedTrigger = matchingTriggers.find((trigger)=>{
100
+ const workflowTriggerIds = (workflow.triggers || []).map((t)=>typeof t === 'object' ? t.id : t);
101
+ return workflowTriggerIds.includes(trigger.id);
102
+ });
103
+ if (!firedTrigger) {
104
+ continue;
105
+ }
106
+ const context = buildContext(args, firedTrigger);
107
+ // Evaluate trigger condition if present
108
+ if (firedTrigger.condition) {
109
+ try {
110
+ const conditionMet = await executor.evaluateCondition(firedTrigger.condition, context);
111
+ if (!conditionMet) {
112
+ logger.debug({
113
+ workflowId: workflow.id,
114
+ triggerId: firedTrigger.id,
115
+ condition: firedTrigger.condition
116
+ }, 'Workflow skipped due to unmet trigger condition');
117
+ continue;
118
+ }
119
+ } catch (error) {
120
+ logger.error({
121
+ workflowId: workflow.id,
122
+ triggerId: firedTrigger.id,
123
+ condition: firedTrigger.condition,
124
+ error: error instanceof Error ? error.message : 'Unknown error'
125
+ }, 'Failed to evaluate trigger condition');
126
+ continue;
127
+ }
128
+ }
129
+ try {
130
+ await executor.execute(workflow, context, req, firedTrigger);
131
+ logger.info({
132
+ workflowId: workflow.id,
133
+ workflowName: workflow.name,
134
+ triggerId: firedTrigger.id,
135
+ triggerName: firedTrigger.name,
136
+ triggerType: type,
137
+ slug,
138
+ hookType
139
+ }, 'Workflow executed successfully');
140
+ } catch (error) {
141
+ logger.error({
142
+ workflowId: workflow.id,
143
+ workflowName: workflow.name,
144
+ triggerId: firedTrigger.id,
145
+ triggerName: firedTrigger.name,
146
+ triggerType: type,
147
+ slug,
148
+ hookType,
149
+ error: error instanceof Error ? error.message : 'Unknown error'
150
+ }, 'Workflow execution failed');
151
+ // Don't throw to prevent breaking the original operation
152
+ }
153
+ }
154
+ logger.info({
155
+ triggerType: type,
156
+ slug,
157
+ hookType,
158
+ workflowCount: workflows.length
159
+ }, `${type} workflow execution completed`);
160
+ } catch (error) {
161
+ logger.error({
162
+ triggerType: type,
163
+ slug,
164
+ hookType,
165
+ error: error instanceof Error ? error.message : 'Unknown error',
166
+ errorStack: error instanceof Error ? error.stack : undefined
167
+ }, `${type} hook execution failed`);
168
+ // Don't throw to prevent breaking the original operation
169
+ }
170
+ };
171
+ };
172
+ // Convenience functions for creating hooks
173
+ export const createCollectionTriggerHook = (collectionSlug, hookType)=>createTriggerHook({
174
+ type: 'collection',
175
+ slug: collectionSlug,
176
+ hookType
177
+ });
178
+ export const createGlobalTriggerHook = (globalSlug, hookType)=>createTriggerHook({
179
+ type: 'global',
180
+ slug: globalSlug,
181
+ hookType
182
+ });
183
+
184
+ //# sourceMappingURL=trigger-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugin/trigger-hook.ts"],"sourcesContent":["import { WorkflowExecutor } from '../core/workflow-executor.js'\n\nexport type TriggerType = 'collection' | 'global'\n\nexport interface TriggerConfig {\n type: TriggerType\n slug: string\n hookType: string\n}\n\n/**\n * Creates a unified hook handler for both collection and global triggers.\n * Works with the new relationship-based data model where triggers are a separate collection.\n */\nexport const createTriggerHook = (config: TriggerConfig) => {\n const { type, slug, hookType } = config\n\n // Build context based on trigger type\n const buildContext = (args: any, firedTrigger?: any) => ({\n steps: {},\n trigger: {\n ...args,\n type,\n firedTrigger,\n ...(type === 'collection'\n ? { collection: slug }\n : { global: slug, operation: hookType }\n )\n }\n })\n\n return async function automationTriggerHook(args: any) {\n const req = 'req' in args ? args.req :\n 'args' in args ? args.args.req :\n undefined\n\n if (!req) {\n throw new Error(`No request object found in ${type} hook arguments`)\n }\n\n const payload = req.payload\n const logger = payload.logger\n\n try {\n logger.info({\n triggerType: type,\n slug,\n hookType\n }, `${type} automation hook triggered`)\n\n const executor = new WorkflowExecutor(payload, logger)\n\n // Step 1: Find all triggers that match this hook event\n const triggerQuery = type === 'collection'\n ? {\n type: { equals: 'collection-hook' },\n collectionSlug: { equals: slug },\n hook: { equals: hookType }\n }\n : {\n type: { equals: 'global-hook' },\n globalSlug: { equals: slug },\n hook: { equals: hookType }\n }\n\n const { docs: matchingTriggers } = await payload.find({\n collection: 'automation-triggers',\n depth: 0,\n limit: 100,\n where: triggerQuery\n })\n\n if (matchingTriggers.length === 0) {\n logger.debug({\n triggerType: type,\n slug,\n hookType\n }, 'No matching triggers found')\n return\n }\n\n const triggerIds = matchingTriggers.map((t: { id: string | number }) => t.id)\n\n // Step 2: Find all enabled workflows that reference any of these triggers\n const { docs: workflows } = await payload.find({\n collection: 'workflows',\n depth: 2, // Load trigger and step details\n limit: 100,\n where: {\n enabled: { equals: true },\n triggers: { in: triggerIds }\n }\n })\n\n if (workflows.length === 0) {\n logger.debug({\n triggerType: type,\n slug,\n hookType,\n triggerIds\n }, 'No enabled workflows found for matching triggers')\n return\n }\n\n // Step 3: Execute each matching workflow\n for (const workflow of workflows) {\n // Find which trigger actually fired (for tracking in WorkflowRuns)\n const firedTrigger = matchingTriggers.find((trigger: { id: string | number }) => {\n const workflowTriggerIds = (workflow.triggers || []).map((t: any) =>\n typeof t === 'object' ? t.id : t\n )\n return workflowTriggerIds.includes(trigger.id)\n })\n\n if (!firedTrigger) {\n continue\n }\n\n const context = buildContext(args, firedTrigger)\n\n // Evaluate trigger condition if present\n if (firedTrigger.condition) {\n try {\n const conditionMet = await executor.evaluateCondition(firedTrigger.condition, context)\n if (!conditionMet) {\n logger.debug({\n workflowId: workflow.id,\n triggerId: firedTrigger.id,\n condition: firedTrigger.condition\n }, 'Workflow skipped due to unmet trigger condition')\n continue\n }\n } catch (error) {\n logger.error({\n workflowId: workflow.id,\n triggerId: firedTrigger.id,\n condition: firedTrigger.condition,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to evaluate trigger condition')\n continue\n }\n }\n\n try {\n await executor.execute(workflow as any, context, req, firedTrigger)\n logger.info({\n workflowId: workflow.id,\n workflowName: workflow.name,\n triggerId: firedTrigger.id,\n triggerName: firedTrigger.name,\n triggerType: type,\n slug,\n hookType\n }, 'Workflow executed successfully')\n } catch (error) {\n logger.error({\n workflowId: workflow.id,\n workflowName: workflow.name,\n triggerId: firedTrigger.id,\n triggerName: firedTrigger.name,\n triggerType: type,\n slug,\n hookType,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Workflow execution failed')\n // Don't throw to prevent breaking the original operation\n }\n }\n\n logger.info({\n triggerType: type,\n slug,\n hookType,\n workflowCount: workflows.length\n }, `${type} workflow execution completed`)\n\n } catch (error) {\n logger.error({\n triggerType: type,\n slug,\n hookType,\n error: error instanceof Error ? error.message : 'Unknown error',\n errorStack: error instanceof Error ? error.stack : undefined\n }, `${type} hook execution failed`)\n // Don't throw to prevent breaking the original operation\n }\n }\n}\n\n// Convenience functions for creating hooks\nexport const createCollectionTriggerHook = (collectionSlug: string, hookType: string) =>\n createTriggerHook({ type: 'collection', slug: collectionSlug, hookType })\n\nexport const createGlobalTriggerHook = (globalSlug: string, hookType: string) =>\n createTriggerHook({ type: 'global', slug: globalSlug, hookType })\n"],"names":["WorkflowExecutor","createTriggerHook","config","type","slug","hookType","buildContext","args","firedTrigger","steps","trigger","collection","global","operation","automationTriggerHook","req","undefined","Error","payload","logger","info","triggerType","executor","triggerQuery","equals","collectionSlug","hook","globalSlug","docs","matchingTriggers","find","depth","limit","where","length","debug","triggerIds","map","t","id","workflows","enabled","triggers","in","workflow","workflowTriggerIds","includes","context","condition","conditionMet","evaluateCondition","workflowId","triggerId","error","message","execute","workflowName","name","triggerName","workflowCount","errorStack","stack","createCollectionTriggerHook","createGlobalTriggerHook"],"mappings":"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"}
@@ -0,0 +1,66 @@
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;
@@ -0,0 +1,59 @@
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