@supergrowthai/tq 1.0.13 → 1.1.1

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 (38) hide show
  1. package/README.md +149 -8
  2. package/dist/{AsyncActions-CZYO8ShR.js → AsyncActions-B8ImDgTo.js} +39 -3
  3. package/dist/AsyncActions-B8ImDgTo.js.map +1 -0
  4. package/dist/{AsyncActions-BOO1ikWz.cjs → AsyncActions-BsxMX_Ib.cjs} +39 -3
  5. package/dist/AsyncActions-BsxMX_Ib.cjs.map +1 -0
  6. package/dist/core/Actions.cjs +23 -1
  7. package/dist/core/Actions.cjs.map +1 -1
  8. package/dist/core/Actions.mjs +23 -1
  9. package/dist/core/Actions.mjs.map +1 -1
  10. package/dist/core/async/AsyncActions.cjs +1 -1
  11. package/dist/core/async/AsyncActions.mjs +1 -1
  12. package/dist/index.cjs +459 -226
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.mjs +459 -226
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/src/core/Actions.d.cts +5 -1
  17. package/dist/src/core/Actions.d.ts +5 -1
  18. package/dist/src/core/TaskHandler.d.cts +6 -0
  19. package/dist/src/core/TaskHandler.d.ts +6 -0
  20. package/dist/src/core/TaskRunner.d.cts +22 -5
  21. package/dist/src/core/TaskRunner.d.ts +22 -5
  22. package/dist/src/core/async/AsyncActions.d.cts +1 -0
  23. package/dist/src/core/async/AsyncActions.d.ts +1 -0
  24. package/dist/src/core/flow/FlowMiddleware.d.cts +6 -1
  25. package/dist/src/core/flow/FlowMiddleware.d.ts +6 -1
  26. package/dist/src/core/flow/IFlowBarrierProvider.d.cts +4 -0
  27. package/dist/src/core/flow/IFlowBarrierProvider.d.ts +4 -0
  28. package/dist/src/core/flow/InMemoryFlowBarrierProvider.d.cts +1 -0
  29. package/dist/src/core/flow/InMemoryFlowBarrierProvider.d.ts +1 -0
  30. package/dist/src/core/lifecycle.d.cts +98 -3
  31. package/dist/src/core/lifecycle.d.ts +98 -3
  32. package/dist/src/providers/ConsoleHealthProvider.d.cts +42 -2
  33. package/dist/src/providers/ConsoleHealthProvider.d.ts +42 -2
  34. package/dist/src/test/lifecycle-events.test.d.cts +31 -0
  35. package/dist/src/test/lifecycle-events.test.d.ts +31 -0
  36. package/package.json +2 -2
  37. package/dist/AsyncActions-BOO1ikWz.cjs.map +0 -1
  38. package/dist/AsyncActions-CZYO8ShR.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Actions.cjs","sources":["../../src/core/Actions.ts"],"sourcesContent":["import {ExecutorActions} from \"./base/interfaces\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport {tId} from \"../utils/task-id-gen.js\";\nimport {CronTask} from \"../adapters\";\nimport type {StartFlowInput, FlowMeta} from \"./flow/types.js\";\nimport type {EntityTaskProjection} from \"./entity/IEntityProjectionProvider.js\";\nimport type {QueueName} from \"@supergrowthai/mq\";\nimport {randomUUID} from \"crypto\";\n\nconst logger = new Logger('Actions', LogLevel.INFO);\n\ninterface ActionEntry<ID = any> {\n type: 'success' | 'fail' | 'addTasks';\n timestamp: number;\n task?: CronTask<ID>; // The task passed to success/fail\n newTasks?: CronTask<ID>[]; // Tasks to add\n result?: unknown; // Result from success(task, result)\n error?: Error | string; // Error from fail(task, error)\n meta?: Record<string, unknown>; // Meta from fail(task, error, meta)\n}\n\ninterface TaskContext<ID = any> {\n task: CronTask<ID> | null; // The task being executed (null for batch contexts)\n actions: ActionEntry<ID>[];\n}\n\nexport interface ActionResults<ID = any> {\n failedTasks: CronTask<ID>[];\n successTasks: CronTask<ID>[];\n newTasks: CronTask<ID>[];\n ignoredTasks: CronTask<ID>[];\n /** RFC-002: Entity projections from startFlow calls (processing status, task_id = flow_id) */\n flowProjections: EntityTaskProjection[];\n}\n\nconst MAX_RESULT_SIZE_BYTES = 256 * 1024; // 256KB\n\nfunction validateResultSize(result: unknown): boolean {\n // Fast path: null and non-string primitives are always small\n if (result === null || typeof result === 'number' || typeof result === 'boolean') return true;\n\n try {\n const json = JSON.stringify(result);\n // json.length is always <= Buffer.byteLength (UTF-8 chars are 1-4 bytes)\n // So if json string length exceeds limit, byte length definitely does too\n if (json.length > MAX_RESULT_SIZE_BYTES) return false;\n return Buffer.byteLength(json, 'utf8') <= MAX_RESULT_SIZE_BYTES;\n } catch {\n // Circular reference or other serialization error\n return false;\n }\n}\n\nfunction enrichTaskWithResult<ID>(task: CronTask<ID>, result: unknown): CronTask<ID> {\n if (result === undefined) return task;\n if (!validateResultSize(result)) return task; // caller logs warning\n task.execution_result = result; // mutate in place — tasks are already extracted copies\n return task;\n}\n\nfunction enrichTaskWithError<ID>(task: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>): CronTask<ID> {\n if (!error && !meta) return task;\n\n const errorFields: Record<string, unknown> = {};\n if (error instanceof Error) {\n errorFields.last_error = error.message;\n errorFields.last_error_stack = error.stack;\n } else if (typeof error === 'string') {\n errorFields.last_error = error;\n }\n\n // Mutate in place — tasks are already extracted copies\n task.execution_stats = {\n ...(task.execution_stats || {}),\n ...errorFields,\n ...(meta || {})\n };\n return task;\n}\n\nexport class Actions<ID = any> implements ExecutorActions<ID> {\n private readonly taskRunnerId: string;\n private readonly taskContexts = new Map<string, TaskContext<ID>>();\n /** RFC-002: Flow projections accumulated from startFlow calls */\n private readonly _flowProjections: EntityTaskProjection[] = [];\n\n /** Logger for multi-task executors — carries runtime-only context (RFC-005) */\n readonly log: Logger;\n\n constructor(taskRunnerId: string) {\n this.taskRunnerId = taskRunnerId;\n // Root actions logger has no task-specific context — only ALS runtime context applies\n this.log = logger.child({});\n }\n\n /**\n * Fork execution context for a specific task (for single-task executors)\n */\n forkForTask(task: CronTask<ID>): ExecutorActions<ID> {\n const taskId = tId(task);\n const parentLogContext = task.metadata?.log_context;\n\n // Initialize context for this task\n const context: TaskContext<ID> = {task, actions: []};\n this.taskContexts.set(taskId, context);\n\n // Create child logger scoped to this task's log_context (RFC-005)\n const taskLog = logger.child(parentLogContext || {});\n\n // Return a scoped actions object that tracks everything in this context\n return {\n log: taskLog,\n\n fail: (t: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>) => {\n context.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task: t,\n error,\n meta\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${tId(t)} (${t.type})`);\n },\n\n success: (t: CronTask<ID>, result?: unknown) => {\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task: t,\n result\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${tId(t)} (${t.type})`);\n },\n\n addTasks: (tasks: CronTask<ID>[]) => {\n // Merge parent log_context onto child tasks (RFC-005: parent keys as defaults, child wins)\n const mergedTasks = parentLogContext\n ? tasks.map(t => ({\n ...t,\n metadata: {\n ...(t.metadata || {}),\n log_context: {...parentLogContext, ...(t.metadata?.log_context || {})}\n }\n }))\n : tasks;\n\n context.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: mergedTasks\n });\n logger.info(`[${this.taskRunnerId}] Task ${taskId} adding ${tasks.length} new tasks`);\n },\n\n startFlow: (input: StartFlowInput): string => {\n return this._startFlowImpl(input, parentLogContext);\n }\n };\n }\n\n // For multi-task executors - they use the root Actions directly (no forking)\n fail(task: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context!.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task,\n error,\n meta\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${taskId} (${task.type})`);\n }\n\n success(task: CronTask<ID>, result?: unknown): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task,\n result\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${taskId} (${task.type})`);\n }\n\n // TODO(P1): Add configurable max child tasks per execution (e.g., 1000).\n // A buggy executor can call addTasks() with unbounded entries, all in memory.\n // Each child can spawn more children — unbounded amplification risk.\n addTasks(tasks: CronTask<ID>[]): void {\n // For multi-task mode, store in a batch-specific context\n logger.info(`[${this.taskRunnerId}] Adding ${tasks.length} new tasks`);\n\n const batchKey = `__batch_${this.taskRunnerId}__`;\n let batchContext = this.taskContexts.get(batchKey);\n if (!batchContext) {\n batchContext = {task: null, actions: []};\n this.taskContexts.set(batchKey, batchContext);\n }\n batchContext.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: tasks\n });\n }\n\n addIgnoredTask(task: CronTask<ID>): void {\n const taskId = tId(task);\n this.taskContexts.set(taskId, {task, actions: []});\n logger.warn(`[${this.taskRunnerId}] Task ignored: ${taskId} (${task.type})`);\n }\n\n /**\n * RFC-002: Start a fan-out/fan-in flow from the root Actions context (multi-task executors).\n */\n startFlow(input: StartFlowInput): string {\n return this._startFlowImpl(input);\n }\n\n /**\n * RFC-002: Internal implementation for startFlow.\n * Used by both root Actions and forked per-task actions.\n */\n private _startFlowImpl(input: StartFlowInput, parentLogContext?: Record<string, string>): string {\n const {steps, config} = input;\n\n if (steps.length === 0) {\n throw new Error('[TQ/RFC-002] startFlow requires at least 1 step');\n }\n\n const flowId = randomUUID();\n const now = new Date();\n const failurePolicy = config.failure_policy || 'continue';\n\n const stepTasks: CronTask<ID>[] = steps.map((step, index) => {\n const flowMeta: FlowMeta = {\n flow_id: flowId,\n step_index: index,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n ...(config.entity ? {entity: config.entity} : {}),\n };\n\n const metadata: Record<string, unknown> = {\n flow_meta: flowMeta as unknown as Record<string, unknown>,\n };\n\n // Inherit parent log_context onto step tasks (RFC-005)\n if (parentLogContext) {\n (metadata as any).log_context = {...parentLogContext};\n }\n\n return {\n type: step.type,\n queue_id: step.queue_id as QueueName,\n payload: step.payload,\n execute_at: now,\n status: 'scheduled' as const,\n created_at: now,\n updated_at: now,\n force_store: true,\n metadata,\n ...(step.entity ? {entity: step.entity} : {}),\n } as CronTask<ID>;\n });\n\n // Create timeout sentinel if configured\n if (config.timeout_ms && config.timeout_ms > 0) {\n const timeoutFlowMeta: FlowMeta = {\n flow_id: flowId,\n step_index: -1,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n is_timeout: true,\n ...(config.entity ? {entity: config.entity} : {}),\n };\n\n stepTasks.push({\n type: '_flow.timeout',\n queue_id: config.join.queue_id as QueueName,\n payload: {flow_id: flowId, is_timeout: true},\n execute_at: new Date(now.getTime() + config.timeout_ms),\n status: 'scheduled' as const,\n created_at: now,\n updated_at: now,\n force_store: true,\n metadata: {\n flow_meta: timeoutFlowMeta as unknown as Record<string, unknown>,\n ...(parentLogContext ? {log_context: {...parentLogContext}} : {}),\n },\n } as unknown as CronTask<ID>);\n }\n\n // Add step tasks via the existing addTasks mechanism\n this.addTasks(stepTasks);\n\n // RFC-002 + RFC-003: If entity present, emit a 'processing' projection with flow_id as task_id\n if (config.entity) {\n this._flowProjections.push({\n task_id: flowId,\n entity_id: config.entity.id,\n entity_type: config.entity.type,\n task_type: config.join.type,\n queue_id: config.join.queue_id,\n status: 'processing',\n created_at: now,\n updated_at: now,\n });\n }\n\n logger.info(`[${this.taskRunnerId}] Started flow ${flowId} with ${steps.length} steps, join: ${config.join.type}`);\n return flowId;\n }\n\n /**\n * Check the result status for a specific task\n * Returns 'success', 'fail', or 'pending' (no action recorded yet)\n */\n getTaskResultStatus(taskId: string): 'success' | 'fail' | 'pending' {\n const context = this.taskContexts.get(taskId);\n if (!context) return 'pending';\n\n for (const action of context.actions) {\n if (action.type === 'success') return 'success';\n if (action.type === 'fail') return 'fail';\n }\n return 'pending';\n }\n\n /**\n * Extract actions for a single task (used by async tasks)\n */\n extractTaskActions(taskId: string): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: [],\n flowProjections: []\n };\n\n const context = this.taskContexts.get(taskId);\n if (!context) return results;\n\n if (context.actions.length === 0 && context.task) {\n // No actions = ignored task\n results.ignoredTasks.push(context.task);\n } else {\n // Process all actions\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n if (action.result !== undefined && !validateResultSize(action.result)) {\n logger.warn(`[${this.taskRunnerId}] Result for task ${tId(action.task)} exceeds size limit, dropping result`);\n }\n results.successTasks.push(enrichTaskWithResult(action.task, action.result));\n // If marking a different task, remove its context\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(enrichTaskWithError(action.task, action.error, action.meta));\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n\n this.taskContexts.delete(taskId);\n return results;\n }\n\n /**\n * Extract sync results including batch context (for sync processing)\n */\n extractSyncResults(excludeTaskIds: string[]): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: [],\n flowProjections: [...this._flowProjections]\n };\n\n const excludeSet = new Set(excludeTaskIds);\n const batchKey = `__batch_${this.taskRunnerId}__`;\n\n // Process all task contexts except excluded ones\n for (const [taskId, context] of this.taskContexts) {\n if (excludeSet.has(taskId)) continue;\n\n if (taskId === batchKey) {\n // Batch context - only has addTasks\n for (const action of context.actions) {\n if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n } else {\n // Regular task context\n if (context.actions.length === 0 && context.task) {\n results.ignoredTasks.push(context.task);\n } else {\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n if (action.result !== undefined && !validateResultSize(action.result)) {\n logger.warn(`[${this.taskRunnerId}] Result for task ${tId(action.task)} exceeds size limit, dropping result`);\n }\n results.successTasks.push(enrichTaskWithResult(action.task, action.result));\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(enrichTaskWithError(action.task, action.error, action.meta));\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n }\n }\n\n // Clear processed contexts\n for (const [taskId] of this.taskContexts) {\n if (!excludeSet.has(taskId)) {\n this.taskContexts.delete(taskId);\n }\n }\n\n // Clear flow projections after extraction\n this._flowProjections.length = 0;\n\n return results;\n }\n\n /**\n * Get all results (mainly for backward compatibility)\n */\n getResults(): ActionResults<ID> {\n return this.extractSyncResults([]);\n }\n\n /**\n * Get the result for a specific task (before extraction).\n * Used by TaskRunner to pass results to lifecycle events.\n */\n getTaskResult(taskId: string): unknown | undefined {\n const context = this.taskContexts.get(taskId);\n if (!context) return undefined;\n\n for (const action of context.actions) {\n if (action.type === 'success' && action.result !== undefined) {\n return action.result;\n }\n }\n return undefined;\n }\n}"],"names":["Logger","LogLevel","tId","randomUUID"],"mappings":"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"}
1
+ {"version":3,"file":"Actions.cjs","sources":["../../src/core/Actions.ts"],"sourcesContent":["import {ExecutorActions} from \"./base/interfaces\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport {tId} from \"../utils/task-id-gen.js\";\nimport {CronTask} from \"../adapters\";\nimport type {StartFlowInput, FlowMeta} from \"./flow/types.js\";\nimport type {EntityTaskProjection} from \"./entity/IEntityProjectionProvider.js\";\nimport type {IFlowLifecycleProvider} from \"./lifecycle.js\";\nimport type {QueueName} from \"@supergrowthai/mq\";\nimport {randomUUID} from \"crypto\";\n\nconst logger = new Logger('Actions', LogLevel.INFO);\n\ninterface ActionEntry<ID = any> {\n type: 'success' | 'fail' | 'addTasks';\n timestamp: number;\n task?: CronTask<ID>; // The task passed to success/fail\n newTasks?: CronTask<ID>[]; // Tasks to add\n result?: unknown; // Result from success(task, result)\n error?: Error | string; // Error from fail(task, error)\n meta?: Record<string, unknown>; // Meta from fail(task, error, meta)\n}\n\ninterface TaskContext<ID = any> {\n task: CronTask<ID> | null; // The task being executed (null for batch contexts)\n actions: ActionEntry<ID>[];\n}\n\nexport interface ActionResults<ID = any> {\n failedTasks: CronTask<ID>[];\n successTasks: CronTask<ID>[];\n newTasks: CronTask<ID>[];\n ignoredTasks: CronTask<ID>[];\n /** RFC-002: Entity projections from startFlow calls (processing status, task_id = flow_id) */\n flowProjections: EntityTaskProjection[];\n}\n\nconst MAX_RESULT_SIZE_BYTES = 256 * 1024; // 256KB\n\nfunction validateResultSize(result: unknown): boolean {\n // Fast path: null and non-string primitives are always small\n if (result === null || typeof result === 'number' || typeof result === 'boolean') return true;\n\n try {\n const json = JSON.stringify(result);\n // json.length is always <= Buffer.byteLength (UTF-8 chars are 1-4 bytes)\n // So if json string length exceeds limit, byte length definitely does too\n if (json.length > MAX_RESULT_SIZE_BYTES) return false;\n return Buffer.byteLength(json, 'utf8') <= MAX_RESULT_SIZE_BYTES;\n } catch {\n // Circular reference or other serialization error\n return false;\n }\n}\n\nfunction enrichTaskWithResult<ID>(task: CronTask<ID>, result: unknown): CronTask<ID> {\n if (result === undefined) return task;\n if (!validateResultSize(result)) return task; // caller logs warning\n task.execution_result = result; // mutate in place — tasks are already extracted copies\n return task;\n}\n\nfunction enrichTaskWithError<ID>(task: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>): CronTask<ID> {\n if (!error && !meta) return task;\n\n const errorFields: Record<string, unknown> = {};\n if (error instanceof Error) {\n errorFields.last_error = error.message;\n errorFields.last_error_stack = error.stack;\n } else if (typeof error === 'string') {\n errorFields.last_error = error;\n }\n\n // Mutate in place — tasks are already extracted copies\n task.execution_stats = {\n ...(task.execution_stats || {}),\n ...errorFields,\n ...(meta || {})\n };\n return task;\n}\n\nexport class Actions<ID = any> implements ExecutorActions<ID> {\n private readonly taskRunnerId: string;\n private readonly taskContexts = new Map<string, TaskContext<ID>>();\n /** RFC-002: Flow projections accumulated from startFlow calls */\n private readonly _flowProjections: EntityTaskProjection[] = [];\n\n /** Logger for multi-task executors — carries runtime-only context (RFC-005) */\n readonly log: Logger;\n\n private readonly flowLifecycleProvider?: IFlowLifecycleProvider;\n /** Process identity (hostname-pid-timestamp) for lifecycle events */\n private readonly workerId: string;\n\n constructor(taskRunnerId: string, flowLifecycleProvider?: IFlowLifecycleProvider, workerId: string = '') {\n this.taskRunnerId = taskRunnerId;\n this.flowLifecycleProvider = flowLifecycleProvider;\n this.workerId = workerId;\n // Root actions logger has no task-specific context — only ALS runtime context applies\n this.log = logger.child({});\n }\n\n /**\n * Fork execution context for a specific task (for single-task executors)\n */\n forkForTask(task: CronTask<ID>): ExecutorActions<ID> {\n const taskId = tId(task);\n const parentLogContext = task.metadata?.log_context;\n\n // Initialize context for this task\n const context: TaskContext<ID> = {task, actions: []};\n this.taskContexts.set(taskId, context);\n\n // Create child logger scoped to this task's log_context (RFC-005)\n const taskLog = logger.child(parentLogContext || {});\n\n // Return a scoped actions object that tracks everything in this context\n return {\n log: taskLog,\n\n fail: (t: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>) => {\n context.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task: t,\n error,\n meta\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${tId(t)} (${t.type})`);\n },\n\n success: (t: CronTask<ID>, result?: unknown) => {\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task: t,\n result\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${tId(t)} (${t.type})`);\n },\n\n addTasks: (tasks: CronTask<ID>[]) => {\n // Merge parent log_context onto child tasks (RFC-005: parent keys as defaults, child wins)\n const mergedTasks = parentLogContext\n ? tasks.map(t => ({\n ...t,\n metadata: {\n ...(t.metadata || {}),\n log_context: {...parentLogContext, ...(t.metadata?.log_context || {})}\n }\n }))\n : tasks;\n\n context.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: mergedTasks\n });\n logger.info(`[${this.taskRunnerId}] Task ${taskId} adding ${tasks.length} new tasks`);\n },\n\n startFlow: (input: StartFlowInput): string => {\n return this._startFlowImpl(input, parentLogContext);\n }\n };\n }\n\n // For multi-task executors - they use the root Actions directly (no forking)\n fail(task: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context!.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task,\n error,\n meta\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${taskId} (${task.type})`);\n }\n\n success(task: CronTask<ID>, result?: unknown): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task,\n result\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${taskId} (${task.type})`);\n }\n\n // TODO(P1): Add configurable max child tasks per execution (e.g., 1000).\n // A buggy executor can call addTasks() with unbounded entries, all in memory.\n // Each child can spawn more children — unbounded amplification risk.\n addTasks(tasks: CronTask<ID>[]): void {\n // For multi-task mode, store in a batch-specific context\n logger.info(`[${this.taskRunnerId}] Adding ${tasks.length} new tasks`);\n\n const batchKey = `__batch_${this.taskRunnerId}__`;\n let batchContext = this.taskContexts.get(batchKey);\n if (!batchContext) {\n batchContext = {task: null, actions: []};\n this.taskContexts.set(batchKey, batchContext);\n }\n batchContext.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: tasks\n });\n }\n\n addIgnoredTask(task: CronTask<ID>): void {\n const taskId = tId(task);\n this.taskContexts.set(taskId, {task, actions: []});\n logger.warn(`[${this.taskRunnerId}] Task ignored: ${taskId} (${task.type})`);\n }\n\n /**\n * RFC-002: Start a fan-out/fan-in flow from the root Actions context (multi-task executors).\n */\n startFlow(input: StartFlowInput): string {\n return this._startFlowImpl(input);\n }\n\n /**\n * RFC-002: Internal implementation for startFlow.\n * Used by both root Actions and forked per-task actions.\n */\n private _startFlowImpl(input: StartFlowInput, parentLogContext?: Record<string, string>): string {\n const {steps, config} = input;\n\n if (steps.length === 0) {\n throw new Error('[TQ/RFC-002] startFlow requires at least 1 step');\n }\n\n const flowId = randomUUID();\n const now = new Date();\n const failurePolicy = config.failure_policy || 'continue';\n\n const stepTasks: CronTask<ID>[] = steps.map((step, index) => {\n const flowMeta: FlowMeta = {\n flow_id: flowId,\n step_index: index,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n ...(config.entity ? {entity: config.entity} : {}),\n };\n\n const metadata: Record<string, unknown> = {\n flow_meta: flowMeta as unknown as Record<string, unknown>,\n };\n\n // Inherit parent log_context onto step tasks (RFC-005)\n if (parentLogContext) {\n (metadata as any).log_context = {...parentLogContext};\n }\n\n return {\n type: step.type,\n queue_id: step.queue_id as QueueName,\n payload: step.payload,\n execute_at: now,\n status: 'scheduled' as const,\n created_at: now,\n updated_at: now,\n force_store: true,\n metadata,\n ...(step.entity ? {entity: step.entity} : {}),\n } as CronTask<ID>;\n });\n\n // Create timeout sentinel if configured\n if (config.timeout_ms && config.timeout_ms > 0) {\n const timeoutFlowMeta: FlowMeta = {\n flow_id: flowId,\n step_index: -1,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n is_timeout: true,\n ...(config.entity ? {entity: config.entity} : {}),\n };\n\n stepTasks.push({\n type: '_flow.timeout',\n queue_id: config.join.queue_id as QueueName,\n payload: {flow_id: flowId, is_timeout: true},\n execute_at: new Date(now.getTime() + config.timeout_ms),\n status: 'scheduled' as const,\n created_at: now,\n updated_at: now,\n force_store: true,\n metadata: {\n flow_meta: timeoutFlowMeta as unknown as Record<string, unknown>,\n ...(parentLogContext ? {log_context: {...parentLogContext}} : {}),\n },\n } as unknown as CronTask<ID>);\n }\n\n // Add step tasks via the existing addTasks mechanism\n this.addTasks(stepTasks);\n\n // RFC-002 + RFC-003: If entity present, emit a 'processing' projection with flow_id as task_id\n if (config.entity) {\n this._flowProjections.push({\n task_id: flowId,\n entity_id: config.entity.id,\n entity_type: config.entity.type,\n task_type: config.join.type,\n queue_id: config.join.queue_id,\n status: 'processing',\n created_at: now,\n updated_at: now,\n });\n }\n\n logger.info(`[${this.taskRunnerId}] Started flow ${flowId} with ${steps.length} steps, join: ${config.join.type}`);\n\n // Emit onFlowStarted lifecycle event\n if (this.flowLifecycleProvider?.onFlowStarted) {\n try {\n const result = this.flowLifecycleProvider.onFlowStarted({\n flow_id: flowId,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n entity: config.entity,\n worker_id: this.workerId,\n consumer_id: this.taskRunnerId,\n started_at: now,\n step_types: steps.map(s => s.type),\n });\n if (result instanceof Promise) {\n result.catch(err => logger.error(`[TQ] Flow lifecycle onFlowStarted error: ${err}`));\n }\n } catch (err) {\n logger.error(`[TQ] Flow lifecycle onFlowStarted error: ${err}`);\n }\n }\n\n return flowId;\n }\n\n /**\n * Check the result status for a specific task\n * Returns 'success', 'fail', or 'pending' (no action recorded yet)\n */\n getTaskResultStatus(taskId: string): 'success' | 'fail' | 'pending' {\n const context = this.taskContexts.get(taskId);\n if (!context) return 'pending';\n\n for (const action of context.actions) {\n if (action.type === 'success') return 'success';\n if (action.type === 'fail') return 'fail';\n }\n return 'pending';\n }\n\n /**\n * Extract actions for a single task (used by async tasks)\n */\n extractTaskActions(taskId: string): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: [],\n flowProjections: []\n };\n\n const context = this.taskContexts.get(taskId);\n if (!context) return results;\n\n if (context.actions.length === 0 && context.task) {\n // No actions = ignored task\n results.ignoredTasks.push(context.task);\n } else {\n // Process all actions\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n if (action.result !== undefined && !validateResultSize(action.result)) {\n logger.warn(`[${this.taskRunnerId}] Result for task ${tId(action.task)} exceeds size limit, dropping result`);\n }\n results.successTasks.push(enrichTaskWithResult(action.task, action.result));\n // If marking a different task, remove its context\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(enrichTaskWithError(action.task, action.error, action.meta));\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n\n this.taskContexts.delete(taskId);\n return results;\n }\n\n /**\n * Extract sync results including batch context (for sync processing)\n */\n extractSyncResults(excludeTaskIds: string[]): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: [],\n flowProjections: [...this._flowProjections]\n };\n\n const excludeSet = new Set(excludeTaskIds);\n const batchKey = `__batch_${this.taskRunnerId}__`;\n\n // Process all task contexts except excluded ones\n for (const [taskId, context] of this.taskContexts) {\n if (excludeSet.has(taskId)) continue;\n\n if (taskId === batchKey) {\n // Batch context - only has addTasks\n for (const action of context.actions) {\n if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n } else {\n // Regular task context\n if (context.actions.length === 0 && context.task) {\n results.ignoredTasks.push(context.task);\n } else {\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n if (action.result !== undefined && !validateResultSize(action.result)) {\n logger.warn(`[${this.taskRunnerId}] Result for task ${tId(action.task)} exceeds size limit, dropping result`);\n }\n results.successTasks.push(enrichTaskWithResult(action.task, action.result));\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(enrichTaskWithError(action.task, action.error, action.meta));\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n }\n }\n\n // Clear processed contexts\n for (const [taskId] of this.taskContexts) {\n if (!excludeSet.has(taskId)) {\n this.taskContexts.delete(taskId);\n }\n }\n\n // Clear flow projections after extraction\n this._flowProjections.length = 0;\n\n return results;\n }\n\n /**\n * Get all results (mainly for backward compatibility)\n */\n getResults(): ActionResults<ID> {\n return this.extractSyncResults([]);\n }\n\n /**\n * Get the result for a specific task (before extraction).\n * Used by TaskRunner to pass results to lifecycle events.\n */\n getTaskResult(taskId: string): unknown | undefined {\n const context = this.taskContexts.get(taskId);\n if (!context) return undefined;\n\n for (const action of context.actions) {\n if (action.type === 'success' && action.result !== undefined) {\n return action.result;\n }\n }\n return undefined;\n }\n}"],"names":["Logger","LogLevel","tId","randomUUID"],"mappings":"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"}
@@ -36,10 +36,12 @@ function enrichTaskWithError(task, error, meta) {
36
36
  return task;
37
37
  }
38
38
  class Actions {
39
- constructor(taskRunnerId) {
39
+ constructor(taskRunnerId, flowLifecycleProvider, workerId = "") {
40
40
  this.taskContexts = /* @__PURE__ */ new Map();
41
41
  this._flowProjections = [];
42
42
  this.taskRunnerId = taskRunnerId;
43
+ this.flowLifecycleProvider = flowLifecycleProvider;
44
+ this.workerId = workerId;
43
45
  this.log = logger.child({});
44
46
  }
45
47
  /**
@@ -231,6 +233,26 @@ class Actions {
231
233
  });
232
234
  }
233
235
  logger.info(`[${this.taskRunnerId}] Started flow ${flowId} with ${steps.length} steps, join: ${config.join.type}`);
236
+ if (this.flowLifecycleProvider?.onFlowStarted) {
237
+ try {
238
+ const result = this.flowLifecycleProvider.onFlowStarted({
239
+ flow_id: flowId,
240
+ total_steps: steps.length,
241
+ join: config.join,
242
+ failure_policy: failurePolicy,
243
+ entity: config.entity,
244
+ worker_id: this.workerId,
245
+ consumer_id: this.taskRunnerId,
246
+ started_at: now,
247
+ step_types: steps.map((s) => s.type)
248
+ });
249
+ if (result instanceof Promise) {
250
+ result.catch((err) => logger.error(`[TQ] Flow lifecycle onFlowStarted error: ${err}`));
251
+ }
252
+ } catch (err) {
253
+ logger.error(`[TQ] Flow lifecycle onFlowStarted error: ${err}`);
254
+ }
255
+ }
234
256
  return flowId;
235
257
  }
236
258
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Actions.mjs","sources":["../../src/core/Actions.ts"],"sourcesContent":["import {ExecutorActions} from \"./base/interfaces\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport {tId} from \"../utils/task-id-gen.js\";\nimport {CronTask} from \"../adapters\";\nimport type {StartFlowInput, FlowMeta} from \"./flow/types.js\";\nimport type {EntityTaskProjection} from \"./entity/IEntityProjectionProvider.js\";\nimport type {QueueName} from \"@supergrowthai/mq\";\nimport {randomUUID} from \"crypto\";\n\nconst logger = new Logger('Actions', LogLevel.INFO);\n\ninterface ActionEntry<ID = any> {\n type: 'success' | 'fail' | 'addTasks';\n timestamp: number;\n task?: CronTask<ID>; // The task passed to success/fail\n newTasks?: CronTask<ID>[]; // Tasks to add\n result?: unknown; // Result from success(task, result)\n error?: Error | string; // Error from fail(task, error)\n meta?: Record<string, unknown>; // Meta from fail(task, error, meta)\n}\n\ninterface TaskContext<ID = any> {\n task: CronTask<ID> | null; // The task being executed (null for batch contexts)\n actions: ActionEntry<ID>[];\n}\n\nexport interface ActionResults<ID = any> {\n failedTasks: CronTask<ID>[];\n successTasks: CronTask<ID>[];\n newTasks: CronTask<ID>[];\n ignoredTasks: CronTask<ID>[];\n /** RFC-002: Entity projections from startFlow calls (processing status, task_id = flow_id) */\n flowProjections: EntityTaskProjection[];\n}\n\nconst MAX_RESULT_SIZE_BYTES = 256 * 1024; // 256KB\n\nfunction validateResultSize(result: unknown): boolean {\n // Fast path: null and non-string primitives are always small\n if (result === null || typeof result === 'number' || typeof result === 'boolean') return true;\n\n try {\n const json = JSON.stringify(result);\n // json.length is always <= Buffer.byteLength (UTF-8 chars are 1-4 bytes)\n // So if json string length exceeds limit, byte length definitely does too\n if (json.length > MAX_RESULT_SIZE_BYTES) return false;\n return Buffer.byteLength(json, 'utf8') <= MAX_RESULT_SIZE_BYTES;\n } catch {\n // Circular reference or other serialization error\n return false;\n }\n}\n\nfunction enrichTaskWithResult<ID>(task: CronTask<ID>, result: unknown): CronTask<ID> {\n if (result === undefined) return task;\n if (!validateResultSize(result)) return task; // caller logs warning\n task.execution_result = result; // mutate in place — tasks are already extracted copies\n return task;\n}\n\nfunction enrichTaskWithError<ID>(task: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>): CronTask<ID> {\n if (!error && !meta) return task;\n\n const errorFields: Record<string, unknown> = {};\n if (error instanceof Error) {\n errorFields.last_error = error.message;\n errorFields.last_error_stack = error.stack;\n } else if (typeof error === 'string') {\n errorFields.last_error = error;\n }\n\n // Mutate in place — tasks are already extracted copies\n task.execution_stats = {\n ...(task.execution_stats || {}),\n ...errorFields,\n ...(meta || {})\n };\n return task;\n}\n\nexport class Actions<ID = any> implements ExecutorActions<ID> {\n private readonly taskRunnerId: string;\n private readonly taskContexts = new Map<string, TaskContext<ID>>();\n /** RFC-002: Flow projections accumulated from startFlow calls */\n private readonly _flowProjections: EntityTaskProjection[] = [];\n\n /** Logger for multi-task executors — carries runtime-only context (RFC-005) */\n readonly log: Logger;\n\n constructor(taskRunnerId: string) {\n this.taskRunnerId = taskRunnerId;\n // Root actions logger has no task-specific context — only ALS runtime context applies\n this.log = logger.child({});\n }\n\n /**\n * Fork execution context for a specific task (for single-task executors)\n */\n forkForTask(task: CronTask<ID>): ExecutorActions<ID> {\n const taskId = tId(task);\n const parentLogContext = task.metadata?.log_context;\n\n // Initialize context for this task\n const context: TaskContext<ID> = {task, actions: []};\n this.taskContexts.set(taskId, context);\n\n // Create child logger scoped to this task's log_context (RFC-005)\n const taskLog = logger.child(parentLogContext || {});\n\n // Return a scoped actions object that tracks everything in this context\n return {\n log: taskLog,\n\n fail: (t: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>) => {\n context.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task: t,\n error,\n meta\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${tId(t)} (${t.type})`);\n },\n\n success: (t: CronTask<ID>, result?: unknown) => {\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task: t,\n result\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${tId(t)} (${t.type})`);\n },\n\n addTasks: (tasks: CronTask<ID>[]) => {\n // Merge parent log_context onto child tasks (RFC-005: parent keys as defaults, child wins)\n const mergedTasks = parentLogContext\n ? tasks.map(t => ({\n ...t,\n metadata: {\n ...(t.metadata || {}),\n log_context: {...parentLogContext, ...(t.metadata?.log_context || {})}\n }\n }))\n : tasks;\n\n context.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: mergedTasks\n });\n logger.info(`[${this.taskRunnerId}] Task ${taskId} adding ${tasks.length} new tasks`);\n },\n\n startFlow: (input: StartFlowInput): string => {\n return this._startFlowImpl(input, parentLogContext);\n }\n };\n }\n\n // For multi-task executors - they use the root Actions directly (no forking)\n fail(task: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context!.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task,\n error,\n meta\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${taskId} (${task.type})`);\n }\n\n success(task: CronTask<ID>, result?: unknown): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task,\n result\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${taskId} (${task.type})`);\n }\n\n // TODO(P1): Add configurable max child tasks per execution (e.g., 1000).\n // A buggy executor can call addTasks() with unbounded entries, all in memory.\n // Each child can spawn more children — unbounded amplification risk.\n addTasks(tasks: CronTask<ID>[]): void {\n // For multi-task mode, store in a batch-specific context\n logger.info(`[${this.taskRunnerId}] Adding ${tasks.length} new tasks`);\n\n const batchKey = `__batch_${this.taskRunnerId}__`;\n let batchContext = this.taskContexts.get(batchKey);\n if (!batchContext) {\n batchContext = {task: null, actions: []};\n this.taskContexts.set(batchKey, batchContext);\n }\n batchContext.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: tasks\n });\n }\n\n addIgnoredTask(task: CronTask<ID>): void {\n const taskId = tId(task);\n this.taskContexts.set(taskId, {task, actions: []});\n logger.warn(`[${this.taskRunnerId}] Task ignored: ${taskId} (${task.type})`);\n }\n\n /**\n * RFC-002: Start a fan-out/fan-in flow from the root Actions context (multi-task executors).\n */\n startFlow(input: StartFlowInput): string {\n return this._startFlowImpl(input);\n }\n\n /**\n * RFC-002: Internal implementation for startFlow.\n * Used by both root Actions and forked per-task actions.\n */\n private _startFlowImpl(input: StartFlowInput, parentLogContext?: Record<string, string>): string {\n const {steps, config} = input;\n\n if (steps.length === 0) {\n throw new Error('[TQ/RFC-002] startFlow requires at least 1 step');\n }\n\n const flowId = randomUUID();\n const now = new Date();\n const failurePolicy = config.failure_policy || 'continue';\n\n const stepTasks: CronTask<ID>[] = steps.map((step, index) => {\n const flowMeta: FlowMeta = {\n flow_id: flowId,\n step_index: index,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n ...(config.entity ? {entity: config.entity} : {}),\n };\n\n const metadata: Record<string, unknown> = {\n flow_meta: flowMeta as unknown as Record<string, unknown>,\n };\n\n // Inherit parent log_context onto step tasks (RFC-005)\n if (parentLogContext) {\n (metadata as any).log_context = {...parentLogContext};\n }\n\n return {\n type: step.type,\n queue_id: step.queue_id as QueueName,\n payload: step.payload,\n execute_at: now,\n status: 'scheduled' as const,\n created_at: now,\n updated_at: now,\n force_store: true,\n metadata,\n ...(step.entity ? {entity: step.entity} : {}),\n } as CronTask<ID>;\n });\n\n // Create timeout sentinel if configured\n if (config.timeout_ms && config.timeout_ms > 0) {\n const timeoutFlowMeta: FlowMeta = {\n flow_id: flowId,\n step_index: -1,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n is_timeout: true,\n ...(config.entity ? {entity: config.entity} : {}),\n };\n\n stepTasks.push({\n type: '_flow.timeout',\n queue_id: config.join.queue_id as QueueName,\n payload: {flow_id: flowId, is_timeout: true},\n execute_at: new Date(now.getTime() + config.timeout_ms),\n status: 'scheduled' as const,\n created_at: now,\n updated_at: now,\n force_store: true,\n metadata: {\n flow_meta: timeoutFlowMeta as unknown as Record<string, unknown>,\n ...(parentLogContext ? {log_context: {...parentLogContext}} : {}),\n },\n } as unknown as CronTask<ID>);\n }\n\n // Add step tasks via the existing addTasks mechanism\n this.addTasks(stepTasks);\n\n // RFC-002 + RFC-003: If entity present, emit a 'processing' projection with flow_id as task_id\n if (config.entity) {\n this._flowProjections.push({\n task_id: flowId,\n entity_id: config.entity.id,\n entity_type: config.entity.type,\n task_type: config.join.type,\n queue_id: config.join.queue_id,\n status: 'processing',\n created_at: now,\n updated_at: now,\n });\n }\n\n logger.info(`[${this.taskRunnerId}] Started flow ${flowId} with ${steps.length} steps, join: ${config.join.type}`);\n return flowId;\n }\n\n /**\n * Check the result status for a specific task\n * Returns 'success', 'fail', or 'pending' (no action recorded yet)\n */\n getTaskResultStatus(taskId: string): 'success' | 'fail' | 'pending' {\n const context = this.taskContexts.get(taskId);\n if (!context) return 'pending';\n\n for (const action of context.actions) {\n if (action.type === 'success') return 'success';\n if (action.type === 'fail') return 'fail';\n }\n return 'pending';\n }\n\n /**\n * Extract actions for a single task (used by async tasks)\n */\n extractTaskActions(taskId: string): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: [],\n flowProjections: []\n };\n\n const context = this.taskContexts.get(taskId);\n if (!context) return results;\n\n if (context.actions.length === 0 && context.task) {\n // No actions = ignored task\n results.ignoredTasks.push(context.task);\n } else {\n // Process all actions\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n if (action.result !== undefined && !validateResultSize(action.result)) {\n logger.warn(`[${this.taskRunnerId}] Result for task ${tId(action.task)} exceeds size limit, dropping result`);\n }\n results.successTasks.push(enrichTaskWithResult(action.task, action.result));\n // If marking a different task, remove its context\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(enrichTaskWithError(action.task, action.error, action.meta));\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n\n this.taskContexts.delete(taskId);\n return results;\n }\n\n /**\n * Extract sync results including batch context (for sync processing)\n */\n extractSyncResults(excludeTaskIds: string[]): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: [],\n flowProjections: [...this._flowProjections]\n };\n\n const excludeSet = new Set(excludeTaskIds);\n const batchKey = `__batch_${this.taskRunnerId}__`;\n\n // Process all task contexts except excluded ones\n for (const [taskId, context] of this.taskContexts) {\n if (excludeSet.has(taskId)) continue;\n\n if (taskId === batchKey) {\n // Batch context - only has addTasks\n for (const action of context.actions) {\n if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n } else {\n // Regular task context\n if (context.actions.length === 0 && context.task) {\n results.ignoredTasks.push(context.task);\n } else {\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n if (action.result !== undefined && !validateResultSize(action.result)) {\n logger.warn(`[${this.taskRunnerId}] Result for task ${tId(action.task)} exceeds size limit, dropping result`);\n }\n results.successTasks.push(enrichTaskWithResult(action.task, action.result));\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(enrichTaskWithError(action.task, action.error, action.meta));\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n }\n }\n\n // Clear processed contexts\n for (const [taskId] of this.taskContexts) {\n if (!excludeSet.has(taskId)) {\n this.taskContexts.delete(taskId);\n }\n }\n\n // Clear flow projections after extraction\n this._flowProjections.length = 0;\n\n return results;\n }\n\n /**\n * Get all results (mainly for backward compatibility)\n */\n getResults(): ActionResults<ID> {\n return this.extractSyncResults([]);\n }\n\n /**\n * Get the result for a specific task (before extraction).\n * Used by TaskRunner to pass results to lifecycle events.\n */\n getTaskResult(taskId: string): unknown | undefined {\n const context = this.taskContexts.get(taskId);\n if (!context) return undefined;\n\n for (const action of context.actions) {\n if (action.type === 'success' && action.result !== undefined) {\n return action.result;\n }\n }\n return undefined;\n }\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Actions.mjs","sources":["../../src/core/Actions.ts"],"sourcesContent":["import {ExecutorActions} from \"./base/interfaces\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport {tId} from \"../utils/task-id-gen.js\";\nimport {CronTask} from \"../adapters\";\nimport type {StartFlowInput, FlowMeta} from \"./flow/types.js\";\nimport type {EntityTaskProjection} from \"./entity/IEntityProjectionProvider.js\";\nimport type {IFlowLifecycleProvider} from \"./lifecycle.js\";\nimport type {QueueName} from \"@supergrowthai/mq\";\nimport {randomUUID} from \"crypto\";\n\nconst logger = new Logger('Actions', LogLevel.INFO);\n\ninterface ActionEntry<ID = any> {\n type: 'success' | 'fail' | 'addTasks';\n timestamp: number;\n task?: CronTask<ID>; // The task passed to success/fail\n newTasks?: CronTask<ID>[]; // Tasks to add\n result?: unknown; // Result from success(task, result)\n error?: Error | string; // Error from fail(task, error)\n meta?: Record<string, unknown>; // Meta from fail(task, error, meta)\n}\n\ninterface TaskContext<ID = any> {\n task: CronTask<ID> | null; // The task being executed (null for batch contexts)\n actions: ActionEntry<ID>[];\n}\n\nexport interface ActionResults<ID = any> {\n failedTasks: CronTask<ID>[];\n successTasks: CronTask<ID>[];\n newTasks: CronTask<ID>[];\n ignoredTasks: CronTask<ID>[];\n /** RFC-002: Entity projections from startFlow calls (processing status, task_id = flow_id) */\n flowProjections: EntityTaskProjection[];\n}\n\nconst MAX_RESULT_SIZE_BYTES = 256 * 1024; // 256KB\n\nfunction validateResultSize(result: unknown): boolean {\n // Fast path: null and non-string primitives are always small\n if (result === null || typeof result === 'number' || typeof result === 'boolean') return true;\n\n try {\n const json = JSON.stringify(result);\n // json.length is always <= Buffer.byteLength (UTF-8 chars are 1-4 bytes)\n // So if json string length exceeds limit, byte length definitely does too\n if (json.length > MAX_RESULT_SIZE_BYTES) return false;\n return Buffer.byteLength(json, 'utf8') <= MAX_RESULT_SIZE_BYTES;\n } catch {\n // Circular reference or other serialization error\n return false;\n }\n}\n\nfunction enrichTaskWithResult<ID>(task: CronTask<ID>, result: unknown): CronTask<ID> {\n if (result === undefined) return task;\n if (!validateResultSize(result)) return task; // caller logs warning\n task.execution_result = result; // mutate in place — tasks are already extracted copies\n return task;\n}\n\nfunction enrichTaskWithError<ID>(task: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>): CronTask<ID> {\n if (!error && !meta) return task;\n\n const errorFields: Record<string, unknown> = {};\n if (error instanceof Error) {\n errorFields.last_error = error.message;\n errorFields.last_error_stack = error.stack;\n } else if (typeof error === 'string') {\n errorFields.last_error = error;\n }\n\n // Mutate in place — tasks are already extracted copies\n task.execution_stats = {\n ...(task.execution_stats || {}),\n ...errorFields,\n ...(meta || {})\n };\n return task;\n}\n\nexport class Actions<ID = any> implements ExecutorActions<ID> {\n private readonly taskRunnerId: string;\n private readonly taskContexts = new Map<string, TaskContext<ID>>();\n /** RFC-002: Flow projections accumulated from startFlow calls */\n private readonly _flowProjections: EntityTaskProjection[] = [];\n\n /** Logger for multi-task executors — carries runtime-only context (RFC-005) */\n readonly log: Logger;\n\n private readonly flowLifecycleProvider?: IFlowLifecycleProvider;\n /** Process identity (hostname-pid-timestamp) for lifecycle events */\n private readonly workerId: string;\n\n constructor(taskRunnerId: string, flowLifecycleProvider?: IFlowLifecycleProvider, workerId: string = '') {\n this.taskRunnerId = taskRunnerId;\n this.flowLifecycleProvider = flowLifecycleProvider;\n this.workerId = workerId;\n // Root actions logger has no task-specific context — only ALS runtime context applies\n this.log = logger.child({});\n }\n\n /**\n * Fork execution context for a specific task (for single-task executors)\n */\n forkForTask(task: CronTask<ID>): ExecutorActions<ID> {\n const taskId = tId(task);\n const parentLogContext = task.metadata?.log_context;\n\n // Initialize context for this task\n const context: TaskContext<ID> = {task, actions: []};\n this.taskContexts.set(taskId, context);\n\n // Create child logger scoped to this task's log_context (RFC-005)\n const taskLog = logger.child(parentLogContext || {});\n\n // Return a scoped actions object that tracks everything in this context\n return {\n log: taskLog,\n\n fail: (t: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>) => {\n context.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task: t,\n error,\n meta\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${tId(t)} (${t.type})`);\n },\n\n success: (t: CronTask<ID>, result?: unknown) => {\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task: t,\n result\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${tId(t)} (${t.type})`);\n },\n\n addTasks: (tasks: CronTask<ID>[]) => {\n // Merge parent log_context onto child tasks (RFC-005: parent keys as defaults, child wins)\n const mergedTasks = parentLogContext\n ? tasks.map(t => ({\n ...t,\n metadata: {\n ...(t.metadata || {}),\n log_context: {...parentLogContext, ...(t.metadata?.log_context || {})}\n }\n }))\n : tasks;\n\n context.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: mergedTasks\n });\n logger.info(`[${this.taskRunnerId}] Task ${taskId} adding ${tasks.length} new tasks`);\n },\n\n startFlow: (input: StartFlowInput): string => {\n return this._startFlowImpl(input, parentLogContext);\n }\n };\n }\n\n // For multi-task executors - they use the root Actions directly (no forking)\n fail(task: CronTask<ID>, error?: Error | string, meta?: Record<string, unknown>): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context!.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task,\n error,\n meta\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${taskId} (${task.type})`);\n }\n\n success(task: CronTask<ID>, result?: unknown): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task,\n result\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${taskId} (${task.type})`);\n }\n\n // TODO(P1): Add configurable max child tasks per execution (e.g., 1000).\n // A buggy executor can call addTasks() with unbounded entries, all in memory.\n // Each child can spawn more children — unbounded amplification risk.\n addTasks(tasks: CronTask<ID>[]): void {\n // For multi-task mode, store in a batch-specific context\n logger.info(`[${this.taskRunnerId}] Adding ${tasks.length} new tasks`);\n\n const batchKey = `__batch_${this.taskRunnerId}__`;\n let batchContext = this.taskContexts.get(batchKey);\n if (!batchContext) {\n batchContext = {task: null, actions: []};\n this.taskContexts.set(batchKey, batchContext);\n }\n batchContext.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: tasks\n });\n }\n\n addIgnoredTask(task: CronTask<ID>): void {\n const taskId = tId(task);\n this.taskContexts.set(taskId, {task, actions: []});\n logger.warn(`[${this.taskRunnerId}] Task ignored: ${taskId} (${task.type})`);\n }\n\n /**\n * RFC-002: Start a fan-out/fan-in flow from the root Actions context (multi-task executors).\n */\n startFlow(input: StartFlowInput): string {\n return this._startFlowImpl(input);\n }\n\n /**\n * RFC-002: Internal implementation for startFlow.\n * Used by both root Actions and forked per-task actions.\n */\n private _startFlowImpl(input: StartFlowInput, parentLogContext?: Record<string, string>): string {\n const {steps, config} = input;\n\n if (steps.length === 0) {\n throw new Error('[TQ/RFC-002] startFlow requires at least 1 step');\n }\n\n const flowId = randomUUID();\n const now = new Date();\n const failurePolicy = config.failure_policy || 'continue';\n\n const stepTasks: CronTask<ID>[] = steps.map((step, index) => {\n const flowMeta: FlowMeta = {\n flow_id: flowId,\n step_index: index,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n ...(config.entity ? {entity: config.entity} : {}),\n };\n\n const metadata: Record<string, unknown> = {\n flow_meta: flowMeta as unknown as Record<string, unknown>,\n };\n\n // Inherit parent log_context onto step tasks (RFC-005)\n if (parentLogContext) {\n (metadata as any).log_context = {...parentLogContext};\n }\n\n return {\n type: step.type,\n queue_id: step.queue_id as QueueName,\n payload: step.payload,\n execute_at: now,\n status: 'scheduled' as const,\n created_at: now,\n updated_at: now,\n force_store: true,\n metadata,\n ...(step.entity ? {entity: step.entity} : {}),\n } as CronTask<ID>;\n });\n\n // Create timeout sentinel if configured\n if (config.timeout_ms && config.timeout_ms > 0) {\n const timeoutFlowMeta: FlowMeta = {\n flow_id: flowId,\n step_index: -1,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n is_timeout: true,\n ...(config.entity ? {entity: config.entity} : {}),\n };\n\n stepTasks.push({\n type: '_flow.timeout',\n queue_id: config.join.queue_id as QueueName,\n payload: {flow_id: flowId, is_timeout: true},\n execute_at: new Date(now.getTime() + config.timeout_ms),\n status: 'scheduled' as const,\n created_at: now,\n updated_at: now,\n force_store: true,\n metadata: {\n flow_meta: timeoutFlowMeta as unknown as Record<string, unknown>,\n ...(parentLogContext ? {log_context: {...parentLogContext}} : {}),\n },\n } as unknown as CronTask<ID>);\n }\n\n // Add step tasks via the existing addTasks mechanism\n this.addTasks(stepTasks);\n\n // RFC-002 + RFC-003: If entity present, emit a 'processing' projection with flow_id as task_id\n if (config.entity) {\n this._flowProjections.push({\n task_id: flowId,\n entity_id: config.entity.id,\n entity_type: config.entity.type,\n task_type: config.join.type,\n queue_id: config.join.queue_id,\n status: 'processing',\n created_at: now,\n updated_at: now,\n });\n }\n\n logger.info(`[${this.taskRunnerId}] Started flow ${flowId} with ${steps.length} steps, join: ${config.join.type}`);\n\n // Emit onFlowStarted lifecycle event\n if (this.flowLifecycleProvider?.onFlowStarted) {\n try {\n const result = this.flowLifecycleProvider.onFlowStarted({\n flow_id: flowId,\n total_steps: steps.length,\n join: config.join,\n failure_policy: failurePolicy,\n entity: config.entity,\n worker_id: this.workerId,\n consumer_id: this.taskRunnerId,\n started_at: now,\n step_types: steps.map(s => s.type),\n });\n if (result instanceof Promise) {\n result.catch(err => logger.error(`[TQ] Flow lifecycle onFlowStarted error: ${err}`));\n }\n } catch (err) {\n logger.error(`[TQ] Flow lifecycle onFlowStarted error: ${err}`);\n }\n }\n\n return flowId;\n }\n\n /**\n * Check the result status for a specific task\n * Returns 'success', 'fail', or 'pending' (no action recorded yet)\n */\n getTaskResultStatus(taskId: string): 'success' | 'fail' | 'pending' {\n const context = this.taskContexts.get(taskId);\n if (!context) return 'pending';\n\n for (const action of context.actions) {\n if (action.type === 'success') return 'success';\n if (action.type === 'fail') return 'fail';\n }\n return 'pending';\n }\n\n /**\n * Extract actions for a single task (used by async tasks)\n */\n extractTaskActions(taskId: string): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: [],\n flowProjections: []\n };\n\n const context = this.taskContexts.get(taskId);\n if (!context) return results;\n\n if (context.actions.length === 0 && context.task) {\n // No actions = ignored task\n results.ignoredTasks.push(context.task);\n } else {\n // Process all actions\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n if (action.result !== undefined && !validateResultSize(action.result)) {\n logger.warn(`[${this.taskRunnerId}] Result for task ${tId(action.task)} exceeds size limit, dropping result`);\n }\n results.successTasks.push(enrichTaskWithResult(action.task, action.result));\n // If marking a different task, remove its context\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(enrichTaskWithError(action.task, action.error, action.meta));\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n\n this.taskContexts.delete(taskId);\n return results;\n }\n\n /**\n * Extract sync results including batch context (for sync processing)\n */\n extractSyncResults(excludeTaskIds: string[]): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: [],\n flowProjections: [...this._flowProjections]\n };\n\n const excludeSet = new Set(excludeTaskIds);\n const batchKey = `__batch_${this.taskRunnerId}__`;\n\n // Process all task contexts except excluded ones\n for (const [taskId, context] of this.taskContexts) {\n if (excludeSet.has(taskId)) continue;\n\n if (taskId === batchKey) {\n // Batch context - only has addTasks\n for (const action of context.actions) {\n if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n } else {\n // Regular task context\n if (context.actions.length === 0 && context.task) {\n results.ignoredTasks.push(context.task);\n } else {\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n if (action.result !== undefined && !validateResultSize(action.result)) {\n logger.warn(`[${this.taskRunnerId}] Result for task ${tId(action.task)} exceeds size limit, dropping result`);\n }\n results.successTasks.push(enrichTaskWithResult(action.task, action.result));\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(enrichTaskWithError(action.task, action.error, action.meta));\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n }\n }\n\n // Clear processed contexts\n for (const [taskId] of this.taskContexts) {\n if (!excludeSet.has(taskId)) {\n this.taskContexts.delete(taskId);\n }\n }\n\n // Clear flow projections after extraction\n this._flowProjections.length = 0;\n\n return results;\n }\n\n /**\n * Get all results (mainly for backward compatibility)\n */\n getResults(): ActionResults<ID> {\n return this.extractSyncResults([]);\n }\n\n /**\n * Get the result for a specific task (before extraction).\n * Used by TaskRunner to pass results to lifecycle events.\n */\n getTaskResult(taskId: string): unknown | undefined {\n const context = this.taskContexts.get(taskId);\n if (!context) return undefined;\n\n for (const action of context.actions) {\n if (action.type === 'success' && action.result !== undefined) {\n return action.result;\n }\n }\n return undefined;\n }\n}"],"names":[],"mappings":"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"}
@@ -2,6 +2,6 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  require("../../client-BxG7LzLv.cjs");
4
4
  require("../../utils/task-id-gen.cjs");
5
- const core_async_AsyncActions = require("../../AsyncActions-BOO1ikWz.cjs");
5
+ const core_async_AsyncActions = require("../../AsyncActions-BsxMX_Ib.cjs");
6
6
  exports.AsyncActions = core_async_AsyncActions.AsyncActions;
7
7
  //# sourceMappingURL=AsyncActions.cjs.map
@@ -1,6 +1,6 @@
1
1
  import "../../client-dvHNt8qU.js";
2
2
  import "../../utils/task-id-gen.mjs";
3
- import { A } from "../../AsyncActions-CZYO8ShR.js";
3
+ import { A } from "../../AsyncActions-B8ImDgTo.js";
4
4
  export {
5
5
  A as AsyncActions
6
6
  };