@forestadmin/workflow-executor 1.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 (123) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +141 -0
  3. package/dist/adapters/activity-log-drainer.d.ts +6 -0
  4. package/dist/adapters/activity-log-drainer.js +21 -0
  5. package/dist/adapters/agent-client-agent-port.d.ts +27 -0
  6. package/dist/adapters/agent-client-agent-port.js +211 -0
  7. package/dist/adapters/ai-client-adapter.d.ts +11 -0
  8. package/dist/adapters/ai-client-adapter.js +38 -0
  9. package/dist/adapters/always-error-ai-model-port.d.ts +8 -0
  10. package/dist/adapters/always-error-ai-model-port.js +23 -0
  11. package/dist/adapters/console-logger.d.ts +7 -0
  12. package/dist/adapters/console-logger.js +15 -0
  13. package/dist/adapters/forest-server-workflow-port.d.ts +25 -0
  14. package/dist/adapters/forest-server-workflow-port.js +163 -0
  15. package/dist/adapters/forestadmin-client-activity-log-port-factory.d.ts +12 -0
  16. package/dist/adapters/forestadmin-client-activity-log-port-factory.js +22 -0
  17. package/dist/adapters/forestadmin-client-activity-log-port.d.ts +15 -0
  18. package/dist/adapters/forestadmin-client-activity-log-port.js +78 -0
  19. package/dist/adapters/pretty-logger.d.ts +9 -0
  20. package/dist/adapters/pretty-logger.js +37 -0
  21. package/dist/adapters/record-id-serializer.d.ts +4 -0
  22. package/dist/adapters/record-id-serializer.js +20 -0
  23. package/dist/adapters/run-to-available-step-mapper.d.ts +4 -0
  24. package/dist/adapters/run-to-available-step-mapper.js +137 -0
  25. package/dist/adapters/server-ai-adapter.d.ts +16 -0
  26. package/dist/adapters/server-ai-adapter.js +60 -0
  27. package/dist/adapters/server-types.d.ts +181 -0
  28. package/dist/adapters/server-types.js +35 -0
  29. package/dist/adapters/step-definition-mapper.d.ts +4 -0
  30. package/dist/adapters/step-definition-mapper.js +68 -0
  31. package/dist/adapters/step-outcome-to-update-step-mapper.d.ts +4 -0
  32. package/dist/adapters/step-outcome-to-update-step-mapper.js +34 -0
  33. package/dist/adapters/with-retry.d.ts +6 -0
  34. package/dist/adapters/with-retry.js +40 -0
  35. package/dist/build-workflow-executor.d.ts +35 -0
  36. package/dist/build-workflow-executor.js +175 -0
  37. package/dist/cli-core.d.ts +26 -0
  38. package/dist/cli-core.js +228 -0
  39. package/dist/cli.d.ts +3 -0
  40. package/dist/cli.js +17 -0
  41. package/dist/defaults.d.ts +9 -0
  42. package/dist/defaults.js +12 -0
  43. package/dist/errors.d.ts +153 -0
  44. package/dist/errors.js +327 -0
  45. package/dist/executors/activity-log.d.ts +14 -0
  46. package/dist/executors/activity-log.js +33 -0
  47. package/dist/executors/agent-with-log.d.ts +33 -0
  48. package/dist/executors/agent-with-log.js +76 -0
  49. package/dist/executors/base-step-executor.d.ts +40 -0
  50. package/dist/executors/base-step-executor.js +267 -0
  51. package/dist/executors/condition-step-executor.d.ts +15 -0
  52. package/dist/executors/condition-step-executor.js +108 -0
  53. package/dist/executors/guidance-step-executor.d.ts +12 -0
  54. package/dist/executors/guidance-step-executor.js +39 -0
  55. package/dist/executors/load-related-record-step-executor.d.ts +38 -0
  56. package/dist/executors/load-related-record-step-executor.js +478 -0
  57. package/dist/executors/mcp-step-executor.d.ts +22 -0
  58. package/dist/executors/mcp-step-executor.js +188 -0
  59. package/dist/executors/read-record-step-executor.d.ts +10 -0
  60. package/dist/executors/read-record-step-executor.js +100 -0
  61. package/dist/executors/record-step-executor.d.ts +19 -0
  62. package/dist/executors/record-step-executor.js +108 -0
  63. package/dist/executors/step-executor-factory.d.ts +24 -0
  64. package/dist/executors/step-executor-factory.js +99 -0
  65. package/dist/executors/summary/step-execution-formatters.d.ts +8 -0
  66. package/dist/executors/summary/step-execution-formatters.js +49 -0
  67. package/dist/executors/summary/step-summary-builder.d.ts +7 -0
  68. package/dist/executors/summary/step-summary-builder.js +52 -0
  69. package/dist/executors/trigger-record-action-step-executor.d.ts +17 -0
  70. package/dist/executors/trigger-record-action-step-executor.js +169 -0
  71. package/dist/executors/update-record-step-executor.d.ts +13 -0
  72. package/dist/executors/update-record-step-executor.js +245 -0
  73. package/dist/http/executor-http-server.d.ts +25 -0
  74. package/dist/http/executor-http-server.js +170 -0
  75. package/dist/http/pending-data-validators.d.ts +25 -0
  76. package/dist/http/pending-data-validators.js +79 -0
  77. package/dist/http/step-serializer.d.ts +3 -0
  78. package/dist/http/step-serializer.js +47 -0
  79. package/dist/in-flight-run-registry.d.ts +9 -0
  80. package/dist/in-flight-run-registry.js +30 -0
  81. package/dist/index.d.ts +38 -0
  82. package/dist/index.js +88 -0
  83. package/dist/ports/activity-log-port.d.ts +24 -0
  84. package/dist/ports/activity-log-port.js +3 -0
  85. package/dist/ports/agent-port.d.ts +54 -0
  86. package/dist/ports/agent-port.js +3 -0
  87. package/dist/ports/ai-model-port.d.ts +7 -0
  88. package/dist/ports/ai-model-port.js +3 -0
  89. package/dist/ports/logger-port.d.ts +6 -0
  90. package/dist/ports/logger-port.js +3 -0
  91. package/dist/ports/run-store.d.ts +9 -0
  92. package/dist/ports/run-store.js +3 -0
  93. package/dist/ports/workflow-port.d.ts +30 -0
  94. package/dist/ports/workflow-port.js +3 -0
  95. package/dist/remote-tool-fetcher.d.ts +19 -0
  96. package/dist/remote-tool-fetcher.js +56 -0
  97. package/dist/runner.d.ts +50 -0
  98. package/dist/runner.js +317 -0
  99. package/dist/schema-cache.d.ts +11 -0
  100. package/dist/schema-cache.js +37 -0
  101. package/dist/schema-resolver.d.ts +11 -0
  102. package/dist/schema-resolver.js +24 -0
  103. package/dist/stores/build-run-store.d.ts +5 -0
  104. package/dist/stores/build-run-store.js +28 -0
  105. package/dist/stores/database-store.d.ts +17 -0
  106. package/dist/stores/database-store.js +119 -0
  107. package/dist/stores/in-memory-store.d.ts +11 -0
  108. package/dist/stores/in-memory-store.js +48 -0
  109. package/dist/types/execution-context.d.ts +37 -0
  110. package/dist/types/execution-context.js +3 -0
  111. package/dist/types/step-execution-data.d.ts +137 -0
  112. package/dist/types/step-execution-data.js +3 -0
  113. package/dist/types/validated/collection.d.ts +126 -0
  114. package/dist/types/validated/collection.js +96 -0
  115. package/dist/types/validated/execution.d.ts +362 -0
  116. package/dist/types/validated/execution.js +43 -0
  117. package/dist/types/validated/step-definition.d.ts +243 -0
  118. package/dist/types/validated/step-definition.js +128 -0
  119. package/dist/types/validated/step-outcome.d.ts +108 -0
  120. package/dist/types/validated/step-outcome.js +66 -0
  121. package/dist/validate-secrets.d.ts +5 -0
  122. package/dist/validate-secrets.js +14 -0
  123. package/package.json +50 -0
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Local mirror of the orchestrator's contract.
3
+ * See forestadmin-server/packages/private-api/src/domain/workflow-orchestrator/types.ts
4
+ *
5
+ * Contains both step-level types (workflow step variants) and the run envelope
6
+ * (HydratedWorkflowRun + user profile + step history).
7
+ */
8
+ export interface ServerWorkflowTransition {
9
+ stepId: string;
10
+ buttonText: string | null;
11
+ buttonColor?: string | null;
12
+ answer?: string;
13
+ }
14
+ export declare enum ServerStepTypeEnum {
15
+ Task = "task",
16
+ Condition = "condition",
17
+ End = "end",
18
+ Escalation = "escalation",
19
+ StartSubWorkflow = "start-sub-workflow",
20
+ CloseSubWorkflow = "close-sub-workflow"
21
+ }
22
+ export declare enum ServerTaskTypeEnum {
23
+ Guideline = "guideline",
24
+ TriggerAction = "trigger-action",
25
+ GetData = "get-data",
26
+ UpdateData = "update-data",
27
+ LoadRelatedRecord = "load-related-record",
28
+ McpServer = "mcp-server"
29
+ }
30
+ export declare enum ServerStepExecutionTypeEnum {
31
+ Manual = "manual",
32
+ AutomatedWithConfirmation = "automated-with-confirmation",
33
+ FullyAutomated = "fully-automated"
34
+ }
35
+ interface ServerWorkflowStepBase {
36
+ type: ServerStepTypeEnum;
37
+ title: string;
38
+ prompt?: string;
39
+ executionType: ServerStepExecutionTypeEnum;
40
+ automaticCompletion: boolean;
41
+ outgoing: ServerWorkflowTransition[];
42
+ }
43
+ export interface ServerWorkflowTaskBase extends ServerWorkflowStepBase {
44
+ type: ServerStepTypeEnum.Task;
45
+ taskType: ServerTaskTypeEnum;
46
+ isSubTask?: boolean;
47
+ prompt: string;
48
+ outgoing: [ServerWorkflowTransition];
49
+ }
50
+ export interface ServerWorkflowTaskGuideline extends ServerWorkflowTaskBase {
51
+ taskType: ServerTaskTypeEnum.Guideline;
52
+ executionType: ServerStepExecutionTypeEnum.Manual;
53
+ completionType: 'simple' | 'user-input';
54
+ inputType?: 'free-text';
55
+ automaticCompletion: false;
56
+ }
57
+ interface ServerWorkflowTaskGetData extends ServerWorkflowTaskBase {
58
+ taskType: ServerTaskTypeEnum.GetData;
59
+ executionType: ServerStepExecutionTypeEnum.FullyAutomated;
60
+ }
61
+ interface ServerWorkflowTaskUpdateData extends ServerWorkflowTaskBase {
62
+ taskType: ServerTaskTypeEnum.UpdateData;
63
+ executionType: ServerStepExecutionTypeEnum.FullyAutomated | ServerStepExecutionTypeEnum.AutomatedWithConfirmation;
64
+ }
65
+ interface ServerWorkflowTaskTriggerAction extends ServerWorkflowTaskBase {
66
+ taskType: ServerTaskTypeEnum.TriggerAction;
67
+ executionType: ServerStepExecutionTypeEnum.FullyAutomated | ServerStepExecutionTypeEnum.AutomatedWithConfirmation;
68
+ }
69
+ interface ServerWorkflowTaskLoadRelatedRecord extends ServerWorkflowTaskBase {
70
+ taskType: ServerTaskTypeEnum.LoadRelatedRecord;
71
+ executionType: ServerStepExecutionTypeEnum.FullyAutomated | ServerStepExecutionTypeEnum.AutomatedWithConfirmation;
72
+ }
73
+ export interface ServerWorkflowTaskMcpServer extends ServerWorkflowTaskBase {
74
+ taskType: ServerTaskTypeEnum.McpServer;
75
+ executionType: ServerStepExecutionTypeEnum.FullyAutomated | ServerStepExecutionTypeEnum.AutomatedWithConfirmation;
76
+ mcpServerId: string;
77
+ }
78
+ export type ServerWorkflowTask = ServerWorkflowTaskGuideline | ServerWorkflowTaskGetData | ServerWorkflowTaskUpdateData | ServerWorkflowTaskTriggerAction | ServerWorkflowTaskLoadRelatedRecord | ServerWorkflowTaskMcpServer;
79
+ export interface ServerWorkflowEnd extends ServerWorkflowStepBase {
80
+ type: ServerStepTypeEnum.End;
81
+ executionType: ServerStepExecutionTypeEnum.Manual;
82
+ automaticCompletion: false;
83
+ outgoing: [];
84
+ }
85
+ export interface ServerWorkflowCondition extends ServerWorkflowStepBase {
86
+ type: ServerStepTypeEnum.Condition;
87
+ executionType: ServerStepExecutionTypeEnum.Manual | ServerStepExecutionTypeEnum.FullyAutomated;
88
+ prompt: string;
89
+ automaticCompletion: false;
90
+ }
91
+ export interface ServerWorkflowEscalation extends ServerWorkflowStepBase {
92
+ type: ServerStepTypeEnum.Escalation;
93
+ prompt: string;
94
+ outgoing: [ServerWorkflowTransition];
95
+ inboxId: string | null;
96
+ }
97
+ export interface ServerStartSubWorkflow extends ServerWorkflowStepBase {
98
+ type: ServerStepTypeEnum.StartSubWorkflow;
99
+ executionType: ServerStepExecutionTypeEnum.Manual;
100
+ outgoing: [ServerWorkflowTransition];
101
+ workflowId: string;
102
+ }
103
+ export interface ServerCloseSubWorkflow extends ServerWorkflowStepBase {
104
+ type: ServerStepTypeEnum.CloseSubWorkflow;
105
+ executionType: ServerStepExecutionTypeEnum.Manual;
106
+ outgoing: [ServerWorkflowTransition];
107
+ parentWorkflowId: string | null;
108
+ }
109
+ export type ServerWorkflowStep = ServerWorkflowTask | ServerWorkflowCondition | ServerWorkflowEnd | ServerWorkflowEscalation | ServerStartSubWorkflow | ServerCloseSubWorkflow;
110
+ export interface ServerUserProfile {
111
+ id: number;
112
+ email: string;
113
+ firstName: string | null;
114
+ lastName: string | null;
115
+ team: string | null;
116
+ renderingId: number;
117
+ role: string | null;
118
+ permissionLevel: string | null;
119
+ tags: Record<string, string>;
120
+ serverToken: string;
121
+ }
122
+ export interface ServerStepHistory {
123
+ stepName: string;
124
+ stepIndex: number;
125
+ done: boolean;
126
+ revised?: boolean;
127
+ cancelled?: boolean;
128
+ originalStepIndex?: number;
129
+ context?: Record<string, unknown>;
130
+ childrenWorkflowId?: string;
131
+ stepDefinition: ServerWorkflowStep;
132
+ }
133
+ /** Mirror of the server's `WorkflowRunState` enum (workflow-run-model.ts). */
134
+ export type ServerWorkflowRunState = 'started' | 'pending' | 'loading' | 'aborted' | 'finished';
135
+ export interface ServerHydratedWorkflowRun {
136
+ id: number;
137
+ workflowId: string;
138
+ collectionId: string;
139
+ collectionName: string | null;
140
+ selectedRecordId: string;
141
+ bpmnVersion: string;
142
+ runState: ServerWorkflowRunState;
143
+ workflowHistory: ServerStepHistory[];
144
+ /** Server types declare `Date`; Express serializes to ISO 8601 string on the wire. */
145
+ createdAt: string;
146
+ updatedAt: string;
147
+ userId: number;
148
+ renderingId: number;
149
+ lockedAt?: string | null;
150
+ userProfile: ServerUserProfile;
151
+ }
152
+ export interface ServerStepHistoryUpdate {
153
+ /** Accepted by the server Joi schema; missing from the server TS type (server-side gap). */
154
+ isLoading?: boolean;
155
+ done?: boolean;
156
+ revised?: boolean;
157
+ cancelled?: boolean;
158
+ context?: Record<string, unknown>;
159
+ }
160
+ export interface ServerStepUpdate {
161
+ stepIndex: number;
162
+ attributes: ServerStepHistoryUpdate;
163
+ }
164
+ export type ServerExecutionStatus =
165
+ /** `nextStepId` is accepted by the server Joi schema; missing from the server TS type. */
166
+ {
167
+ type: 'success';
168
+ nextStepId?: string;
169
+ } | {
170
+ type: 'error';
171
+ message: string;
172
+ } | {
173
+ type: 'awaiting-input';
174
+ };
175
+ export interface ServerUpdateStepRequest {
176
+ runId: number;
177
+ stepUpdate: ServerStepUpdate;
178
+ executionStatus: ServerExecutionStatus;
179
+ }
180
+ export {};
181
+ //# sourceMappingURL=server-types.d.ts.map
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ /**
3
+ * Local mirror of the orchestrator's contract.
4
+ * See forestadmin-server/packages/private-api/src/domain/workflow-orchestrator/types.ts
5
+ *
6
+ * Contains both step-level types (workflow step variants) and the run envelope
7
+ * (HydratedWorkflowRun + user profile + step history).
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ServerStepExecutionTypeEnum = exports.ServerTaskTypeEnum = exports.ServerStepTypeEnum = void 0;
11
+ var ServerStepTypeEnum;
12
+ (function (ServerStepTypeEnum) {
13
+ ServerStepTypeEnum["Task"] = "task";
14
+ ServerStepTypeEnum["Condition"] = "condition";
15
+ ServerStepTypeEnum["End"] = "end";
16
+ ServerStepTypeEnum["Escalation"] = "escalation";
17
+ ServerStepTypeEnum["StartSubWorkflow"] = "start-sub-workflow";
18
+ ServerStepTypeEnum["CloseSubWorkflow"] = "close-sub-workflow";
19
+ })(ServerStepTypeEnum || (exports.ServerStepTypeEnum = ServerStepTypeEnum = {}));
20
+ var ServerTaskTypeEnum;
21
+ (function (ServerTaskTypeEnum) {
22
+ ServerTaskTypeEnum["Guideline"] = "guideline";
23
+ ServerTaskTypeEnum["TriggerAction"] = "trigger-action";
24
+ ServerTaskTypeEnum["GetData"] = "get-data";
25
+ ServerTaskTypeEnum["UpdateData"] = "update-data";
26
+ ServerTaskTypeEnum["LoadRelatedRecord"] = "load-related-record";
27
+ ServerTaskTypeEnum["McpServer"] = "mcp-server";
28
+ })(ServerTaskTypeEnum || (exports.ServerTaskTypeEnum = ServerTaskTypeEnum = {}));
29
+ var ServerStepExecutionTypeEnum;
30
+ (function (ServerStepExecutionTypeEnum) {
31
+ ServerStepExecutionTypeEnum["Manual"] = "manual";
32
+ ServerStepExecutionTypeEnum["AutomatedWithConfirmation"] = "automated-with-confirmation";
33
+ ServerStepExecutionTypeEnum["FullyAutomated"] = "fully-automated";
34
+ })(ServerStepExecutionTypeEnum || (exports.ServerStepExecutionTypeEnum = ServerStepExecutionTypeEnum = {}));
35
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLXR5cGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXJzL3NlcnZlci10eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7OztHQU1HOzs7QUFTSCxJQUFZLGtCQU9YO0FBUEQsV0FBWSxrQkFBa0I7SUFDNUIsbUNBQWEsQ0FBQTtJQUNiLDZDQUF1QixDQUFBO0lBQ3ZCLGlDQUFXLENBQUE7SUFDWCwrQ0FBeUIsQ0FBQTtJQUN6Qiw2REFBdUMsQ0FBQTtJQUN2Qyw2REFBdUMsQ0FBQTtBQUN6QyxDQUFDLEVBUFcsa0JBQWtCLGtDQUFsQixrQkFBa0IsUUFPN0I7QUFFRCxJQUFZLGtCQU9YO0FBUEQsV0FBWSxrQkFBa0I7SUFDNUIsNkNBQXVCLENBQUE7SUFDdkIsc0RBQWdDLENBQUE7SUFDaEMsMENBQW9CLENBQUE7SUFDcEIsZ0RBQTBCLENBQUE7SUFDMUIsK0RBQXlDLENBQUE7SUFDekMsOENBQXdCLENBQUE7QUFDMUIsQ0FBQyxFQVBXLGtCQUFrQixrQ0FBbEIsa0JBQWtCLFFBTzdCO0FBRUQsSUFBWSwyQkFJWDtBQUpELFdBQVksMkJBQTJCO0lBQ3JDLGdEQUFpQixDQUFBO0lBQ2pCLHdGQUF5RCxDQUFBO0lBQ3pELGlFQUFrQyxDQUFBO0FBQ3BDLENBQUMsRUFKVywyQkFBMkIsMkNBQTNCLDJCQUEyQixRQUl0QyJ9
@@ -0,0 +1,4 @@
1
+ import type { ServerWorkflowStep } from './server-types';
2
+ import type { StepDefinition } from '../types/validated/step-definition';
3
+ export default function toStepDefinition(serverStep: ServerWorkflowStep): StepDefinition;
4
+ //# sourceMappingURL=step-definition-mapper.d.ts.map
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = toStepDefinition;
4
+ const server_types_1 = require("./server-types");
5
+ const errors_1 = require("../errors");
6
+ const step_definition_1 = require("../types/validated/step-definition");
7
+ function mapTask(task) {
8
+ // executionType is passed through as-is; each schema's .default().catch() handles
9
+ // missing or unsupported values without requiring an explicit mapping here.
10
+ const base = { prompt: task.prompt, executionType: task.executionType, title: task.title };
11
+ switch (task.taskType) {
12
+ case server_types_1.ServerTaskTypeEnum.McpServer:
13
+ return step_definition_1.McpStepDefinitionSchema.parse({
14
+ ...base,
15
+ type: step_definition_1.StepType.Mcp,
16
+ mcpServerId: task.mcpServerId,
17
+ });
18
+ case server_types_1.ServerTaskTypeEnum.Guideline:
19
+ return step_definition_1.GuidanceStepDefinitionSchema.parse({ ...base, type: step_definition_1.StepType.Guidance });
20
+ case server_types_1.ServerTaskTypeEnum.GetData:
21
+ return step_definition_1.ReadRecordStepDefinitionSchema.parse({ ...base, type: step_definition_1.StepType.ReadRecord });
22
+ case server_types_1.ServerTaskTypeEnum.UpdateData:
23
+ return step_definition_1.UpdateRecordStepDefinitionSchema.parse({ ...base, type: step_definition_1.StepType.UpdateRecord });
24
+ case server_types_1.ServerTaskTypeEnum.TriggerAction:
25
+ return step_definition_1.TriggerActionStepDefinitionSchema.parse({ ...base, type: step_definition_1.StepType.TriggerAction });
26
+ case server_types_1.ServerTaskTypeEnum.LoadRelatedRecord:
27
+ return step_definition_1.LoadRelatedRecordStepDefinitionSchema.parse({
28
+ ...base,
29
+ type: step_definition_1.StepType.LoadRelatedRecord,
30
+ });
31
+ default:
32
+ throw new errors_1.InvalidStepDefinitionError(`Unknown taskType: "${task.taskType}"`);
33
+ }
34
+ }
35
+ function mapCondition(condition) {
36
+ const options = condition.outgoing
37
+ .map(t => t.answer ?? t.buttonText)
38
+ .filter((v) => typeof v === 'string' && v.length > 0);
39
+ if (options.length < 2) {
40
+ throw new errors_1.InvalidStepDefinitionError(`Condition step requires at least 2 options, got ${options.length}`);
41
+ }
42
+ return step_definition_1.ConditionStepDefinitionSchema.parse({
43
+ type: step_definition_1.StepType.Condition,
44
+ prompt: condition.prompt,
45
+ executionType: condition.executionType,
46
+ title: condition.title,
47
+ options,
48
+ });
49
+ }
50
+ // Server uses `type:'task' + taskType` for non-condition steps and `outgoing[]` for conditions;
51
+ // executor uses flat StepDefinition with `options[]`. Unsupported server types
52
+ // (end/escalation/sub-workflow) throw UnsupportedStepTypeError.
53
+ function toStepDefinition(serverStep) {
54
+ switch (serverStep.type) {
55
+ case 'task':
56
+ return mapTask(serverStep);
57
+ case 'condition':
58
+ return mapCondition(serverStep);
59
+ case 'end':
60
+ case 'escalation':
61
+ case 'start-sub-workflow':
62
+ case 'close-sub-workflow':
63
+ throw new errors_1.UnsupportedStepTypeError(serverStep.type);
64
+ default:
65
+ throw new errors_1.InvalidStepDefinitionError(`Unknown server step type: "${serverStep.type}"`);
66
+ }
67
+ }
68
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1kZWZpbml0aW9uLW1hcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZGFwdGVycy9zdGVwLWRlZmluaXRpb24tbWFwcGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBMkVBLG1DQWdCQztBQXBGRCxpREFBb0Q7QUFDcEQsc0NBQWlGO0FBQ2pGLHdFQVM0QztBQUU1QyxTQUFTLE9BQU8sQ0FBQyxJQUF3QjtJQUN2QyxrRkFBa0Y7SUFDbEYsNEVBQTRFO0lBQzVFLE1BQU0sSUFBSSxHQUFHLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUUzRixRQUFRLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUN0QixLQUFLLGlDQUFrQixDQUFDLFNBQVM7WUFDL0IsT0FBTyx5Q0FBdUIsQ0FBQyxLQUFLLENBQUM7Z0JBQ25DLEdBQUcsSUFBSTtnQkFDUCxJQUFJLEVBQUUsMEJBQVEsQ0FBQyxHQUFHO2dCQUNsQixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7YUFDOUIsQ0FBQyxDQUFDO1FBQ0wsS0FBSyxpQ0FBa0IsQ0FBQyxTQUFTO1lBQy9CLE9BQU8sOENBQTRCLENBQUMsS0FBSyxDQUFDLEVBQUUsR0FBRyxJQUFJLEVBQUUsSUFBSSxFQUFFLDBCQUFRLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUNsRixLQUFLLGlDQUFrQixDQUFDLE9BQU87WUFDN0IsT0FBTyxnREFBOEIsQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLElBQUksRUFBRSxJQUFJLEVBQUUsMEJBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQ3RGLEtBQUssaUNBQWtCLENBQUMsVUFBVTtZQUNoQyxPQUFPLGtEQUFnQyxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxFQUFFLElBQUksRUFBRSwwQkFBUSxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUM7UUFDMUYsS0FBSyxpQ0FBa0IsQ0FBQyxhQUFhO1lBQ25DLE9BQU8sbURBQWlDLENBQUMsS0FBSyxDQUFDLEVBQUUsR0FBRyxJQUFJLEVBQUUsSUFBSSxFQUFFLDBCQUFRLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQztRQUM1RixLQUFLLGlDQUFrQixDQUFDLGlCQUFpQjtZQUN2QyxPQUFPLHVEQUFxQyxDQUFDLEtBQUssQ0FBQztnQkFDakQsR0FBRyxJQUFJO2dCQUNQLElBQUksRUFBRSwwQkFBUSxDQUFDLGlCQUFpQjthQUNqQyxDQUFDLENBQUM7UUFDTDtZQUNFLE1BQU0sSUFBSSxtQ0FBMEIsQ0FDbEMsc0JBQXVCLElBQTZCLENBQUMsUUFBUSxHQUFHLENBQ2pFLENBQUM7SUFDTixDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMsWUFBWSxDQUFDLFNBQWtDO0lBQ3RELE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxRQUFRO1NBQy9CLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FBQztTQUNsQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQWUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLFFBQVEsSUFBSSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBRXJFLElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN2QixNQUFNLElBQUksbUNBQTBCLENBQ2xDLG1EQUFtRCxPQUFPLENBQUMsTUFBTSxFQUFFLENBQ3BFLENBQUM7SUFDSixDQUFDO0lBRUQsT0FBTywrQ0FBNkIsQ0FBQyxLQUFLLENBQUM7UUFDekMsSUFBSSxFQUFFLDBCQUFRLENBQUMsU0FBUztRQUN4QixNQUFNLEVBQUUsU0FBUyxDQUFDLE1BQU07UUFDeEIsYUFBYSxFQUFFLFNBQVMsQ0FBQyxhQUFhO1FBQ3RDLEtBQUssRUFBRSxTQUFTLENBQUMsS0FBSztRQUN0QixPQUFPO0tBQ1IsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELGdHQUFnRztBQUNoRywrRUFBK0U7QUFDL0UsZ0VBQWdFO0FBQ2hFLFNBQXdCLGdCQUFnQixDQUFDLFVBQThCO0lBQ3JFLFFBQVEsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3hCLEtBQUssTUFBTTtZQUNULE9BQU8sT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQzdCLEtBQUssV0FBVztZQUNkLE9BQU8sWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xDLEtBQUssS0FBSyxDQUFDO1FBQ1gsS0FBSyxZQUFZLENBQUM7UUFDbEIsS0FBSyxvQkFBb0IsQ0FBQztRQUMxQixLQUFLLG9CQUFvQjtZQUN2QixNQUFNLElBQUksaUNBQXdCLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3REO1lBQ0UsTUFBTSxJQUFJLG1DQUEwQixDQUNsQyw4QkFBK0IsVUFBK0IsQ0FBQyxJQUFJLEdBQUcsQ0FDdkUsQ0FBQztJQUNOLENBQUM7QUFDSCxDQUFDIn0=
@@ -0,0 +1,4 @@
1
+ import type { ServerUpdateStepRequest } from './server-types';
2
+ import type { StepOutcome } from '../types/validated/step-outcome';
3
+ export default function toUpdateStepRequest(runId: string, outcome: StepOutcome): ServerUpdateStepRequest;
4
+ //# sourceMappingURL=step-outcome-to-update-step-mapper.d.ts.map
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = toUpdateStepRequest;
4
+ function toExecutionStatus(outcome) {
5
+ if (outcome.status === 'error') {
6
+ // Joi.string().required() on the server rejects empty strings — fall back
7
+ // so an executor that produces error='' doesn't trigger an infinite re-dispatch.
8
+ return { type: 'error', message: outcome.error || 'Unknown error' };
9
+ }
10
+ if (outcome.status === 'awaiting-input') {
11
+ return { type: 'awaiting-input' };
12
+ }
13
+ return { type: 'success' };
14
+ }
15
+ // Write to `context` so the round-trip with run-to-available-step-mapper stays ISO (reverse mapper
16
+ // reads status/error/selectedOption from ServerStepHistory.context).
17
+ function toUpdateStepRequest(runId, outcome) {
18
+ const context = { status: outcome.status };
19
+ if (outcome.error !== undefined)
20
+ context.error = outcome.error;
21
+ if (outcome.type === 'condition' && outcome.selectedOption !== undefined) {
22
+ context.selectedOption = outcome.selectedOption;
23
+ }
24
+ const attributes = {
25
+ done: outcome.status !== 'awaiting-input',
26
+ context,
27
+ };
28
+ return {
29
+ runId: Number(runId),
30
+ stepUpdate: { stepIndex: outcome.stepIndex, attributes },
31
+ executionStatus: toExecutionStatus(outcome),
32
+ };
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1vdXRjb21lLXRvLXVwZGF0ZS1zdGVwLW1hcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZGFwdGVycy9zdGVwLW91dGNvbWUtdG8tdXBkYXRlLXN0ZXAtbWFwcGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBdUJBLHNDQXFCQztBQXJDRCxTQUFTLGlCQUFpQixDQUFDLE9BQW9CO0lBQzdDLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxPQUFPLEVBQUUsQ0FBQztRQUMvQiwwRUFBMEU7UUFDMUUsaUZBQWlGO1FBQ2pGLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsS0FBSyxJQUFJLGVBQWUsRUFBRSxDQUFDO0lBQ3RFLENBQUM7SUFFRCxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QyxPQUFPLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLENBQUM7SUFDcEMsQ0FBQztJQUVELE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7QUFDN0IsQ0FBQztBQUVELG1HQUFtRztBQUNuRyxxRUFBcUU7QUFDckUsU0FBd0IsbUJBQW1CLENBQ3pDLEtBQWEsRUFDYixPQUFvQjtJQUVwQixNQUFNLE9BQU8sR0FBNEIsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ3BFLElBQUksT0FBTyxDQUFDLEtBQUssS0FBSyxTQUFTO1FBQUUsT0FBTyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO0lBRS9ELElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxXQUFXLElBQUksT0FBTyxDQUFDLGNBQWMsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUN6RSxPQUFPLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUM7SUFDbEQsQ0FBQztJQUVELE1BQU0sVUFBVSxHQUE0QjtRQUMxQyxJQUFJLEVBQUUsT0FBTyxDQUFDLE1BQU0sS0FBSyxnQkFBZ0I7UUFDekMsT0FBTztLQUNSLENBQUM7SUFFRixPQUFPO1FBQ0wsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUM7UUFDcEIsVUFBVSxFQUFFLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFO1FBQ3hELGVBQWUsRUFBRSxpQkFBaUIsQ0FBQyxPQUFPLENBQUM7S0FDNUMsQ0FBQztBQUNKLENBQUMifQ==
@@ -0,0 +1,6 @@
1
+ import type { Logger } from '../ports/logger-port';
2
+ export default function withRetry<T>(label: string, fn: () => Promise<T>, { logger, extraRetryStatuses }: {
3
+ logger: Logger;
4
+ extraRetryStatuses?: number[];
5
+ }): Promise<T>;
6
+ //# sourceMappingURL=with-retry.d.ts.map
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = withRetry;
4
+ const errors_1 = require("../errors");
5
+ const RETRY_DELAYS_MS = [100, 500, 2000];
6
+ const RETRYABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]);
7
+ function sleep(ms) {
8
+ return new Promise(resolve => {
9
+ setTimeout(resolve, ms);
10
+ });
11
+ }
12
+ function isRetryable(err, extra) {
13
+ const { status } = err;
14
+ if (typeof status !== 'number')
15
+ return false;
16
+ return RETRYABLE_STATUS.has(status) || extra.includes(status);
17
+ }
18
+ async function withRetry(label, fn, { logger, extraRetryStatuses = [] }) {
19
+ let lastError;
20
+ for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt += 1) {
21
+ try {
22
+ // eslint-disable-next-line no-await-in-loop
23
+ return await fn();
24
+ }
25
+ catch (err) {
26
+ lastError = err;
27
+ if (!isRetryable(err, extraRetryStatuses) || attempt === RETRY_DELAYS_MS.length)
28
+ throw err;
29
+ logger.warn(`"${label}" failed, retrying`, {
30
+ attempt: attempt + 1,
31
+ status: err.status,
32
+ error: (0, errors_1.extractErrorMessage)(err),
33
+ });
34
+ // eslint-disable-next-line no-await-in-loop
35
+ await sleep(RETRY_DELAYS_MS[attempt]);
36
+ }
37
+ }
38
+ throw lastError;
39
+ }
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2l0aC1yZXRyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZGFwdGVycy93aXRoLXJldHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBb0JBLDRCQXlCQztBQTNDRCxzQ0FBZ0Q7QUFFaEQsTUFBTSxlQUFlLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUssQ0FBQyxDQUFDO0FBQzFDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFFakUsU0FBUyxLQUFLLENBQUMsRUFBVTtJQUN2QixPQUFPLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1FBQzNCLFVBQVUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxXQUFXLENBQUMsR0FBWSxFQUFFLEtBQWU7SUFDaEQsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLEdBQTBCLENBQUM7SUFDOUMsSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFFN0MsT0FBTyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUNoRSxDQUFDO0FBRWMsS0FBSyxVQUFVLFNBQVMsQ0FDckMsS0FBYSxFQUNiLEVBQW9CLEVBQ3BCLEVBQUUsTUFBTSxFQUFFLGtCQUFrQixHQUFHLEVBQUUsRUFBcUQ7SUFFdEYsSUFBSSxTQUFrQixDQUFDO0lBRXZCLEtBQUssSUFBSSxPQUFPLEdBQUcsQ0FBQyxFQUFFLE9BQU8sSUFBSSxlQUFlLENBQUMsTUFBTSxFQUFFLE9BQU8sSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUN0RSxJQUFJLENBQUM7WUFDSCw0Q0FBNEM7WUFDNUMsT0FBTyxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBQ3BCLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsU0FBUyxHQUFHLEdBQUcsQ0FBQztZQUNoQixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxrQkFBa0IsQ0FBQyxJQUFJLE9BQU8sS0FBSyxlQUFlLENBQUMsTUFBTTtnQkFBRSxNQUFNLEdBQUcsQ0FBQztZQUMzRixNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxvQkFBb0IsRUFBRTtnQkFDekMsT0FBTyxFQUFFLE9BQU8sR0FBRyxDQUFDO2dCQUNwQixNQUFNLEVBQUcsR0FBMkIsQ0FBQyxNQUFNO2dCQUMzQyxLQUFLLEVBQUUsSUFBQSw0QkFBbUIsRUFBQyxHQUFHLENBQUM7YUFDaEMsQ0FBQyxDQUFDO1lBQ0gsNENBQTRDO1lBQzVDLE1BQU0sS0FBSyxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3hDLENBQUM7SUFDSCxDQUFDO0lBRUQsTUFBTSxTQUFTLENBQUM7QUFDbEIsQ0FBQyJ9
@@ -0,0 +1,35 @@
1
+ import type { Logger } from './ports/logger-port';
2
+ import type { RunnerState } from './runner';
3
+ import type { AiConfiguration } from '@forestadmin/ai-proxy';
4
+ import type { Options as SequelizeOptions } from 'sequelize';
5
+ export interface WorkflowExecutor {
6
+ start(): Promise<void>;
7
+ stop(): Promise<void>;
8
+ readonly state: RunnerState;
9
+ }
10
+ export interface ExecutorOptions {
11
+ envSecret: string;
12
+ authSecret: string;
13
+ agentUrl: string;
14
+ httpPort: number;
15
+ forestServerUrl?: string;
16
+ aiConfigurations?: AiConfiguration[];
17
+ pollingIntervalMs?: number;
18
+ logger?: Logger;
19
+ stopTimeoutMs?: number;
20
+ stepTimeoutMs?: number;
21
+ aiInvokeTimeoutMs?: number;
22
+ maxChainDepth?: number;
23
+ schemaCacheTtlMs?: number;
24
+ forceAiError?: boolean;
25
+ }
26
+ export type DatabaseExecutorOptions = ExecutorOptions & ({
27
+ database: SequelizeOptions & {
28
+ uri: string;
29
+ };
30
+ } | {
31
+ database: SequelizeOptions;
32
+ });
33
+ export declare function buildInMemoryExecutor(options: ExecutorOptions): WorkflowExecutor;
34
+ export declare function buildDatabaseExecutor(options: DatabaseExecutorOptions): WorkflowExecutor;
35
+ //# sourceMappingURL=build-workflow-executor.d.ts.map
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildInMemoryExecutor = buildInMemoryExecutor;
7
+ exports.buildDatabaseExecutor = buildDatabaseExecutor;
8
+ const forestadmin_client_1 = require("@forestadmin/forestadmin-client");
9
+ const sequelize_1 = require("sequelize");
10
+ const agent_client_agent_port_1 = __importDefault(require("./adapters/agent-client-agent-port"));
11
+ const ai_client_adapter_1 = __importDefault(require("./adapters/ai-client-adapter"));
12
+ const always_error_ai_model_port_1 = __importDefault(require("./adapters/always-error-ai-model-port"));
13
+ const console_logger_1 = __importDefault(require("./adapters/console-logger"));
14
+ const forest_server_workflow_port_1 = __importDefault(require("./adapters/forest-server-workflow-port"));
15
+ const forestadmin_client_activity_log_port_factory_1 = __importDefault(require("./adapters/forestadmin-client-activity-log-port-factory"));
16
+ const server_ai_adapter_1 = __importDefault(require("./adapters/server-ai-adapter"));
17
+ const defaults_1 = require("./defaults");
18
+ const executor_http_server_1 = __importDefault(require("./http/executor-http-server"));
19
+ const runner_1 = __importDefault(require("./runner"));
20
+ const schema_cache_1 = __importDefault(require("./schema-cache"));
21
+ const database_store_1 = __importDefault(require("./stores/database-store"));
22
+ const in_memory_store_1 = __importDefault(require("./stores/in-memory-store"));
23
+ const FORCE_EXIT_DELAY_MS = 5000;
24
+ // A bad timeout config (0, negative, non-finite) must fall back to the default rather than
25
+ // silently disabling the timeout — `?? default` only catches null/undefined, not 0/negative.
26
+ function positiveOrDefault(value, fallback) {
27
+ return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : fallback;
28
+ }
29
+ function buildCommonDependencies(options) {
30
+ const forestServerUrl = options.forestServerUrl ?? defaults_1.DEFAULT_FOREST_SERVER_URL;
31
+ const logger = options.logger ?? new console_logger_1.default();
32
+ const workflowPort = new forest_server_workflow_port_1.default({
33
+ envSecret: options.envSecret,
34
+ forestServerUrl,
35
+ logger,
36
+ });
37
+ const forceAiError = options.forceAiError && process.env.NODE_ENV !== 'production';
38
+ if (forceAiError) {
39
+ logger.info('FORCE_AI_ERROR is enabled — AI calls will always fail. Do not use in production.', {});
40
+ }
41
+ else if (options.forceAiError && process.env.NODE_ENV === 'production') {
42
+ logger.info('FORCE_AI_ERROR is set but ignored in production.', {});
43
+ }
44
+ let aiModelPort;
45
+ if (forceAiError) {
46
+ aiModelPort = new always_error_ai_model_port_1.default();
47
+ }
48
+ else if (options.aiConfigurations?.length) {
49
+ aiModelPort = new ai_client_adapter_1.default(options.aiConfigurations);
50
+ }
51
+ else {
52
+ aiModelPort = new server_ai_adapter_1.default({ forestServerUrl, envSecret: options.envSecret });
53
+ }
54
+ // A TTL of 0/negative/non-finite would silently make the cache always-stale, so fall back.
55
+ const schemaCache = new schema_cache_1.default(positiveOrDefault(options.schemaCacheTtlMs, defaults_1.DEFAULT_SCHEMA_CACHE_TTL_MS));
56
+ const agentPort = new agent_client_agent_port_1.default({
57
+ agentUrl: options.agentUrl,
58
+ authSecret: options.authSecret,
59
+ schemaCache,
60
+ });
61
+ const activityLogsService = new forestadmin_client_1.ActivityLogsService(new forestadmin_client_1.ForestHttpApi(), {
62
+ forestServerUrl,
63
+ headers: { 'Forest-Application-Source': 'WorkflowExecutor' },
64
+ });
65
+ const activityLogPortFactory = new forestadmin_client_activity_log_port_factory_1.default(activityLogsService, logger);
66
+ return {
67
+ agentPort,
68
+ schemaCache,
69
+ workflowPort,
70
+ aiModelPort,
71
+ activityLogPortFactory,
72
+ logger,
73
+ pollingIntervalMs: options.pollingIntervalMs ?? defaults_1.DEFAULT_POLLING_INTERVAL_MS,
74
+ envSecret: options.envSecret,
75
+ authSecret: options.authSecret,
76
+ stopTimeoutMs: options.stopTimeoutMs,
77
+ stepTimeoutMs: positiveOrDefault(options.stepTimeoutMs, defaults_1.DEFAULT_STEP_TIMEOUT_MS),
78
+ aiInvokeTimeoutMs: positiveOrDefault(options.aiInvokeTimeoutMs, defaults_1.DEFAULT_AI_INVOKE_TIMEOUT_MS),
79
+ maxChainDepth: options.maxChainDepth,
80
+ };
81
+ }
82
+ function createWorkflowExecutor(runner, server, logger) {
83
+ let shutdownPromise = null;
84
+ const shutdown = async () => {
85
+ try {
86
+ await server.stop();
87
+ }
88
+ catch (err) {
89
+ logger.error('HTTP server close failed during shutdown', {
90
+ error: err instanceof Error ? err.message : String(err),
91
+ });
92
+ }
93
+ await runner.stop();
94
+ };
95
+ const onSignal = async () => {
96
+ logger.info?.('Received shutdown signal, stopping gracefully...', {});
97
+ try {
98
+ if (!shutdownPromise)
99
+ shutdownPromise = shutdown();
100
+ await shutdownPromise;
101
+ process.exitCode = 0;
102
+ }
103
+ catch (error) {
104
+ logger.error('Graceful shutdown failed', {
105
+ error: error instanceof Error ? error.message : String(error),
106
+ });
107
+ process.exitCode = 1;
108
+ }
109
+ // Safety net: force exit if the event loop doesn't drain
110
+ // eslint-disable-next-line no-console
111
+ setTimeout(() => {
112
+ logger.error('Process did not exit after shutdown — forcing exit', {});
113
+ process.exit(process.exitCode ?? 1);
114
+ }, FORCE_EXIT_DELAY_MS).unref();
115
+ };
116
+ return {
117
+ get state() {
118
+ return runner.state;
119
+ },
120
+ async start() {
121
+ await runner.start();
122
+ await server.start();
123
+ process.on('SIGTERM', onSignal);
124
+ process.on('SIGINT', onSignal);
125
+ },
126
+ async stop() {
127
+ process.removeListener('SIGTERM', onSignal);
128
+ process.removeListener('SIGINT', onSignal);
129
+ if (!shutdownPromise)
130
+ shutdownPromise = shutdown();
131
+ await shutdownPromise;
132
+ },
133
+ };
134
+ }
135
+ function buildInMemoryExecutor(options) {
136
+ const deps = buildCommonDependencies(options);
137
+ const runner = new runner_1.default({
138
+ ...deps,
139
+ runStore: new in_memory_store_1.default(),
140
+ });
141
+ const server = new executor_http_server_1.default({
142
+ port: options.httpPort,
143
+ runner,
144
+ authSecret: options.authSecret,
145
+ workflowPort: deps.workflowPort,
146
+ logger: deps.logger,
147
+ });
148
+ return createWorkflowExecutor(runner, server, deps.logger);
149
+ }
150
+ function buildDatabaseExecutor(options) {
151
+ const deps = buildCommonDependencies(options);
152
+ const { uri, ...sequelizeOptions } = options.database;
153
+ // Silence Sequelize's verbose SQL logger by default so our structured logs
154
+ // stay readable. Caller can still opt in via options.database.logging.
155
+ // An explicit `logging: undefined` in the caller overrides our default via
156
+ // spread, so we re-apply the default when the merged value ends up undefined.
157
+ const sequelizeDefaults = { logging: false };
158
+ const mergedOptions = { ...sequelizeDefaults, ...sequelizeOptions };
159
+ if (mergedOptions.logging === undefined)
160
+ mergedOptions.logging = false;
161
+ const sequelize = uri ? new sequelize_1.Sequelize(uri, mergedOptions) : new sequelize_1.Sequelize(mergedOptions);
162
+ const runner = new runner_1.default({
163
+ ...deps,
164
+ runStore: new database_store_1.default({ sequelize }),
165
+ });
166
+ const server = new executor_http_server_1.default({
167
+ port: options.httpPort,
168
+ runner,
169
+ authSecret: options.authSecret,
170
+ workflowPort: deps.workflowPort,
171
+ logger: deps.logger,
172
+ });
173
+ return createWorkflowExecutor(runner, server, deps.logger);
174
+ }
175
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQtd29ya2Zsb3ctZXhlY3V0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYnVpbGQtd29ya2Zsb3ctZXhlY3V0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFxTUEsc0RBaUJDO0FBRUQsc0RBMEJDO0FBN09ELHdFQUFxRjtBQUNyRix5Q0FBc0M7QUFFdEMsaUdBQXNFO0FBQ3RFLHFGQUEyRDtBQUMzRCx1R0FBMkU7QUFDM0UsK0VBQXNEO0FBQ3RELHlHQUE4RTtBQUM5RSwySUFBOEc7QUFDOUcscUZBQTJEO0FBQzNELHlDQU1vQjtBQUNwQix1RkFBNkQ7QUFDN0Qsc0RBQThCO0FBQzlCLGtFQUF5QztBQUN6Qyw2RUFBb0Q7QUFDcEQsK0VBQXFEO0FBRXJELE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0FBK0JqQywyRkFBMkY7QUFDM0YsNkZBQTZGO0FBQzdGLFNBQVMsaUJBQWlCLENBQUMsS0FBeUIsRUFBRSxRQUFnQjtJQUNwRSxPQUFPLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO0FBQzdGLENBQUM7QUFFRCxTQUFTLHVCQUF1QixDQUFDLE9BQXdCO0lBQ3ZELE1BQU0sZUFBZSxHQUFHLE9BQU8sQ0FBQyxlQUFlLElBQUksb0NBQXlCLENBQUM7SUFDN0UsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sSUFBSSxJQUFJLHdCQUFhLEVBQUUsQ0FBQztJQUVyRCxNQUFNLFlBQVksR0FBRyxJQUFJLHFDQUF3QixDQUFDO1FBQ2hELFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztRQUM1QixlQUFlO1FBQ2YsTUFBTTtLQUNQLENBQUMsQ0FBQztJQUVILE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxZQUFZLElBQUksT0FBTyxDQUFD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
@@ -0,0 +1,26 @@
1
+ import type { Logger } from './ports/logger-port';
2
+ import { type DatabaseExecutorOptions, type ExecutorOptions, type WorkflowExecutor } from './build-workflow-executor';
3
+ export interface CliArgs {
4
+ help: boolean;
5
+ version: boolean;
6
+ inMemory: boolean;
7
+ pretty: boolean;
8
+ json: boolean;
9
+ }
10
+ export interface CliConfig {
11
+ executorOptions: ExecutorOptions;
12
+ databaseUrl?: string;
13
+ mode: 'in-memory' | 'database';
14
+ }
15
+ export interface CliFactories {
16
+ buildInMemory: (options: ExecutorOptions) => WorkflowExecutor;
17
+ buildDatabase: (options: DatabaseExecutorOptions) => WorkflowExecutor;
18
+ }
19
+ export declare function parseArgs(argv: string[]): CliArgs;
20
+ export declare function pickLogger(args: CliArgs, stdout?: NodeJS.WriteStream): Logger;
21
+ export declare function readEnvConfig(env: NodeJS.ProcessEnv, args: CliArgs): CliConfig;
22
+ export declare function printHelp(): void;
23
+ export declare function printVersion(): void;
24
+ export declare function logStartup(logger: Logger, config: CliConfig): void;
25
+ export declare function runCli(argv: string[], env: NodeJS.ProcessEnv, factories: CliFactories): Promise<WorkflowExecutor | null>;
26
+ //# sourceMappingURL=cli-core.d.ts.map