@girverket/xenocline 0.0.9

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 (112) hide show
  1. package/LICENSE.md +66 -0
  2. package/README.md +739 -0
  3. package/dist/aggregator.d.ts +53 -0
  4. package/dist/aggregator.js +31 -0
  5. package/dist/aggregator.js.map +1 -0
  6. package/dist/constants.d.ts +2 -0
  7. package/dist/context.d.ts +3 -0
  8. package/dist/event/aggregator.d.ts +16 -0
  9. package/dist/event/aggregator.js +29 -0
  10. package/dist/event/aggregator.js.map +1 -0
  11. package/dist/event/event.d.ts +14 -0
  12. package/dist/event/event.js +12 -0
  13. package/dist/event/event.js.map +1 -0
  14. package/dist/event/handler.d.ts +7 -0
  15. package/dist/event/handler.js +8 -0
  16. package/dist/event/handler.js.map +1 -0
  17. package/dist/event/node.d.ts +40 -0
  18. package/dist/event/node.js +24 -0
  19. package/dist/event/node.js.map +1 -0
  20. package/dist/event/phase.d.ts +15 -0
  21. package/dist/event/phase.js +12 -0
  22. package/dist/event/phase.js.map +1 -0
  23. package/dist/event/process.d.ts +14 -0
  24. package/dist/event/process.js +15 -0
  25. package/dist/event/process.js.map +1 -0
  26. package/dist/event/transition.d.ts +45 -0
  27. package/dist/event/transition.js +35 -0
  28. package/dist/event/transition.js.map +1 -0
  29. package/dist/event.d.ts +30 -0
  30. package/dist/execution/aggregator.d.ts +23 -0
  31. package/dist/execution/aggregator.js +81 -0
  32. package/dist/execution/aggregator.js.map +1 -0
  33. package/dist/execution/event.d.ts +26 -0
  34. package/dist/execution/event.js +29 -0
  35. package/dist/execution/event.js.map +1 -0
  36. package/dist/execution/next.d.ts +7 -0
  37. package/dist/execution/next.js +137 -0
  38. package/dist/execution/next.js.map +1 -0
  39. package/dist/execution/node.d.ts +4 -0
  40. package/dist/execution/node.js +194 -0
  41. package/dist/execution/node.js.map +1 -0
  42. package/dist/execution/phase.d.ts +5 -0
  43. package/dist/execution/phase.js +23 -0
  44. package/dist/execution/phase.js.map +1 -0
  45. package/dist/execution/process.d.ts +35 -0
  46. package/dist/execution/process.js +115 -0
  47. package/dist/execution/process.js.map +1 -0
  48. package/dist/input.d.ts +6 -0
  49. package/dist/input.js +4 -0
  50. package/dist/input.js.map +1 -0
  51. package/dist/logger.d.ts +12 -0
  52. package/dist/node/aggregatornode.d.ts +40 -0
  53. package/dist/node/aggregatornode.js +41 -0
  54. package/dist/node/aggregatornode.js.map +1 -0
  55. package/dist/node/node.d.ts +18 -0
  56. package/dist/node/node.js +80 -0
  57. package/dist/node/node.js.map +1 -0
  58. package/dist/node/phasenode.d.ts +49 -0
  59. package/dist/node/phasenode.js +37 -0
  60. package/dist/node/phasenode.js.map +1 -0
  61. package/dist/output.d.ts +6 -0
  62. package/dist/phase.d.ts +23 -0
  63. package/dist/phase.js +24 -0
  64. package/dist/phase.js.map +1 -0
  65. package/dist/process.d.ts +15 -0
  66. package/dist/process.js +106 -0
  67. package/dist/process.js.map +1 -0
  68. package/dist/transition/beginning.d.ts +19 -0
  69. package/dist/transition/beginning.js +31 -0
  70. package/dist/transition/beginning.js.map +1 -0
  71. package/dist/transition/connection.d.ts +55 -0
  72. package/dist/transition/connection.js +90 -0
  73. package/dist/transition/connection.js.map +1 -0
  74. package/dist/transition/decision.d.ts +20 -0
  75. package/dist/transition/decision.js +47 -0
  76. package/dist/transition/decision.js.map +1 -0
  77. package/dist/transition/next.d.ts +13 -0
  78. package/dist/transition/next.js +81 -0
  79. package/dist/transition/next.js.map +1 -0
  80. package/dist/transition/termination.d.ts +17 -0
  81. package/dist/transition/termination.js +50 -0
  82. package/dist/transition/termination.js.map +1 -0
  83. package/dist/transition/transition.d.ts +16 -0
  84. package/dist/transition/transition.js +72 -0
  85. package/dist/transition/transition.js.map +1 -0
  86. package/dist/util/general.d.ts +4 -0
  87. package/dist/util/general.js +6 -0
  88. package/dist/util/general.js.map +1 -0
  89. package/dist/utility/event/eventfilter.d.ts +7 -0
  90. package/dist/utility/event/eventfilter.js +15 -0
  91. package/dist/utility/event/eventfilter.js.map +1 -0
  92. package/dist/utility/event/filteredhandler.d.ts +13 -0
  93. package/dist/utility/event/filteredhandler.js +18 -0
  94. package/dist/utility/event/filteredhandler.js.map +1 -0
  95. package/dist/utility/event/logginghandler.d.ts +12 -0
  96. package/dist/xenocline.cjs +1362 -0
  97. package/dist/xenocline.cjs.map +1 -0
  98. package/dist/xenocline.d.ts +72 -0
  99. package/dist/xenocline.js +21 -0
  100. package/dist/xenocline.js.map +1 -0
  101. package/output/kodrdriv/260109-2305-commit-message.md +3 -0
  102. package/output/kodrdriv/260109-2307-release-notes.md +28 -0
  103. package/output/kodrdriv/260109-2318-commit-message.md +6 -0
  104. package/output/kodrdriv/260109-2321-release-notes.md +39 -0
  105. package/output/kodrdriv/RELEASE_NOTES.md +37 -0
  106. package/output/kodrdriv/RELEASE_TITLE.md +1 -0
  107. package/output/kodrdriv/agentic-reflection-commit-2026-01-10T07-05-39-771Z.md +52 -0
  108. package/output/kodrdriv/agentic-reflection-commit-2026-01-10T07-18-31-315Z.md +55 -0
  109. package/output/kodrdriv/agentic-reflection-release-2026-01-10T07-07-33-739Z.md +257 -0
  110. package/output/kodrdriv/agentic-reflection-release-2026-01-10T07-21-54-717Z.md +394 -0
  111. package/package.json +69 -0
  112. package/scripts/pre-commit-hook.sh +53 -0
@@ -0,0 +1,115 @@
1
+ import { executeNode } from './node.js';
2
+ import { createAggregatorState } from './aggregator.js';
3
+ import { EMPTY_INPUT } from '../input.js';
4
+ import { validateProcess } from '../process.js';
5
+ import { clean } from '../util/general.js';
6
+ import { createProcessEvent } from '../event/process.js';
7
+ import { createBeginningEvent } from '../event/transition.js';
8
+ import { createEventState, dispatchEvent } from './event.js';
9
+
10
+ const DEFAULT_PROCESS_EXECUTION_OPTIONS = {
11
+ input: EMPTY_INPUT,
12
+ context: {},
13
+ eventHandlers: []
14
+ };
15
+ async function executeProcess(processInstance, beginning, options) {
16
+ const processExecutionOptions = {
17
+ ...DEFAULT_PROCESS_EXECUTION_OPTIONS,
18
+ ...clean(options || {})
19
+ };
20
+ if (options && options.input) {
21
+ processExecutionOptions.input = options.input;
22
+ }
23
+ if (options && options.eventHandlers) {
24
+ processExecutionOptions.eventHandlers = options.eventHandlers;
25
+ }
26
+ const validationErrors = validateProcess(processInstance);
27
+ if (validationErrors.length > 0) {
28
+ const errorMessages = validationErrors.map((err)=>err.error).join('\n');
29
+ throw new Error(`Invalid process definition:\n${errorMessages}`);
30
+ }
31
+ const eventState = createEventState(processExecutionOptions.eventHandlers);
32
+ const state = {
33
+ process: processInstance,
34
+ context: processExecutionOptions.context,
35
+ results: {},
36
+ phaseResults: {},
37
+ activeExecutions: new Map(),
38
+ errors: [],
39
+ ...createAggregatorState(),
40
+ eventState: eventState
41
+ };
42
+ dispatchEvent(state.eventState, createProcessEvent(processInstance.name, 'start', processInstance, {
43
+ input: processExecutionOptions.input,
44
+ context: state.context
45
+ }), state.context);
46
+ dispatchEvent(state.eventState, createBeginningEvent(beginning.id, 'start', beginning, {
47
+ input: processExecutionOptions.input
48
+ }), state.context);
49
+ const initialInput = await beginning.begin(processExecutionOptions.input, state.context);
50
+ dispatchEvent(state.eventState, createBeginningEvent(beginning.id, 'begin', beginning, {
51
+ input: initialInput
52
+ }), state.context);
53
+ const initialNodeId = beginning.targetNodeId;
54
+ if (!state.process.phases[initialNodeId]) {
55
+ throw new Error(`Start phase ID "${initialNodeId}" not found in process phases.`);
56
+ }
57
+ try {
58
+ await executeNode(initialNodeId, initialInput, state);
59
+ const allPromises = Array.from(state.activeExecutions.values());
60
+ if (allPromises.length > 0) {
61
+ await Promise.all(allPromises);
62
+ }
63
+ } catch (error) {
64
+ const errorMessage = error instanceof Error ? error.message : String(error);
65
+ state.errors.push({
66
+ message: "Critical error during process execution",
67
+ details: errorMessage,
68
+ nodeId: initialNodeId
69
+ });
70
+ // eslint-disable-next-line no-console
71
+ console.error("[EXECUTE_PROCESS_CRITICAL_ERROR]", {
72
+ processName: processInstance.name,
73
+ error: errorMessage,
74
+ collectedErrors: state.errors
75
+ });
76
+ }
77
+ // Check for and reject any pending aggregators that never completed
78
+ if (state.aggregatorDeferreds && state.aggregatorDeferreds.size > 0) {
79
+ const pendingNodeIds = state.pendingAggregatorIds ? state.pendingAggregatorIds().join(', ') : 'unknown';
80
+ // eslint-disable-next-line no-console
81
+ console.warn(`[EXECUTE_PROCESS_PENDING_AGGREGATORS] Process execution completed with pending aggregators: ${pendingNodeIds}. These will be rejected.`, {
82
+ processName: processInstance.name,
83
+ pendingNodeIds
84
+ });
85
+ // Reject all pending aggregators to prevent hanging promises
86
+ for (const nodeId of state.aggregatorDeferreds.keys()){
87
+ const deferred = state.aggregatorDeferreds.get(nodeId);
88
+ if (deferred) {
89
+ const error = new Error(`Aggregator node '${nodeId}' did not receive all expected inputs before process completion. This may indicate a process design issue where not all paths leading to the aggregator were executed.`);
90
+ deferred.reject(error);
91
+ state.errors.push({
92
+ nodeId,
93
+ message: error.message,
94
+ details: {
95
+ reason: 'incomplete_aggregation'
96
+ }
97
+ });
98
+ }
99
+ }
100
+ // Clear the map after rejecting all
101
+ state.aggregatorDeferreds.clear();
102
+ }
103
+ dispatchEvent(state.eventState, createProcessEvent(processInstance.name, 'end', processInstance, {
104
+ input: processExecutionOptions.input,
105
+ context: state.context
106
+ }), state.context);
107
+ return [
108
+ state.results,
109
+ state.phaseResults,
110
+ state.context
111
+ ];
112
+ }
113
+
114
+ export { DEFAULT_PROCESS_EXECUTION_OPTIONS, executeProcess };
115
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sources":["../../src/execution/process.ts"],"sourcesContent":["import { executeNode } from './node';\nimport { Context } from '../context';\nimport {\n AggregatorState,\n createAggregatorState\n} from './aggregator';\nimport { EMPTY_INPUT, Input } from '../input';\nimport { Output } from '../output';\nimport { Process, validateProcess } from '../process';\nimport { Beginning } from '../transition/beginning';\nimport { clean } from '../util/general';\nimport { Event, EventHandler, EventState, createBeginningEvent, createEventState, createProcessEvent } from '../event';\nimport { dispatchEvent } from './event';\n\nexport interface PhaseResults {\n [key: string]: Output;\n}\n\nexport interface ProcessResults {\n [key: string]: Output;\n}\n\ninterface ProcessExecutionError {\n message: string;\n details?: any;\n nodeId?: string;\n}\n\nexport interface ProcessExecutionOptions<I extends Input = Input, C extends Context = Context> {\n input: I;\n context: C;\n eventHandlers?: ReadonlyArray<EventHandler<Event, C>>;\n}\n\nexport const DEFAULT_PROCESS_EXECUTION_OPTIONS: ProcessExecutionOptions<Input, Context> = {\n input: EMPTY_INPUT,\n context: {} as Context,\n eventHandlers: [],\n}\n\nexport interface ExecutionState<C extends Context = Context> extends AggregatorState {\n process: Readonly<Process>;\n context: C;\n phaseResults: Record<string, Output>;\n results: Record<string, Output>;\n activeExecutions: Map<string, Promise<Output>>;\n errors: ProcessExecutionError[];\n readonly eventState: Readonly<EventState<C>>;\n}\n\nexport async function executeProcess<I extends Input = Input, O extends Output = Output, C extends Context = Context>(\n processInstance: Readonly<Process>,\n beginning: Beginning<I, C>,\n options?: Partial<ProcessExecutionOptions<I, C>>\n): Promise<[Record<string, O>, Record<string, O>, C]> {\n\n const processExecutionOptions: ProcessExecutionOptions<I, C> = {\n ...(DEFAULT_PROCESS_EXECUTION_OPTIONS as unknown as ProcessExecutionOptions<I, C>),\n ...clean(options || {}),\n };\n if (options && options.input) {\n processExecutionOptions.input = options.input;\n }\n if (options && options.eventHandlers) {\n processExecutionOptions.eventHandlers = options.eventHandlers;\n }\n\n const validationErrors = validateProcess(processInstance);\n if (validationErrors.length > 0) {\n const errorMessages = validationErrors.map(err => err.error).join('\\n');\n throw new Error(`Invalid process definition:\\n${errorMessages}`);\n }\n\n const eventState = createEventState<C>(processExecutionOptions.eventHandlers);\n\n const state: ExecutionState<C> = {\n process: processInstance,\n context: processExecutionOptions.context as C,\n results: {},\n phaseResults: {},\n activeExecutions: new Map<string, Promise<Output>>(),\n errors: [],\n ...createAggregatorState(),\n eventState: eventState,\n };\n\n dispatchEvent(\n state.eventState,\n createProcessEvent(processInstance.name, 'start', processInstance, { input: processExecutionOptions.input, context: state.context }),\n state.context\n );\n\n dispatchEvent(\n state.eventState,\n createBeginningEvent(beginning.id, 'start', beginning as Beginning<I, C>, { input: processExecutionOptions.input }),\n state.context\n );\n\n const initialInput = await beginning.begin(processExecutionOptions.input, state.context);\n dispatchEvent(\n state.eventState,\n createBeginningEvent(beginning.id, 'begin', beginning as Beginning<I, C>, { input: initialInput }),\n state.context\n );\n\n const initialNodeId = beginning.targetNodeId;\n\n if (!state.process.phases[initialNodeId]) {\n throw new Error(`Start phase ID \"${initialNodeId}\" not found in process phases.`);\n }\n\n try {\n await executeNode(initialNodeId, initialInput, state as unknown as ExecutionState<Context>);\n\n const allPromises = Array.from(state.activeExecutions.values());\n if (allPromises.length > 0) {\n await Promise.all(allPromises);\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n state.errors.push({ message: \"Critical error during process execution\", details: errorMessage, nodeId: initialNodeId });\n // eslint-disable-next-line no-console\n console.error(\"[EXECUTE_PROCESS_CRITICAL_ERROR]\", { processName: processInstance.name, error: errorMessage, collectedErrors: state.errors });\n }\n\n // Check for and reject any pending aggregators that never completed\n if (state.aggregatorDeferreds && state.aggregatorDeferreds.size > 0) {\n const pendingNodeIds = state.pendingAggregatorIds ? state.pendingAggregatorIds().join(', ') : 'unknown';\n // eslint-disable-next-line no-console\n console.warn(`[EXECUTE_PROCESS_PENDING_AGGREGATORS] Process execution completed with pending aggregators: ${pendingNodeIds}. These will be rejected.`, { processName: processInstance.name, pendingNodeIds });\n\n // Reject all pending aggregators to prevent hanging promises\n for (const nodeId of state.aggregatorDeferreds.keys()) {\n const deferred = state.aggregatorDeferreds.get(nodeId);\n if (deferred) {\n const error = new Error(`Aggregator node '${nodeId}' did not receive all expected inputs before process completion. This may indicate a process design issue where not all paths leading to the aggregator were executed.`);\n deferred.reject(error);\n state.errors.push({\n nodeId,\n message: error.message,\n details: { reason: 'incomplete_aggregation' }\n });\n }\n }\n // Clear the map after rejecting all\n state.aggregatorDeferreds.clear();\n }\n\n dispatchEvent(\n state.eventState,\n createProcessEvent(processInstance.name, 'end', processInstance, { input: processExecutionOptions.input, context: state.context }),\n state.context\n );\n\n return [state.results as Record<string, O>, state.phaseResults as Record<string, O>, state.context];\n}\n\n\n"],"names":["DEFAULT_PROCESS_EXECUTION_OPTIONS","input","EMPTY_INPUT","context","eventHandlers","executeProcess","processInstance","beginning","options","processExecutionOptions","clean","validationErrors","validateProcess","length","errorMessages","map","err","error","join","Error","eventState","createEventState","state","process","results","phaseResults","activeExecutions","Map","errors","createAggregatorState","dispatchEvent","createProcessEvent","name","createBeginningEvent","id","initialInput","begin","initialNodeId","targetNodeId","phases","executeNode","allPromises","Array","from","values","Promise","all","errorMessage","message","String","push","details","nodeId","console","processName","collectedErrors","aggregatorDeferreds","size","pendingNodeIds","pendingAggregatorIds","warn","keys","deferred","get","reject","reason","clear"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface Input {
2
+ [key: string]: unknown;
3
+ }
4
+ export declare const EMPTY_INPUT: Input;
5
+ export declare const isInput: (input: unknown) => input is Input;
6
+ export declare const validateInput: (input: unknown) => input is Input;
package/dist/input.js ADDED
@@ -0,0 +1,4 @@
1
+ const EMPTY_INPUT = {};
2
+
3
+ export { EMPTY_INPUT };
4
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sources":["../src/input.ts"],"sourcesContent":["export interface Input {\n [key: string]: unknown;\n}\n\nexport const EMPTY_INPUT: Input = {};\n\nexport const isInput = (input: unknown): input is Input => {\n return typeof input === 'object' && input !== null && !Array.isArray(input);\n};\n\nexport const validateInput = (input: unknown): input is Input => {\n if (!isInput(input)) {\n throw new Error('Input must be an object');\n }\n return true;\n};\n"],"names":["EMPTY_INPUT"],"mappings":"AAIO,MAAMA,WAAAA,GAAqB;;;;"}
@@ -0,0 +1,12 @@
1
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'verbose' | 'silly';
2
+ export interface Logger {
3
+ name: string;
4
+ debug: (message: string, ...args: any[]) => void;
5
+ info: (message: string, ...args: any[]) => void;
6
+ warn: (message: string, ...args: any[]) => void;
7
+ error: (message: string, ...args: any[]) => void;
8
+ verbose: (message: string, ...args: any[]) => void;
9
+ silly: (message: string, ...args: any[]) => void;
10
+ }
11
+ export declare const DEFAULT_LOGGER: Logger;
12
+ export declare const wrapLogger: (toWrap: Logger, name?: string) => Logger;
@@ -0,0 +1,40 @@
1
+ import { Aggregator } from '../aggregator';
2
+ import { Next } from '../transition/next';
3
+ import { Context } from '../context';
4
+ import { Output } from '../output';
5
+ import { Node } from './node';
6
+ /**
7
+ * Represents a node in the process that aggregates multiple inputs of type IA
8
+ * into a single output of type O.
9
+ *
10
+ * @template O - The type of the output produced by this node's aggregate function. Must extend Output.
11
+ * @template C - The type of the context object passed to the aggregate function. Must extend Context.
12
+ */
13
+ export interface AggregatorNode<O extends Output = Output, // Output from the aggregate function
14
+ C extends Context = Context> extends Node<O, C> {
15
+ type: 'aggregator';
16
+ /**
17
+ * The core aggregation logic for this node.
18
+ * It takes an array of input items and a context, and returns a Promise resolving to the aggregated output.
19
+ * @param input - An input item of type Input.
20
+ * @param context - The context object.
21
+ * @returns A Promise that resolves to the aggregated output of type O.
22
+ */
23
+ aggregator: Aggregator<O, C>;
24
+ }
25
+ export interface AggregatorNodeOptions<O extends Output = Output, C extends Context = Context> {
26
+ next?: Next<O, C>;
27
+ }
28
+ export declare const DEFAULT_AGGREGATOR_NODE_OPTIONS: AggregatorNodeOptions<Output, Context>;
29
+ export declare const createAggregatorNode: <O extends Output = Output, C extends Context = Context>(id: string, aggregator: Aggregator<O, C>, options?: Partial<AggregatorNodeOptions<O, C>>) => Readonly<AggregatorNode<O, C>>;
30
+ /**
31
+ * Type guard to check if an object is an AggregatorNode.
32
+ *
33
+ * @param obj - The object to check.
34
+ * @returns True if the object is an AggregatorNode, false otherwise.
35
+ */
36
+ export declare const isAggregatorNode: (obj: any) => obj is AggregatorNode<any, any>;
37
+ export declare const validateAggregatorNode: (item: any, coordinates?: string[]) => Array<{
38
+ coordinates: string[];
39
+ error: string;
40
+ }>;
@@ -0,0 +1,41 @@
1
+ import { clean } from '../util/general.js';
2
+ import { createNode, isNode } from './node.js';
3
+
4
+ const DEFAULT_AGGREGATOR_NODE_OPTIONS = {};
5
+ const createAggregatorNode = (id, aggregator, options)=>{
6
+ let aggregatorNodeOptions = {
7
+ ...DEFAULT_AGGREGATOR_NODE_OPTIONS
8
+ };
9
+ if (options) {
10
+ aggregatorNodeOptions = {
11
+ ...aggregatorNodeOptions,
12
+ ...clean(options)
13
+ };
14
+ }
15
+ return {
16
+ ...createNode('aggregator', id, {
17
+ next: aggregatorNodeOptions.next
18
+ }),
19
+ aggregator
20
+ };
21
+ };
22
+ /**
23
+ * Type guard to check if an object is an AggregatorNode.
24
+ *
25
+ * @param obj - The object to check.
26
+ * @returns True if the object is an AggregatorNode, false otherwise.
27
+ */ const isAggregatorNode = (obj)=>{
28
+ if (!isNode(obj) || obj.type !== 'aggregator') {
29
+ return false;
30
+ }
31
+ // At this point, obj is a Node with type 'aggregator'.
32
+ // Now check for AggregatorNode specific properties.
33
+ const potentialAggNode = obj; // Cast to access specific props
34
+ if (!(typeof potentialAggNode.aggregator === 'object' && potentialAggNode.aggregator !== null && typeof potentialAggNode.aggregator.aggregate === 'function')) {
35
+ return false;
36
+ }
37
+ return true; // Not Termination and not a recognized array type for 'next'
38
+ };
39
+
40
+ export { DEFAULT_AGGREGATOR_NODE_OPTIONS, createAggregatorNode, isAggregatorNode };
41
+ //# sourceMappingURL=aggregatornode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregatornode.js","sources":["../../src/node/aggregatornode.ts"],"sourcesContent":["import { Aggregator, validateAggregator } from '../aggregator';\nimport { Next } from '../transition/next';\nimport { Context } from '../context';\nimport { Output } from '../output';\nimport { createNode, isNode, Node, validateNode } from './node';\nimport { clean } from '../util/general';\n\n/**\n * Represents a node in the process that aggregates multiple inputs of type IA\n * into a single output of type O.\n *\n * @template O - The type of the output produced by this node's aggregate function. Must extend Output.\n * @template C - The type of the context object passed to the aggregate function. Must extend Context.\n */\nexport interface AggregatorNode<\n O extends Output = Output, // Output from the aggregate function\n C extends Context = Context, // Context object\n> extends Node<O, C> { // MODIFIED: Extends Node\n type: 'aggregator'; // Overrides Node.type\n // id: string; // Unique identifier for this aggregator node within the process - inherited from Node\n\n /**\n * The core aggregation logic for this node.\n * It takes an array of input items and a context, and returns a Promise resolving to the aggregated output.\n * @param input - An input item of type Input.\n * @param context - The context object.\n * @returns A Promise that resolves to the aggregated output of type O.\n */\n aggregator: Aggregator<O, C>;\n}\n\nexport interface AggregatorNodeOptions<O extends Output = Output, C extends Context = Context> {\n next?: Next<O, C>;\n}\n\nexport const DEFAULT_AGGREGATOR_NODE_OPTIONS: AggregatorNodeOptions<Output, Context> = {\n}\n\nexport const createAggregatorNode = <O extends Output = Output, C extends Context = Context>(\n id: string,\n aggregator: Aggregator<O, C>,\n options?: Partial<AggregatorNodeOptions<O, C>>\n): Readonly<AggregatorNode<O, C>> => {\n let aggregatorNodeOptions: AggregatorNodeOptions<O, C> = { ...DEFAULT_AGGREGATOR_NODE_OPTIONS } as unknown as AggregatorNodeOptions<O, C>;\n if (options) {\n aggregatorNodeOptions = { ...aggregatorNodeOptions, ...clean(options) };\n }\n\n return {\n ...createNode('aggregator', id, { next: aggregatorNodeOptions.next }),\n aggregator,\n } as AggregatorNode<O, C>;\n};\n\n\n/**\n * Type guard to check if an object is an AggregatorNode.\n *\n * @param obj - The object to check.\n * @returns True if the object is an AggregatorNode, false otherwise.\n */\nexport const isAggregatorNode = (obj: any): obj is AggregatorNode<any, any> => {\n if (!isNode(obj) || obj.type !== 'aggregator') {\n return false;\n }\n\n // At this point, obj is a Node with type 'aggregator'.\n // Now check for AggregatorNode specific properties.\n const potentialAggNode = obj as AggregatorNode<any, any>; // Cast to access specific props\n\n if (!(\n typeof potentialAggNode.aggregator === 'object' && potentialAggNode.aggregator !== null && typeof potentialAggNode.aggregator.aggregate === 'function'\n )) {\n return false;\n }\n\n return true; // Not Termination and not a recognized array type for 'next'\n};\n\nexport const validateAggregatorNode = (item: any, coordinates?: string[]): Array<{ coordinates: string[], error: string }> => {\n const errors: Array<{ coordinates: string[], error: string }> = [];\n const currentCoordinates = [...(coordinates || []), 'AggregatorNode'];\n\n errors.push(...validateNode(item, currentCoordinates));\n\n currentCoordinates.push(`AggregatorNode: ${item.id}`);\n\n if (item.aggregator === undefined) {\n errors.push({ coordinates: [...currentCoordinates], error: 'aggregator is undefined.' });\n } else {\n errors.push(...validateAggregator(item.aggregator, currentCoordinates));\n }\n\n return errors;\n};"],"names":["DEFAULT_AGGREGATOR_NODE_OPTIONS","createAggregatorNode","id","aggregator","options","aggregatorNodeOptions","clean","createNode","next","isAggregatorNode","obj","isNode","type","potentialAggNode","aggregate"],"mappings":";;;AAmCO,MAAMA,+BAAAA,GAA0E;AAGhF,MAAMC,oBAAAA,GAAuB,CAChCC,EAAAA,EACAC,UAAAA,EACAC,OAAAA,GAAAA;AAEA,IAAA,IAAIC,qBAAAA,GAAqD;AAAE,QAAA,GAAGL;AAAgC,KAAA;AAC9F,IAAA,IAAII,OAAAA,EAAS;QACTC,qBAAAA,GAAwB;AAAE,YAAA,GAAGA,qBAAqB;AAAE,YAAA,GAAGC,MAAMF,OAAAA;AAAS,SAAA;AAC1E,IAAA;IAEA,OAAO;QACH,GAAGG,UAAAA,CAAW,cAAcL,EAAAA,EAAI;AAAEM,YAAAA,IAAAA,EAAMH,sBAAsBG;SAAK,CAAE;AACrEL,QAAAA;AACJ,KAAA;AACJ;AAGA;;;;;IAMO,MAAMM,gBAAAA,GAAmB,CAACC,GAAAA,GAAAA;AAC7B,IAAA,IAAI,CAACC,MAAAA,CAAOD,GAAAA,CAAAA,IAAQA,GAAAA,CAAIE,IAAI,KAAK,YAAA,EAAc;QAC3C,OAAO,KAAA;AACX,IAAA;;;IAIA,MAAMC,gBAAAA,GAAmBH;AAEzB,IAAA,IAAI,EACA,OAAOG,iBAAiBV,UAAU,KAAK,YAAYU,gBAAAA,CAAiBV,UAAU,KAAK,IAAA,IAAQ,OAAOU,gBAAAA,CAAiBV,UAAU,CAACW,SAAS,KAAK,UAAS,CAAA,EACtJ;QACC,OAAO,KAAA;AACX,IAAA;AAEA,IAAA,OAAO;AACX;;;;"}
@@ -0,0 +1,18 @@
1
+ import { Context } from '../context';
2
+ import { Output } from '../output';
3
+ import { Next } from '../transition/next';
4
+ export interface Node<O extends Output = Output, C extends Context = Context> {
5
+ id: string;
6
+ type: 'aggregator' | 'phase';
7
+ next?: Next<O, C>;
8
+ }
9
+ export interface NodeOptions<O extends Output = Output, C extends Context = Context> {
10
+ next?: Next<O, C>;
11
+ }
12
+ export declare const DEFAULT_NODE_OPTIONS: NodeOptions<Output, Context>;
13
+ export declare const createNode: <O extends Output = Output, C extends Context = Context>(type: "aggregator" | "phase", id: string, options?: Partial<NodeOptions<O, C>>) => Readonly<Node<O, C>>;
14
+ export declare const isNode: (item: any) => item is Node;
15
+ export declare const validateNode: (item: any, coordinates?: string[]) => Array<{
16
+ coordinates: string[];
17
+ error: string;
18
+ }>;
@@ -0,0 +1,80 @@
1
+ import { clean } from '../util/general.js';
2
+ import { validateNext, isNext } from '../transition/next.js';
3
+
4
+ const DEFAULT_NODE_OPTIONS = {};
5
+ const createNode = (type, id, options)=>{
6
+ let nodeOptions = {
7
+ ...DEFAULT_NODE_OPTIONS
8
+ };
9
+ if (options) {
10
+ nodeOptions = {
11
+ ...nodeOptions,
12
+ ...clean(options)
13
+ };
14
+ }
15
+ return {
16
+ id,
17
+ type,
18
+ next: nodeOptions.next
19
+ };
20
+ };
21
+ const isNode = (item)=>{
22
+ return item !== null && typeof item === 'object' && typeof item.id === 'string' && (item.type === 'aggregator' || item.type === 'phase') && (item.next === undefined || isNext(item.next));
23
+ };
24
+ const validateNode = (item, coordinates)=>{
25
+ const errors = [];
26
+ const currentCoordinates = [
27
+ ...coordinates || [],
28
+ 'Node'
29
+ ];
30
+ if (item === undefined || item === null) {
31
+ errors.push({
32
+ coordinates: [
33
+ ...currentCoordinates
34
+ ],
35
+ error: 'Node is undefined or null.'
36
+ });
37
+ return errors;
38
+ }
39
+ if (typeof item !== 'object') {
40
+ errors.push({
41
+ coordinates: [
42
+ ...currentCoordinates
43
+ ],
44
+ error: 'Node is not an object.'
45
+ });
46
+ return errors;
47
+ }
48
+ if (item.id === undefined || typeof item.id !== 'string') {
49
+ errors.push({
50
+ coordinates: [
51
+ ...currentCoordinates
52
+ ],
53
+ error: 'Node id is undefined or not a string.'
54
+ });
55
+ }
56
+ if (item.type === undefined || typeof item.type !== 'string') {
57
+ errors.push({
58
+ coordinates: [
59
+ ...currentCoordinates
60
+ ],
61
+ error: 'Node type is undefined or not a string.'
62
+ });
63
+ }
64
+ if (item.type !== 'aggregator' && item.type !== 'phase') {
65
+ errors.push({
66
+ coordinates: [
67
+ ...currentCoordinates
68
+ ],
69
+ error: 'Node type is not a valid type.'
70
+ });
71
+ }
72
+ currentCoordinates.push(`Node: ${item.id}`);
73
+ if (item.next !== undefined) {
74
+ errors.push(...validateNext(item.next, currentCoordinates));
75
+ }
76
+ return errors;
77
+ };
78
+
79
+ export { DEFAULT_NODE_OPTIONS, createNode, isNode, validateNode };
80
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sources":["../../src/node/node.ts"],"sourcesContent":["import { clean } from \"../util/general\";\nimport { Context } from \"../context\";\nimport { Output } from \"../output\";\nimport { isNext, Next, validateNext } from \"../transition/next\";\n\nexport interface Node<O extends Output = Output, C extends Context = Context> {\n id: string;\n type: 'aggregator' | 'phase';\n\n // The next step can be a direct termination, a list of connections, or a list of decisions,\n // all based on the output O of this aggregator node. Note that next can be undefined, when that happens \n // a termination transition is assumed.\n next?: Next<O, C>;\n}\n\nexport interface NodeOptions<O extends Output = Output, C extends Context = Context> {\n next?: Next<O, C>;\n}\n\nexport const DEFAULT_NODE_OPTIONS: NodeOptions<Output, Context> = {\n}\n\nexport const createNode = <O extends Output = Output, C extends Context = Context>(type: 'aggregator' | 'phase', id: string, options?: Partial<NodeOptions<O, C>>): Readonly<Node<O, C>> => {\n let nodeOptions: NodeOptions<O, C> = { ...DEFAULT_NODE_OPTIONS } as unknown as NodeOptions<O, C>;\n if (options) {\n nodeOptions = { ...nodeOptions, ...clean(options) };\n }\n\n return {\n id,\n type,\n next: nodeOptions.next,\n };\n};\n\nexport const isNode = (item: any): item is Node => {\n return item !== null && typeof item === 'object' && typeof item.id === 'string' && (item.type === 'aggregator' || item.type === 'phase') && (item.next === undefined || isNext(item.next));\n};\n\nexport const validateNode = (item: any, coordinates?: string[]): Array<{ coordinates: string[], error: string }> => {\n const errors: Array<{ coordinates: string[], error: string }> = [];\n const currentCoordinates = [...(coordinates || []), 'Node'];\n\n\n if (item === undefined || item === null) {\n errors.push({ coordinates: [...currentCoordinates], error: 'Node is undefined or null.' });\n return errors;\n }\n\n if (typeof item !== 'object') {\n errors.push({ coordinates: [...currentCoordinates], error: 'Node is not an object.' });\n return errors;\n }\n\n if (item.id === undefined || typeof item.id !== 'string') {\n errors.push({ coordinates: [...currentCoordinates], error: 'Node id is undefined or not a string.' });\n }\n\n if (item.type === undefined || typeof item.type !== 'string') {\n errors.push({ coordinates: [...currentCoordinates], error: 'Node type is undefined or not a string.' });\n }\n\n if (item.type !== 'aggregator' && item.type !== 'phase') {\n errors.push({ coordinates: [...currentCoordinates], error: 'Node type is not a valid type.' });\n }\n\n currentCoordinates.push(`Node: ${item.id}`);\n\n if (item.next !== undefined) {\n errors.push(...validateNext(item.next, currentCoordinates));\n }\n\n return errors;\n}"],"names":["DEFAULT_NODE_OPTIONS","createNode","type","id","options","nodeOptions","clean","next","isNode","item","undefined","isNext","validateNode","coordinates","errors","currentCoordinates","push","error","validateNext"],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { Next } from '../transition/next';
2
+ import { Context } from '../context';
3
+ import { Input } from '../input';
4
+ import { Output } from '../output';
5
+ import { Phase } from '../phase';
6
+ import { Node } from './node';
7
+ export type ProcessMethod<O extends Output = Output, C extends Context = Context> = (output: O, context: C) => Promise<[O, C]>;
8
+ export type PrepareMethod<I extends Input = Input, C extends Context = Context> = (input: I, context: C) => Promise<[I, C]>;
9
+ export interface PhaseNode<I extends Input = Input, // Input to this phase instance
10
+ O extends Output = Output> extends Node {
11
+ type: 'phase';
12
+ phase: Phase<I, O>;
13
+ /**
14
+ * The prepare method is called before the phase is executed.
15
+ * It receives the input and current context, and returns both (potentially modified).
16
+ * The returned context replaces the process context.
17
+ *
18
+ * CONCURRENCY WARNING: In processes with parallel execution paths (fan-out),
19
+ * multiple nodes may execute simultaneously. Each node's prepare method receives
20
+ * the shared context and can modify it. These modifications happen sequentially
21
+ * within each node but parallel nodes may overwrite each other's context changes.
22
+ *
23
+ * Best practice: Use unique context keys per node/path to avoid conflicts,
24
+ * or ensure context modifications are idempotent and merge-safe.
25
+ */
26
+ prepare?: PrepareMethod;
27
+ /**
28
+ * The process method is called after the phase is executed, but before the next node is executed.
29
+ * It receives the phase output and current context, and returns both (potentially modified).
30
+ * The returned context replaces the process context.
31
+ *
32
+ * CONCURRENCY WARNING: Same as prepare - parallel execution paths may cause
33
+ * context mutations to overwrite each other. Design your context updates carefully
34
+ * when using fan-out patterns.
35
+ */
36
+ process?: ProcessMethod;
37
+ }
38
+ export interface PhaseNodeOptions<I extends Input = Input, O extends Output = Output, C extends Context = Context> {
39
+ next?: Next<O, C>;
40
+ prepare?: PrepareMethod<I, C>;
41
+ process?: ProcessMethod<O, C>;
42
+ }
43
+ export declare const DEFAULT_PHASE_NODE_OPTIONS: PhaseNodeOptions<Input, Output, Context>;
44
+ export declare const createPhaseNode: <I extends Input = Input, O extends Output = Output, C extends Context = Context>(id: string, phase: Phase<I, O>, options?: Partial<PhaseNodeOptions<I, O, C>>) => Readonly<PhaseNode<I, O>>;
45
+ export declare const isPhaseNode: (obj: any) => obj is PhaseNode<any, any>;
46
+ export declare const validatePhaseNode: (item: any, coordinates?: string[]) => Array<{
47
+ coordinates: string[];
48
+ error: string;
49
+ }>;
@@ -0,0 +1,37 @@
1
+ import { isPhase } from '../phase.js';
2
+ import { createNode, isNode } from './node.js';
3
+ import { clean } from '../util/general.js';
4
+
5
+ const DEFAULT_PHASE_NODE_OPTIONS = {};
6
+ const createPhaseNode = (id, phase, options)=>{
7
+ let phaseNodeOptions = {
8
+ ...DEFAULT_PHASE_NODE_OPTIONS
9
+ };
10
+ if (options) {
11
+ phaseNodeOptions = {
12
+ ...phaseNodeOptions,
13
+ ...clean(options)
14
+ };
15
+ }
16
+ return {
17
+ ...createNode('phase', id, {
18
+ next: phaseNodeOptions.next
19
+ }),
20
+ phase,
21
+ prepare: phaseNodeOptions.prepare,
22
+ process: phaseNodeOptions.process
23
+ };
24
+ };
25
+ const isPhaseNode = (obj)=>{
26
+ if (!isNode(obj) || obj.type !== 'phase') {
27
+ return false;
28
+ }
29
+ const potentialPhaseNode = obj;
30
+ if (!(potentialPhaseNode.phase && typeof potentialPhaseNode.phase === 'object' && isPhase(potentialPhaseNode.phase))) {
31
+ return false;
32
+ }
33
+ return true;
34
+ };
35
+
36
+ export { DEFAULT_PHASE_NODE_OPTIONS, createPhaseNode, isPhaseNode };
37
+ //# sourceMappingURL=phasenode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phasenode.js","sources":["../../src/node/phasenode.ts"],"sourcesContent":["import { Next } from '../transition/next';\nimport { Context } from '../context';\nimport { Input } from '../input';\nimport { Output } from '../output';\nimport { isPhase, Phase, validatePhase } from '../phase';\nimport { createNode, isNode, Node, validateNode } from './node';\nimport { clean } from '../util/general';\n\nexport type ProcessMethod<O extends Output = Output, C extends Context = Context> = (output: O, context: C) => Promise<[O, C]>;\nexport type PrepareMethod<I extends Input = Input, C extends Context = Context> = (input: I, context: C) => Promise<[I, C]>;\n\nexport interface PhaseNode<\n I extends Input = Input, // Input to this phase instance\n O extends Output = Output, // Output from this phase instance\n> extends Node {\n type: 'phase';\n phase: Phase<I, O>; // The actual phase instance\n\n /**\n * The prepare method is called before the phase is executed.\n * It receives the input and current context, and returns both (potentially modified).\n * The returned context replaces the process context.\n *\n * CONCURRENCY WARNING: In processes with parallel execution paths (fan-out),\n * multiple nodes may execute simultaneously. Each node's prepare method receives\n * the shared context and can modify it. These modifications happen sequentially\n * within each node but parallel nodes may overwrite each other's context changes.\n *\n * Best practice: Use unique context keys per node/path to avoid conflicts,\n * or ensure context modifications are idempotent and merge-safe.\n */\n prepare?: PrepareMethod;\n\n /**\n * The process method is called after the phase is executed, but before the next node is executed.\n * It receives the phase output and current context, and returns both (potentially modified).\n * The returned context replaces the process context.\n *\n * CONCURRENCY WARNING: Same as prepare - parallel execution paths may cause\n * context mutations to overwrite each other. Design your context updates carefully\n * when using fan-out patterns.\n */\n process?: ProcessMethod;\n}\n\nexport interface PhaseNodeOptions<I extends Input = Input, O extends Output = Output, C extends Context = Context> {\n next?: Next<O, C>;\n prepare?: PrepareMethod<I, C>;\n process?: ProcessMethod<O, C>;\n}\n\nexport const DEFAULT_PHASE_NODE_OPTIONS: PhaseNodeOptions<Input, Output, Context> = {\n}\n\nexport const createPhaseNode = <I extends Input = Input, O extends Output = Output, C extends Context = Context>(\n id: string,\n phase: Phase<I, O>,\n options?: Partial<PhaseNodeOptions<I, O, C>>\n): Readonly<PhaseNode<I, O>> => {\n let phaseNodeOptions: PhaseNodeOptions<I, O, C> = { ...DEFAULT_PHASE_NODE_OPTIONS } as unknown as PhaseNodeOptions<I, O, C>;\n if (options) {\n phaseNodeOptions = { ...phaseNodeOptions, ...clean(options) };\n }\n\n return {\n ...createNode('phase', id, { next: phaseNodeOptions.next }),\n phase,\n prepare: phaseNodeOptions.prepare,\n process: phaseNodeOptions.process,\n } as PhaseNode<I, O>;\n};\n\nexport const isPhaseNode = (obj: any): obj is PhaseNode<any, any> => {\n if (!isNode(obj) || obj.type !== 'phase') {\n return false;\n }\n const potentialPhaseNode = obj as PhaseNode<any, any>;\n\n if (!(\n potentialPhaseNode.phase && typeof potentialPhaseNode.phase === 'object' && isPhase(potentialPhaseNode.phase)\n )) {\n return false;\n }\n\n return true;\n};\n\nexport const validatePhaseNode = (item: any, coordinates?: string[]): Array<{ coordinates: string[], error: string }> => {\n const errors: Array<{ coordinates: string[], error: string }> = [];\n const currentCoordinates = [...(coordinates || []), 'PhaseNode'];\n\n errors.push(...validateNode(item, currentCoordinates));\n\n currentCoordinates.push(`PhaseNode: ${item.id}`);\n\n if (item.phase === undefined) {\n errors.push({ coordinates: [...currentCoordinates], error: 'phase is undefined.' });\n } else {\n errors.push(...validatePhase(item.phase, currentCoordinates));\n }\n\n return errors;\n};\n"],"names":["DEFAULT_PHASE_NODE_OPTIONS","createPhaseNode","id","phase","options","phaseNodeOptions","clean","createNode","next","prepare","process","isPhaseNode","obj","isNode","type","potentialPhaseNode","isPhase"],"mappings":";;;;AAmDO,MAAMA,0BAAAA,GAAuE;AAG7E,MAAMC,eAAAA,GAAkB,CAC3BC,EAAAA,EACAC,KAAAA,EACAC,OAAAA,GAAAA;AAEA,IAAA,IAAIC,gBAAAA,GAA8C;AAAE,QAAA,GAAGL;AAA2B,KAAA;AAClF,IAAA,IAAII,OAAAA,EAAS;QACTC,gBAAAA,GAAmB;AAAE,YAAA,GAAGA,gBAAgB;AAAE,YAAA,GAAGC,MAAMF,OAAAA;AAAS,SAAA;AAChE,IAAA;IAEA,OAAO;QACH,GAAGG,UAAAA,CAAW,SAASL,EAAAA,EAAI;AAAEM,YAAAA,IAAAA,EAAMH,iBAAiBG;SAAK,CAAE;AAC3DL,QAAAA,KAAAA;AACAM,QAAAA,OAAAA,EAASJ,iBAAiBI,OAAO;AACjCC,QAAAA,OAAAA,EAASL,iBAAiBK;AAC9B,KAAA;AACJ;AAEO,MAAMC,cAAc,CAACC,GAAAA,GAAAA;AACxB,IAAA,IAAI,CAACC,MAAAA,CAAOD,GAAAA,CAAAA,IAAQA,GAAAA,CAAIE,IAAI,KAAK,OAAA,EAAS;QACtC,OAAO,KAAA;AACX,IAAA;AACA,IAAA,MAAMC,kBAAAA,GAAqBH,GAAAA;AAE3B,IAAA,IAAI,EACAG,kBAAAA,CAAmBZ,KAAK,IAAI,OAAOY,kBAAAA,CAAmBZ,KAAK,KAAK,QAAA,IAAYa,OAAAA,CAAQD,kBAAAA,CAAmBZ,KAAK,CAAA,CAAA,EAC7G;QACC,OAAO,KAAA;AACX,IAAA;IAEA,OAAO,IAAA;AACX;;;;"}
@@ -0,0 +1,6 @@
1
+ export interface Output {
2
+ [key: string]: unknown;
3
+ }
4
+ export declare const EMPTY_OUTPUT: Output;
5
+ export declare const isOutput: (output: unknown) => output is Output;
6
+ export declare const validateOutput: (output: unknown) => output is Output;
@@ -0,0 +1,23 @@
1
+ import { Input } from './input';
2
+ import { Output } from './output';
3
+ export interface VerifyMethodResponse {
4
+ verified: boolean;
5
+ messages: string[];
6
+ }
7
+ export type VerifyMethod<I extends Input = Input> = (input: I) => Promise<VerifyMethodResponse>;
8
+ export type ExecuteMethod<T extends Input = Input, U extends Output = Output> = (input: T) => Promise<U>;
9
+ export interface Phase<T extends Input = Input, U extends Output = Output> {
10
+ name: string;
11
+ verify?: VerifyMethod<T>;
12
+ execute: (input: T) => Promise<U>;
13
+ }
14
+ export interface PhaseOptions<T extends Input = Input, U extends Output = Output> {
15
+ execute: ExecuteMethod<T, U>;
16
+ verify?: VerifyMethod<T>;
17
+ }
18
+ export declare const createPhase: <T extends Input = Input, U extends Output = Output>(name: string, options: Partial<PhaseOptions<T, U>>) => Readonly<Phase<T, U>>;
19
+ export declare const isPhase: <T extends Input = Input, U extends Output = Output>(obj: any) => obj is Phase<T, U>;
20
+ export declare const validatePhase: (item: any, coordinates?: string[]) => Array<{
21
+ coordinates: string[];
22
+ error: string;
23
+ }>;
package/dist/phase.js ADDED
@@ -0,0 +1,24 @@
1
+ import { clean } from './util/general.js';
2
+
3
+ const createPhase = (name, options)=>{
4
+ const defaultOptions = {
5
+ execute: async (input)=>{
6
+ return input;
7
+ }
8
+ };
9
+ const phaseOptions = {
10
+ ...defaultOptions,
11
+ ...clean(options)
12
+ };
13
+ return {
14
+ name,
15
+ execute: phaseOptions.execute,
16
+ verify: phaseOptions.verify
17
+ };
18
+ };
19
+ const isPhase = (obj)=>{
20
+ return obj !== undefined && obj !== null && typeof obj === 'object' && typeof obj.name === 'string' && typeof obj.execute === 'function';
21
+ };
22
+
23
+ export { createPhase, isPhase };
24
+ //# sourceMappingURL=phase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase.js","sources":["../src/phase.ts"],"sourcesContent":["import { clean } from \"./util/general\";\nimport { Input } from \"./input\";\nimport { Output } from \"./output\";\n\nexport interface VerifyMethodResponse {\n verified: boolean;\n messages: string[];\n}\n\nexport type VerifyMethod<I extends Input = Input> = (input: I) => Promise<VerifyMethodResponse>;\n\nexport type ExecuteMethod<T extends Input = Input, U extends Output = Output> = (input: T) => Promise<U>;\n\nexport interface Phase<T extends Input = Input, U extends Output = Output> {\n name: string;\n verify?: VerifyMethod<T>;\n execute: (input: T) => Promise<U>;\n}\n\nexport interface PhaseOptions<T extends Input = Input, U extends Output = Output> {\n execute: ExecuteMethod<T, U>;\n verify?: VerifyMethod<T>;\n}\n\n\nexport const createPhase = <T extends Input = Input, U extends Output = Output>(\n name: string,\n options: Partial<PhaseOptions<T, U>>\n): Readonly<Phase<T, U>> => {\n\n const defaultOptions: PhaseOptions<T, U> = {\n execute: async (input: T) => {\n return input as unknown as U;\n }\n };\n\n const phaseOptions: PhaseOptions<T, U> = { ...defaultOptions, ...clean(options) };\n\n return {\n name,\n execute: phaseOptions.execute,\n verify: phaseOptions.verify,\n };\n}\n\nexport const isPhase = <T extends Input = Input, U extends Output = Output>(obj: any): obj is Phase<T, U> => {\n return obj !== undefined && obj !== null && typeof obj === 'object' && typeof obj.name === 'string' && typeof obj.execute === 'function';\n}\n\nexport const validatePhase = (item: any, coordinates?: string[]): Array<{ coordinates: string[], error: string }> => {\n const errors: Array<{ coordinates: string[], error: string }> = [];\n const currentCoordinates = [...(coordinates || []), 'Phase'];\n\n if (item === undefined || item === null) {\n errors.push({ coordinates: [...currentCoordinates], error: 'Phase is undefined or null.' });\n return errors;\n }\n\n if (item.name === undefined || typeof item.name !== 'string') {\n errors.push({ coordinates: [...currentCoordinates], error: 'Phase name is undefined or not a string.' });\n }\n\n currentCoordinates.push(`Phase: ${item.name}`);\n\n if (item.execute === undefined || typeof item.execute !== 'function') {\n errors.push({ coordinates: [...currentCoordinates], error: 'Phase execute is undefined or not a function.' });\n }\n\n return errors;\n}"],"names":["createPhase","name","options","defaultOptions","execute","input","phaseOptions","clean","verify","isPhase","obj","undefined"],"mappings":";;AAyBO,MAAMA,WAAAA,GAAc,CACvBC,IAAAA,EACAC,OAAAA,GAAAA;AAGA,IAAA,MAAMC,cAAAA,GAAqC;AACvCC,QAAAA,OAAAA,EAAS,OAAOC,KAAAA,GAAAA;YACZ,OAAOA,KAAAA;AACX,QAAA;AACJ,KAAA;AAEA,IAAA,MAAMC,YAAAA,GAAmC;AAAE,QAAA,GAAGH,cAAc;AAAE,QAAA,GAAGI,MAAML,OAAAA;AAAS,KAAA;IAEhF,OAAO;AACHD,QAAAA,IAAAA;AACAG,QAAAA,OAAAA,EAASE,aAAaF,OAAO;AAC7BI,QAAAA,MAAAA,EAAQF,aAAaE;AACzB,KAAA;AACJ;AAEO,MAAMC,UAAU,CAAqDC,GAAAA,GAAAA;AACxE,IAAA,OAAOA,GAAAA,KAAQC,SAAAA,IAAaD,GAAAA,KAAQ,IAAA,IAAQ,OAAOA,GAAAA,KAAQ,QAAA,IAAY,OAAOA,GAAAA,CAAIT,IAAI,KAAK,QAAA,IAAY,OAAOS,GAAAA,CAAIN,OAAO,KAAK,UAAA;AAClI;;;;"}
@@ -0,0 +1,15 @@
1
+ import { AggregatorNode } from './node/aggregatornode';
2
+ import { PhaseNode } from './node/phasenode';
3
+ export interface ProcessOptions {
4
+ phases: Record<string, PhaseNode | AggregatorNode>;
5
+ }
6
+ export interface Process {
7
+ name: string;
8
+ phases: Record<string, PhaseNode | AggregatorNode>;
9
+ }
10
+ export declare const createProcess: (name: string, options: Partial<ProcessOptions>) => Readonly<Process>;
11
+ export declare const isProcess: (obj: any) => obj is Process;
12
+ export declare const validateProcess: (item: any, coordinates?: string[]) => Array<{
13
+ coordinates: string[];
14
+ error: string;
15
+ }>;