/** * FeatureExecutor - Executes feature steps and manages rollbacks * * Handles the actual execution of feature steps, including: * - Processing each step type (action, database, notification, etc.) * - Managing rollback on failure * - Tracking feature state and completed steps * - Handling signals and checkpoints */ import ProductBuilder from '../products/services/products.service'; import { IProductFeature } from '../types'; import { IFeatureServiceConfig, IFeatureExecutionResult, IExecuteFeatureOptions } from './types'; export declare class UnresolvedInputReferenceError extends Error { readonly reference: string; readonly required: boolean; readonly code = "UNRESOLVED_INPUT_REFERENCE"; constructor(reference: string, required: boolean); } /** * FeatureExecutor handles the execution of feature steps */ export declare class FeatureExecutor { private config; private _processorService; private productBuilder; private processorApiService; private featureApiService; private _graphService; private _databaseService; private _brokersService; private _storageService; private _vectorService; private _sessionsService; private _quotaService; private _fallbackService; private state; private feature; private productId; /** Session supplied to the feature; inherited by every nested operation. */ private readonly inheritedSession?; /** Pending signals waiting to be resolved */ private pendingSignals; /** Signal polling interval (ms) */ private signalPollInterval; /** Signal polling timer */ private signalPollTimer; /** Session log fields for logging */ private sessionLogFields; /** LogService instance for logging operations */ private logService; /** Base log fields inherited by all step logs */ private baseLogs; private _privateKey; /** When true, product was already loaded by caller (e.g. FeatureService); skip duplicate init in execute(). */ private readonly preInitializedProduct; /** Set when a graph step runs; we disconnect once at end of execute() instead of per-step. */ private graphConnectionUsed; /** Pre-fetched bootstrap data per step tag (feature batch prefetch). */ private stepBootstrapCache; private functionInvocations; /** Step telemetry is accumulated and persisted with the terminal feature record in one round trip. */ private pendingProcessorResults; constructor(config: IFeatureServiceConfig & { access_key: string; }, feature: IProductFeature, options: IExecuteFeatureOptions, private_key: string, sessionLogFields?: { session_user_id?: string; session_id?: string; session_tag?: string; }, preInitializedBuilder?: ProductBuilder); /** Debug-only structured execution trace. Payloads are recursively redacted. */ private trace; /** Brokers expose the same session as separate tag/token fields. */ private inheritedBrokerSession; /** * Get auth payload for API calls */ private getAuthPayload; /** Product private key for processor result encryption; must always match backend decryption key. No fallback to workspace key. */ private getProcessorResultEncryptionKey; /** Lazy-initialized processor (shares productBuilder to avoid duplicate product init per step). */ private getProcessorService; /** Lazy-initialized graph service. */ private getGraphService; /** Lazy-initialized database service. */ private getDatabaseService; /** Lazy-initialized broker service. Used so ctx.events.produce follows the standard Events publish path. */ private getBrokersService; /** Lazy-initialized storage service. Used for storage steps (upload/download/delete) instead of processor. */ private getStorageService; /** Lazy-initialized vector service. Used for vector steps (query/upsert/delete/execute action). */ private getVectorService; /** Lazy-initialized session service for ctx.sessions lifecycle steps. */ private getSessionsService; /** Lazy-initialized quota service. */ private getQuotaService; /** Lazy-initialized fallback service. */ private getFallbackService; /** * Persist feature execution result to backend */ private persistExecutionResult; /** * Step processor results must always use component: 'feature_step'. * step_type is the step kind: action, notification, storage, produce, database_action, graph, vector, quota, fallback, child_workflow, sleep, wait_for_signal, checkpoint, feature. */ private getStepTypeForResult; /** * Persist individual step execution to backend (input/output per step in processor result). * Processor results for steps always have component: 'feature_step' and step_type set to the step kind. */ private persistStepResult; /** * Initialize logging service and base log fields */ private initializeLogging; /** * Log a step execution event */ private logStepEvent; /** * Execute the feature */ execute(): Promise>; private executeInContext; /** * Execute a single step */ private executeStep; private executeStepInContext; /** * Execute an action step */ private executeActionStep; /** * Execute a database step: use query/insert/update/delete/upsert for DB operations, execute() for named actions. */ private executeDatabaseStep; /** * Execute a notification step */ private executeNotificationStep; /** * Execute a storage step using StorageService (upload, download, or delete by input shape). */ private executeStorageStep; /** * Execute a produce step (message broker produce to topic). * Uses BrokersService so ctx.events.produce has the same behavior as ductape.events.produce (pool, tracking, cache). */ private executeProduceStep; /** * Execute a graph step * Supports: execute (custom action), createNode, updateNode, deleteNode, * createRelationship, deleteRelationship, query */ private executeGraphStep; /** * Execute a vector step (query, upsert, deleteVectors, or custom action via execute). */ private executeVectorStep; /** Execute a product session lifecycle step. */ private executeSessionStep; /** Execute a portable application function through a local handler or signed HTTP transport. */ private executeFunctionStep; /** * Execute a quota step */ private executeQuotaStep; /** * Execute a fallback step */ private executeFallbackStep; /** * Execute a child feature step */ private executeChildWorkflowStep; /** * Execute a sleep step */ private executeSleepStep; /** * Execute a wait for signal step * Polls the backend API for signal delivery until received or timeout */ private executeWaitForSignalStep; /** * Start polling the backend for signal delivery */ private startSignalPolling; /** * Stop the signal polling timer */ private stopSignalPolling; /** * Deliver a signal to this feature (called by external signal handler) */ deliverSignal(signalName: string, payload: unknown): boolean; /** * Execute a checkpoint step */ private executeCheckpointStep; /** * Execute rollback for completed steps */ private executeRollback; /** * Execute a rollback handler */ private executeRollbackHandler; /** * Resolve input by replacing data references and all $ operators (per docs/operators). * Top-level keys are resolved in parallel for better performance. */ private resolveInput; /** * Resolve a single value: refs ($Input{}, $Step{}, etc.) and operators ($Add, $Concat, etc.) */ private resolveValue; /** Strip surrounding quotes from a string literal (e.g. '"foo"' -> 'foo') */ private unquote; /** * Resolve string value: data references and all $ operators from docs/operators * Supports: $Input{}, $Step{}, $Sequence{}, $State{}, $StepOutput{}, $Now, * $Add, $Subtract, $Concat, $Substring, $Trim, $Split, $Pick, $Join, * $Uppercase, $Lowercase, $Dateformat, $Replace, $Filter, $Find, $Size, $Length */ private resolveStringValue; /** * Get nested value from object using dot notation */ private getNestedValue; /** * Get ordered steps respecting dependencies */ private getOrderedSteps; /** * Pre-fetch all action/notification/storage bootstrap data for the given steps in one backend call. * Results are cached in stepBootstrapCache by step tag so step executors can skip their own bootstrap calls. */ private prefetchStepBootstrap; /** * Find a step by tag */ private findStep; /** * Evaluate a condition string. * Supports: (cond1) || (cond2), (cond1) && (cond2), and in each part: ==, ===, !=, !==, >, <, >=, <=. * Left/right can be $Step{}, $Input{}, etc. (resolved before comparison). */ private evaluateCondition; /** Comparison operators in parse order (multi-char before single-char). */ private static readonly CONDITION_OP_REGEX; /** * Coerce a trimmed condition literal (after resolve) to a comparable value: boolean, number, or string. */ private conditionLiteral; private evaluateConditionPart; private compareLooseEqual; /** * Compare for ordering (>, <, >=, <=). Uses numeric comparison when both sides are numeric, else string. */ private compareOrdered; /** * Returns true if the value tree contains any $ operator reference ($Input{}, $Step{}, $Sequence{}, etc.). * Used to distinguish output templates (to resolve) from type-only schemas (to ignore for persistence). */ private hasOperatorRefsInOutput; /** * Returns true if the object looks like a feature output type schema (e.g. { orderId: { type: 'string' }, ... }) * rather than a template with $ operators or literal values. */ private isOutputTypeSchema; /** * Determine feature output for persistence and return value. * - If feature.output has $ operator refs: resolve template to actual values (matches definition). * - If feature.output is a type-only schema: use execution result (last step or step_outputs) so stored result matches runtime output, not the schema. * - If no feature.output: use last step result or {}. */ private determineWorkflowOutput; /** * Build output with same keys as feature definition, values from step_outputs (last step first, then others). * Ensures persisted result shape matches the feature definition output shape. */ private buildOutputFromStepsToMatchDefinition; /** * Sleep for specified duration */ private sleep; /** * Resume a feature from a previous state * * @param options - Resume options including completed steps, state, and starting point */ resume(options: IResumeOptions): Promise>; } /** * Options for resuming a feature */ export interface IResumeOptions { /** Previously completed steps */ completed_steps?: string[]; /** Previous feature state */ state?: Record; /** Resume from specific checkpoint */ from_checkpoint?: string; /** Resume from specific step */ from_step?: string; /** Steps to skip */ skip_steps?: string[]; /** Override step outputs */ step_outputs?: Record; } export default FeatureExecutor;