@xtr-dev/payload-automation 0.0.43 → 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 (74) 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/index.d.ts +3 -2
  26. package/dist/index.js +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/plugin/config-types.d.ts +43 -5
  29. package/dist/plugin/config-types.js +3 -1
  30. package/dist/plugin/config-types.js.map +1 -1
  31. package/dist/plugin/index.d.ts +1 -1
  32. package/dist/plugin/index.js +82 -28
  33. package/dist/plugin/index.js.map +1 -1
  34. package/dist/plugin/trigger-hook.d.ts +13 -0
  35. package/dist/plugin/trigger-hook.js +184 -0
  36. package/dist/plugin/trigger-hook.js.map +1 -0
  37. package/dist/steps/create-step.d.ts +66 -0
  38. package/dist/steps/create-step.js +59 -0
  39. package/dist/steps/create-step.js.map +1 -0
  40. package/dist/steps/index.d.ts +2 -0
  41. package/dist/steps/index.js +3 -0
  42. package/dist/steps/index.js.map +1 -1
  43. package/dist/steps/read-document-handler.js +1 -1
  44. package/dist/steps/read-document-handler.js.map +1 -1
  45. package/dist/steps/update-document-handler.js +1 -1
  46. package/dist/steps/update-document-handler.js.map +1 -1
  47. package/dist/triggers/hook-options.d.ts +34 -0
  48. package/dist/triggers/hook-options.js +158 -0
  49. package/dist/triggers/hook-options.js.map +1 -0
  50. package/dist/triggers/index.d.ts +2 -2
  51. package/dist/triggers/index.js +1 -2
  52. package/dist/triggers/index.js.map +1 -1
  53. package/dist/types/index.d.ts +8 -0
  54. package/dist/types/index.js +4 -5
  55. package/dist/types/index.js.map +1 -1
  56. package/dist/utils/validation.d.ts +64 -0
  57. package/dist/utils/validation.js +107 -0
  58. package/dist/utils/validation.js.map +1 -0
  59. package/package.json +2 -1
  60. package/dist/plugin/collection-hook.d.ts +0 -1
  61. package/dist/plugin/collection-hook.js +0 -92
  62. package/dist/plugin/collection-hook.js.map +0 -1
  63. package/dist/plugin/global-hook.d.ts +0 -1
  64. package/dist/plugin/global-hook.js +0 -83
  65. package/dist/plugin/global-hook.js.map +0 -1
  66. package/dist/triggers/collection-trigger.d.ts +0 -2
  67. package/dist/triggers/collection-trigger.js +0 -36
  68. package/dist/triggers/collection-trigger.js.map +0 -1
  69. package/dist/triggers/global-trigger.d.ts +0 -2
  70. package/dist/triggers/global-trigger.js +0 -29
  71. package/dist/triggers/global-trigger.js.map +0 -1
  72. package/dist/triggers/types.d.ts +0 -5
  73. package/dist/triggers/types.js +0 -3
  74. package/dist/triggers/types.js.map +0 -1
@@ -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":"AAAA,SAASA,gBAAgB,QAAQ,+BAA8B;AAU/D;;;CAGC,GACD,OAAO,MAAMC,oBAAoB,CAACC;IAChC,MAAM,EAAEC,IAAI,EAAEC,IAAI,EAAEC,QAAQ,EAAE,GAAGH;IAEjC,sCAAsC;IACtC,MAAMI,eAAe,CAACC,MAAWC,eAAwB,CAAA;YACvDC,OAAO,CAAC;YACRC,SAAS;gBACP,GAAGH,IAAI;gBACPJ;gBACAK;gBACA,GAAIL,SAAS,eACT;oBAAEQ,YAAYP;gBAAK,IACnB;oBAAEQ,QAAQR;oBAAMS,WAAWR;gBAAS,CAAC;YAE3C;QACF,CAAA;IAEA,OAAO,eAAeS,sBAAsBP,IAAS;QACnD,MAAMQ,MAAM,SAASR,OAAOA,KAAKQ,GAAG,GAClC,UAAUR,OAAOA,KAAKA,IAAI,CAACQ,GAAG,GAC9BC;QAEF,IAAI,CAACD,KAAK;YACR,MAAM,IAAIE,MAAM,CAAC,2BAA2B,EAAEd,KAAK,eAAe,CAAC;QACrE;QAEA,MAAMe,UAAUH,IAAIG,OAAO;QAC3B,MAAMC,SAASD,QAAQC,MAAM;QAE7B,IAAI;YACFA,OAAOC,IAAI,CAAC;gBACVC,aAAalB;gBACbC;gBACAC;YACF,GAAG,GAAGF,KAAK,0BAA0B,CAAC;YAEtC,MAAMmB,WAAW,IAAItB,iBAAiBkB,SAASC;YAE/C,uDAAuD;YACvD,MAAMI,eAAepB,SAAS,eAC1B;gBACEA,MAAM;oBAAEqB,QAAQ;gBAAkB;gBAClCC,gBAAgB;oBAAED,QAAQpB;gBAAK;gBAC/BsB,MAAM;oBAAEF,QAAQnB;gBAAS;YAC3B,IACA;gBACEF,MAAM;oBAAEqB,QAAQ;gBAAc;gBAC9BG,YAAY;oBAAEH,QAAQpB;gBAAK;gBAC3BsB,MAAM;oBAAEF,QAAQnB;gBAAS;YAC3B;YAEJ,MAAM,EAAEuB,MAAMC,gBAAgB,EAAE,GAAG,MAAMX,QAAQY,IAAI,CAAC;gBACpDnB,YAAY;gBACZoB,OAAO;gBACPC,OAAO;gBACPC,OAAOV;YACT;YAEA,IAAIM,iBAAiBK,MAAM,KAAK,GAAG;gBACjCf,OAAOgB,KAAK,CAAC;oBACXd,aAAalB;oBACbC;oBACAC;gBACF,GAAG;gBACH;YACF;YAEA,MAAM+B,aAAaP,iBAAiBQ,GAAG,CAAC,CAACC,IAA+BA,EAAEC,EAAE;YAE5E,0EAA0E;YAC1E,MAAM,EAAEX,MAAMY,SAAS,EAAE,GAAG,MAAMtB,QAAQY,IAAI,CAAC;gBAC7CnB,YAAY;gBACZoB,OAAO;gBACPC,OAAO;gBACPC,OAAO;oBACLQ,SAAS;wBAAEjB,QAAQ;oBAAK;oBACxBkB,UAAU;wBAAEC,IAAIP;oBAAW;gBAC7B;YACF;YAEA,IAAII,UAAUN,MAAM,KAAK,GAAG;gBAC1Bf,OAAOgB,KAAK,CAAC;oBACXd,aAAalB;oBACbC;oBACAC;oBACA+B;gBACF,GAAG;gBACH;YACF;YAEA,yCAAyC;YACzC,KAAK,MAAMQ,YAAYJ,UAAW;gBAChC,mEAAmE;gBACnE,MAAMhC,eAAeqB,iBAAiBC,IAAI,CAAC,CAACpB;oBAC1C,MAAMmC,qBAAqB,AAACD,CAAAA,SAASF,QAAQ,IAAI,EAAE,AAAD,EAAGL,GAAG,CAAC,CAACC,IACxD,OAAOA,MAAM,WAAWA,EAAEC,EAAE,GAAGD;oBAEjC,OAAOO,mBAAmBC,QAAQ,CAACpC,QAAQ6B,EAAE;gBAC/C;gBAEA,IAAI,CAAC/B,cAAc;oBACjB;gBACF;gBAEA,MAAMuC,UAAUzC,aAAaC,MAAMC;gBAEnC,wCAAwC;gBACxC,IAAIA,aAAawC,SAAS,EAAE;oBAC1B,IAAI;wBACF,MAAMC,eAAe,MAAM3B,SAAS4B,iBAAiB,CAAC1C,aAAawC,SAAS,EAAED;wBAC9E,IAAI,CAACE,cAAc;4BACjB9B,OAAOgB,KAAK,CAAC;gCACXgB,YAAYP,SAASL,EAAE;gCACvBa,WAAW5C,aAAa+B,EAAE;gCAC1BS,WAAWxC,aAAawC,SAAS;4BACnC,GAAG;4BACH;wBACF;oBACF,EAAE,OAAOK,OAAO;wBACdlC,OAAOkC,KAAK,CAAC;4BACXF,YAAYP,SAASL,EAAE;4BACvBa,WAAW5C,aAAa+B,EAAE;4BAC1BS,WAAWxC,aAAawC,SAAS;4BACjCK,OAAOA,iBAAiBpC,QAAQoC,MAAMC,OAAO,GAAG;wBAClD,GAAG;wBACH;oBACF;gBACF;gBAEA,IAAI;oBACF,MAAMhC,SAASiC,OAAO,CAACX,UAAiBG,SAAShC,KAAKP;oBACtDW,OAAOC,IAAI,CAAC;wBACV+B,YAAYP,SAASL,EAAE;wBACvBiB,cAAcZ,SAASa,IAAI;wBAC3BL,WAAW5C,aAAa+B,EAAE;wBAC1BmB,aAAalD,aAAaiD,IAAI;wBAC9BpC,aAAalB;wBACbC;wBACAC;oBACF,GAAG;gBACL,EAAE,OAAOgD,OAAO;oBACdlC,OAAOkC,KAAK,CAAC;wBACXF,YAAYP,SAASL,EAAE;wBACvBiB,cAAcZ,SAASa,IAAI;wBAC3BL,WAAW5C,aAAa+B,EAAE;wBAC1BmB,aAAalD,aAAaiD,IAAI;wBAC9BpC,aAAalB;wBACbC;wBACAC;wBACAgD,OAAOA,iBAAiBpC,QAAQoC,MAAMC,OAAO,GAAG;oBAClD,GAAG;gBACH,yDAAyD;gBAC3D;YACF;YAEAnC,OAAOC,IAAI,CAAC;gBACVC,aAAalB;gBACbC;gBACAC;gBACAsD,eAAenB,UAAUN,MAAM;YACjC,GAAG,GAAG/B,KAAK,6BAA6B,CAAC;QAE3C,EAAE,OAAOkD,OAAO;YACdlC,OAAOkC,KAAK,CAAC;gBACXhC,aAAalB;gBACbC;gBACAC;gBACAgD,OAAOA,iBAAiBpC,QAAQoC,MAAMC,OAAO,GAAG;gBAChDM,YAAYP,iBAAiBpC,QAAQoC,MAAMQ,KAAK,GAAG7C;YACrD,GAAG,GAAGb,KAAK,sBAAsB,CAAC;QAClC,yDAAyD;QAC3D;IACF;AACF,EAAC;AAED,2CAA2C;AAC3C,OAAO,MAAM2D,8BAA8B,CAACrC,gBAAwBpB,WAClEJ,kBAAkB;QAAEE,MAAM;QAAcC,MAAMqB;QAAgBpB;IAAS,GAAE;AAE3E,OAAO,MAAM0D,0BAA0B,CAACpC,YAAoBtB,WAC1DJ,kBAAkB;QAAEE,MAAM;QAAUC,MAAMuB;QAAYtB;IAAS,GAAE"}
@@ -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
@@ -0,0 +1 @@
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"}
@@ -1,3 +1,5 @@
1
+ export { createStep } from './create-step.js';
2
+ export type { StepDefinition, StepTask } from './create-step.js';
1
3
  export { CreateDocumentStepTask } from './create-document.js';
2
4
  export { createDocumentHandler } from './create-document-handler.js';
3
5
  export { DeleteDocumentStepTask } from './delete-document.js';
@@ -1,3 +1,6 @@
1
+ // Step factory for creating new steps
2
+ export { createStep } from './create-step.js';
3
+ // Built-in steps
1
4
  export { CreateDocumentStepTask } from './create-document.js';
2
5
  export { createDocumentHandler } from './create-document-handler.js';
3
6
  export { DeleteDocumentStepTask } from './delete-document.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/steps/index.ts"],"sourcesContent":["export { 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,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"}
1
+ {"version":3,"sources":["../../src/steps/index.ts"],"sourcesContent":["// Step factory for creating new steps\nexport { createStep } from './create-step.js'\nexport type { StepDefinition, StepTask } from './create-step.js'\n\n// 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":["createStep","CreateDocumentStepTask","createDocumentHandler","DeleteDocumentStepTask","deleteDocumentHandler","HttpRequestStepTask","httpStepHandler","ReadDocumentStepTask","readDocumentHandler","SendEmailStepTask","sendEmailHandler","UpdateDocumentStepTask","updateDocumentHandler"],"mappings":"AAAA,sCAAsC;AACtC,SAASA,UAAU,QAAQ,mBAAkB;AAG7C,iBAAiB;AACjB,SAASC,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"}
@@ -44,7 +44,7 @@ export const readDocumentHandler = async ({ input, req })=>{
44
44
  };
45
45
  } catch (error) {
46
46
  return {
47
- errorName: error instanceof Error ? error.message : 'Failed to read document(s)',
47
+ errorMessage: error instanceof Error ? error.message : 'Failed to read document(s)',
48
48
  state: 'failed'
49
49
  };
50
50
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/steps/read-document-handler.ts"],"sourcesContent":["import type { TaskHandler } from \"payload\"\n\nexport const readDocumentHandler: TaskHandler<'read-document'> = async ({ input, req }) => {\n if (!input) {\n throw new Error('No input provided')\n }\n\n const { id, collectionSlug, depth, limit, locale, sort, where } = input\n\n if (!collectionSlug || typeof collectionSlug !== 'string') {\n throw new Error('Collection slug is required')\n }\n\n try {\n // If ID is provided, find by ID\n if (id) {\n const result = await req.payload.findByID({\n id: id.toString(),\n collection: collectionSlug,\n depth: typeof depth === 'number' ? depth : undefined,\n locale: locale || undefined,\n req\n })\n\n return {\n output: {\n doc: result,\n totalDocs: 1\n },\n state: 'succeeded'\n }\n }\n\n // Otherwise, find multiple documents\n const parsedWhere = where ? (typeof where === 'string' ? JSON.parse(where) : where) : {}\n\n const result = await req.payload.find({\n collection: collectionSlug,\n depth: typeof depth === 'number' ? depth : undefined,\n limit: typeof limit === 'number' ? limit : 10,\n locale: locale || undefined,\n req,\n sort: sort || undefined,\n where: parsedWhere\n })\n\n return {\n output: {\n doc: result.docs,\n totalDocs: result.totalDocs\n },\n state: 'succeeded'\n }\n } catch (error) {\n return {\n errorName: error instanceof Error ? error.message : 'Failed to read document(s)',\n state: 'failed'\n }\n }\n}\n"],"names":["readDocumentHandler","input","req","Error","id","collectionSlug","depth","limit","locale","sort","where","result","payload","findByID","toString","collection","undefined","output","doc","totalDocs","state","parsedWhere","JSON","parse","find","docs","error","errorName","message"],"mappings":"AAEA,OAAO,MAAMA,sBAAoD,OAAO,EAAEC,KAAK,EAAEC,GAAG,EAAE;IACpF,IAAI,CAACD,OAAO;QACV,MAAM,IAAIE,MAAM;IAClB;IAEA,MAAM,EAAEC,EAAE,EAAEC,cAAc,EAAEC,KAAK,EAAEC,KAAK,EAAEC,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAE,GAAGT;IAElE,IAAI,CAACI,kBAAkB,OAAOA,mBAAmB,UAAU;QACzD,MAAM,IAAIF,MAAM;IAClB;IAEA,IAAI;QACF,gCAAgC;QAChC,IAAIC,IAAI;YACN,MAAMO,SAAS,MAAMT,IAAIU,OAAO,CAACC,QAAQ,CAAC;gBACxCT,IAAIA,GAAGU,QAAQ;gBACfC,YAAYV;gBACZC,OAAO,OAAOA,UAAU,WAAWA,QAAQU;gBAC3CR,QAAQA,UAAUQ;gBAClBd;YACF;YAEA,OAAO;gBACLe,QAAQ;oBACNC,KAAKP;oBACLQ,WAAW;gBACb;gBACAC,OAAO;YACT;QACF;QAEA,qCAAqC;QACrC,MAAMC,cAAcX,QAAS,OAAOA,UAAU,WAAWY,KAAKC,KAAK,CAACb,SAASA,QAAS,CAAC;QAEvF,MAAMC,SAAS,MAAMT,IAAIU,OAAO,CAACY,IAAI,CAAC;YACpCT,YAAYV;YACZC,OAAO,OAAOA,UAAU,WAAWA,QAAQU;YAC3CT,OAAO,OAAOA,UAAU,WAAWA,QAAQ;YAC3CC,QAAQA,UAAUQ;YAClBd;YACAO,MAAMA,QAAQO;YACdN,OAAOW;QACT;QAEA,OAAO;YACLJ,QAAQ;gBACNC,KAAKP,OAAOc,IAAI;gBAChBN,WAAWR,OAAOQ,SAAS;YAC7B;YACAC,OAAO;QACT;IACF,EAAE,OAAOM,OAAO;QACd,OAAO;YACLC,WAAWD,iBAAiBvB,QAAQuB,MAAME,OAAO,GAAG;YACpDR,OAAO;QACT;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/steps/read-document-handler.ts"],"sourcesContent":["import type { TaskHandler } from \"payload\"\n\nexport const readDocumentHandler: TaskHandler<'read-document'> = async ({ input, req }) => {\n if (!input) {\n throw new Error('No input provided')\n }\n\n const { id, collectionSlug, depth, limit, locale, sort, where } = input\n\n if (!collectionSlug || typeof collectionSlug !== 'string') {\n throw new Error('Collection slug is required')\n }\n\n try {\n // If ID is provided, find by ID\n if (id) {\n const result = await req.payload.findByID({\n id: id.toString(),\n collection: collectionSlug,\n depth: typeof depth === 'number' ? depth : undefined,\n locale: locale || undefined,\n req\n })\n\n return {\n output: {\n doc: result,\n totalDocs: 1\n },\n state: 'succeeded'\n }\n }\n\n // Otherwise, find multiple documents\n const parsedWhere = where ? (typeof where === 'string' ? JSON.parse(where) : where) : {}\n\n const result = await req.payload.find({\n collection: collectionSlug,\n depth: typeof depth === 'number' ? depth : undefined,\n limit: typeof limit === 'number' ? limit : 10,\n locale: locale || undefined,\n req,\n sort: sort || undefined,\n where: parsedWhere\n })\n\n return {\n output: {\n doc: result.docs,\n totalDocs: result.totalDocs\n },\n state: 'succeeded'\n }\n } catch (error) {\n return {\n errorMessage: error instanceof Error ? error.message : 'Failed to read document(s)',\n state: 'failed'\n }\n }\n}\n"],"names":["readDocumentHandler","input","req","Error","id","collectionSlug","depth","limit","locale","sort","where","result","payload","findByID","toString","collection","undefined","output","doc","totalDocs","state","parsedWhere","JSON","parse","find","docs","error","errorMessage","message"],"mappings":"AAEA,OAAO,MAAMA,sBAAoD,OAAO,EAAEC,KAAK,EAAEC,GAAG,EAAE;IACpF,IAAI,CAACD,OAAO;QACV,MAAM,IAAIE,MAAM;IAClB;IAEA,MAAM,EAAEC,EAAE,EAAEC,cAAc,EAAEC,KAAK,EAAEC,KAAK,EAAEC,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAE,GAAGT;IAElE,IAAI,CAACI,kBAAkB,OAAOA,mBAAmB,UAAU;QACzD,MAAM,IAAIF,MAAM;IAClB;IAEA,IAAI;QACF,gCAAgC;QAChC,IAAIC,IAAI;YACN,MAAMO,SAAS,MAAMT,IAAIU,OAAO,CAACC,QAAQ,CAAC;gBACxCT,IAAIA,GAAGU,QAAQ;gBACfC,YAAYV;gBACZC,OAAO,OAAOA,UAAU,WAAWA,QAAQU;gBAC3CR,QAAQA,UAAUQ;gBAClBd;YACF;YAEA,OAAO;gBACLe,QAAQ;oBACNC,KAAKP;oBACLQ,WAAW;gBACb;gBACAC,OAAO;YACT;QACF;QAEA,qCAAqC;QACrC,MAAMC,cAAcX,QAAS,OAAOA,UAAU,WAAWY,KAAKC,KAAK,CAACb,SAASA,QAAS,CAAC;QAEvF,MAAMC,SAAS,MAAMT,IAAIU,OAAO,CAACY,IAAI,CAAC;YACpCT,YAAYV;YACZC,OAAO,OAAOA,UAAU,WAAWA,QAAQU;YAC3CT,OAAO,OAAOA,UAAU,WAAWA,QAAQ;YAC3CC,QAAQA,UAAUQ;YAClBd;YACAO,MAAMA,QAAQO;YACdN,OAAOW;QACT;QAEA,OAAO;YACLJ,QAAQ;gBACNC,KAAKP,OAAOc,IAAI;gBAChBN,WAAWR,OAAOQ,SAAS;YAC7B;YACAC,OAAO;QACT;IACF,EAAE,OAAOM,OAAO;QACd,OAAO;YACLC,cAAcD,iBAAiBvB,QAAQuB,MAAME,OAAO,GAAG;YACvDR,OAAO;QACT;IACF;AACF,EAAC"}
@@ -31,7 +31,7 @@ export const updateDocumentHandler = async ({ input, req })=>{
31
31
  };
32
32
  } catch (error) {
33
33
  return {
34
- errorName: error instanceof Error ? error.message : 'Failed to update document',
34
+ errorMessage: error instanceof Error ? error.message : 'Failed to update document',
35
35
  state: 'failed'
36
36
  };
37
37
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/steps/update-document-handler.ts"],"sourcesContent":["import type { TaskHandler } from \"payload\"\n\nexport const updateDocumentHandler: TaskHandler<'update-document'> = async ({ input, req }) => {\n if (!input) {\n throw new Error('No input provided')\n }\n\n const { id, collectionSlug, data, draft, locale } = input\n\n if (!collectionSlug || typeof collectionSlug !== 'string') {\n throw new Error('Collection slug is required')\n }\n\n if (!id) {\n throw new Error('Document ID is required')\n }\n\n if (!data) {\n throw new Error('Update data is required')\n }\n\n try {\n const parsedData = typeof data === 'string' ? JSON.parse(data) : data\n\n const result = await req.payload.update({\n id: id.toString(),\n collection: collectionSlug,\n data: parsedData,\n draft: draft || false,\n locale: locale || undefined,\n req\n })\n\n return {\n output: {\n id: result.id,\n doc: result\n },\n state: 'succeeded'\n }\n } catch (error) {\n return {\n errorName: error instanceof Error ? error.message : 'Failed to update document',\n state: 'failed'\n }\n }\n}\n"],"names":["updateDocumentHandler","input","req","Error","id","collectionSlug","data","draft","locale","parsedData","JSON","parse","result","payload","update","toString","collection","undefined","output","doc","state","error","errorName","message"],"mappings":"AAEA,OAAO,MAAMA,wBAAwD,OAAO,EAAEC,KAAK,EAAEC,GAAG,EAAE;IACxF,IAAI,CAACD,OAAO;QACV,MAAM,IAAIE,MAAM;IAClB;IAEA,MAAM,EAAEC,EAAE,EAAEC,cAAc,EAAEC,IAAI,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAGP;IAEpD,IAAI,CAACI,kBAAkB,OAAOA,mBAAmB,UAAU;QACzD,MAAM,IAAIF,MAAM;IAClB;IAEA,IAAI,CAACC,IAAI;QACP,MAAM,IAAID,MAAM;IAClB;IAEA,IAAI,CAACG,MAAM;QACT,MAAM,IAAIH,MAAM;IAClB;IAEA,IAAI;QACF,MAAMM,aAAa,OAAOH,SAAS,WAAWI,KAAKC,KAAK,CAACL,QAAQA;QAEjE,MAAMM,SAAS,MAAMV,IAAIW,OAAO,CAACC,MAAM,CAAC;YACtCV,IAAIA,GAAGW,QAAQ;YACfC,YAAYX;YACZC,MAAMG;YACNF,OAAOA,SAAS;YAChBC,QAAQA,UAAUS;YAClBf;QACF;QAEA,OAAO;YACLgB,QAAQ;gBACNd,IAAIQ,OAAOR,EAAE;gBACbe,KAAKP;YACP;YACAQ,OAAO;QACT;IACF,EAAE,OAAOC,OAAO;QACd,OAAO;YACLC,WAAWD,iBAAiBlB,QAAQkB,MAAME,OAAO,GAAG;YACpDH,OAAO;QACT;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/steps/update-document-handler.ts"],"sourcesContent":["import type { TaskHandler } from \"payload\"\n\nexport const updateDocumentHandler: TaskHandler<'update-document'> = async ({ input, req }) => {\n if (!input) {\n throw new Error('No input provided')\n }\n\n const { id, collectionSlug, data, draft, locale } = input\n\n if (!collectionSlug || typeof collectionSlug !== 'string') {\n throw new Error('Collection slug is required')\n }\n\n if (!id) {\n throw new Error('Document ID is required')\n }\n\n if (!data) {\n throw new Error('Update data is required')\n }\n\n try {\n const parsedData = typeof data === 'string' ? JSON.parse(data) : data\n\n const result = await req.payload.update({\n id: id.toString(),\n collection: collectionSlug,\n data: parsedData,\n draft: draft || false,\n locale: locale || undefined,\n req\n })\n\n return {\n output: {\n id: result.id,\n doc: result\n },\n state: 'succeeded'\n }\n } catch (error) {\n return {\n errorMessage: error instanceof Error ? error.message : 'Failed to update document',\n state: 'failed'\n }\n }\n}\n"],"names":["updateDocumentHandler","input","req","Error","id","collectionSlug","data","draft","locale","parsedData","JSON","parse","result","payload","update","toString","collection","undefined","output","doc","state","error","errorMessage","message"],"mappings":"AAEA,OAAO,MAAMA,wBAAwD,OAAO,EAAEC,KAAK,EAAEC,GAAG,EAAE;IACxF,IAAI,CAACD,OAAO;QACV,MAAM,IAAIE,MAAM;IAClB;IAEA,MAAM,EAAEC,EAAE,EAAEC,cAAc,EAAEC,IAAI,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAGP;IAEpD,IAAI,CAACI,kBAAkB,OAAOA,mBAAmB,UAAU;QACzD,MAAM,IAAIF,MAAM;IAClB;IAEA,IAAI,CAACC,IAAI;QACP,MAAM,IAAID,MAAM;IAClB;IAEA,IAAI,CAACG,MAAM;QACT,MAAM,IAAIH,MAAM;IAClB;IAEA,IAAI;QACF,MAAMM,aAAa,OAAOH,SAAS,WAAWI,KAAKC,KAAK,CAACL,QAAQA;QAEjE,MAAMM,SAAS,MAAMV,IAAIW,OAAO,CAACC,MAAM,CAAC;YACtCV,IAAIA,GAAGW,QAAQ;YACfC,YAAYX;YACZC,MAAMG;YACNF,OAAOA,SAAS;YAChBC,QAAQA,UAAUS;YAClBf;QACF;QAEA,OAAO;YACLgB,QAAQ;gBACNd,IAAIQ,OAAOR,EAAE;gBACbe,KAAKP;YACP;YACAQ,OAAO;QACT;IACF,EAAE,OAAOC,OAAO;QACd,OAAO;YACLC,cAAcD,iBAAiBlB,QAAQkB,MAAME,OAAO,GAAG;YACvDH,OAAO;QACT;IACF;AACF,EAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Grouped hook options for better UX in the admin panel.
3
+ * Organized by category instead of a flat list of 32+ hooks.
4
+ */
5
+ export interface HookOption {
6
+ value: string;
7
+ label: string;
8
+ description?: string;
9
+ }
10
+ export interface HookOptionGroup {
11
+ label: string;
12
+ options: HookOption[];
13
+ }
14
+ /**
15
+ * Collection hook options grouped by category.
16
+ */
17
+ export declare const collectionHookGroups: HookOptionGroup[];
18
+ /**
19
+ * Global hook options grouped by category.
20
+ */
21
+ export declare const globalHookGroups: HookOptionGroup[];
22
+ /**
23
+ * Flat list of collection hook options for select fields.
24
+ */
25
+ export declare const collectionHookOptions: HookOption[];
26
+ /**
27
+ * Flat list of global hook options for select fields.
28
+ */
29
+ export declare const globalHookOptions: HookOption[];
30
+ /**
31
+ * All hook values as a simple string array for validation.
32
+ */
33
+ export declare const allCollectionHooks: string[];
34
+ export declare const allGlobalHooks: string[];