@ronaldroe/micro-flow 1.3.9 → 3.0.0

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 (54) hide show
  1. package/README.md +51 -10
  2. package/dist/src/classes/base.js +2 -2
  3. package/dist/src/classes/base.js.map +3 -3
  4. package/dist/src/classes/callable_registry.js +1 -1
  5. package/dist/src/classes/callable_registry.js.map +2 -2
  6. package/dist/src/classes/events/event.js +1 -1
  7. package/dist/src/classes/events/event.js.map +3 -3
  8. package/dist/src/classes/index.js +1 -1
  9. package/dist/src/classes/index.js.map +3 -3
  10. package/dist/src/classes/instance_state.js +2 -0
  11. package/dist/src/classes/instance_state.js.map +7 -0
  12. package/dist/src/classes/state.js +1 -1
  13. package/dist/src/classes/state.js.map +3 -3
  14. package/dist/src/classes/steps/case.js +1 -1
  15. package/dist/src/classes/steps/case.js.map +3 -3
  16. package/dist/src/classes/steps/conditional_step.js +1 -1
  17. package/dist/src/classes/steps/conditional_step.js.map +3 -3
  18. package/dist/src/classes/steps/delay_step.js +1 -1
  19. package/dist/src/classes/steps/delay_step.js.map +3 -3
  20. package/dist/src/classes/steps/flow_control_step.js +1 -1
  21. package/dist/src/classes/steps/flow_control_step.js.map +3 -3
  22. package/dist/src/classes/steps/logic_step.js +1 -1
  23. package/dist/src/classes/steps/logic_step.js.map +3 -3
  24. package/dist/src/classes/steps/loop_step.js +1 -1
  25. package/dist/src/classes/steps/loop_step.js.map +3 -3
  26. package/dist/src/classes/steps/step.js +1 -1
  27. package/dist/src/classes/steps/step.js.map +3 -3
  28. package/dist/src/classes/steps/switch_step.js +1 -1
  29. package/dist/src/classes/steps/switch_step.js.map +3 -3
  30. package/dist/src/classes/workflow.js +1 -1
  31. package/dist/src/classes/workflow.js.map +3 -3
  32. package/dist/src/enums/delay_types.js.map +1 -1
  33. package/dist/src/enums/logic_step_types.js.map +3 -3
  34. package/dist/src/enums/sub_step_types.js +1 -1
  35. package/dist/src/enums/sub_step_types.js.map +2 -2
  36. package/package.json +1 -1
  37. package/src/classes/base.js +42 -10
  38. package/src/classes/callable_registry.js +82 -0
  39. package/src/classes/events/event.js +3 -3
  40. package/src/classes/index.js +2 -0
  41. package/src/classes/instance_state.js +277 -0
  42. package/src/classes/state.js +20 -49
  43. package/src/classes/steps/case.js +34 -4
  44. package/src/classes/steps/conditional_step.js +72 -5
  45. package/src/classes/steps/delay_step.js +23 -8
  46. package/src/classes/steps/flow_control_step.js +21 -4
  47. package/src/classes/steps/logic_step.js +63 -45
  48. package/src/classes/steps/loop_step.js +88 -3
  49. package/src/classes/steps/step.js +238 -20
  50. package/src/classes/steps/switch_step.js +68 -9
  51. package/src/classes/workflow.js +280 -62
  52. package/src/enums/delay_types.js +1 -1
  53. package/src/enums/logic_step_types.js +2 -2
  54. package/src/enums/sub_step_types.js +10 -10
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/classes/workflow.js"],
4
- "sourcesContent": ["import crypto from 'crypto';\nimport Base from './base.js';\nimport { base_types } from '../enums/index.js';\n\n/**\n * Workflow class for managing and executing a sequence of steps.\n * @class Workflow\n * @extends Base\n */\nexport default class Workflow extends Base {\n /**\n * Creates a new Workflow instance.\n * @param {Object} options - Configuration options.\n * @param {string} [options.name] - Name of the workflow.\n * @param {boolean} [options.exit_on_error=false] - Whether to exit on error.\n * @param {Array<Step>} [options.steps=[]] - Array of steps to add to the workflow.\n * @param {boolean} [options.throw_on_empty=false] - Whether to throw error if workflow is empty.\n */\n constructor({\n name,\n exit_on_error = false,\n steps = [],\n throw_on_empty = false\n }) {\n super({ name, base_type: base_types.WORKFLOW });\n\n this.initializeWorkflowState();\n\n this.addSteps(steps);\n\n this.exit_on_error = exit_on_error;\n this.throw_on_empty = throw_on_empty;\n this.sessions = {};\n this.current_session_id = null;\n }\n\n /**\n * Executes the workflow by running all steps in sequence.\n * @async\n * @returns {Promise<Workflow>} The workflow instance with execution results.\n * @throws {Error} Throws if workflow is empty and throw_on_empty is true.\n */\n async execute() {\n if (!this.current_session_id) {\n this.current_session_id = crypto.randomUUID();\n }\n\n if (this.isEmpty()) {\n if (this.throw_on_empty) {\n throw new Error('Cannot execute an empty workflow');\n }\n\n this.markAsComplete();\n this.prepareResult('Workflow is empty', null);\n return this;\n }\n \n this.markAsRunning();\n\n for (let i = 0; i < this._steps.length; i++) {\n if (this.should_break) {\n this.log(this.getState('event_names.workflow').WORKFLOW_BREAK_EXECUTED, `Workflow \"${this.name}\" execution broken at step ${this._steps[i].name} - ${this._steps[i].id}.`);\n break;\n }\n\n if (this.should_skip) {\n this.log(\n this.getState('events.workflow.event_names.WORKFLOW_STEP_SKIPPED'),\n `Workflow \"${this.name}\" skipping step ${this._steps[i].name} - ${this._steps[i].id}.`\n );\n this.should_skip = false;\n continue;\n }\n\n this.current_step = this._steps[i].id;\n\n try {\n const step_result = await this.step();\n this.prepareResult('Success', step_result);\n } catch (error) {\n this.markAsFailed();\n this.prepareResult(`Workflow execution failed at step ${this.steps_by_id[this.current_step].name} - ${this.current_step}`, { error });\n \n if (this.exit_on_error) {\n return this;\n }\n }\n\n if (this.should_pause) {\n this.markAsPaused();\n this.should_pause = false;\n return this;\n }\n }\n\n this.markAsComplete();\n return this;\n }\n\n /**\n * Resumes a paused workflow.\n * @async\n * @returns {Promise<Workflow>} The workflow instance.\n */\n async resume() {\n this.should_pause = false;\n this.timing.resume_time = new Date();\n\n this.getState('events.workflow').emit(\n this.getState('event_names.workflow').WORKFLOW_RESUMED,\n this.getState()\n );\n return this.execute();\n }\n\n /**\n * Executes a single step in the workflow.\n * @async\n * @returns {Promise<*>} The result of the step execution.\n */\n async step() {\n const step = this.steps_by_id[this.current_step];\n\n step.parentWorkflowId = this.id;\n const result = await step.execute();\n\n if (step.status === this.getState('statuses.step.FAILED')) {\n throw step.errors[step.errors.length - 1] ?? new Error(`Step \"${step.name}\" failed`);\n }\n\n return result;\n }\n\n /**\n * Adds a step to the workflow.\n * @param {Step} step - The step to add.\n * @throws {Error} Throws if step is not a valid Step instance.\n */\n addStep(step) {\n if (typeof step.getCallableType !== 'function') {\n throw new Error('Invalid step type. Must be an instance of Step.');\n }\n\n if (!Array.isArray(this._steps)) {\n this._steps = [];\n }\n\n if (!this.steps_by_id || typeof this.steps_by_id !== 'object') {\n this.steps_by_id = {};\n }\n\n this.steps_by_id[step.id] = step;\n\n step.parentWorkflowId = this.id;\n this._steps.push(step);\n }\n\n /**\n * Adds a step at a specific index in the workflow.\n * @param {Step} step - The step to add.\n * @param {number} index - The index at which to insert the step.\n */\n addStepAtIndex(step, index) {\n if (!this.steps_by_id || typeof this.steps_by_id !== 'object') {\n this.steps_by_id = {};\n }\n\n this.steps_by_id[step.id] = step;\n step.parentWorkflowId = this.id;\n this._steps.splice(index, 0, step);\n }\n\n /**\n * Adds multiple steps to the workflow.\n * @param {Step[]} steps - Array of steps to add.\n */\n addSteps(steps) {\n steps.forEach(step => this.addStep(step));\n }\n\n /**\n * Clears all steps from the workflow.\n */\n clearSteps() {\n this._steps = [];\n }\n\n /**\n * Closes the current session and stores a snapshot of the workflow state.\n */\n closeCurrentSession() {\n if (!this.current_session_id) {\n return;\n }\n\n this.sessions[this.current_session_id] = {\n results: [...this.results],\n status: this.status,\n timing: { ...this.timing },\n closed_at: new Date()\n };\n this.current_session_id = null;\n }\n\n /**\n * Deletes a step from the workflow by its ID.\n * @param {string} stepId - The ID of the step to delete.\n */\n deleteStep(stepId) {\n this._steps = this._steps.filter(step => step.id !== stepId);\n }\n\n /**\n * Deletes a step from the workflow by its index.\n * @param {number} index - The index of the step to delete.\n */\n deleteStepByIndex(index) {\n this._steps.splice(index, 1);\n }\n\n /**\n * Initializes the workflow state with default values.\n */\n initializeWorkflowState() {\n this.results = [];\n this.exit_on_error = false;\n this.current_step = null;\n this.should_break = false;\n this.should_continue = false;\n this.should_pause = false;\n this.should_skip = false;\n this.status = this.getState('statuses.workflow').CREATED;\n this._steps = [];\n this.throw_on_empty = this.throw_on_empty;\n this.timing = {\n ...this.timing,\n create_time: new Date(),\n pause_time: null,\n resume_time: null,\n }\n\n const workflows = this.getState('workflows');\n workflows[this.id] = this;\n this.setState('workflows', workflows);\n\n this.log(\n this.getState('event_names.workflow').WORKFLOW_CREATED,\n `Workflow \"${this.name}\" initialized.`\n );\n }\n\n /**\n * Checks if the workflow has no steps.\n * @returns {boolean} True if the workflow is empty.\n */\n isEmpty() {\n return !this._steps || !this._steps.length\n }\n\n /**\n * Marks the workflow as complete and closes the current session.\n */\n markAsComplete() {\n super.markAsComplete();\n this.closeCurrentSession();\n }\n\n /**\n * Marks the workflow as created.\n * @returns {string} The CREATED status.\n */\n markAsCreated() {\n this.timing.create_time = new Date();\n \n this.log(\n this.getState('event_names.workflow').WORKFLOW_CREATED,\n `Workflow \"${this.name}\" created.`\n );\n\n return this.getState('statuses.workflow').CREATED;\n }\n\n /**\n * Marks the workflow as failed and closes the current session.\n */\n markAsFailed() {\n super.markAsFailed();\n this.closeCurrentSession();\n }\n\n /**\n * Marks the workflow as paused.\n */\n markAsPaused() {\n this.timing.pause_time = new Date();\n this.status = this.getState('statuses.workflow').PAUSED;\n\n this.getState('events.workflow').emit(\n this.getState('event_names.workflow').WORKFLOW_PAUSED,\n this.getState()\n );\n }\n \n /**\n * Marks the workflow as resumed.\n */\n markAsResumed() {\n this.timing.resume_time = new Date();\n this.status = this.getState('statuses.workflow').RUNNING;\n\n this.getState('events.workflow').emit(\n this.getState('event_names.workflow').WORKFLOW_RESUMED,\n this.getState()\n );\n }\n\n /**\n * Moves a step from one index to another.\n * @param {number} fromIndex - The current index of the step.\n * @param {number} toIndex - The target index for the step.\n */\n moveStep(fromIndex, toIndex) {\n const [step] = this._steps.splice(fromIndex, 1);\n this._steps.splice(toIndex, 0, step);\n\n this.getState('events.workflow').emit(\n this.getState('event_names.workflow').WORKFLOW_STEP_MOVED,\n this.getState()\n );\n }\n\n /**\n * Pauses the workflow execution.\n */\n pause() {\n this.should_pause = true;\n this.timing.pause_time = new Date();\n\n this.getState('events.workflow').emit(\n this.getState('event_names.workflow').WORKFLOW_PAUSED,\n this.getState()\n );\n }\n\n /**\n * Removes and returns the last step from the workflow.\n * @returns {Step} The last step.\n */\n popStep() {\n return this._steps.pop();\n }\n\n /**\n * Prepares a result object and adds it to the results array.\n * @param {string} message - Result message.\n * @param {*} data - Result data.\n */\n prepareResult(message, data) {\n this.results.push({ message, data });\n }\n\n /**\n * Adds a step to the end of the workflow.\n * @param {Step} step - The step to add.\n */\n pushStep(step) {\n this.addStep(step);\n }\n\n /**\n * Adds multiple steps to the end of the workflow.\n * @param {Step[]} steps - Array of steps to add.\n */\n pushSteps(steps) {\n steps.forEach(step => this.addStep(step));\n }\n\n /**\n * Removes and returns the first step from the workflow.\n * @returns {Step} The first step.\n */\n shiftStep() {\n return this._steps.shift();\n }\n\n /**\n * Adds a step to the beginning of the workflow.\n * @param {Step} step - The step to add.\n * @throws {Error} Throws if step is not a valid Step instance.\n */\n unshiftStep(step) {\n if (typeof step.getCallableType !== 'function') {\n throw new Error('Invalid step type. Must be an instance of Step.');\n }\n\n if (!this.steps_by_id || typeof this.steps_by_id !== 'object') {\n this.steps_by_id = {};\n }\n\n this.steps_by_id[step.id] = step;\n\n step.parentWorkflowId = this.id;\n this._steps.unshift(step);\n }\n\n /**\n * Gets the array of steps in the workflow.\n * @returns {Step[]} Array of steps.\n */\n get steps() {\n return this._steps;\n }\n\n /**\n * Sets the steps array by adding multiple steps.\n * @param {Step[]} steps - Array of steps to add.\n */\n set steps(steps) {\n steps.forEach((step, index) => {\n if (typeof step.getCallableType !== 'function') {\n throw new Error(`Invalid step type. Step at index ${index} is not an instance of Step.`);\n }\n });\n\n this.addSteps(steps);\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["crypto", "Base", "base_types", "Workflow", "__name", "name", "exit_on_error", "steps", "throw_on_empty", "i", "step_result", "error", "step", "result", "index", "stepId", "workflows", "fromIndex", "toIndex", "message", "data"]
4
+ "sourcesContent": ["import crypto from 'crypto';\nimport Base from './base.js';\nimport CallableRegistry from './callable_registry.js';\nimport Step from './steps/step.js';\nimport State from './state.js';\nimport { statuses, event_names, events, types, conditional_step_comparators, messages } from './instance_state.js';\nimport { base_types } from '../enums/index.js';\n\n/**\n * Workflow class for managing and executing a sequence of steps.\n * @class Workflow\n * @extends Base\n */\nexport default class Workflow extends Base {\n /**\n * Creates a new Workflow instance.\n * @param {Object} options - Configuration options.\n * @param {string} [options.name] - Name of the workflow.\n * @param {CallableRegistry|null} [options.callable_registry=null] - Registry for callable objects.\n * @param {boolean} [options.exit_on_error=false] - Whether to exit on error.\n * @param {Array<Step>} [options.steps=[]] - Array of steps to add to the workflow.\n * @param {boolean} [options.throw_on_empty=false] - Whether to throw error if workflow is empty.\n * @param {boolean} [options.use_state_singleton=false] - Deprecated. When true, this workflow (and every\n * `Step` it owns) reads/writes `getState`/`setState`/`deleteState` calls through the process-wide `State`\n * singleton instead of this workflow's own state.\n */\n constructor({\n name,\n callable_registry = null,\n exit_on_error = false,\n result_per_step = false,\n result_per_step_function = null,\n steps = [],\n throw_on_empty = false,\n use_state_singleton = false,\n }) {\n super({ name, base_type: base_types.WORKFLOW, use_state_singleton });\n\n this.callable_registry = callable_registry ?? new CallableRegistry();\n this.current_session_id = null;\n this.exit_on_error = exit_on_error;\n this.result_per_step = result_per_step;\n this.sessions = {};\n this.throw_on_empty = throw_on_empty;\n this.result_per_step_function = result_per_step_function;\n\n // _steps/steps_by_id must exist before initializeWorkflowState(): it reads this._steps\n // (to set current_step) and logs, which serializes `this` - both need this._steps to\n // already be an array, even when no steps are passed (addSteps([]) never calls addStep,\n // so it wouldn't otherwise get initialized).\n this._steps = [];\n this.steps_by_id = {};\n this.addSteps(steps);\n this.initializeWorkflowState();\n }\n\n /**\n * Executes the workflow by running all steps in sequence.\n * If the workflow is currently `paused`, resumes from the step after the one\n * that was running when it paused, rather than starting over from the beginning.\n * @async\n * @returns {Promise<Workflow>} The workflow instance with execution results.\n * @throws {Error} Throws if workflow is empty and throw_on_empty is true.\n */\n async execute() {\n if (!this.current_session_id) {\n this.current_session_id = crypto.randomUUID();\n }\n\n if (this.isEmpty()) {\n if (this.throw_on_empty) {\n throw new Error('Cannot execute an empty workflow');\n }\n\n this.markAsComplete();\n await this.prepareResult('Workflow is empty', null);\n return this;\n }\n\n const is_resuming = this.status === statuses.workflow.PAUSED;\n const paused_at_index = this._steps.findIndex(step => step.id === this.current_step);\n const start_index = is_resuming ? paused_at_index + 1 : 0;\n\n this.markAsRunning();\n\n for (let i = start_index; i < this._steps.length; i++) {\n if (this.should_break) {\n this.log(event_names.workflow.WORKFLOW_BREAK_EXECUTED, `Workflow \"${this.name}\" execution broken at step ${this._steps[i].name} - ${this._steps[i].id}.`);\n break;\n }\n\n if (this.should_skip) {\n this.log(\n event_names.workflow.WORKFLOW_STEP_SKIPPED,\n `Workflow \"${this.name}\" skipping step ${this._steps[i].name} - ${this._steps[i].id}.`\n );\n this.should_skip = false;\n continue;\n }\n\n this.current_step = this._steps[i].id;\n\n try {\n const step_result = await this.step();\n await this.prepareResult('Success', step_result);\n } catch (error) {\n this.markAsFailed();\n await this.prepareResult(`Workflow execution failed at step ${this.steps_by_id[this.current_step].name} - ${this.current_step}`, { error });\n \n if (this.exit_on_error) {\n return this;\n }\n }\n\n if (this.should_pause) {\n this.markAsPaused();\n this.should_pause = false;\n return this;\n }\n }\n\n this.markAsComplete();\n return this.prepareForSerialization();\n }\n\n /**\n * Resumes a paused workflow.\n * @async\n * @returns {Promise<Workflow>} The workflow instance.\n */\n async resume() {\n this.should_pause = false;\n this.timing.resume_time = new Date();\n\n events.workflow.emit(\n event_names.workflow.WORKFLOW_RESUMED,\n this.getState()\n );\n return this.execute();\n }\n\n /**\n * Executes a single step in the workflow.\n * @async\n * @returns {Promise<*>} The result of the step execution.\n */\n async step() {\n const step = this.steps_by_id[this.current_step];\n\n const result = await step.execute();\n\n if (step.status === statuses.step.FAILED) {\n throw step.errors[step.errors.length - 1] ?? new Error(`Step \"${step.name}\" failed`);\n }\n\n return result;\n }\n\n /**\n * Adds a step to the workflow.\n * @param {Step} step - The step to add.\n * @throws {Error} Throws if step is not a valid Step instance.\n */\n addStep(step) {\n // This check only ensures that the getCallableType method exists,\n // which is a characteristic of Step instances\n if (typeof step.getCallableType !== 'function') {\n throw new Error('Invalid input. Must be an instance of Step.');\n }\n\n if (!Array.isArray(this._steps)) {\n this._steps = [];\n }\n\n if (!this.steps_by_id || typeof this.steps_by_id !== 'object') {\n this.steps_by_id = {};\n }\n\n this.steps_by_id[step.id] = step;\n\n step.parent_workflow_id = this.id;\n step.parent_workflow = this.prepareForSerialization();\n step.use_state_singleton = this.use_state_singleton;\n step.state = this.state;\n this._steps.push(step);\n }\n\n /**\n * Adds a step at a specific index in the workflow.\n * @param {Step} step - The step to add.\n * @param {number} index - The index at which to insert the step.\n */\n addStepAtIndex(step, index) {\n if (!this.steps_by_id || typeof this.steps_by_id !== 'object') {\n this.steps_by_id = {};\n }\n\n this.steps_by_id[step.id] = step;\n step.parent_workflow_id = this.id;\n step.parent_workflow = this.prepareForSerialization();\n step.use_state_singleton = this.use_state_singleton;\n step.state = this.state;\n this._steps.splice(index, 0, step);\n }\n\n /**\n * Adds multiple steps to the workflow.\n * @param {Step[]} steps - Array of steps to add.\n */\n addSteps(steps) {\n if (!Array.isArray(steps)) {\n throw new Error('Invalid input. Must be an array of Step instances.');\n }\n\n steps.forEach(step => this.addStep(step));\n }\n\n /**\n * Clears all steps from the workflow.\n */\n clearSteps() {\n this._steps = [];\n this.steps_by_id = {};\n }\n\n /**\n * Closes the current session and stores a snapshot of the workflow state.\n */\n closeCurrentSession() {\n if (!this.current_session_id) {\n return;\n }\n\n this.sessions[this.current_session_id] = {\n results: [...this.results],\n status: this.status,\n timing: { ...this.timing },\n closed_at: new Date()\n };\n this.current_session_id = null;\n }\n\n /**\n * Deletes a step from the workflow by its ID.\n * @param {string} stepId - The ID of the step to delete.\n */\n deleteStep(stepId) {\n if (!Array.isArray(this._steps)) {\n this._steps = [];\n }\n\n this._steps = this._steps.filter(step => step.id !== stepId);\n }\n\n /**\n * Deletes a step from the workflow by its index.\n * @param {number} index - The index of the step to delete.\n */\n deleteStepByIndex(index) {\n if (!Array.isArray(this._steps)) {\n this._steps = [];\n }\n\n this._steps.splice(index, 1);\n }\n\n /**\n * Resolves a nested property path within this workflow's own state - the low-level counterpart\n * to `getState()`. Falls back to the deprecated `State` singleton's resolver when\n * `use_state_singleton` is `true`.\n * @param {string} path - Path to the state property.\n * @param {boolean} [emit=true] - Only meaningful when `use_state_singleton` is `true`; whether\n * to emit the singleton's `GET_FROM_PROPERTY_PATH` state event.\n * @returns {*} The value at the specified path, or undefined if not found.\n */\n getStateFromPropertyPath(path, emit = true) {\n if (this.use_state_singleton) {\n console.warn('The state singleton has been deprecated. Use the .prepareForSerialization() method on the workflow instance instead.');\n return State.getFromPropertyPath(path, emit);\n }\n\n return this.state.getStateFromPropertyPath(path);\n }\n\n /**\n * Initializes the workflow state with default values.\n */\n initializeWorkflowState() {\n this.current_step = ! this.isEmpty() ? this._steps[0].id : null;\n this.results = this.results ?? [];\n this.sessions = this.sessions ?? {};\n this.should_break = this.should_break ?? false;\n this.should_continue = this.should_continue ?? false;\n this.should_pause = this.should_pause ?? false;\n this.should_skip = this.should_skip ?? false;\n this.status = this.status ?? statuses.workflow.CREATED;\n this.timing = {\n ...this.timing,\n create_time: this.timing?.create_time ?? new Date(),\n pause_time: this.timing?.pause_time ?? null,\n resume_time: this.timing?.resume_time ?? null,\n }\n\n if (this.use_state_singleton) {\n // The deprecated `State` singleton is shared by every workflow that opts into it, so it\n // still needs an id-keyed registry (unlike per-instance state, which only ever has one\n // workflow to represent and can just reference it directly - see the else branch).\n const workflows = this.getState('workflows');\n workflows[this.id] = this;\n this.setState('workflows', workflows);\n } else {\n this.setState('workflow', this);\n }\n\n this.log(\n event_names.workflow.WORKFLOW_CREATED,\n `Workflow \"${this.name}\" initialized.`\n );\n }\n\n /**\n * Checks if the workflow has no steps.\n * @returns {boolean} True if the workflow is empty.\n */\n isEmpty() {\n return !Array.isArray(this._steps) || !this._steps.length;\n }\n\n /**\n * Marks the workflow as complete and closes the current session.\n */\n markAsComplete() {\n super.markAsComplete();\n this.closeCurrentSession();\n }\n\n /**\n * Marks the workflow as created.\n * @returns {string} The CREATED status.\n */\n markAsCreated() {\n this.timing.create_time = new Date();\n \n this.log(\n event_names.workflow.WORKFLOW_CREATED,\n `Workflow \"${this.name}\" created.`\n );\n\n return statuses.workflow.CREATED;\n }\n\n /**\n * Marks the workflow as failed and closes the current session.\n */\n markAsFailed() {\n super.markAsFailed();\n this.closeCurrentSession();\n }\n\n /**\n * Marks the workflow as paused.\n */\n markAsPaused() {\n this.timing.pause_time = new Date();\n this.status = statuses.workflow.PAUSED;\n\n events.workflow.emit(\n event_names.workflow.WORKFLOW_PAUSED,\n this.getState()\n );\n }\n\n /**\n * Marks the workflow as resumed.\n */\n markAsResumed() {\n this.timing.resume_time = new Date();\n this.status = statuses.workflow.RUNNING;\n\n events.workflow.emit(\n event_names.workflow.WORKFLOW_RESUMED,\n this.getState()\n );\n }\n\n /**\n * Moves a step from one index to another.\n * @param {number} fromIndex - The current index of the step.\n * @param {number} toIndex - The target index for the step.\n */\n moveStep(fromIndex, toIndex) {\n const [step] = this._steps.splice(fromIndex, 1);\n this._steps.splice(toIndex, 0, step);\n\n events.workflow.emit(\n event_names.workflow.WORKFLOW_STEP_MOVED,\n this.getState()\n );\n }\n\n /**\n * Parses a property path string into an array of keys, supporting both dot notation and\n * bracket notation (e.g. `\"users[0].name\"`). Pure utility - not affected by `use_state_singleton`.\n * @param {string} path - The path to parse.\n * @returns {string[]} Array of property keys.\n */\n parseStatePath(path) {\n return this.use_state_singleton ? State.parsePath(path) : this.state.parseStatePath(path);\n }\n\n /**\n * Pauses the workflow execution.\n */\n pause() {\n this.should_pause = true;\n this.timing.pause_time = new Date();\n\n events.workflow.emit(\n event_names.workflow.WORKFLOW_PAUSED,\n this.getState()\n );\n }\n\n /**\n * Removes and returns the last step from the workflow.\n * @returns {Step} The last step.\n */\n popStep() {\n return this._steps.pop();\n }\n\n /**\n * Inserts safely serializable properties of the workflow into a new object for serialization.\n * @returns {Object} An object containing the workflow's properties ready for serialization.\n */\n prepareForSerialization() {\n const serialized_workflow = {\n id: this.id,\n current_session_id: this.current_session_id,\n current_step: this.current_step,\n exit_on_error: this.exit_on_error,\n name: this.name,\n sessions: this.sessions,\n status: this.status,\n steps: this._steps.map(step => step.prepareForSerialization()),\n throw_on_empty: this.throw_on_empty,\n timing: this.timing,\n results: this.results,\n use_state_singleton: this.use_state_singleton,\n };\n\n return serialized_workflow;\n }\n\n /**\n * Prepares a result object and adds it to the results array.\n * @param {string} message - Result message.\n * @param {*} data - Result data.\n */\n async prepareResult(message, data) {\n if (this.result_per_step && typeof this.result_per_step_function === 'function') {\n await this.result_per_step_function(this.prepareForSerialization());\n }\n\n const result = { message, data };\n this.results.push(result);\n }\n\n /**\n * Adds a step to the end of the workflow.\n * @param {Step} step - The step to add.\n */\n pushStep(step) {\n this.addStep(step);\n }\n\n /**\n * Adds multiple steps to the end of the workflow.\n * @param {Step[]} steps - Array of steps to add.\n */\n pushSteps(steps) {\n steps.forEach(step => this.addStep(step));\n }\n\n /**\n * Serializes the workflow into a JSON string.\n * @returns {string} The JSON string representation of the workflow.\n */\n serialize() {\n return JSON.stringify(this.prepareForSerialization());\n }\n\n /**\n * Sets a nested property value within this workflow's own state, creating intermediate\n * objects/arrays as needed - the low-level counterpart to `setState()`. Falls back to the\n * deprecated `State` singleton's setter when `use_state_singleton` is `true`.\n * @param {string} path - Path to the state property.\n * @param {*} value - The value to set at the specified path.\n * @param {boolean} [emit=true] - Only meaningful when `use_state_singleton` is `true`; whether\n * to emit the singleton's `SET_TO_PROPERTY_PATH` state event.\n */\n setStateToPropertyPath(path, value, emit = true) {\n if (this.use_state_singleton) {\n console.warn('The state singleton has been deprecated. Use the .prepareForSerialization() method on the workflow instance instead.');\n State.setToPropertyPath(path, value, emit);\n return;\n }\n\n this.state.setStateToPropertyPath(path, value);\n }\n\n /**\n * Removes and returns the first step from the workflow.\n * @returns {Step} The first step.\n */\n shiftStep() {\n return this._steps.shift();\n }\n\n /**\n * Adds a step to the beginning of the workflow.\n * @param {Step} step - The step to add.\n * @throws {Error} Throws if step is not a valid Step instance.\n */\n unshiftStep(step) {\n if (typeof step.getCallableType !== 'function') {\n throw new Error('Invalid step type. Must be an instance of Step.');\n }\n\n if (!this.steps_by_id || typeof this.steps_by_id !== 'object') {\n this.steps_by_id = {};\n }\n\n this.steps_by_id[step.id] = step;\n\n step.parent_workflow_id = this.id;\n step.use_state_singleton = this.use_state_singleton;\n step.state = this.state;\n this._steps.unshift(step);\n }\n\n /**\n * Custom JSON serializer\n * @returns {Object} The JSON representation of the workflow.\n */\n toJSON() {\n return this.prepareForSerialization();\n }\n\n /**\n * Gets the array of steps in the workflow.\n * @returns {Step[]} Array of steps.\n */\n get steps() {\n return this._steps;\n }\n\n /**\n * Sets the steps array by adding multiple steps.\n * @param {Step[]} steps - Array of steps to add.\n */\n set steps(steps) {\n this.addSteps(steps);\n }\n\n /**\n * Deserializes a JSON string into a Workflow instance and hydrates it.\n * @param {string} serialized_workflow - The JSON string representation of the workflow.\n * @param {CallableRegistry|null} [callable_registry] - Registry used to resolve function callables in the workflow's steps.\n * @returns {Workflow} The hydrated Workflow instance.\n * @throws {Error} Throws if the serialized workflow is not a string.\n */\n static hydrateSerialized(serialized_workflow, callable_registry = null) {\n // TODO: Validate structure of serialized workflow\n if (typeof serialized_workflow !== 'string') {\n throw new Error('Invalid serialized workflow. Must be a string.');\n }\n\n const parsed = JSON.parse(serialized_workflow);\n\n return Workflow.hydrate(parsed, callable_registry);\n }\n\n /**\n * Hydrates a parsed workflow object into a Workflow instance.\n * @param {Object} parsed_workflow - The parsed workflow object.\n * @param {CallableRegistry|null} [callable_registry] - Registry used to resolve function callables in the workflow's steps.\n * @returns {Workflow} The hydrated Workflow instance.\n * @throws {Error} Throws if the parsed workflow is not a valid object.\n */\n static hydrate(parsed_workflow, callable_registry = null) {\n // TODO: Validate structure of serialized workflow\n // TODO: Use event system to handle errors?\n if (typeof parsed_workflow !== 'object' || parsed_workflow === null) {\n throw new Error('Invalid parsed workflow. Must be a valid object.');\n }\n\n const hydrated_workflow = new Workflow({\n name: parsed_workflow.name,\n callable_registry,\n exit_on_error: parsed_workflow.exit_on_error,\n steps: parsed_workflow.steps.map(step => Step.hydrateAny(step, callable_registry)),\n throw_on_empty: parsed_workflow.throw_on_empty,\n use_state_singleton: parsed_workflow.use_state_singleton ?? false,\n });\n\n // The constructor above (via Base) always generates a fresh id, and addStep() has\n // already stamped that fresh id onto each step's parent_workflow_id and (in singleton mode)\n // registered the workflow under it in the singleton's `workflows` registry. Restoring the\n // real id below would otherwise leave both referencing a discarded id, so fix them up here\n // too. Per-instance state needs no such fixup for its `workflow` key - it's the same live\n // object, so the id mutation below is reflected automatically.\n const stale_id = hydrated_workflow.id;\n hydrated_workflow.id = parsed_workflow.id;\n\n if (hydrated_workflow.use_state_singleton) {\n const workflows = hydrated_workflow.getState('workflows');\n delete workflows[stale_id];\n workflows[hydrated_workflow.id] = hydrated_workflow;\n hydrated_workflow.setState('workflows', workflows);\n }\n\n hydrated_workflow.steps.forEach(step => {\n step.parent_workflow_id = hydrated_workflow.id;\n });\n\n hydrated_workflow.current_session_id = parsed_workflow.current_session_id;\n hydrated_workflow.current_step = parsed_workflow.current_step ?? hydrated_workflow.current_step;\n hydrated_workflow.sessions = parsed_workflow.sessions ?? {};\n hydrated_workflow.status = parsed_workflow.status;\n hydrated_workflow.timing = parsed_workflow.timing;\n hydrated_workflow.results = parsed_workflow.results;\n\n return hydrated_workflow;\n }\n}\n\n// Framework constants, exposed as static members rather than duplicated into every\n// Workflow's own state (see instance_state.js, the canonical source for these values).\nWorkflow.statuses = statuses;\nWorkflow.event_names = event_names;\nWorkflow.events = events;\nWorkflow.types = types;\nWorkflow.conditional_step_comparators = conditional_step_comparators;\nWorkflow.messages = messages;\n"],
5
+ "mappings": "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",
6
+ "names": ["crypto", "Base", "CallableRegistry", "Step", "State", "statuses", "event_names", "events", "types", "conditional_step_comparators", "messages", "base_types", "Workflow", "__name", "name", "callable_registry", "exit_on_error", "result_per_step", "result_per_step_function", "steps", "throw_on_empty", "use_state_singleton", "is_resuming", "paused_at_index", "step", "start_index", "step_result", "error", "result", "index", "stepId", "path", "emit", "workflows", "fromIndex", "toIndex", "message", "data", "value", "serialized_workflow", "parsed", "parsed_workflow", "hydrated_workflow", "stale_id"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/enums/delay_types.js"],
4
- "sourcesContent": ["/**\n * Enumeration of delay types for DelayStep.\n * \n * @enum {string}\n * @readonly\n * @example\n * import delay_types from 'micro-flow';\n * \n * const delayStep = new DelayStep({\n * name: 'wait-5-seconds',\n * delay_type: delay_types.RELATIVE,\n * delay_duration: 5000\n * });\n */\nconst delay_types = {\n /**\n * Delay until a specific absolute timestamp or Date.\n * Use with delay_timestamp property.\n * @type {string}\n */\n ABSOLUTE: 'absolute',\n \n /**\n * Delay for a relative duration in milliseconds.\n * Use with delay_duration property.\n * @type {string}\n */\n RELATIVE: 'relative',\n};\n\nexport default delay_types;\n"],
4
+ "sourcesContent": ["/**\n * Enumeration of delay types for DelayStep.\n * \n * @enum {string}\n * @readonly\n * @example\n * import delay_types from 'micro-flow';\n * \n * const delay_step = new DelayStep({\n * name: 'wait-5-seconds',\n * delay_type: delay_types.RELATIVE,\n * delay_duration: 5000\n * });\n */\nconst delay_types = {\n /**\n * Delay until a specific absolute timestamp or Date.\n * Use with delay_timestamp property.\n * @type {string}\n */\n ABSOLUTE: 'absolute',\n \n /**\n * Delay for a relative duration in milliseconds.\n * Use with delay_duration property.\n * @type {string}\n */\n RELATIVE: 'relative',\n};\n\nexport default delay_types;\n"],
5
5
  "mappings": "AAcA,MAAMA,EAAc,CAMlB,SAAU,WAOV,SAAU,UACZ,EAEA,IAAOC,EAAQD",
6
6
  "names": ["delay_types", "delay_types_default"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/enums/logic_step_types.js"],
4
- "sourcesContent": ["/**\n * Enumeration of logic step types for control flow operations.\n * These types define different kinds of logic-based workflow steps.\n * \n * @enum {string}\n * @readonly\n */\nconst LogicStepTypes = {\n CONDITIONAL: 'conditional',\n LOOP: 'loop',\n FLOW_CONTROL: 'flow_control',\n SWITCH: 'switch',\n SKIP: 'skip'\n};\n\nexport default LogicStepTypes;\n"],
5
- "mappings": "AAOA,MAAMA,EAAiB,CACrB,YAAa,cACb,KAAM,OACN,aAAc,eACd,OAAQ,SACR,KAAM,MACR,EAEA,IAAOC,EAAQD",
6
- "names": ["LogicStepTypes", "logic_step_types_default"]
4
+ "sourcesContent": ["/**\n * Enumeration of logic step types for control flow operations.\n * These types define different kinds of logic-based workflow steps.\n * \n * @enum {string}\n * @readonly\n */\nconst logic_step_types = {\n CONDITIONAL: 'conditional',\n LOOP: 'loop',\n FLOW_CONTROL: 'flow_control',\n SWITCH: 'switch',\n SKIP: 'skip'\n};\n\nexport default logic_step_types;\n"],
5
+ "mappings": "AAOA,MAAMA,EAAmB,CACvB,YAAa,cACb,KAAM,OACN,aAAc,eACd,OAAQ,SACR,KAAM,MACR,EAEA,IAAOC,EAAQD",
6
+ "names": ["logic_step_types", "logic_step_types_default"]
7
7
  }
@@ -1,2 +1,2 @@
1
- const t={Step:"step",LogicStep:"logic",ConditionalStep:"conditional",FlowControlStep:"flow_control",LoopStep:"loop",SwitchStep:"switch",Case:"case",DelayStep:"delay"};var o=t;export{o as default};
1
+ const t={step:"step",logic_step:"logic",conditional_step:"conditional",flow_control_step:"flow_control",loop_step:"loop",switch_step:"switch",case:"case",delay_step:"delay"};var o=t;export{o as default};
2
2
  //# sourceMappingURL=sub_step_types.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/enums/sub_step_types.js"],
4
- "sourcesContent": ["/**\n * Enumeration of sub-step types used in the workflow system.\n * @type {Object.<string, string>}\n * @readonly\n * @example\n * console.log(sub_step_types.Step); // \"step\"\n * console.log(sub_step_types.ConditionalStep); // \"conditional\"\n */\nconst sub_step_types = {\n Step: 'step',\n LogicStep: 'logic',\n ConditionalStep: 'conditional',\n FlowControlStep: 'flow_control',\n LoopStep: 'loop',\n SwitchStep: 'switch',\n Case: 'case',\n DelayStep: 'delay',\n};\n\nexport default sub_step_types;\n"],
5
- "mappings": "AAQA,MAAMA,EAAiB,CACrB,KAAM,OACN,UAAW,QACX,gBAAiB,cACjB,gBAAiB,eACjB,SAAU,OACV,WAAY,SACZ,KAAM,OACN,UAAW,OACb,EAEA,IAAOC,EAAQD",
4
+ "sourcesContent": ["/**\n * Enumeration of sub-step types used in the workflow system.\n * @type {Object.<string, string>}\n * @readonly\n * @example\n * console.log(sub_step_types.step); // \"step\"\n * console.log(sub_step_types.conditional_step); // \"conditional\"\n */\nconst sub_step_types = {\n step: 'step',\n logic_step: 'logic',\n conditional_step: 'conditional',\n flow_control_step: 'flow_control',\n loop_step: 'loop',\n switch_step: 'switch',\n case: 'case',\n delay_step: 'delay',\n};\n\nexport default sub_step_types;\n"],
5
+ "mappings": "AAQA,MAAMA,EAAiB,CACrB,KAAM,OACN,WAAY,QACZ,iBAAkB,cAClB,kBAAmB,eACnB,UAAW,OACX,YAAa,SACb,KAAM,OACN,WAAY,OACd,EAEA,IAAOC,EAAQD",
6
6
  "names": ["sub_step_types", "sub_step_types_default"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronaldroe/micro-flow",
3
- "version": "1.3.9",
3
+ "version": "3.0.0",
4
4
  "description": "A lightweight, flexible workflow orchestration library for Node.js and browser environments. Build complex, sequential processes with ease using an intuitive API that supports conditional logic, flow control, event handling, and state management.",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -1,6 +1,7 @@
1
1
  import crypto from 'crypto';
2
2
  import { base_types } from '../enums/index.js';
3
3
  import State from './state.js';
4
+ import { InstanceState } from './instance_state.js';
4
5
 
5
6
  /**
6
7
  * Base class for workflows and steps.
@@ -13,12 +14,20 @@ export default class Base {
13
14
  * @param {Object} options - Configuration options.
14
15
  * @param {string} [options.name] - Name of the instance.
15
16
  * @param {string} [options.base_type=base_types.STEP] - Type of the base instance.
17
+ * @param {boolean} [options.use_state_singleton=false] - Deprecated. When true, `getState`/`setState`/`deleteState`
18
+ * fall back to the process-wide `State` singleton instead of this instance's own state. `Workflow` passes this
19
+ * value down to every `Step` it owns, so it only needs to be set once, on the workflow.
20
+ * @param {InstanceState|null} [options.state=null] - The `InstanceState` this instance's `getState`/`setState`/
21
+ * `deleteState` calls should read and write. `Workflow` creates its own on construction and shares it with its
22
+ * `Step`s; a `Step` created standalone (not yet added to a workflow) gets its own until it's added to one.
16
23
  */
17
- constructor({ name, base_type = base_types.STEP }) {
24
+ constructor({ name, base_type = base_types.STEP, use_state_singleton = false, state = null }) {
18
25
  this.id = crypto.randomUUID();
19
26
  this.name = name ?? `${base_type}-${this.id}`;
20
27
 
21
28
  this.base_type = base_type;
29
+ this.use_state_singleton = use_state_singleton;
30
+ this.state = use_state_singleton ? null : (state ?? new InstanceState());
22
31
  this.timing = {
23
32
  cancel_time: null,
24
33
  complete_time: null,
@@ -52,10 +61,10 @@ export default class Base {
52
61
  return;
53
62
  }
54
63
 
55
- const logMessage = message ? `\n[${this.base_type.toUpperCase()} - ${this.name}] ${message}` : `\n[${this.base_type.toUpperCase()} - ${this.name}] Event: ${event_name}`;
56
- const logType = event_name.endsWith('_failed') ? 'error' : 'log';
64
+ const log_message = message ? `\n[${this.base_type.toUpperCase()} - ${this.name}] ${message}` : `\n[${this.base_type.toUpperCase()} - ${this.name}] Event: ${event_name}`;
65
+ const log_type = event_name.endsWith('_failed') ? 'error' : 'log';
57
66
 
58
- console[logType](logMessage);
67
+ console[log_type](log_message);
59
68
  }
60
69
 
61
70
  /**
@@ -115,28 +124,51 @@ export default class Base {
115
124
 
116
125
  // State management methods
117
126
  /**
118
- * Gets a value from the global state.
127
+ * Gets a value from this instance's own state (the `Workflow`'s state, shared with its `Step`s).
128
+ * Set `use_state_singleton: true` (on the owning `Workflow`) to instead read from the
129
+ * deprecated, process-wide `State` singleton.
119
130
  * @param {string} path - Path to the state property.
120
131
  * @returns {*} The state value at the specified path.
121
132
  */
122
133
  getState(path) {
123
- return State.get(path);
134
+ if (this.use_state_singleton) {
135
+ console.warn('The state singleton has been deprecated. Use the .prepareForSerialization() method on the workflow instance instead.');
136
+ return State.get(path);
137
+ }
138
+
139
+ return this.state.get(path);
124
140
  }
125
141
 
126
142
  /**
127
- * Sets a value in the global state.
143
+ * Sets a value in this instance's own state (the `Workflow`'s state, shared with its `Step`s).
144
+ * Set `use_state_singleton: true` (on the owning `Workflow`) to instead write to the
145
+ * deprecated, process-wide `State` singleton.
128
146
  * @param {string} path - Path to the state property.
129
147
  * @param {*} value - Value to set.
130
148
  */
131
149
  setState(path, value) {
132
- State.set(path, value);
150
+ if (this.use_state_singleton) {
151
+ console.warn('The state singleton has been deprecated. Use the .prepareForSerialization() method on the workflow instance instead.');
152
+ State.set(path, value);
153
+ return;
154
+ }
155
+
156
+ this.state.set(path, value);
133
157
  }
134
158
 
135
159
  /**
136
- * Deletes a property from the global state.
160
+ * Deletes a property from this instance's own state (the `Workflow`'s state, shared with its `Step`s).
161
+ * Set `use_state_singleton: true` (on the owning `Workflow`) to instead delete from the
162
+ * deprecated, process-wide `State` singleton.
137
163
  * @param {string} path - Path to the state property to delete.
138
164
  */
139
165
  deleteState(path) {
140
- State.delete(path);
166
+ if (this.use_state_singleton) {
167
+ console.warn('The state singleton has been deprecated. Use the .prepareForSerialization() method on the workflow instance instead.');
168
+ State.delete(path);
169
+ return;
170
+ }
171
+
172
+ this.state.delete(path);
141
173
  }
142
174
  }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Provides a registry for callable functions to be used with persistence mode.
3
+ * This class allows you to register, retrieve, check for, and deregister callable functions by name.
4
+ */
5
+ export default class CallableRegistry {
6
+ #registry;
7
+
8
+ /**
9
+ * Registry for callable functions to be used with persistence mode.
10
+ */
11
+ constructor() {
12
+ this.clear();
13
+ }
14
+
15
+ /**
16
+ * Clears all callable entries from the registry.
17
+ */
18
+ clear() {
19
+ this.#registry = {};
20
+ }
21
+
22
+ /**
23
+ * Removes a callable from the registry.
24
+ * @param {string} name - The name of the callable to remove.
25
+ * @throws Will throw an error if no callable is registered under the given name.
26
+ */
27
+ deregister(name) {
28
+ if (!this.has(name)) {
29
+ throw new Error(`No callable registered under the name "${name}".`);
30
+ }
31
+
32
+ delete this.#registry[name];
33
+ }
34
+
35
+ /**
36
+ * Retrieves a callable from the registry.
37
+ * @param {string} name - The name of the callable to retrieve.
38
+ * @returns {Function} The callable function registered under the given name.
39
+ * @throws Will throw an error if no callable is registered under the given name.
40
+ */
41
+ get(name) {
42
+ if (!this.has(name)) {
43
+ throw new Error(`No callable registered under the name "${name}".`);
44
+ }
45
+
46
+ return this.#registry[name];
47
+ }
48
+
49
+ /**
50
+ * Checks if a callable is registered under the given name.
51
+ * @param {string} name - The name of the callable to check.
52
+ * @returns {boolean} True if a callable is registered under the given name, false otherwise.
53
+ */
54
+ has(name) {
55
+ return Object.hasOwn(this.#registry, name);
56
+ }
57
+
58
+ /**
59
+ * Registers a callable function under a given name.
60
+ * @param {string} name - The name to register the callable under.
61
+ * @param {Function} callable - The function to register as a callable.
62
+ * @throws Will throw an error if the provided callable is not a function.
63
+ */
64
+ register(name, callable) {
65
+ if (typeof callable !== 'function') {
66
+ throw new Error('Only functions can be registered as callables.');
67
+ }
68
+
69
+ this.#registry[name] = callable;
70
+ }
71
+
72
+ /**
73
+ * Registers multiple callables from an object mapping names to functions.
74
+ * @param {Object} callables - An object where keys are names and values are functions to register.
75
+ * @throws Will throw an error if any of the provided callables is not a function.
76
+ */
77
+ registerMany(callables) {
78
+ for (const [name, callable] of Object.entries(callables)) {
79
+ this.register(name, callable);
80
+ }
81
+ }
82
+ }
@@ -40,7 +40,7 @@ class Event extends EventTarget {
40
40
  */
41
41
  emit(event_name, data, bubbles = false, cancelable = true) {
42
42
  const seen = new WeakSet();
43
- const workingData = JSON.parse(JSON.stringify(data, (key, value) => {
43
+ const working_data = JSON.parse(JSON.stringify(data, (key, value) => {
44
44
  if (typeof value === 'object' && value !== null) {
45
45
  if (seen.has(value)) return undefined;
46
46
  seen.add(value);
@@ -49,7 +49,7 @@ class Event extends EventTarget {
49
49
  }));
50
50
 
51
51
  const custom_event = new CustomEvent(event_name, {
52
- detail: workingData,
52
+ detail: working_data,
53
53
  bubbles,
54
54
  cancelable
55
55
  });
@@ -57,7 +57,7 @@ class Event extends EventTarget {
57
57
 
58
58
  try {
59
59
  const channel = new BroadcastChannel(event_name);
60
- channel.postMessage(workingData);
60
+ channel.postMessage(working_data);
61
61
  channel.close();
62
62
  } catch (e) {
63
63
  console.warn(warnings.BROADCAST_FAILED, e);
@@ -1,5 +1,7 @@
1
1
  export * from './events/index.js';
2
2
  export { default as Base } from './base.js';
3
+ export { default as CallableRegistry } from './callable_registry.js';
3
4
  export { default as State } from './state.js';
5
+ export { InstanceState } from './instance_state.js';
4
6
  export { default as Workflow } from './workflow.js';
5
7
  export * from './steps/index.js';