import * as workflow from '@temporalio/workflow'; import { EntitiesState, EntityAction, EntityStrategy } from '../store'; import { DetailedDiff } from 'deep-object-diff'; import { Schema } from 'normalizr'; import { TemporalOptions, Workflow } from './Workflow'; import { ActionOptions } from '../decorators'; import { EnhancedEntity, SchemaManager } from '../store/SchemaManager'; import { StateManager } from '../store/StateManager'; import { Duration } from '@temporalio/common'; import { LRUCacheWithDelete } from 'mnemonist'; /** * Configuration structure defining how entity paths and associated workflows are managed. * * This type outlines the available options for configuring entity management within workflows. It includes * essential details such as entity identifiers, workflow behavior, and conditions for workflow execution. * * ## Properties * - **`entityName`** (optional): Represents the entity's name used for identification purposes. * - **`path`** (optional): Describes the path in the state where the entity data is stored. * - **`workflowType`** (optional): Specifies the workflow type that corresponds to this entity. * - **`idAttribute`** (optional): Identifies the attribute(s) that uniquely determine the entity; can be a string or an array for composite keys. * - **`isMany`** (optional): Boolean indicating whether the path refers to multiple entities. * - **`includeParentId`** (optional): If true, includes parent identifiers in the workflow IDs to ensure they are unique. * - **`autoStart`** (optional): Determines if the workflow should initiate automatically once configured conditions are met. * - **`cancellationType`** (optional): Determines the child workflow's cancellation policy using values from `workflow.ChildWorkflowCancellationType`. * - **`parentClosePolicy`** (optional): Defines the effect of a parent workflow's closure on the child workflow, using `workflow.ParentClosePolicy`. * - **`workflowIdConflictPolicy`** (optional): Dictates how to handle workflow ID conflicts, utilizing values from `workflow.WorkflowIdConflictPolicy`. * - **`workflowIdReusePolicy`** (optional): Indicates policy for workflow ID reuse, using values from `workflow.WorkflowIdReusePolicy`. * - **`workflowTaskTimeout`** (optional): Duration after which the workflow should time out if it hasn't completed. * - **`startDelay`** (optional): Duration to wait before starting the workflow. * - **`retry`** (optional): Configuration object defining retry parameters for the workflow: * - `initialInterval`: Initial retry interval in milliseconds. * - `maximumInterval`: Maximum interval for retries. * - `backoffCoefficient`: Coefficient for retry backoff calculations. * - `maximumAttempts`: Maximum retry attempts allowed. * - **`startToCloseTimeout`** (optional): Duration after which the workflow should time out if it hasn't completed. * - **`condition`** (optional): Function determining whether the workflow should start, given the entity and related data. * - **`getSubscriptions`** (optional): Function returning an array of subscription configurations based on an update subscription object. * - **`processData`** (optional): Function for processing entity data before starting the workflow, providing ready-to-use data for workflow context. * * ## Usage Example * ```typescript * const configPath: ManagedPath = { * entityName: "User", * path: "users", * idAttribute: "userId", * autoStart: true, * processData: (entity, data) => ({ ...entity, modified: true }), * }; * ``` * * ## Notes * - The `ManagedPath` type captures a comprehensive set of configuration options for entity management, supporting both single and composite entities. * - Proper configuration is crucial for robust, automated workflow operations, ensuring effective entity lifecycle handling. */ export type ManagedPath = { entityName?: string; path?: string; workflowType?: string; idAttribute?: string | string[]; isMany?: boolean; includeParentId?: boolean; autoStart?: boolean; cancellationType?: workflow.ChildWorkflowCancellationType; parentClosePolicy?: workflow.ParentClosePolicy; workflowIdConflictPolicy?: workflow.WorkflowIdConflictPolicy; workflowIdReusePolicy?: workflow.WorkflowIdReusePolicy; workflowTaskTimeout?: Duration; startDelay?: Duration; retry?: { initialInterval?: number; maximumInterval?: number; backoffCoefficient?: number; maximumAttempts?: number; }; startToCloseTimeout?: string; condition?: (entity: Record, data: StatefulWorkflow['data']) => boolean; strategy?: '$set' | '$merge'; subscriptions?: { update?: { enabled?: boolean; sync?: boolean; strategy?: '$set' | '$merge'; selector?: string; }; delete?: { enabled?: boolean; sync?: boolean; strategy?: '$set' | '$merge'; selector?: string; }; }; processData?: (entity: Record, data: StatefulWorkflow['data']) => Record; }; /** * Defines the configuration structure for managing entity paths and associated workflows. * * This type specifies the layout and options available for configuring how entities are managed * within workflows, capturing details such as entity identifiers, workflow types, and start conditions. * @see ManagedPath */ export type ManagedPaths = { [path: string]: ManagedPath; }; /** * Subscription configuration for workflow state changes. * * Defines how a workflow subscribes to state changes from another workflow, * specifying what signals to receive and under what conditions. * * ## Usage Example * ```typescript * const workflowSubscription: Subscription = { * workflowId: "order-processing-workflow", * signalName: "orderUpdated", * selector: "*", * entityName: "Order", * condition: (state) => state.status === "Pending", * }; * ``` * * ## Notes * - Subscriptions facilitate complex, event-driven interactions within workflow systems, leveraging properties * such as `signalName` and `selector` to fine-tune reactions. * - Optional fields provide flexibility for hierarchical and condition-based designs, enhancing adaptability in various workflows. * - Proper subscription management ensures responsive and efficient workflows, enabling precise event handling and state transitions. * * @property {string} workflowId - The ID of the workflow being subscribed to. * @property {string} subscriptionId - Unique identifier for this subscription. * @property {'update' | 'delete'} signalName - The type of signal to subscribe to. * @property {string} selector - Path selector pattern to filter state changes. * @property {string} [parent] - Optional parent entity identifier. * @property {string} [child] - Optional child entity identifier. * @property {string[]} [ancestorWorkflowIds] - IDs of ancestor workflows to prevent circular updates. * @property {(state: any) => boolean} [condition] - Optional function to further filter changes. * @property {boolean} [sync] - Whether updates should be processed synchronously. * @property {'$set' | '$merge'} [strategy] - Strategy for applying updates to state. */ type Subscription = { workflowId: string; subscriptionId: string; signalName: 'update' | 'delete'; selector: string; parent: string; child: string; ancestorWorkflowIds: string[]; condition?: (state: any) => boolean; sync?: boolean; strategy?: '$set' | '$merge'; }; /** * Parameters for initializing a stateful workflow, providing configuration and data context. * * This type captures the essential details and optional settings needed to instantiate and * manage a stateful workflow, including entity, API, and subscription configurations. * * ## Properties * - `id`: A string serving as the unique identifier for the workflow instance. * - `entityName`: The name of the entity associated with this workflow, used for context and identification. * - `data` (optional): A generic parameter `D` representing the data specific to the entity within the workflow. * - `state` (optional): The state of entities at the moment of workflow initialization, used for context and processing. * - `status`: The current status of the workflow, indicating its operational state. * - `apiUrl` (optional): The URL for API interactions related to the workflow, facilitating external communication if needed. * - `apiToken` (optional): A token for authenticating API requests, providing secure access to external systems. * - `subscriptions` (optional): An array of `Subscription` objects, defining event-driven connections for the workflow. * - `autoStart` (optional): A boolean indicating if the workflow should start automatically upon initialization. * - `ancestorWorkflowIds` (optional): An array of strings denoting the IDs of ancestor workflows, useful for lineage tracking. * * ## Usage Example * ```typescript * const workflowParams: StatefulWorkflowParams = { * id: "workflow-123", * entityName: "Order", * status: "active", * autoStart: true, * subscriptions: [orderSubscription], * }; * ``` */ export type StatefulWorkflowParams = { id: string; entityName: string; data?: D; state?: EntitiesState; status: string; apiUrl?: string; apiToken?: string; subscriptions?: Subscription[]; autoStart?: boolean; ancestorWorkflowIds?: string[]; startDelay?: Duration; }; /** * Options for configuring a stateful workflow, focusing on schema and execution settings. * * This type provides configuration options for setting up workflows, emphasizing schema integration * and auto-start capabilities for seamless workflow operations. * * ## Properties * - `schema` (optional): A `schema.Entity` object representing the data schema for the workflow, * crucial for data validation and normalization. * - `schemaName` (optional): The name of the schema, assisting in referencing and managing various schemas. * - `autoStart` (optional): A boolean indicating whether the workflow should initiate automatically. * - `apiUrl` (optional): The API endpoint used for workflow-related communications. * - `workflowType` (optional): The type of the workflow, identifying the workflow's structure and purpose. * * ## Usage Example * ```typescript * const workflowOptions: StatefulWorkflowOptions = { * schemaName: "OrderSchema", * autoStart: true, * workflowType: "order-processing", * apiUrl: "https://api.example.com", * }; * ``` */ export type StatefulWorkflowOptions = { schema?: EnhancedEntity; schemaName?: string; saveStateToMemo?: boolean; apiUrl?: string; workflowType?: string; children?: { autoStart?: boolean; update?: { enabled?: boolean; sync?: boolean; strategy?: '$set' | '$merge'; }; delete?: { enabled?: boolean; sync?: boolean; strategy?: '$set' | '$merge'; }; }; } & TemporalOptions; /** * Represents a pending change awaiting application within a workflow, detailing the modifications and approach. * * This type specifies pending updates or deletions along with the strategy to apply changes, * assisting workflows in maintaining accurate state adjustments. * * ## Properties * - `updates` (optional): A record of fields and values marked for updating, keyed by entity attributes. * - `deletions` (optional): A record of fields designated for deletion, identifying which data should be removed. * - `entityName`: The name of the entity to which changes are applied, offering context for the modifications. * - `strategy` (optional): Specifies the change application strategy, either '$set' or '$merge', * determining overwrite or merge behavior. * - `changeOrigin` (optional): A string identifying the source of change, useful for auditing and reverse-tracing. * - `sync` (optional): A boolean indicating if the change should be synchronized immediately, emphasizing real-time application. * - `action` (optional): An `EntityAction` instance representing any associated actions that arise from the change. * * ## Usage Example * ```typescript * const pendingChange: PendingChange = { * updates: { status: "shipped" }, * entityName: "Order", * strategy: '$merge', * changeOrigin: "user-update", * }; * ``` */ export type PendingChange = { updates?: Record; deletions?: Record; entityName: string; strategy?: EntityStrategy; changeOrigin?: string; sync?: boolean; action?: EntityAction; }; /** * Metadata related to an action method within a stateful workflow, including options for execution. * * This interface defines metadata for action methods, encapsulating execution options * accessible via the workflow framework. * * ## Properties * - `method`: A key representing the action method within the `StatefulWorkflow`, indicating what function is being described. * - `options` (optional): An `ActionOptions` object specifying configuration details or execution modifiers for the method. * * ## Usage Example * ```typescript * const actionMetadata: ActionMetadata = { * method: "updateOrderStatus", * options: { retries: 3 }, * }; * ``` */ export interface ActionMetadata { method: keyof StatefulWorkflow; options?: ActionOptions; } /** * Entry detailing a connection to an ancestor workflow, maintaining identification and relationship data. * * This type manages the association with ancestor workflows, storing identification details * and the external workflow handle for effective cross-workflow communication. * * ## Properties * - `entityId`: The ID of the related entity, serving as a primary identifier for association. * - `entityName`: The name of the entity, facilitating context and clarity within multiple workflows. * - `isParent`: A boolean indicating if the ancestor workflow is directly a parent, clarifying lineage roles. * - `handle`: An `ExternalWorkflowHandle` object, affording access to the ancestor workflow's external interface. * * ## Usage Example * ```typescript * const ancestorEntry: AncestorHandleEntry = { * entityId: "order-789", * entityName: "Order", * isParent: true, * handle: orderWorkflowHandle, * }; * ``` */ export type AncestorHandleEntry = { entityId: string; entityName: string; isParent: boolean; handle: workflow.ExternalWorkflowHandle; }; export type StateEventListener = { newState: EntitiesState; previousState: EntitiesState; changeType: 'added' | 'updated' | 'deleted'; changes: DetailedDiff; origins: string[]; }; export type LoadDataResult = { data?: Partial; updates?: EntitiesState; strategy?: EntityStrategy; }; export declare abstract class StatefulWorkflow

extends Workflow { /** * Internal state binding flags */ private _actionsBound; protected _eventsBound: boolean; private readonly selectorPatternCache; /** * Converts a selector string into a regular expression pattern for matching paths. * * @private * @param {string} selector - The selector string to convert. * @returns {RegExp} A regular expression that matches paths according to the selector pattern. */ private getSelectorPattern; /** * Internal reference object to hold the values for memo properties. */ private _memoProperties; /** * Internal flag used to determine if there is currently an @Action() running (executeUpdate). */ protected actionRunning: boolean; /** * Determines whether the workflow is a long running continueAsNew type workflow or a short lived one. * When true, the workflow will use the continueAsNew mechanism to restart itself with the same parameters * when it reaches certain limits (history size, iterations, etc.). */ protected isContinueable: boolean; /** * Flag indicating whether the workflow should continue as new in the next iteration. * * When set to `true`, the workflow will be recreated with a new history after the current * iteration completes. This is useful for: * * - Preventing workflow histories from growing too large * - Managing long-running workflows efficiently * - Implementing workflow versioning and updates * - Clearing accumulated state when needed * * The workflow will automatically continue as new when: * - The history size approaches Temporal's limit (default ~40MB) * - The maximum number of iterations is reached * - This flag is manually set to true * * @example * ```typescript * class MyWorkflow extends Workflow { * async execute() { * // After processing a large batch of data * if (this.processedItemCount > 1000) { * this.continueAsNew = true; * return this.result; * } * } * } * ``` * * @default false * @see {@link https://docs.temporal.io/workflows#continue-as-new Temporal Continue-as-New Documentation} */ protected continueAsNew: boolean; /** * Internal reference to the StateManager instance for this workflow. */ protected stateManager: StateManager; /** * Internal reference to the StateManager instance for this workflow. */ protected schemaManager: SchemaManager; /** * Current workflow iteration count. */ protected iteration: number; /** * Internal reference to the Schema instance for this workflow. */ protected schema: Schema; /** * The `conditionTimeout` property is utilized in the `StatefulWorkflow` class to manage timeout settings * for workflow conditions. This optional parameter allows the developer to define a specific duration * for which the workflow should wait for certain conditions to be satisfied before proceeding. * * Example: * ```typescript * protected conditionTimeout: Duration = Duration.fromMinutes(1); * ``` * * ### Usage: * - **Context**: Used within the `executeWorkflow` method to prevent indefinite waits in case certain * conditions are not met in a timely manner. * * - **Definition**: * ```typescript * protected conditionTimeout?: Duration | undefined = undefined; * ``` * * - **Integration**: Applied in scenarios where `await workflow.condition()` is called, controlling how long * the workflow can pause before proceeding. * * ### Configuration: * - **Default Value**: `undefined`, implying no timeout unless explicitly set. * - **Custom Values**: Use the `Duration` type to set a desired wait duration: * ```typescript * this.conditionTimeout = Duration.fromSeconds(30); * ``` * * **Considerations**: * - **Performance**: Setting appropriate timeouts ensures the workflow remains responsive and avoids long pauses. * - **Scalability**: Timeouts should align with the overall system architecture, especially for systems with * nested or multiple workflows. * - **Failure Handling**: Implement retries or alternative paths to handle situations where conditions * remain unmet beyond the timeout. */ protected conditionTimeout: Duration | undefined; /** * Optional method that can be implemented by subclasses to define custom continue-as-new behavior. * If implemented, this method will be called when the workflow reaches its maximum iterations. * @returns A promise that resolves when the continue-as-new process is complete. */ protected onContinue?(): Promise>; /** * Optional method that can be implemented by extending classes to load data from external sources. * This method is called automatically when pendingUpdate is true. * * @returns A promise that resolves to an object containing data and/or updates to be applied to the state */ protected loadData?(): Promise>; /** * Determines whether data should be loaded in the workflow based on internal state. * * This method checks if the `loadData` function exists and if there is a pending update. * It is essential to ensure data is only loaded when necessary, avoiding unnecessary calls * or updates. * * @returns {boolean} * - `true` if the workflow has a `loadData` method and a pending update, meaning data * needs to be refreshed. * - `false` otherwise, indicating that no data needs to be loaded. */ protected shouldLoadData(): boolean; /** * Sets the API token for the workflow. * This token is used for authenticating API requests made by the workflow. * * @param apiToken - The API token to set. */ protected apiToken?: string; /** * Signal to set or update the API token for the workflow. * * This signal allows external systems or child workflows to update the API token used by * this workflow. Once the token is set, it marks the workflow's state as needing an update * (`pendingUpdate`), and forwards the token update signal to child workflows. * * @param {string} apiToken - The new API token to be used by the workflow. If the new token * differs from the current token, the workflow will trigger a pending update and propagate * the token to its child workflows. * @returns {void} */ setApiToken(apiToken: string): void; protected id: string; protected entityName: string; /** * Getter and setter for the workflow's internal state. * * The `state` property represents the current state of the workflow's entities, * managed by the `schemaManager`. This property can be used to retrieve or update * the entire state of the workflow. * * When the state is updated, it is directly set in the schema manager, ensuring * that all entity-related operations reflect the latest state. * * @returns {EntitiesState} * - The current state of all entities in the workflow. */ getState(): EntitiesState; get state(): EntitiesState; setState(state: EntitiesState): Promise; /** * Retrieves the workflow's entity-specific data from the schema manager. * * This getter dynamically fetches the data associated with the specific entity (`entityName`) * and `id` of the workflow from the `SchemaManager`. The retrieved data is wrapped in a * proxy that allows for real-time updates. Any mutations to the data trigger state changes * and are automatically dispatched via the `SchemaManager`. * * The getter handles the complexity of normalized data, ensuring that the denormalization * process respects the relationships defined in the schema. * * @returns {P['data']} * - The current data for the entity, denormalized and proxied for real-time updates. */ protected get data(): P['data']; /** * Getter and setter for the workflow's entity-specific data, managed by the SchemaManager. * * **Getter**: This retrieves the workflow's data associated with the entity (`entityName`) * and `id`. The data is automatically **denormalized** using the entity schema, so it * includes any relational data. The getter returns a **proxied** version of the data, * allowing the workflow to react to any changes made to the data. * * The Proxy intercepts interactions with the data. If you modify the data, the proxy * triggers an update to the workflow's state, and the SchemaManager normalizes the new data. * * **Setter**: This updates the workflow's data by dispatching a state update via the * SchemaManager. When new data is set, it is **normalized** according to the entity schema, * then saved to the workflow's internal state. * * The setter works asynchronously, as the update is dispatched through the workflow's * event-driven state management, ensuring that changes are synchronized with child * workflows and other parts of the system. * * ### Example Usage: * Suppose you have a `BookWorkflow` managing a `Book` entity with multiple `Chapters`: * * ```typescript * @Workflow({ * schema: schemas.Book, * schemaName: 'Book', * }) * export class BookWorkflow extends StatefulWorkflow< * StatefulWorkflowParams, * StatefulWorkflowOptions * > { * @Property({ path: 'chapters' }) * protected chapters!: ChapterModel[]; * * @Action() * protected async addChapter(action: AddChapterAction): Promise { * // Access current data through the getter * if (!this.data) { * throw new Error('No book data available yet'); * } * // Add a new chapter to the book * const newChapter = action.payload.chapter; * this.chapters.push(newChapter); * return this.data; // Return the updated book data * } * } * ``` * * In the above example: * - The `data` getter is used to fetch the current state of the `Book` entity, which includes its `Chapters`. * - The Proxy automatically tracks changes to the `chapters` array. When a new chapter is added, the workflow updates its state and triggers the necessary state changes. * * **Real-Time Updates with Proxy**: * The data is wrapped in a Proxy, so any modification to the `Book` or its `Chapters` will automatically trigger an update. For example, if you modify a specific chapter: * * ```typescript * // Update the title of a specific chapter * this.chapters[0].title = 'New Chapter Title'; * ``` * * This change will be automatically detected, and the Proxy will trigger an update, saving the new title and ensuring that the state remains synchronized. * * **SchemaManager's Role**: * The `SchemaManager` normalizes the data when setting it and denormalizes it when retrieving it. The Proxy ensures real-time synchronization between the denormalized data and the internal state. * * @returns {P['data']} * - The denormalized data for the entity, proxied for real-time updates. */ protected set data(data: any); /** * Boolean flag indicating a pending update, setting this to true will result in loadData() being called if it is defined. */ protected pendingUpdate: boolean; /** * An array of pending changes that are in the StateManager queue waiting to be processed. */ get pendingChanges(): import("typescript-algos").Queue; /** * An array of workflows that have open subscriptions to this workflows state. */ protected subscriptions: Subscription[]; /** * A map to keep track of workflows that have open subscriptions to this workflows state. */ protected subscriptionHandles: LRUCacheWithDelete; /** * Defines paths within the workflow's state that are automatically managed, often * involving child workflows or nested entities. This allows workflows to handle * complex, hierarchical data structures with ease. * * **managedPaths** is a mapping of entity properties to configurations that control * how these properties (and their related entities) are managed by the parent workflow. * Each path in `managedPaths` defines how the workflow should interact with a nested * entity or set of entities, including: * * - Automatically starting child workflows for these entities. * - Handling the relationships between parent and child workflows. * - Synchronizing state between the parent workflow and child workflows. * * ### Key Configuration Options: * * - **`entityName`**: The name of the entity managed at this path. This corresponds to the entity name * as defined in the schema. * * - **`path`**: The key in the parent entity where the nested entity (or entities) are located. * For example, in a `Book` entity, the path could be `'chapters'`, representing a list of `Chapter` entities. * * - **`workflowType`**: The type of the child workflow to start for the nested entities. This could be * a `ChapterWorkflow` for chapters in a book or a `TaskWorkflow` for tasks in a project. * * - **`idAttribute`**: The unique identifier or combination of attributes that uniquely identify the * nested entities. This can be a single field (e.g., `'id'`) or an array of fields for composite keys * (e.g., `['projectId', 'taskId']`). * * - **`isMany`**: Indicates whether the path contains multiple entities (e.g., an array of chapters * in a book). If `true`, the workflow will manage multiple entities at this path. * * - **`includeParentId`**: If `true`, the parent entity's ID is included in the child workflow's ID. * This is useful when child workflows need to track their parent entity (e.g., a chapter must know * which book it belongs to). * * - **`autoStart`**: Automatically starts child workflows for the entities at this path. * When `true`, each entity in the path will have its corresponding child workflow started automatically. * * - **`cancellationType`**: Defines the cancellation policy for the child workflows. For example, this * can ensure that child workflows are canceled if the parent workflow is canceled or errors out. * * - **`parentClosePolicy`**: Determines how the child workflows should behave when the parent workflow * closes. For instance, child workflows can be canceled when the parent is done, or they can continue * running independently. * * - **`condition`**: A function that specifies whether a child workflow should be started for a particular * entity based on its data. This provides fine-grained control over when child workflows are started. * * - **`processData`**: A function that processes the entity's data before starting the child workflow. * This is useful when additional data needs to be passed to the child workflow, such as including * the parent entity's information. * * ### Example Usage: * Suppose you have a `ProjectWorkflow` that manages a `Project` entity with nested `Task` entities: * * ```typescript * @Workflow({ * schema: schemas.Project, * schemaName: 'Project', * autoStart: true * }) * export class ProjectWorkflow extends StatefulWorkflow< * StatefulWorkflowParams, * StatefulWorkflowOptions * > { * protected managedPaths: ManagedPaths = { * tasks: { * idAttribute: 'id', * entityName: 'Task', * workflowType: 'TaskWorkflow', * autoStart: true, * includeParentId: true, * processData: (task, project) => { * task.projectId = project.id; // Attach the project ID to the task * return task; * } * } * }; * } * ``` * * In the example above: * * - **`tasks`**: The `tasks` path defines how the `Task` entities within a `Project` are managed. * Each task is treated as a separate entity, and a `TaskWorkflow` is automatically started for each. * * - **`idAttribute: 'id'`**: The unique identifier for each task is the `id` field. * * - **`autoStart: true`**: Child workflows for tasks are automatically started when the project * workflow is executed. * * - **`includeParentId: true`**: The `TaskWorkflow` will receive the `projectId` to keep track of which * project each task belongs to. * * - **`processData`**: Before starting the `TaskWorkflow`, the `processData` function attaches the * project ID to each task. * * ### Custom Child Workflow Conditions: * In some cases, you may only want to start child workflows based on certain conditions. This can be * controlled using the `condition` option. * * For example, you might only want to start a `TaskWorkflow` if the task is marked as "important": * * ```typescript * protected managedPaths: ManagedPaths = { * tasks: { * idAttribute: 'id', * entityName: 'Task', * workflowType: 'TaskWorkflow', * autoStart: true, * condition: (task, project) => task.isImportant * } * }; * ``` * * In this case, only tasks with `isImportant: true` will have their corresponding `TaskWorkflow` started. * * ### Child Workflow Cancellation and Close Policies: * The `cancellationType` and `parentClosePolicy` settings define how child workflows are managed when the * parent workflow is canceled or closed. For example: * * ```typescript * protected managedPaths: ManagedPaths = { * tasks: { * idAttribute: 'id', * entityName: 'Task', * workflowType: 'TaskWorkflow', * autoStart: true, * cancellationType: workflow.ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED, * parentClosePolicy: workflow.ParentClosePolicy.PARENT_CLOSE_POLICY_REQUEST_CANCEL * } * }; * ``` * * In this configuration: * * - **`cancellationType: WAIT_CANCELLATION_COMPLETED`**: The parent workflow waits for the child workflows * to complete before canceling them. * * - **`parentClosePolicy: REQUEST_CANCEL`**: When the parent workflow finishes, it requests the cancellation * of its child workflows. * * ### ManagedPaths Summary: * - `managedPaths` is essential for handling nested entities in workflows. * - It automates the creation and management of child workflows. * - It provides flexibility in defining how and when child workflows are started, as well as how their * lifecycle is controlled. * * @type {ManagedPaths} */ protected managedPaths: ManagedPaths; /** * The apiUrl for this workflows entity. */ protected apiUrl?: string; /** * An array to keep track of ancestor workflow's ids. */ protected ancestorWorkflowIds: string[]; /** * The initial parameters as provided to this workflow when started. */ protected params: P; /** * The initial options as provided to this workflow when started. */ protected options: O; /** * A map to keep track of handles to ancestor workflows. */ protected ancestorHandles: LRUCacheWithDelete; /** * Constructs an instance of the class with the specified parameters and options. * * @constructor * @param {P} params - The parameters for initializing the instance. It may include: * - `ancestorWorkflowIds`: Optional list of ancestor workflow identifiers. * - `id`: Optional identifier for the instance. * - `entityName`: Optional name of the entity associated with this instance. * - `subscriptions`: Optional array of subscriptions to be registered. * - `state`: Optional initial state for the entity. * - `data`: Optional data to update the entity. * - `status`: Optional status of the workflow; defaults to 'running'. * - `apiUrl`: Optional URL for API interactions. * - `apiToken`: Optional token for API authentication. * @param {O} options - Configuration options which might include: * - `schemaName`: Optional schema name for the entity. * - `schema`: Schema object for the entity. * - `apiUrl`: Default API URL if not provided in params. * * Initializes: * - The `stateManager` by retrieving it from `StateManager` using the workflow's info. * - The `ancestorHandles` map if `ancestorWorkflowIds` are present. * - The schema using either the parameters or options. * - Subscriptions using the provided parameter subscriptions. * * Sets up state management by listening for state changes and initializes any pending operations. */ constructor(params: P, options: O); protected onSetup(): Promise; /** * Executes the workflow in a controlled and synchronized manner, ensuring thread safety * by using a mutex on the 'executeWorkflow' function. * * @protected * @async * @returns {Promise} Resolves with the result of the workflow execution, or with any * data processed if terminal state is reached without error. Rejects if an error state is * encountered. * * Actions: * - Configures managed paths based on the schema, if available. * - Continuously executes the workflow logic while the current iteration is within the * allowed maximum iterations (`maxIterations`). * - Waits for certain conditions to be met using the workflow's condition, pausing and * resuming execution based on the workflow status. * - Loads data, executes the primary task, and checks for terminal states, resolving * or rejecting the promise based on the success or failure of the workflow. * - Manages iterations, respecting maximum iterations and handling scenarios where * the new state of execution may need to continue based on workflow constraints. * - Handles any execution errors appropriately by delegating to a specified error handler. * * This function logs relevant debug information, including entity details and current * execution states, making it suitable for tracing workflow progress through complex stages. */ protected executeWorkflow(): Promise; /** * Updates the state of an entity within the system with the given data and updates. This function * ensures that changes are dispatched appropriately, either as part of a specific `action` or * through a direct update of normalized entities. * * @param {Object} parameters An object containing all parameters required to perform the update. * @param {Record} [parameters.data] * Optional. A record containing the raw data to be normalized and used for the update. The data structure * should match the expected schema for the entity being updated. * @param {any} [parameters.updates] * Optional. Pre-normalized update data for directly updating the entity's state. If not provided, * and if `data` is specified, `data` will be normalized to create updates. * @param {string} parameters.entityName * The name of the entity for which the state update is being applied. This is used to fetch and use the * correct schema for normalization if `data` is provided. * @param {any} [parameters.action] * Optional. An action object that encapsulates specific state changes or commands to be dispatched directly. * If provided, the function prioritizes dispatching this action. * @param {string} [parameters.strategy='$merge'] * Optional. The strategy used when merging updates into the current state. Defaults to '$merge' which * merges new data into existing state. * @param {any} [parameters.changeOrigin] * Optional. Indicates the origin of the changes, such as user input or automated system process. This * can be used for logging or conditional logic during dispatch. * @param {boolean} [parameters.sync=true] * Optional. A boolean flag indicating whether the state change should be synchronous. Defaults to `true`, * meaning operations are synchronous by default. * * @returns {void} * This method does not return a value but will log errors or trace information to facilitate debugging. * * @throws Will log an error if both `data` and `updates` are invalid or cannot be processed. * * @example * // Example usage: * update({ * data: { id: 1, name: 'John Doe' }, * entityName: 'User', * strategy: '$replace', * changeOrigin: 'client', * sync: false * }); * * @remark * Ensure that either `data` or `updates` are provided. If neither can be normalised or used, * the method logs an error indicating the failure if no action is supplied. */ update({ data, updates, entityName, action, strategy, changeOrigin, sync }: PendingChange & { data?: Record; }): void; /** * Deletes entries of a specified entity type from the state, based on given data or predefined deletions. * This function facilitates the removal of entities by dispatching the appropriate delete action after * optionally normalizing the input data. * * @param {Object} parameters An object containing all parameters required to perform the deletion. * @param {Record} [parameters.data] * Optional. A record containing the raw data that specifies the entities to be deleted. This data will * be normalized according to the entity's schema if provided. * @param {any} [parameters.deletions] * Optional. Pre-normalized deletion data that directly specifies which entities should be removed. * If not provided, and if `data` is specified, `data` will be normalized to infer deletions. * @param {any} [parameters.action] * Optional. An action object that encapsulates specific state changes or commands to be dispatched directly. * If provided, the function prioritizes dispatching this action. * @param {string} parameters.entityName * The name of the entity type from which the specified entries should be deleted. This is crucial for * ensuring that the correct schema is used for normalization if `data` is supplied. * @param {any} [parameters.changeOrigin] * Optional. An identifier for the origin of the delete request, such as user action or internal mechanic, * used for logging or conditional logic during dispatch. * @param {boolean} [parameters.sync=true] * Optional. A boolean indicating whether the deletion operation should be synchronous. Defaults to `true`, * which implies synchronous operations. * * @returns {void} * This method does not return a value but logs errors or trace information to help diagnose issues. * * @throws Will log an error if both `data` and `deletions` are invalid or cannot be processed. * * @example * // Example usage: * delete({ * data: { id: 2 }, * entityName: 'User', * changeOrigin: 'admin', * sync: false * }); * * @remark * Ensure that either `data` or `deletions` are provided. If neither can be normalised or used, * the method logs an error indicating the failure if no action is supplied. */ delete({ data, action, deletions, entityName, changeOrigin, sync }: PendingChange & { data?: Record; }): void; /** * Adds a subscription to the current instance, ensuring that it is unique. * * @signal * @public * @async * @param {Subscription} subscription - The subscription object that contains details * about the workflow and subscription IDs. It has the following properties: * - `workflowId`: The unique identifier of the workflow. * - `subscriptionId`: The unique identifier of the subscription within the workflow. * @returns {Promise} A promise that resolves when the subscription handling is complete. * * Operations: * - Logs a trace of the subscription process for debugging, indicating the class, entity, and ID. * - Checks if the subscription already exists by comparing both `workflowId` and `subscriptionId`. * - If the subscription is unique, it adds the subscription to the `subscriptions` list. * - Sets up a handle for interacting with the specified workflow via `subscriptionHandles`. */ subscribe(subscription: Subscription): Promise; /** * Removes a subscription from the current instance based on the given subscription details. * * @signal * @public * @async * @param {Subscription} subscription - The subscription object that contains details * about the workflow and subscription IDs. It has the following properties: * - `workflowId`: The unique identifier of the workflow. * - `subscriptionId`: The unique identifier of the subscription within the workflow. * @returns {Promise} A promise that resolves when the unsubscription process is complete. * * Operations: * - Logs a trace of the unsubscription process for debugging purposes, indicating the class, entity, and ID. * - Searches for the subscription in the `subscriptions` list using the `workflowId` and `subscriptionId`. * - If a matching subscription is found, it deletes the corresponding workflow handle from `subscriptionHandles`. * - Removes the identified subscription from the `subscriptions` list. */ unsubscribe(subscription: Subscription): Promise; /** * Processes the current state of the entity, ensuring all pending changes are applied * when no actions are currently running. * * @before 'execute' * @protected * @async * @returns {Promise} A promise that resolves once the state processing is complete and any pending changes are applied. * * Operations: * - Checks if an action is currently running (`actionRunning`). If so, logs an informational message * and waits for the action to complete using the workflow condition. * - Logs a debug message indicating the start of the state processing. * - If there are any pending changes, it triggers the `stateManager` to process these changes. */ protected processState(): Promise; /** * Handles changes in the entity's state by processing state differences and * triggering appropriate events based on the nature of these changes. * * @mutex 'processState' * @protected * @async * @param {Object} param0 - The object containing state change details, including: * - `newState`: The state of the entities after changes have been applied. * - `previousState`: The state of the entities before changes were applied. * - `differences`: An object detailing the differences between the new and previous states. * Includes `added`, `updated`, and `deleted` properties. * - `changeOrigins`: An array of strings indicating the origins of the changes. * @returns {Promise} A promise that resolves when all state change handling is complete. * * Operations: * - Logs a debug message indicating the transition and processing of state changes. * - Checks if there are any differences in the state (`added`, `updated`, `deleted`). * - Based on the differences: * - Emits a 'created' event if the entity was newly added. * - Emits an 'updated' event if the entity was modified. * - Emits a 'deleted' event if the entity was removed, potentially setting the status to 'cancelled' if the deletion event fails. * - Processes the states of child entities and related subscriptions if applicable, triggering further handling mechanisms. * - Sets the `pendingIteration` flag to true, signaling readiness for further processing. */ protected stateChanged({ newState, previousState, differences, changeOrigins }: { newState: EntitiesState; previousState: EntitiesState; differences: DetailedDiff; changeOrigins: string[]; }): Promise; /** * Updates the workflow's memo with the current state, ensuring that any changes are persisted. * * @protected * @async * @returns {Promise} A promise that resolves once the current state has been conditionally saved to memo. * * Operations: * - Logs information about the memo update process, including the current workflow ID. * - Retrieves the existing memo and flattens the current state and memo properties for comparison. * - Compares the existing memo state with the new state: * - Updates the `updatedMemo` object with changes detected between the current and new states. * - Marks the `hasChanges` flag if any changes exist. * - Deletes keys from `updatedMemo` if they exist in the current memo but not in the new state. * - If changes are detected (`hasChanges` is true), the method updates the workflow memo with: * - The new state details. * - The current iteration count and workflow status. * - A timestamp representing the last update. */ protected upsertToMemo(): Promise; /** * Handles the propagation of changes to subscribed workflows by processing updates and deletions * based on the current and previous states and their differences. * * @protected * @async * @param {EntitiesState} newState - The current state of the entities after changes have been applied. * @param {DetailedDiff} differences - An object detailing the changes between the new and previous states, * including `added`, `updated`, and `deleted` differences. * @param {EntitiesState} previousState - The state of the entities prior to changes being applied. * @param {string[]} changeOrigins - A list of change origin identifiers. * @returns {Promise} A promise that resolves when the subscription processing is complete. * * Operations: * - Logs a trace message to indicate the start of subscription processing. * - Iterates over the list of subscriptions, checking each for conditions to propagate changes: * - Extracts relevant changes for each subscription using selectors and conditions. * - If changes should be propagated: * - Retrieves the workflow handle associated with the subscription. * - Sends `update` signals to the workflow with details of the changes if any updates exist. * - Sends `delete` signals if there are deletions. * - Logs traces for each propagated signal to facilitate debugging. * - Catches and logs errors encountered during the signaling process to ensure robust error handling. */ protected processSubscriptions(newState: EntitiesState, differences: DetailedDiff, previousState: EntitiesState, changeOrigins: string[]): Promise; /** * Determines whether changes should be propagated to subscriptions based on selectors and conditions. * * @private * @param {EntitiesState} newState - The new state after changes. * @param {DetailedDiff} differences - The detailed differences between states. * @param {string} selector - The selector pattern to match against changes. * @param {Function} [condition] - Optional function to further filter changes. * @param {string[]} [changeOrigins] - Origins of the changes to prevent circular updates. * @param {string[]} [ancestorWorkflowIds=[]] - IDs of ancestor workflows to prevent circular dependencies. * @returns {boolean} True if changes should be propagated, false otherwise. */ private shouldPropagate; /** * Extracts changes that match a specific selector from the differences between states. * * @private * @param {DetailedDiff} differences - The detailed differences between states. * @param {string} selector - The selector pattern to match against changes. * @param {EntitiesState} newState - The new state after changes. * @param {EntitiesState} previousState - The previous state before changes. * @returns {{ updates: EntitiesState; deletions: EntitiesState }} Object containing filtered updates and deletions. */ private extractChangesForSelector; /** * Processes the child state to handle differences between the new and previous states. * * This method traces the processing of child states for a given entity by recursively * handling managed paths defined in the `managedPaths` object. It processes both array * and non-array entities, checking for deletions and triggering appropriate actions. * * ## Parameters * - `newState`: The new state of the entities to be processed. * - `differences`: A detailed representation of differences between states that guides processing. * - `previousState`: The previous state of the entities before the change. * - `changeOrigins`: An array of strings representing the origins of changes triggering the update. * * ## Return * - A `Promise` that resolves when all processing of child states is complete. * * ## Method Details * - Utilizes `limitRecursion` to work with a restricted view of entity states for comparison. - Iterates over `managedPaths` to process entities based on their paths configuration. * - Handles array and non-array entities through `processArrayItems` and `processItem` methods. * - Detects deleted items by checking their presence in differences and invokes `handleDeletion`. * * ## Usage Example * ```typescript * await processChildState(newEntityState, detailedDiff, oldEntityState, origins); * ``` * * ## Notes * - The processing handles complex nested entities and their lifecycle changes. * - Ensure `managedPaths` is configured correctly to enable precise state management. * * ## Logging * - Logs trace and debug messages for monitoring the processing flow. */ protected processChildState(newState: EntitiesState, differences: DetailedDiff, previousState: EntitiesState, changeOrigins: string[]): Promise; /** * Processes a single, non-array item within the entity state. * * This method is responsible for handling an individual item specified by the managed * path configuration, applying necessary processing based on the detected differences * between the new and previous states. * * ## Parameters * - `newState`: The current state of all entities, from which the item's new value is derived. * - `itemValue`: The item's current value extracted using the managed path. * - `config`: An object containing configuration details about the path under management. * - `differences`: Details of changes between the new and previous states to direct processing steps. * - `previousState`: The state of all entities prior to applying changes. * - `changeOrigins`: An array that specifies the origins related to the modifications in state. * - `path`: The managed path's string representation, indicating the item's location within the state. * * ## Return * - A `Promise` that resolves once the processing of the individual item is complete. * * ## Method Details * - Determines the composite identifier for the item using `getCompositeKey` if necessary. * - Delegates the processing to `processSingleItem`, ensuring that the item is handled * according to the differences and configuration. * * ## Usage Example * ```typescript * await processItem(currentEntityState, entityValue, pathConfig, stateDiff, oldEntityState, origins, pathStr); * ``` * * ## Notes * - Requires proper configuration of the `idAttribute` within `ManagedPath` to uniquely * identify items. * - Intended for internal usage in managing state changes specific to one item. */ private processItem; /** * Determines if a specific item has been deleted based on the differences between states. * * This method checks the `differences` object to see if an item, identified by the * `entityName` and `itemId`, is marked as deleted. It looks for the item's presence * in the deleted entities section of the detailed differences. * * ## Parameters * - `differences`: A `DetailedDiff` object containing changes between the new and previous entity states. * - `entityName`: The name of the entity type to which the item belongs, used to locate the item in the differences. * - `itemId`: The unique identifier of the item being checked for deletion. * * ## Return * - Returns a `boolean`: * - `true` if the item is detected as deleted. * - `false` if the item is not marked as deleted. * * ## Method Details * - Retrieves the deleted entities for the specified `entityName` from the differences object. * - Checks if the `itemId` exists among these deleted entities. * - Considers an item deleted if it exists but its corresponding value is `undefined` in the `deleted` records. * * ## Usage Example * ```typescript * const isDeleted = isItemDeleted(stateDiff, 'entityName', 'uniqueItemId'); * ``` * * ## Notes * - Relies on correctly structured `DetailedDiff` where deleted entity records are nested * under a `deleted` key with proper entity name subkeys. * - Designed for use in processing state changes that involve detecting and handling deletions. */ private isItemDeleted; /** * Handles the deletion of an item by canceling associated workflows. * * This method constructs a unique workflow identifier from the given configuration and * composite ID, using it to locate any active workflow handles. If a handle is found, * it proceeds to cancel the associated child workflow. * * ## Parameters * - `config`: The `ManagedPath` configuration object containing path and workflow-specific settings. * - `compositeId`: A string representing the unique composite identifier for the entity item. * * ## Return * - A `Promise` indicating the completion of the deletion handling process. * * ## Method Details * - Constructs the `workflowId` by potentially incorporating the parent ID based on the * `includeParentId` flag within `config`. * - Retrieves the workflow handle from the internal `handles` map using the constructed `workflowId`. * - If a valid handle exists, invokes `cancelChildWorkflow` to terminate the workflow associated * with the deleted item. * * ## Usage Example * ```typescript * await handleDeletion(pathConfig, 'entityCompositeId'); * ``` * * ## Notes * - Assumes the existence of a `handles` map that associates workflow IDs with their handles. * - The cancellation logic and additional side effects, if any, are encapsulated within `cancelChildWorkflow`. * - Designed to provide clean-up operations upon detecting entity state deletions. */ private handleDeletion; /** * Processes an array of items within the entity state. * * This method iterates over each item in the provided array, applying necessary processing * of individual elements based on differences and configuration specifications, supporting * effective state management of array entities. * * ## Parameters * - `newState`: The updated state containing the latest set of entity data. * - `items`: An array of items to be processed individually. * - `config`: Configuration details from the `ManagedPath` specifying how to manage array items. * - `differences`: The detailed differences object used to guide processing actions appropriate to state changes. * - `previousState`: The state of entities prior to applying the current updates. * - `changeOrigins`: A collection of strings identifying where changes in the state originated. * * ## Return * - A `Promise` indicating that the processing of all items in the array is complete. * * ## Method Details * - Logs the entry into the processing routine for monitoring and traceability. * - For each item, determines its unique identifier using either a composite key or a direct attribute value, * as denoted in `config.idAttribute`. * - Delegates the processing of each identified item to the `processSingleItem` method, handling the specific * transformation or validation based on detected differences and changes. * * ## Usage Example * ```typescript * await processArrayItems(updatedState, entityItems, pathConfig, stateDiffs, priorState, origins); * ``` * * ## Notes * - It is crucial that `ManagedPath` is set up correctly for accurate identifier extraction, especially when * dealing with composite keys. * - Effective for cases where entities and their updates are represented in array form. * - The process ensures individual scrutiny and management of each element in the array. */ protected processArrayItems(config: ManagedPath, newState: EntitiesState, previousState: EntitiesState, differences: DetailedDiff, changeOrigins: string[], items?: any[], previousItems?: any[]): Promise; /** * Processes a single entity item, managing workflows based on its state changes. * * This method oversees the handling of a specific item within the entity state, * determining if workflow actions are required due to state changes or workflow presence. * * @protected * @async * @param {ManagedPath} config - Configuration details specific to this entity's path, guiding processing actions. * @param {string} itemId - The identifier for the item being processed, which may be part of a composite key. * @param {EntitiesState} newState - The state object reflecting current entity data after applying updates. * @param {EntitiesState} previousState - The state of the entity before recent changes were applied. * @param {DetailedDiff} differences - Object encapsulating differences between the new and previous states to aid decision-making. * @param {string[]} changeOrigins - A list of identifiers representing the origin of changes to avoid recursive updates. * @param {any} newItem - The current state of the item being processed. * @param {any} previousItem - The previous state of the item being processed. * @returns {Promise} A promise indicating when the processing of the single item is complete. */ protected processSingleItem(config: ManagedPath, itemId: string, newState: EntitiesState, previousState: EntitiesState, differences: DetailedDiff, changeOrigins: string[], newItem: any, previousItem: any): Promise; /** * Configures the managed paths for entity processing based on a given parent schema. * * This function initializes the `managedPaths` with details extracted from a defined * parent schema, setting up configuration for handling nested entity paths and their * associated workflows. * * ## Parameters * - `parentSchema`: The schema object that includes a nested `schema` property specifying child schemas. * Each child schema must define `_idAttribute` and `_key` for configuration. * * ## Return * - This function does not return a value but populates the `managedPaths` property. * * ## Method Details * - Logs a debug message to record the initiation of managed path configuration, providing context on the entity. * - Validates the existence of a `schema` property within the `parentSchema`, throwing an error if absent. * - Iterates over the child schemas described within `parentSchema.schema`, processing each to populate `managedPaths`: * - Determines if the schema represents an array to set the `isMany` property. * - Configures individual path settings, including the path, identifier attribute, workflow type, auto-start settings, * and entity name, combining these with any pre-existing configurations from `managedPaths`. * * ## Usage Example * ```typescript * configureManagedPaths(entityParentSchema); * ``` * * ## Notes * - Assumes that each child schema provides essential attributes (`_idAttribute` and `_key`) for managing workflows. * - The method relies on the structure provided by `parentSchema` to accurately configure management paths * necessary for processing entity states. */ protected configureManagedPaths(parentSchema: Schema & { schema?: { [key: string]: Schema & [{ _idAttribute: string; _key: string; }]; }; }): void; /** * Initiates a child workflow based on the provided configuration and state data. * * This method handles the creation and initialization of child workflows according to the * specified managed path configuration. It processes entity data, constructs appropriate * workflow parameters, and manages the lifecycle of child workflows within the parent context. * * @param {ManagedPath} config - Configuration object that defines workflow behavior and entity relationships. * Contains settings such as workflow type, entity name, ID attributes, and execution policies. * @param {any} state - The current state of the entity that will be used to initialize the child workflow. * @param {any} newState - The complete state context in which the child workflow will operate. * @returns {Promise} A promise that resolves when the child workflow has been successfully started * or when the start operation has been appropriately handled (e.g., when autoStart is disabled). * * @throws Will propagate errors from workflow creation, though these are caught internally * and logged for diagnostic purposes. * * ## Key Features * - Supports conditional workflow initialization based on entity state * - Configurable retry policies for resilient workflow execution * - Flexible ID generation for workflow instances * - Customizable timeout and cancellation behaviors * - Automatic parent-child relationship management * * ## Configuration Options * - **workflowType**: Defines the type of workflow to be started * - **entityName**: Specifies the entity type being managed * - **idAttribute**: Identifies which property(s) to use as the entity's unique identifier * - **cancellationType**: Controls how child workflows respond to cancellation requests * - **parentClosePolicy**: Determines child workflow behavior when parent closes * - **retry**: Configures the retry strategy for workflow execution * * ## Usage Example * ```typescript * await startChildWorkflow(managedConfig, itemState, completeState); * ``` * * ## Notes * - Assumes the presence of entity and workflow management support within the system * - Handles asynchronous operations with comprehensive error handling for fault tolerance * - Provides detailed logging for workflow initialization and lifecycle events * - Respects autoStart and condition configurations to determine execution eligibility */ protected startChildWorkflow(config: ManagedPath, id: string, workflowId: string, newItem: any, newState: any): Promise; /** * Updates an existing child workflow with new state information. * * This method handles the propagation of state changes from the parent workflow to its child workflows. * It processes the differences between previous and new states, and signals the appropriate updates * to the child workflow based on configuration settings. * * @param {workflow.ChildWorkflowHandle} handle - The handle to the child workflow to update. * @param {any} previousItem - The previous state of the item associated with the child workflow. * @param {any} previousState - The previous overall state context. * @param {any} newItem - The updated state of the item associated with the child workflow. * @param {any} newState - The updated overall state context. * @param {DetailedDiff} differences - The detailed differences between previous and new states. * @param {ManagedPath} config - Configuration for the managed path that defines update behavior. * @returns {Promise} A promise that resolves when the update operation is complete. * * @throws Will propagate errors from workflow signaling operations, though these are caught * internally and logged for diagnostic purposes. * * ## Key Features * - Conditional updates based on configuration settings * - Support for different update strategies (merge vs. replace) * - Intelligent handling of entity relationships * - Detailed logging of update operations * * ## Update Process * 1. Validates update eligibility based on autoStart and condition settings * 2. Extracts entity ID and prepares update payload * 3. Processes data through optional transformation functions * 4. Signals the child workflow with the update * 5. Handles any errors that occur during the update process * * ## Configuration Options * - **subscriptions.update.strategy**: Determines how updates are applied ('$set' or '$merge') * - **subscriptions.update.sync**: Controls whether updates are processed synchronously * - **processData**: Optional function to transform data before sending to child workflow * * ## Notes * - Update operations respect the subscription configuration in the managed path * - Provides comprehensive error handling with detailed logging * - Supports custom data transformation through the processData function */ protected updateChildWorkflow(config: ManagedPath, handle: workflow.ChildWorkflowHandle, newItem: any, newState: any, previousState: any, differences: DetailedDiff): Promise; /** * Cancels a running child workflow. * * This method safely terminates a child workflow by removing its handle from internal tracking * and sending a cancellation signal. It includes error handling to ensure the parent workflow * continues execution even if cancellation encounters issues. * * @param {workflow.ChildWorkflowHandle} handle - The handle to the child workflow to be cancelled. * @returns {Promise} A promise that resolves when the cancellation operation is complete. * * @throws Will catch and log any errors that occur during the cancellation process without * propagating them to the caller. * * ## Key Features * - Safe removal of workflow handle from internal tracking * - Graceful error handling during cancellation * - Detailed logging of cancellation operations * * ## Cancellation Process * 1. Logs the cancellation attempt for traceability * 2. Removes the workflow handle from internal tracking to prevent restart attempts * 3. Obtains an external workflow handle for the target workflow * 4. Sends the cancellation signal to the workflow * 5. Catches and logs any errors that occur during the process * * ## Usage Example * ```typescript * await cancelChildWorkflow(activeHandle); * ``` * * ## Notes * - Ensures the workflow handle is valid before attempting cancellation * - Removes the handle from tracking before cancellation to prevent restart attempts * - Provides detailed error logging to aid in debugging cancellation issues * - Uses the external workflow handle mechanism for cancellation operations */ protected cancelChildWorkflow(handle: workflow.ChildWorkflowHandle): Promise; /** * Handles workflow continuation when maximum iterations are reached. * * This method manages the transition to a new workflow instance when the current instance * reaches its iteration limit. It ensures all handlers have completed their work before * initiating the continuation process, and supports both custom and default continuation methods. * * @returns {Promise} A promise that resolves when the continuation process is complete. * * @throws May throw errors if the continuation process fails, though these are typically * handled by the Temporal workflow engine. * * ## Key Features * - Supports custom continuation methods via _continueAsNewMethod or continueAsNewHandler * - Ensures all handlers have finished before continuation * - Preserves workflow state, status, and subscriptions during transition * - Maintains workflow metadata such as memo and search attributes * * ## Continuation Process * 1. Identifies the appropriate continuation method (custom or default) * 2. Waits for all workflow handlers to complete their execution * 3. If a custom continuation method exists, invokes it directly * 4. Otherwise, creates a continuation function with the current workflow configuration * 5. Executes the continuation with the current workflow state and parameters * * ## Usage Example * ```typescript * await handleMaxIterations(); * ``` * * ## Notes * - Uses workflow.condition to ensure all handlers have finished before continuation * - Preserves workflow context including state, status, and subscriptions * - Maintains workflow metadata such as memo and search attributes * - Uses type assertions to access internal properties due to TypeScript limitations */ protected handleMaxIterations(): Promise; /** * Loads data from an external source and enqueues it for state updates. * * This method invokes the workflow's loadData method (if defined) to fetch data from external * sources, then processes and normalizes that data before dispatching it to the state manager. * It supports both direct data objects and pre-normalized updates. * * @returns {Promise} A promise that resolves when the data loading and enqueueing process is complete. * * @throws May propagate errors from the loadData method if they occur during data fetching. * * ## Key Features * - Conditional execution based on the existence of a loadData method * - Support for both raw data objects and pre-normalized updates * - Configurable update strategy ('$merge' by default) * - Intelligent handling of empty or missing data * * ## Data Loading Process * 1. Checks if the workflow implements a loadData method * 2. Invokes the loadData method to fetch external data * 3. Extracts data, updates, and strategy from the result * 4. Normalizes raw data into entity updates if needed * 5. Dispatches the updates to the state manager with the specified strategy * * ## Expected loadData Return Format * ```typescript * { * data?: Record, // Raw data object to be normalized * updates?: EntitiesState, // Pre-normalized entity updates * strategy?: '$set' | '$merge' // Update strategy to apply * } * ``` * * ## Usage Example * ```typescript * await loadDataAndEnqueue(); * ``` * * ## Notes * - Skips state updates if both data and updates are empty or undefined * - Uses the entity's schema for data normalization * - Logs debugging information about the data loading process * - Uses type assertions to handle TypeScript limitations */ protected loadDataAndEnqueue(): Promise; /** * Binds class properties based on metadata decorators. * * This method configures property accessors (getters and setters) for class properties * that have been decorated with metadata. It supports memoization, path-based access, * and custom property behaviors defined through decorators. * * @returns {Promise} A promise that resolves when all properties have been bound. * * ## Key Features * - Metadata-driven property configuration * - Support for memoized properties * - Path-based property access using dot notation * - Configurable property behaviors (get/set/enumerable) * * ## Property Binding Process * 1. Invokes the parent class's bindProperties method * 2. Collects property metadata from class decorators * 3. Iterates through each property with metadata * 4. Configures getters and setters based on metadata options * 5. Handles special cases like memoization and path-based access * * ## Supported Metadata Options * - **memo**: Enables property memoization with an optional key * - **path**: Specifies a dot-notation path for accessing nested data * - **get/set**: Controls whether getters/setters are created * - **enumerable**: Controls property visibility during enumeration * * ## Usage Example * ```typescript * await bindProperties(); * ``` * * ## Notes * - Uses the dottie library for path-based property access * - Stores memoized values in the _memoProperties object * - Supports both direct property access and path-based access * - Designed to work with the Property decorator from the decorators module */ protected bindProperties(): Promise; /** * Binds action methods to workflow handlers based on metadata decorators. * * This method configures workflow action handlers for methods that have been decorated * with action metadata. It sets up the execution context, validation, and behavior * policies for each action method. * * @returns {Promise} A promise that resolves when all actions have been bound. * * ## Key Features * - Metadata-driven action configuration * - Automatic validation of action inputs * - Prevention of redundant action binding * - Configurable handler unfinished policies * * ## Action Binding Process * 1. Checks if actions have already been bound to prevent redundancy * 2. Collects action metadata from class decorators * 3. Retrieves associated validators for input validation * 4. Iterates through each action with metadata * 5. Configures workflow handlers with appropriate execution policies * 6. Marks actions as bound to prevent future rebinding * * ## Handler Configuration * - **method**: The class method to be executed when the action is triggered * - **validator**: Optional function to validate action inputs * - **unfinishedPolicy**: Policy for handling unfinished actions (defaults to ABANDON) * * ## Usage Example * ```typescript * await bindActions(); * ``` * * ## Notes * - Triggered automatically during workflow initialization via the @On('init') decorator * - Uses the ACTIONS_METADATA_KEY and VALIDATOR_METADATA_KEY for metadata access * - Sets the HandlerUnfinishedPolicy.ABANDON as the default unfinished policy * - Prevents multiple bindings of the same actions through the _actionsBound flag */ protected bindActions(): Promise; /** * Binds event handlers to workflow and state manager events based on metadata decorators. * * This method configures event listeners for methods that have been decorated with event * metadata. It sets up handlers for both workflow-level events and state manager events, * ensuring that decorated methods are called when the corresponding events are emitted. * * @returns {Promise} A promise that resolves when all event handlers have been bound. * * ## Key Features * - Metadata-driven event handler configuration * - Support for both workflow and state manager events * - Prevention of redundant event handler binding * - Asynchronous event handling with Promise resolution * * ## Event Binding Process * 1. Checks if event handlers have already been bound to prevent redundancy * 2. Collects event metadata from class decorators * 3. Iterates through each event handler with metadata * 4. Determines the appropriate event emitter (workflow or state manager) * 5. Registers event listeners with proper event names * 6. Marks event handlers as bound to prevent future rebinding * * ## Event Handler Configuration * - **event**: The event name to listen for (prefixed with 'state:' for state manager events) * - **method**: The class method to be executed when the event is triggered * * ## Usage Example * ```typescript * await bindEventHandlers(); * ``` * * ## Notes * - Events prefixed with 'state:' are bound to the state manager * - Other events are bound to the workflow instance itself * - Event handlers are executed asynchronously with Promise resolution * - Prevents multiple bindings of the same handlers through the _eventsBound flag */ protected bindEventHandlers(): Promise; /** * Executes an action method within the workflow with concurrency control. * * This method provides a controlled execution environment for workflow actions, * ensuring that actions don't overlap and that the workflow state is properly * managed before, during, and after action execution. * * @param {keyof StatefulWorkflow} methodName - The name of the method to execute. * @param {any} input - The input data to pass to the action method. * @returns {Promise} A promise that resolves with the result of the action method * or rejects with any error that occurred during execution. * * @throws Will propagate any errors thrown by the action method after logging them. * * ## Key Features * - Concurrency control to prevent overlapping action executions * - Comprehensive error handling and logging * - Automatic state management before and after execution * - Support for any action method defined on the workflow * * ## Execution Process * 1. Sets the actionRunning flag to prevent concurrent executions * 2. Attempts to execute the specified method with the provided input * 3. Logs any errors that occur during execution * 4. Sets the pendingUpdate flag to trigger state processing * 5. Resets the actionRunning flag when execution completes * * ## Usage Example * ```typescript * const result = await runAction('processItem', itemData); * ``` * * ## Notes * - Used internally by the workflow handler system * - Ensures actions are executed in a controlled manner * - Provides consistent error handling for all action methods * - Sets pendingUpdate to true to ensure state is processed after action execution */ protected runAction(methodName: keyof StatefulWorkflow, input: any): Promise; /** * Cleans up event listeners to prevent memory leaks in the shared V8 VM. * * This method should be called before a workflow completes or during continueAsNew * to ensure that event listeners don't persist between workflow executions in the * shared VM environment. * * ## Cleanup actions: * - Removes the stateChanged listener from the stateManager * - Cleans up the StateManager (cache, state, event listeners) * - Calls the parent class cleanup method * - Resets StatefulWorkflow-specific flags * * @returns {void} */ protected cleanup(): void; } export {};