@objectstack/service-automation 3.0.8 → 3.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine.ts","../src/plugin.ts","../src/plugins/crud-nodes-plugin.ts","../src/plugins/logic-nodes-plugin.ts","../src/plugins/http-connector-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { FlowParsed, FlowNodeParsed } from '@objectstack/spec/automation';\nimport type { AutomationContext, AutomationResult, IAutomationService } from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport { FlowSchema } from '@objectstack/spec/automation';\n\n// ─── Node Executor Interface (Plugin Extension Point) ───────────────\n\n/**\n * Each node type corresponds to a NodeExecutor.\n * Third-party plugins only need to implement this interface and register\n * it with the engine to extend automation capabilities.\n */\nexport interface NodeExecutor {\n /** Corresponds to FlowNodeAction enum value */\n readonly type: string;\n\n /**\n * Execute a node\n * @param node - Current node definition\n * @param variables - Flow variable context (read/write)\n * @param context - Trigger context\n * @returns Execution result (may include output data, branch conditions, etc.)\n */\n execute(\n node: FlowNodeParsed,\n variables: Map<string, unknown>,\n context: AutomationContext,\n ): Promise<NodeExecutionResult>;\n}\n\nexport interface NodeExecutionResult {\n success: boolean;\n output?: Record<string, unknown>;\n error?: string;\n /** Used by decision nodes — returns the selected branch label */\n branchLabel?: string;\n}\n\n// ─── Trigger Interface (Plugin Extension Point) ─────────────────────\n\n/**\n * Trigger interface. Schedule/Event/API triggers are registered via plugins.\n */\nexport interface FlowTrigger {\n readonly type: string;\n start(flowName: string, callback: (ctx: AutomationContext) => Promise<void>): void;\n stop(flowName: string): void;\n}\n\n// ─── Core Automation Engine ─────────────────────────────────────────\n\nexport class AutomationEngine implements IAutomationService {\n private flows = new Map<string, FlowParsed>();\n private nodeExecutors = new Map<string, NodeExecutor>();\n private triggers = new Map<string, FlowTrigger>();\n private logger: Logger;\n\n constructor(logger: Logger) {\n this.logger = logger;\n }\n\n // ── Plugin Extension API ──────────────────────────────\n\n /** Register a node executor (called by plugins) */\n registerNodeExecutor(executor: NodeExecutor): void {\n if (this.nodeExecutors.has(executor.type)) {\n this.logger.warn(`Node executor '${executor.type}' replaced`);\n }\n this.nodeExecutors.set(executor.type, executor);\n this.logger.info(`Node executor registered: ${executor.type}`);\n }\n\n /** Unregister a node executor (hot-unplug) */\n unregisterNodeExecutor(type: string): void {\n this.nodeExecutors.delete(type);\n this.logger.info(`Node executor unregistered: ${type}`);\n }\n\n /** Register a trigger (called by plugins) */\n registerTrigger(trigger: FlowTrigger): void {\n this.triggers.set(trigger.type, trigger);\n this.logger.info(`Trigger registered: ${trigger.type}`);\n }\n\n /** Unregister a trigger (hot-unplug) */\n unregisterTrigger(type: string): void {\n this.triggers.delete(type);\n this.logger.info(`Trigger unregistered: ${type}`);\n }\n\n /** Get all registered node types */\n getRegisteredNodeTypes(): string[] {\n return [...this.nodeExecutors.keys()];\n }\n\n /** Get all registered trigger types */\n getRegisteredTriggerTypes(): string[] {\n return [...this.triggers.keys()];\n }\n\n // ── IAutomationService Contract Implementation ────────\n\n registerFlow(name: string, definition: unknown): void {\n const parsed = FlowSchema.parse(definition);\n this.flows.set(name, parsed);\n this.logger.info(`Flow registered: ${name}`);\n }\n\n unregisterFlow(name: string): void {\n this.flows.delete(name);\n this.logger.info(`Flow unregistered: ${name}`);\n }\n\n async listFlows(): Promise<string[]> {\n return [...this.flows.keys()];\n }\n\n async execute(flowName: string, context?: AutomationContext): Promise<AutomationResult> {\n const startTime = Date.now();\n const flow = this.flows.get(flowName);\n\n if (!flow) {\n return { success: false, error: `Flow '${flowName}' not found` };\n }\n\n // Initialize variable context\n const variables = new Map<string, unknown>();\n if (flow.variables) {\n for (const v of flow.variables) {\n if (v.isInput && context?.params?.[v.name] !== undefined) {\n variables.set(v.name, context.params[v.name]);\n }\n }\n }\n // Inject trigger record\n if (context?.record) {\n variables.set('$record', context.record);\n }\n\n try {\n // Find the start node\n const startNode = flow.nodes.find(n => n.type === 'start');\n if (!startNode) {\n return { success: false, error: 'Flow has no start node' };\n }\n\n // DAG traversal execution\n await this.executeNode(startNode, flow, variables, context ?? {});\n\n // Collect output variables\n const output: Record<string, unknown> = {};\n if (flow.variables) {\n for (const v of flow.variables) {\n if (v.isOutput) {\n output[v.name] = variables.get(v.name);\n }\n }\n }\n\n return {\n success: true,\n output,\n durationMs: Date.now() - startTime,\n };\n } catch (err: unknown) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n\n // Error handling strategy\n if (flow.errorHandling?.strategy === 'retry') {\n return this.retryExecution(flowName, context, startTime, flow.errorHandling);\n }\n return {\n success: false,\n error: errorMessage,\n durationMs: Date.now() - startTime,\n };\n }\n }\n\n // ── DAG Traversal Core ──────────────────────────────────\n\n private async executeNode(\n node: FlowNodeParsed,\n flow: FlowParsed,\n variables: Map<string, unknown>,\n context: AutomationContext,\n ): Promise<void> {\n if (node.type === 'end') return;\n\n // Find executor\n const executor = this.nodeExecutors.get(node.type);\n if (!executor) {\n // start node without executor is fine — just skip\n if (node.type !== 'start') {\n throw new Error(`No executor registered for node type '${node.type}'`);\n }\n } else {\n // Execute node\n const result = await executor.execute(node, variables, context);\n if (!result.success) {\n throw new Error(`Node '${node.id}' failed: ${result.error}`);\n }\n // Write back output variables\n if (result.output) {\n for (const [key, value] of Object.entries(result.output)) {\n variables.set(`${node.id}.${key}`, value);\n }\n }\n }\n\n // Find next nodes (filter by edge conditions)\n const outEdges = flow.edges.filter(e => e.source === node.id);\n for (const edge of outEdges) {\n if (edge.condition && !this.evaluateCondition(edge.condition, variables)) {\n continue;\n }\n const nextNode = flow.nodes.find(n => n.id === edge.target);\n if (nextNode) {\n await this.executeNode(nextNode, flow, variables, context);\n }\n }\n }\n\n private evaluateCondition(expression: string, variables: Map<string, unknown>): boolean {\n // MVP: Simple template replacement + expression evaluation.\n // Flow definitions are authored by trusted developers/admins.\n // TODO: Replace with safe expression evaluator (e.g., jexl) for production.\n let resolved = expression;\n for (const [key, value] of variables) {\n resolved = resolved.split(`{${key}}`).join(String(value));\n }\n try {\n return new Function(`return (${resolved})`)() as boolean;\n } catch {\n return false;\n }\n }\n\n private async retryExecution(\n flowName: string,\n context: AutomationContext | undefined,\n startTime: number,\n errorHandling: { maxRetries?: number; retryDelayMs?: number },\n ): Promise<AutomationResult> {\n const maxRetries = errorHandling.maxRetries ?? 3;\n const delay = errorHandling.retryDelayMs ?? 1000;\n\n for (let i = 0; i < maxRetries; i++) {\n await new Promise(r => setTimeout(r, delay));\n const result = await this.execute(flowName, context);\n if (result.success) return result;\n }\n return { success: false, error: 'Max retries exceeded', durationMs: Date.now() - startTime };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { AutomationEngine } from './engine.js';\n\n/**\n * Configuration options for the AutomationServicePlugin.\n */\nexport interface AutomationServicePluginOptions {\n /** Enable debug logging for flow execution */\n debug?: boolean;\n}\n\n/**\n * AutomationServicePlugin — Core engine plugin\n *\n * Responsibilities:\n * 1. init phase: Create engine instance, register as 'automation' service\n * 2. start phase: Trigger 'automation:ready' hook for node plugin registration\n * 3. destroy phase: Clean up resources\n *\n * Does NOT implement any specific nodes — nodes are registered by other plugins\n * via the engine's extension API.\n *\n * @example\n * ```ts\n * import { LiteKernel } from '@objectstack/core';\n * import { AutomationServicePlugin } from '@objectstack/service-automation';\n *\n * const kernel = new LiteKernel();\n * kernel.use(new AutomationServicePlugin());\n * await kernel.bootstrap();\n *\n * const automation = kernel.getService('automation');\n * ```\n */\nexport class AutomationServicePlugin implements Plugin {\n name = 'com.objectstack.service-automation';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies: string[] = [];\n\n private engine?: AutomationEngine;\n private readonly options: AutomationServicePluginOptions;\n\n constructor(options: AutomationServicePluginOptions = {}) {\n this.options = options;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n this.engine = new AutomationEngine(ctx.logger);\n\n // Register as global service — other plugins access via ctx.getService('automation')\n ctx.registerService('automation', this.engine);\n\n if (this.options.debug) {\n ctx.hook('automation:beforeExecute', async (flowName: string) => {\n ctx.logger.debug(`[Automation] Before execute: ${flowName}`);\n });\n }\n\n ctx.logger.info('[Automation] Engine initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (!this.engine) return;\n\n // Trigger hook to notify engine is ready — other plugins can start registering nodes\n await ctx.trigger('automation:ready', this.engine);\n\n const nodeTypes = this.engine.getRegisteredNodeTypes();\n ctx.logger.info(\n `[Automation] Engine started with ${nodeTypes.length} node types: ${nodeTypes.join(', ') || '(none)'}`,\n );\n }\n\n async destroy(): Promise<void> {\n this.engine = undefined;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { AutomationEngine } from '../engine.js';\n\n/**\n * CRUD Node Plugin — Provides get_record / create_record / update_record / delete_record\n *\n * Dependencies: service-automation (engine)\n *\n * In a full runtime environment these nodes would delegate to ObjectQL (data layer).\n * This MVP implementation provides the extension point structure.\n */\nexport class CrudNodesPlugin implements Plugin {\n name = 'com.objectstack.automation.crud-nodes';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies = ['com.objectstack.service-automation'];\n\n async init(ctx: PluginContext): Promise<void> {\n const engine = ctx.getService<AutomationEngine>('automation');\n\n // get_record node executor\n engine.registerNodeExecutor({\n type: 'get_record',\n async execute(node, _variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n // In production, this would query via ObjectQL:\n // const ql = ctx.getService('objectql');\n // const records = await ql.find(config.object, config.filters);\n return {\n success: true,\n output: { records: [], object: config?.object },\n };\n },\n });\n\n // create_record node executor\n engine.registerNodeExecutor({\n type: 'create_record',\n async execute(node, _variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n return {\n success: true,\n output: { id: 'new-record-id', object: config?.object },\n };\n },\n });\n\n // update_record node executor\n engine.registerNodeExecutor({\n type: 'update_record',\n async execute(_node, _variables, _context) {\n return { success: true };\n },\n });\n\n // delete_record node executor\n engine.registerNodeExecutor({\n type: 'delete_record',\n async execute(_node, _variables, _context) {\n return { success: true };\n },\n });\n\n ctx.logger.info('[CRUD Nodes] 4 node executors registered');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { AutomationEngine } from '../engine.js';\n\n/**\n * Logic Node Plugin — Provides decision / assignment / loop nodes\n *\n * Dependencies: service-automation (engine)\n */\nexport class LogicNodesPlugin implements Plugin {\n name = 'com.objectstack.automation.logic-nodes';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies = ['com.objectstack.service-automation'];\n\n async init(ctx: PluginContext): Promise<void> {\n const engine = ctx.getService<AutomationEngine>('automation');\n\n // decision node — conditional branching\n engine.registerNodeExecutor({\n type: 'decision',\n async execute(node, variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n const conditions = (config?.conditions ?? []) as Array<{ label: string; expression: string }>;\n\n for (const cond of conditions) {\n // MVP: Simple template replacement + expression evaluation.\n // Flow definitions are authored by trusted developers/admins.\n // TODO: Replace with safe expression evaluator (e.g., jexl) for production.\n let expr = cond.expression;\n for (const [k, v] of variables) {\n expr = expr.split(`{${k}}`).join(String(v));\n }\n try {\n if (new Function(`return (${expr})`)()) {\n return { success: true, branchLabel: cond.label };\n }\n } catch {\n // Continue to next condition\n }\n }\n return { success: true, branchLabel: 'default' };\n },\n });\n\n // assignment node — set variables\n engine.registerNodeExecutor({\n type: 'assignment',\n async execute(node, variables, _context) {\n const config = (node.config ?? {}) as Record<string, unknown>;\n for (const [key, value] of Object.entries(config)) {\n variables.set(key, value);\n }\n return { success: true };\n },\n });\n\n // loop node — iterate over a collection\n engine.registerNodeExecutor({\n type: 'loop',\n async execute(node, variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n const collectionName = config?.collection as string | undefined;\n if (collectionName) {\n const collection = variables.get(collectionName);\n if (Array.isArray(collection)) {\n variables.set('$loopItems', collection);\n variables.set('$loopIndex', 0);\n }\n }\n return { success: true };\n },\n });\n\n ctx.logger.info('[Logic Nodes] 3 node executors registered');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { AutomationEngine } from '../engine.js';\n\n/**\n * HTTP + Connector Node Plugin — Provides http_request / connector_action nodes\n *\n * Dependencies: service-automation (engine)\n */\nexport class HttpConnectorPlugin implements Plugin {\n name = 'com.objectstack.automation.http-connector';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies = ['com.objectstack.service-automation'];\n\n async init(ctx: PluginContext): Promise<void> {\n const engine = ctx.getService<AutomationEngine>('automation');\n\n // http_request node executor\n engine.registerNodeExecutor({\n type: 'http_request',\n async execute(node, _variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n const url = config?.url as string | undefined;\n const method = (config?.method as string) ?? 'GET';\n const headers = config?.headers as Record<string, string> | undefined;\n const body = config?.body;\n\n if (!url) {\n return { success: false, error: 'http_request: url is required' };\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n const data = await response.json();\n\n return {\n success: response.ok,\n output: { response: data, status: response.status },\n error: response.ok ? undefined : `HTTP ${response.status}`,\n };\n },\n });\n\n // connector_action node — calls a registered connector\n engine.registerNodeExecutor({\n type: 'connector_action',\n async execute(node, _variables, _context) {\n const connectorConfig = node.connectorConfig;\n if (!connectorConfig) {\n return { success: false, error: 'connector_action: connectorConfig is required' };\n }\n\n ctx.logger.info(\n `Connector action: ${connectorConfig.connectorId}.${connectorConfig.actionId}`,\n );\n\n // In production, this would look up the connector from a registry\n // and execute the specified action with the mapped inputs\n return { success: true, output: { connectorResult: {} } };\n },\n });\n\n ctx.logger.info('[HTTP Connector] 2 node executors registered');\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/engine.ts","../src/plugin.ts","../src/plugins/crud-nodes-plugin.ts","../src/plugins/logic-nodes-plugin.ts","../src/plugins/http-connector-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { FlowParsed, FlowNodeParsed, FlowEdgeParsed } from '@objectstack/spec/automation';\nimport type { ExecutionLog } from '@objectstack/spec/automation';\nimport type { AutomationContext, AutomationResult, IAutomationService } from '@objectstack/spec/contracts';\nimport type { Logger } from '@objectstack/spec/contracts';\nimport { FlowSchema } from '@objectstack/spec/automation';\n\n// ─── Node Executor Interface (Plugin Extension Point) ───────────────\n\n/**\n * Each node type corresponds to a NodeExecutor.\n * Third-party plugins only need to implement this interface and register\n * it with the engine to extend automation capabilities.\n */\nexport interface NodeExecutor {\n /** Corresponds to FlowNodeAction enum value */\n readonly type: string;\n\n /**\n * Execute a node\n * @param node - Current node definition\n * @param variables - Flow variable context (read/write)\n * @param context - Trigger context\n * @returns Execution result (may include output data, branch conditions, etc.)\n */\n execute(\n node: FlowNodeParsed,\n variables: Map<string, unknown>,\n context: AutomationContext,\n ): Promise<NodeExecutionResult>;\n}\n\nexport interface NodeExecutionResult {\n success: boolean;\n output?: Record<string, unknown>;\n error?: string;\n /** Used by decision nodes — returns the selected branch label */\n branchLabel?: string;\n}\n\n// ─── Trigger Interface (Plugin Extension Point) ─────────────────────\n\n/**\n * Trigger interface. Schedule/Event/API triggers are registered via plugins.\n */\nexport interface FlowTrigger {\n readonly type: string;\n start(flowName: string, callback: (ctx: AutomationContext) => Promise<void>): void;\n stop(flowName: string): void;\n}\n\n// ─── Core Automation Engine ─────────────────────────────────────────\n\n/**\n * Internal execution step log entry.\n */\ninterface StepLogEntry {\n nodeId: string;\n nodeType: string;\n nodeLabel?: string;\n status: 'success' | 'failure' | 'skipped';\n startedAt: string;\n completedAt?: string;\n durationMs?: number;\n error?: { code: string; message: string; stack?: string };\n}\n\n/**\n * Internal execution log entry — compatible with ExecutionLog from spec.\n */\ninterface ExecutionLogEntry {\n id: string;\n flowName: string;\n flowVersion?: number;\n status: ExecutionLog['status'];\n startedAt: string;\n completedAt?: string;\n durationMs?: number;\n trigger: { type: string; userId?: string; object?: string; recordId?: string };\n steps: StepLogEntry[];\n variables?: Record<string, unknown>;\n output?: unknown;\n error?: string;\n}\n\nexport class AutomationEngine implements IAutomationService {\n private flows = new Map<string, FlowParsed>();\n private flowEnabled = new Map<string, boolean>();\n private flowVersionHistory = new Map<string, Array<{ version: number; definition: FlowParsed; createdAt: string }>>();\n private nodeExecutors = new Map<string, NodeExecutor>();\n private triggers = new Map<string, FlowTrigger>();\n private executionLogs: ExecutionLogEntry[] = [];\n private maxLogSize = 1000;\n private logger: Logger;\n private runCounter = 0;\n\n constructor(logger: Logger) {\n this.logger = logger;\n }\n\n // ── Plugin Extension API ──────────────────────────────\n\n /** Register a node executor (called by plugins) */\n registerNodeExecutor(executor: NodeExecutor): void {\n if (this.nodeExecutors.has(executor.type)) {\n this.logger.warn(`Node executor '${executor.type}' replaced`);\n }\n this.nodeExecutors.set(executor.type, executor);\n this.logger.info(`Node executor registered: ${executor.type}`);\n }\n\n /** Unregister a node executor (hot-unplug) */\n unregisterNodeExecutor(type: string): void {\n this.nodeExecutors.delete(type);\n this.logger.info(`Node executor unregistered: ${type}`);\n }\n\n /** Register a trigger (called by plugins) */\n registerTrigger(trigger: FlowTrigger): void {\n this.triggers.set(trigger.type, trigger);\n this.logger.info(`Trigger registered: ${trigger.type}`);\n }\n\n /** Unregister a trigger (hot-unplug) */\n unregisterTrigger(type: string): void {\n this.triggers.delete(type);\n this.logger.info(`Trigger unregistered: ${type}`);\n }\n\n /** Get all registered node types */\n getRegisteredNodeTypes(): string[] {\n return [...this.nodeExecutors.keys()];\n }\n\n /** Get all registered trigger types */\n getRegisteredTriggerTypes(): string[] {\n return [...this.triggers.keys()];\n }\n\n // ── IAutomationService Contract Implementation ────────\n\n registerFlow(name: string, definition: unknown): void {\n const parsed = FlowSchema.parse(definition);\n\n // DAG cycle detection\n this.detectCycles(parsed);\n\n // Version history management\n const history = this.flowVersionHistory.get(name) ?? [];\n history.push({\n version: parsed.version,\n definition: parsed,\n createdAt: new Date().toISOString(),\n });\n this.flowVersionHistory.set(name, history);\n\n this.flows.set(name, parsed);\n if (!this.flowEnabled.has(name)) {\n this.flowEnabled.set(name, true);\n }\n this.logger.info(`Flow registered: ${name} (version ${parsed.version})`);\n }\n\n unregisterFlow(name: string): void {\n this.flows.delete(name);\n this.flowEnabled.delete(name);\n this.flowVersionHistory.delete(name);\n this.logger.info(`Flow unregistered: ${name}`);\n }\n\n async listFlows(): Promise<string[]> {\n return [...this.flows.keys()];\n }\n\n async getFlow(name: string): Promise<FlowParsed | null> {\n return this.flows.get(name) ?? null;\n }\n\n async toggleFlow(name: string, enabled: boolean): Promise<void> {\n if (!this.flows.has(name)) {\n throw new Error(`Flow '${name}' not found`);\n }\n this.flowEnabled.set(name, enabled);\n this.logger.info(`Flow '${name}' ${enabled ? 'enabled' : 'disabled'}`);\n }\n\n /** Get flow version history */\n getFlowVersionHistory(name: string): Array<{ version: number; definition: FlowParsed; createdAt: string }> {\n return this.flowVersionHistory.get(name) ?? [];\n }\n\n /** Rollback flow to a specific version */\n rollbackFlow(name: string, version: number): void {\n const history = this.flowVersionHistory.get(name);\n if (!history) {\n throw new Error(`Flow '${name}' has no version history`);\n }\n const entry = history.find(h => h.version === version);\n if (!entry) {\n throw new Error(`Version ${version} not found for flow '${name}'`);\n }\n this.flows.set(name, entry.definition);\n this.logger.info(`Flow '${name}' rolled back to version ${version}`);\n }\n\n async listRuns(flowName: string, options?: { limit?: number; cursor?: string }): Promise<ExecutionLogEntry[]> {\n const limit = options?.limit ?? 20;\n const logs = this.executionLogs.filter(l => l.flowName === flowName);\n return logs.slice(-limit).reverse();\n }\n\n async getRun(runId: string): Promise<ExecutionLogEntry | null> {\n return this.executionLogs.find(l => l.id === runId) ?? null;\n }\n\n async execute(flowName: string, context?: AutomationContext): Promise<AutomationResult> {\n const startTime = Date.now();\n const flow = this.flows.get(flowName);\n\n if (!flow) {\n return { success: false, error: `Flow '${flowName}' not found` };\n }\n\n // Check if flow is disabled\n if (this.flowEnabled.get(flowName) === false) {\n return { success: false, error: `Flow '${flowName}' is disabled` };\n }\n\n // Initialize variable context\n const variables = new Map<string, unknown>();\n if (flow.variables) {\n for (const v of flow.variables) {\n if (v.isInput && context?.params?.[v.name] !== undefined) {\n variables.set(v.name, context.params[v.name]);\n }\n }\n }\n // Inject trigger record\n if (context?.record) {\n variables.set('$record', context.record);\n }\n\n const runId = `run_${++this.runCounter}`;\n const startedAt = new Date().toISOString();\n const steps: StepLogEntry[] = [];\n\n try {\n // Find the start node\n const startNode = flow.nodes.find(n => n.type === 'start');\n if (!startNode) {\n return { success: false, error: 'Flow has no start node' };\n }\n\n // Validate node input schemas before execution\n this.validateNodeInputSchemas(flow, variables);\n\n // DAG traversal execution\n await this.executeNode(startNode, flow, variables, context ?? {}, steps);\n\n // Collect output variables\n const output: Record<string, unknown> = {};\n if (flow.variables) {\n for (const v of flow.variables) {\n if (v.isOutput) {\n output[v.name] = variables.get(v.name);\n }\n }\n }\n\n const durationMs = Date.now() - startTime;\n\n // Record execution log\n this.recordLog({\n id: runId,\n flowName,\n flowVersion: flow.version,\n status: 'completed',\n startedAt,\n completedAt: new Date().toISOString(),\n durationMs,\n trigger: {\n type: context?.event ?? 'manual',\n userId: context?.userId,\n object: context?.object,\n },\n steps,\n output,\n });\n\n return {\n success: true,\n output,\n durationMs,\n };\n } catch (err: unknown) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n\n // Record failed execution log\n const durationMs = Date.now() - startTime;\n this.recordLog({\n id: runId,\n flowName,\n flowVersion: flow.version,\n status: 'failed',\n startedAt,\n completedAt: new Date().toISOString(),\n durationMs,\n trigger: {\n type: context?.event ?? 'manual',\n userId: context?.userId,\n object: context?.object,\n },\n steps,\n error: errorMessage,\n });\n\n // Error handling strategy\n if (flow.errorHandling?.strategy === 'retry') {\n return this.retryExecution(flowName, context, startTime, flow.errorHandling);\n }\n return {\n success: false,\n error: errorMessage,\n durationMs,\n };\n }\n }\n\n // ── DAG Traversal Core ──────────────────────────────────\n\n private recordLog(entry: ExecutionLogEntry): void {\n this.executionLogs.push(entry);\n // Evict oldest logs when exceeding max size\n if (this.executionLogs.length > this.maxLogSize) {\n this.executionLogs.splice(0, this.executionLogs.length - this.maxLogSize);\n }\n }\n\n /**\n * Detect cycles in the flow graph (DAG validation).\n * Uses DFS with coloring (white/gray/black) to detect back edges.\n * Throws an error with cycle details if a cycle is found.\n */\n private detectCycles(flow: FlowParsed): void {\n const WHITE = 0, GRAY = 1, BLACK = 2;\n const color = new Map<string, number>();\n const parent = new Map<string, string>();\n\n // Build adjacency list from edges\n const adj = new Map<string, string[]>();\n for (const node of flow.nodes) {\n color.set(node.id, WHITE);\n adj.set(node.id, []);\n }\n for (const edge of flow.edges) {\n const targets = adj.get(edge.source);\n if (targets) targets.push(edge.target);\n }\n\n const dfs = (nodeId: string): string[] | null => {\n color.set(nodeId, GRAY);\n for (const neighbor of adj.get(nodeId) ?? []) {\n if (color.get(neighbor) === GRAY) {\n // Back edge found — reconstruct cycle\n const cycle = [neighbor, nodeId];\n let cur = nodeId;\n while (cur !== neighbor) {\n cur = parent.get(cur)!;\n if (cur) cycle.push(cur);\n else break;\n }\n return cycle.reverse();\n }\n if (color.get(neighbor) === WHITE) {\n parent.set(neighbor, nodeId);\n const result = dfs(neighbor);\n if (result) return result;\n }\n }\n color.set(nodeId, BLACK);\n return null;\n };\n\n for (const node of flow.nodes) {\n if (color.get(node.id) === WHITE) {\n const cycle = dfs(node.id);\n if (cycle) {\n throw new Error(`Flow contains a cycle: ${cycle.join(' → ')}. Only DAG flows are allowed.`);\n }\n }\n }\n }\n\n /**\n * Get the runtime type name of a value for schema validation.\n */\n private getValueType(value: unknown): string {\n if (Array.isArray(value)) return 'array';\n if (typeof value === 'object' && value !== null) return 'object';\n return typeof value;\n }\n\n /**\n * Validate node input schemas before execution.\n * Checks that node config matches declared inputSchema if present.\n */\n private validateNodeInputSchemas(flow: FlowParsed, _variables: Map<string, unknown>): void {\n for (const node of flow.nodes) {\n if (node.inputSchema && node.config) {\n for (const [paramName, paramDef] of Object.entries(node.inputSchema)) {\n if (paramDef.required && !(paramName in (node.config as Record<string, unknown>))) {\n throw new Error(\n `Node '${node.id}' missing required input parameter '${paramName}'`,\n );\n }\n const value = (node.config as Record<string, unknown>)[paramName];\n if (value !== undefined) {\n const actualType = this.getValueType(value);\n if (actualType !== paramDef.type) {\n throw new Error(\n `Node '${node.id}' parameter '${paramName}' expected type '${paramDef.type}' but got '${actualType}'`,\n );\n }\n }\n }\n }\n }\n }\n\n /**\n * Execute a node with timeout support, fault edge handling, and step logging.\n */\n private async executeNode(\n node: FlowNodeParsed,\n flow: FlowParsed,\n variables: Map<string, unknown>,\n context: AutomationContext,\n steps: StepLogEntry[],\n ): Promise<void> {\n if (node.type === 'end') return;\n\n const stepStart = Date.now();\n const stepStartedAt = new Date().toISOString();\n\n // Find executor\n const executor = this.nodeExecutors.get(node.type);\n if (!executor) {\n // start node without executor is fine — just skip\n if (node.type !== 'start') {\n steps.push({\n nodeId: node.id,\n nodeType: node.type,\n status: 'failure',\n startedAt: stepStartedAt,\n completedAt: new Date().toISOString(),\n durationMs: Date.now() - stepStart,\n error: { code: 'NO_EXECUTOR', message: `No executor registered for node type '${node.type}'` },\n });\n throw new Error(`No executor registered for node type '${node.type}'`);\n }\n // Log start node step\n steps.push({\n nodeId: node.id,\n nodeType: node.type,\n status: 'success',\n startedAt: stepStartedAt,\n completedAt: new Date().toISOString(),\n durationMs: Date.now() - stepStart,\n });\n } else {\n // Execute node with optional timeout\n let result: NodeExecutionResult;\n try {\n if (node.timeoutMs && node.timeoutMs > 0) {\n result = await this.executeWithTimeout(\n executor.execute(node, variables, context),\n node.timeoutMs,\n node.id,\n );\n } else {\n result = await executor.execute(node, variables, context);\n }\n } catch (execErr: unknown) {\n const errMsg = execErr instanceof Error ? execErr.message : String(execErr);\n steps.push({\n nodeId: node.id,\n nodeType: node.type,\n status: 'failure',\n startedAt: stepStartedAt,\n completedAt: new Date().toISOString(),\n durationMs: Date.now() - stepStart,\n error: { code: 'EXECUTION_ERROR', message: errMsg },\n });\n\n // Check for fault edges\n const faultEdge = flow.edges.find(e => e.source === node.id && e.type === 'fault');\n if (faultEdge) {\n variables.set('$error', { nodeId: node.id, message: errMsg });\n const faultTarget = flow.nodes.find(n => n.id === faultEdge.target);\n if (faultTarget) {\n await this.executeNode(faultTarget, flow, variables, context, steps);\n return;\n }\n }\n throw execErr;\n }\n\n if (!result.success) {\n const errMsg = result.error ?? 'Unknown error';\n steps.push({\n nodeId: node.id,\n nodeType: node.type,\n status: 'failure',\n startedAt: stepStartedAt,\n completedAt: new Date().toISOString(),\n durationMs: Date.now() - stepStart,\n error: { code: 'NODE_FAILURE', message: errMsg },\n });\n\n // Write error output to variable context for downstream nodes\n variables.set('$error', { nodeId: node.id, message: errMsg, output: result.output });\n\n // Check for fault edges\n const faultEdge = flow.edges.find(e => e.source === node.id && e.type === 'fault');\n if (faultEdge) {\n const faultTarget = flow.nodes.find(n => n.id === faultEdge.target);\n if (faultTarget) {\n await this.executeNode(faultTarget, flow, variables, context, steps);\n return;\n }\n }\n throw new Error(`Node '${node.id}' failed: ${errMsg}`);\n }\n\n // Log successful step\n steps.push({\n nodeId: node.id,\n nodeType: node.type,\n status: 'success',\n startedAt: stepStartedAt,\n completedAt: new Date().toISOString(),\n durationMs: Date.now() - stepStart,\n });\n\n // Write back output variables\n if (result.output) {\n for (const [key, value] of Object.entries(result.output)) {\n variables.set(`${node.id}.${key}`, value);\n }\n }\n }\n\n // Find next nodes — separate conditional and unconditional edges\n const outEdges = flow.edges.filter(\n e => e.source === node.id && e.type !== 'fault',\n );\n\n const conditionalEdges: FlowEdgeParsed[] = [];\n const unconditionalEdges: FlowEdgeParsed[] = [];\n for (const edge of outEdges) {\n if (edge.condition) {\n conditionalEdges.push(edge);\n } else {\n unconditionalEdges.push(edge);\n }\n }\n\n // Conditional edges: evaluate sequentially (mutually exclusive)\n for (const edge of conditionalEdges) {\n if (this.evaluateCondition(edge.condition!, variables)) {\n const nextNode = flow.nodes.find(n => n.id === edge.target);\n if (nextNode) {\n await this.executeNode(nextNode, flow, variables, context, steps);\n }\n }\n }\n\n // Unconditional edges: execute in parallel (Promise.all)\n if (unconditionalEdges.length > 0) {\n const parallelTasks = unconditionalEdges\n .map(edge => flow.nodes.find(n => n.id === edge.target))\n .filter((n): n is FlowNodeParsed => n != null)\n .map(nextNode => this.executeNode(nextNode, flow, variables, context, steps));\n\n await Promise.all(parallelTasks);\n }\n }\n\n /**\n * Execute a promise with timeout using Promise.race.\n */\n private executeWithTimeout(\n promise: Promise<NodeExecutionResult>,\n timeoutMs: number,\n nodeId: string,\n ): Promise<NodeExecutionResult> {\n return Promise.race([\n promise,\n new Promise<NodeExecutionResult>((_, reject) =>\n setTimeout(() => reject(new Error(`Node '${nodeId}' timed out after ${timeoutMs}ms`)), timeoutMs),\n ),\n ]);\n }\n\n /**\n * Safe expression evaluator.\n * Uses simple operator-based parsing without `new Function`.\n * Supports: comparisons (>, <, >=, <=, ==, !=, ===, !==),\n * boolean literals (true, false), and basic arithmetic.\n */\n evaluateCondition(expression: string, variables: Map<string, unknown>): boolean {\n // Template replacement: {varName} → value\n let resolved = expression;\n for (const [key, value] of variables) {\n resolved = resolved.split(`{${key}}`).join(String(value));\n }\n resolved = resolved.trim();\n\n try {\n // Boolean literals\n if (resolved === 'true') return true;\n if (resolved === 'false') return false;\n\n // Comparison operators (ordered by length to match longer operators first)\n const operators = ['===', '!==', '>=', '<=', '!=', '==', '>', '<'] as const;\n for (const op of operators) {\n const idx = resolved.indexOf(op);\n if (idx !== -1) {\n const left = resolved.slice(0, idx).trim();\n const right = resolved.slice(idx + op.length).trim();\n return this.compareValues(left, op, right);\n }\n }\n\n // Numeric truthy check\n const numVal = Number(resolved);\n if (!isNaN(numVal)) return numVal !== 0;\n\n return false;\n } catch {\n return false;\n }\n }\n\n /**\n * Compare two string-represented values with an operator.\n */\n private compareValues(left: string, op: string, right: string): boolean {\n const lNum = Number(left);\n const rNum = Number(right);\n const bothNumeric = !isNaN(lNum) && !isNaN(rNum) && left !== '' && right !== '';\n\n if (bothNumeric) {\n switch (op) {\n case '>': return lNum > rNum;\n case '<': return lNum < rNum;\n case '>=': return lNum >= rNum;\n case '<=': return lNum <= rNum;\n case '==': case '===': return lNum === rNum;\n case '!=': case '!==': return lNum !== rNum;\n default: return false;\n }\n }\n // String comparison\n switch (op) {\n case '==': case '===': return left === right;\n case '!=': case '!==': return left !== right;\n case '>': return left > right;\n case '<': return left < right;\n case '>=': return left >= right;\n case '<=': return left <= right;\n default: return false;\n }\n }\n\n /**\n * Retry execution with exponential backoff, jitter, and recursive protection.\n * Uses an iterative loop with an internal retry flag to prevent recursive call stacking.\n */\n private async retryExecution(\n flowName: string,\n context: AutomationContext | undefined,\n startTime: number,\n errorHandling: {\n maxRetries?: number;\n retryDelayMs?: number;\n backoffMultiplier?: number;\n maxRetryDelayMs?: number;\n jitter?: boolean;\n },\n ): Promise<AutomationResult> {\n const maxRetries = errorHandling.maxRetries ?? 3;\n const baseDelay = errorHandling.retryDelayMs ?? 1000;\n const multiplier = errorHandling.backoffMultiplier ?? 1;\n const maxDelay = errorHandling.maxRetryDelayMs ?? 30000;\n const useJitter = errorHandling.jitter ?? false;\n\n let lastError = 'Max retries exceeded';\n for (let i = 0; i < maxRetries; i++) {\n // Calculate delay with exponential backoff\n let delay = Math.min(baseDelay * Math.pow(multiplier, i), maxDelay);\n if (useJitter) {\n delay = delay * (0.5 + Math.random() * 0.5);\n }\n await new Promise(r => setTimeout(r, delay));\n\n // Execute directly without recursion into retryExecution again\n const result = await this.executeWithoutRetry(flowName, context);\n if (result.success) return result;\n lastError = result.error ?? 'Unknown error';\n }\n return { success: false, error: lastError, durationMs: Date.now() - startTime };\n }\n\n /**\n * Execute a flow without triggering retry logic (used by retryExecution to prevent recursion).\n */\n private async executeWithoutRetry(\n flowName: string,\n context?: AutomationContext,\n ): Promise<AutomationResult> {\n const startTime = Date.now();\n const flow = this.flows.get(flowName);\n\n if (!flow) {\n return { success: false, error: `Flow '${flowName}' not found` };\n }\n if (this.flowEnabled.get(flowName) === false) {\n return { success: false, error: `Flow '${flowName}' is disabled` };\n }\n\n const variables = new Map<string, unknown>();\n if (flow.variables) {\n for (const v of flow.variables) {\n if (v.isInput && context?.params?.[v.name] !== undefined) {\n variables.set(v.name, context.params[v.name]);\n }\n }\n }\n if (context?.record) {\n variables.set('$record', context.record);\n }\n\n const runId = `run_${++this.runCounter}`;\n const startedAt = new Date().toISOString();\n const steps: StepLogEntry[] = [];\n\n try {\n const startNode = flow.nodes.find(n => n.type === 'start');\n if (!startNode) {\n return { success: false, error: 'Flow has no start node' };\n }\n\n await this.executeNode(startNode, flow, variables, context ?? {}, steps);\n\n const output: Record<string, unknown> = {};\n if (flow.variables) {\n for (const v of flow.variables) {\n if (v.isOutput) {\n output[v.name] = variables.get(v.name);\n }\n }\n }\n\n const durationMs = Date.now() - startTime;\n this.recordLog({\n id: runId,\n flowName,\n flowVersion: flow.version,\n status: 'completed',\n startedAt,\n completedAt: new Date().toISOString(),\n durationMs,\n trigger: {\n type: context?.event ?? 'manual',\n userId: context?.userId,\n object: context?.object,\n },\n steps,\n output,\n });\n\n return { success: true, output, durationMs };\n } catch (err: unknown) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n const durationMs = Date.now() - startTime;\n this.recordLog({\n id: runId,\n flowName,\n flowVersion: flow.version,\n status: 'failed',\n startedAt,\n completedAt: new Date().toISOString(),\n durationMs,\n trigger: {\n type: context?.event ?? 'manual',\n userId: context?.userId,\n object: context?.object,\n },\n steps,\n error: errorMessage,\n });\n return { success: false, error: errorMessage, durationMs };\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { AutomationEngine } from './engine.js';\n\n/**\n * Configuration options for the AutomationServicePlugin.\n */\nexport interface AutomationServicePluginOptions {\n /** Enable debug logging for flow execution */\n debug?: boolean;\n}\n\n/**\n * AutomationServicePlugin — Core engine plugin\n *\n * Responsibilities:\n * 1. init phase: Create engine instance, register as 'automation' service\n * 2. start phase: Trigger 'automation:ready' hook for node plugin registration\n * 3. destroy phase: Clean up resources\n *\n * Does NOT implement any specific nodes — nodes are registered by other plugins\n * via the engine's extension API.\n *\n * @example\n * ```ts\n * import { LiteKernel } from '@objectstack/core';\n * import { AutomationServicePlugin } from '@objectstack/service-automation';\n *\n * const kernel = new LiteKernel();\n * kernel.use(new AutomationServicePlugin());\n * await kernel.bootstrap();\n *\n * const automation = kernel.getService('automation');\n * ```\n */\nexport class AutomationServicePlugin implements Plugin {\n name = 'com.objectstack.service-automation';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies: string[] = [];\n\n private engine?: AutomationEngine;\n private readonly options: AutomationServicePluginOptions;\n\n constructor(options: AutomationServicePluginOptions = {}) {\n this.options = options;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n this.engine = new AutomationEngine(ctx.logger);\n\n // Register as global service — other plugins access via ctx.getService('automation')\n ctx.registerService('automation', this.engine);\n\n if (this.options.debug) {\n ctx.hook('automation:beforeExecute', async (flowName: string) => {\n ctx.logger.debug(`[Automation] Before execute: ${flowName}`);\n });\n }\n\n ctx.logger.info('[Automation] Engine initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (!this.engine) return;\n\n // Trigger hook to notify engine is ready — other plugins can start registering nodes\n await ctx.trigger('automation:ready', this.engine);\n\n const nodeTypes = this.engine.getRegisteredNodeTypes();\n ctx.logger.info(\n `[Automation] Engine started with ${nodeTypes.length} node types: ${nodeTypes.join(', ') || '(none)'}`,\n );\n }\n\n async destroy(): Promise<void> {\n this.engine = undefined;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { AutomationEngine } from '../engine.js';\n\n/**\n * CRUD Node Plugin — Provides get_record / create_record / update_record / delete_record\n *\n * Dependencies: service-automation (engine)\n *\n * In a full runtime environment these nodes would delegate to ObjectQL (data layer).\n * This MVP implementation provides the extension point structure.\n */\nexport class CrudNodesPlugin implements Plugin {\n name = 'com.objectstack.automation.crud-nodes';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies = ['com.objectstack.service-automation'];\n\n async init(ctx: PluginContext): Promise<void> {\n const engine = ctx.getService<AutomationEngine>('automation');\n\n // get_record node executor\n engine.registerNodeExecutor({\n type: 'get_record',\n async execute(node, _variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n // In production, this would query via ObjectQL:\n // const ql = ctx.getService('objectql');\n // const records = await ql.find(config.object, config.filters);\n return {\n success: true,\n output: { records: [], object: config?.object },\n };\n },\n });\n\n // create_record node executor\n engine.registerNodeExecutor({\n type: 'create_record',\n async execute(node, _variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n return {\n success: true,\n output: { id: 'new-record-id', object: config?.object },\n };\n },\n });\n\n // update_record node executor\n engine.registerNodeExecutor({\n type: 'update_record',\n async execute(_node, _variables, _context) {\n return { success: true };\n },\n });\n\n // delete_record node executor\n engine.registerNodeExecutor({\n type: 'delete_record',\n async execute(_node, _variables, _context) {\n return { success: true };\n },\n });\n\n ctx.logger.info('[CRUD Nodes] 4 node executors registered');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { AutomationEngine } from '../engine.js';\n\n/**\n * Logic Node Plugin — Provides decision / assignment / loop nodes\n *\n * Dependencies: service-automation (engine)\n */\nexport class LogicNodesPlugin implements Plugin {\n name = 'com.objectstack.automation.logic-nodes';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies = ['com.objectstack.service-automation'];\n\n async init(ctx: PluginContext): Promise<void> {\n const engine = ctx.getService<AutomationEngine>('automation');\n\n // decision node — conditional branching\n engine.registerNodeExecutor({\n type: 'decision',\n async execute(node, variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n const conditions = (config?.conditions ?? []) as Array<{ label: string; expression: string }>;\n\n for (const cond of conditions) {\n if (engine.evaluateCondition(cond.expression, variables)) {\n return { success: true, branchLabel: cond.label };\n }\n }\n return { success: true, branchLabel: 'default' };\n },\n });\n\n // assignment node — set variables\n engine.registerNodeExecutor({\n type: 'assignment',\n async execute(node, variables, _context) {\n const config = (node.config ?? {}) as Record<string, unknown>;\n for (const [key, value] of Object.entries(config)) {\n variables.set(key, value);\n }\n return { success: true };\n },\n });\n\n // loop node — iterate over a collection\n engine.registerNodeExecutor({\n type: 'loop',\n async execute(node, variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n const collectionName = config?.collection as string | undefined;\n if (collectionName) {\n const collection = variables.get(collectionName);\n if (Array.isArray(collection)) {\n variables.set('$loopItems', collection);\n variables.set('$loopIndex', 0);\n }\n }\n return { success: true };\n },\n });\n\n ctx.logger.info('[Logic Nodes] 3 node executors registered');\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport type { AutomationEngine } from '../engine.js';\n\n/**\n * HTTP + Connector Node Plugin — Provides http_request / connector_action nodes\n *\n * Dependencies: service-automation (engine)\n */\nexport class HttpConnectorPlugin implements Plugin {\n name = 'com.objectstack.automation.http-connector';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies = ['com.objectstack.service-automation'];\n\n async init(ctx: PluginContext): Promise<void> {\n const engine = ctx.getService<AutomationEngine>('automation');\n\n // http_request node executor\n engine.registerNodeExecutor({\n type: 'http_request',\n async execute(node, _variables, _context) {\n const config = node.config as Record<string, unknown> | undefined;\n const url = config?.url as string | undefined;\n const method = (config?.method as string) ?? 'GET';\n const headers = config?.headers as Record<string, string> | undefined;\n const body = config?.body;\n\n if (!url) {\n return { success: false, error: 'http_request: url is required' };\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n const data = await response.json();\n\n return {\n success: response.ok,\n output: { response: data, status: response.status },\n error: response.ok ? undefined : `HTTP ${response.status}`,\n };\n },\n });\n\n // connector_action node — calls a registered connector\n engine.registerNodeExecutor({\n type: 'connector_action',\n async execute(node, _variables, _context) {\n const connectorConfig = node.connectorConfig;\n if (!connectorConfig) {\n return { success: false, error: 'connector_action: connectorConfig is required' };\n }\n\n ctx.logger.info(\n `Connector action: ${connectorConfig.connectorId}.${connectorConfig.actionId}`,\n );\n\n // In production, this would look up the connector from a registry\n // and execute the specified action with the mapped inputs\n return { success: true, output: { connectorResult: {} } };\n },\n });\n\n ctx.logger.info('[HTTP Connector] 2 node executors registered');\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/service-automation",
3
- "version": "3.0.8",
3
+ "version": "3.0.10",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Automation Service for ObjectStack — implements IAutomationService with plugin-based DAG flow execution engine",
6
6
  "type": "module",
@@ -14,13 +14,13 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "@objectstack/core": "3.0.8",
18
- "@objectstack/spec": "3.0.8"
17
+ "@objectstack/core": "3.0.10",
18
+ "@objectstack/spec": "3.0.10"
19
19
  },
20
20
  "devDependencies": {
21
21
  "typescript": "^5.0.0",
22
22
  "vitest": "^4.0.18",
23
- "@types/node": "^25.2.3"
23
+ "@types/node": "^25.3.0"
24
24
  },
25
25
  "scripts": {
26
26
  "build": "tsup --config ../../../tsup.config.ts",