arvo-event-handler 3.0.14 → 3.0.16
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.
- package/dist/ArvoEventHandler/index.d.ts +20 -123
- package/dist/ArvoEventHandler/index.js +5 -112
- package/dist/ArvoMachine/createMachine.d.ts +103 -158
- package/dist/ArvoMachine/createMachine.js +59 -181
- package/dist/ArvoMachine/index.d.ts +5 -57
- package/dist/ArvoMachine/index.js +8 -117
- package/dist/ArvoMachine/types.d.ts +0 -82
- package/dist/ArvoMachine/utils.d.ts +0 -15
- package/dist/ArvoMachine/utils.js +0 -15
- package/dist/ArvoOrchestrationUtils/createEmitableEvent.d.ts +31 -0
- package/dist/ArvoOrchestrationUtils/createEmitableEvent.js +21 -3
- package/dist/ArvoOrchestrationUtils/error.d.ts +22 -0
- package/dist/ArvoOrchestrationUtils/error.js +21 -0
- package/dist/ArvoOrchestrationUtils/handlerErrors.d.ts +30 -2
- package/dist/ArvoOrchestrationUtils/handlerErrors.js +19 -2
- package/dist/ArvoOrchestrationUtils/inputValidation.d.ts +47 -0
- package/dist/ArvoOrchestrationUtils/inputValidation.js +120 -0
- package/dist/ArvoOrchestrationUtils/orchestrationExecutionState.d.ts +24 -1
- package/dist/ArvoOrchestrationUtils/orchestrationExecutionState.js +9 -1
- package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/acquireLockWithValidation.d.ts +5 -1
- package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/acquireLockWithValidation.js +5 -1
- package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/index.d.ts +44 -5
- package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/index.js +17 -5
- package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/validateAndParseSubject.d.ts +6 -1
- package/dist/ArvoOrchestrationUtils/orchestrationExecutionWrapper/validateAndParseSubject.js +6 -1
- package/dist/ArvoOrchestrationUtils/servicesValidation.d.ts +14 -6
- package/dist/ArvoOrchestrationUtils/servicesValidation.js +14 -6
- package/dist/ArvoOrchestrator/factory.d.ts +18 -15
- package/dist/ArvoOrchestrator/factory.js +19 -16
- package/dist/ArvoOrchestrator/index.d.ts +51 -19
- package/dist/ArvoOrchestrator/index.js +29 -17
- package/dist/ArvoOrchestrator/types.d.ts +74 -49
- package/dist/ArvoResumable/factory.d.ts +31 -36
- package/dist/ArvoResumable/factory.js +29 -18
- package/dist/ArvoResumable/index.d.ts +69 -65
- package/dist/ArvoResumable/index.js +49 -92
- package/dist/ArvoResumable/types.d.ts +177 -72
- package/dist/IArvoEventHandler/index.d.ts +29 -15
- package/package.json +2 -2
|
@@ -28,170 +28,22 @@ var arvo_core_1 = require("arvo-core");
|
|
|
28
28
|
var xstate_1 = require("xstate");
|
|
29
29
|
var _1 = __importDefault(require("."));
|
|
30
30
|
var servicesValidation_1 = require("../ArvoOrchestrationUtils/servicesValidation");
|
|
31
|
+
var errors_1 = require("../errors");
|
|
31
32
|
var object_1 = require("../utils/object");
|
|
32
33
|
var utils_1 = require("./utils");
|
|
33
34
|
/**
|
|
34
35
|
* Establishes the foundation for creating Arvo-compatible state machines.
|
|
35
36
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* to ensure compatibility with the Arvo event-driven system.
|
|
37
|
+
* Designed for synchronous state machine orchestrations in Arvo's event-driven architecture.
|
|
38
|
+
* Builds upon XState with Arvo-specific constraints to enforce predictable state transitions.
|
|
39
39
|
*
|
|
40
|
-
* @
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* It builds upon XState, providing a tailored implementation that:
|
|
48
|
-
*
|
|
49
|
-
* 1. Enforces synchronous behavior to maintain predictable state transitions
|
|
50
|
-
* 3. Implements Arvo-specific constraints and features
|
|
51
|
-
*
|
|
52
|
-
* Key features:
|
|
53
|
-
* - Synchronous execution: Ensures deterministic behavior in event-driven systems
|
|
54
|
-
* - Built-in actions: Includes `enqueueArvoEvent` for Arvo event handling
|
|
55
|
-
* - Constraint checking: Prevents usage of asynchronous features like 'actors' or 'delays'
|
|
56
|
-
*
|
|
57
|
-
* @remarks
|
|
58
|
-
* While `setupArvoMachine` is based on XState's `setup` and `createMachine` functions,
|
|
59
|
-
* it includes Arvo-specific modifications and restrictions. For a deeper understanding
|
|
60
|
-
* of the underlying XState concepts, refer to the official XState documentation:
|
|
61
|
-
* - XState setup: https://stately.ai/docs/setup
|
|
62
|
-
* - XState createMachine: https://stately.ai/docs/machines
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* Here's a comprehensive example demonstrating how to use `setupArvoMachine`:
|
|
66
|
-
*
|
|
67
|
-
* ```typescript
|
|
68
|
-
* import { setupArvoMachine } from 'arvo-xstate'
|
|
69
|
-
* import { createArvoOrchestratorContract, ArvoErrorSchema, createArvoContract } from 'arvo-core'
|
|
70
|
-
* import { z } from 'zod'
|
|
71
|
-
*
|
|
72
|
-
* // Define the LLM orchestrator contract
|
|
73
|
-
* const llmContract = createArvoOrchestratorContract({
|
|
74
|
-
* uri: `#/orchestrators/llm/`,
|
|
75
|
-
* type: 'llm',
|
|
76
|
-
* versions: {
|
|
77
|
-
* '0.0.1': {
|
|
78
|
-
* init: z.object({
|
|
79
|
-
* request: z.string(),
|
|
80
|
-
* llm: z.enum(['gpt-4', 'gpt-4o']),
|
|
81
|
-
* }),
|
|
82
|
-
* complete: z.object({
|
|
83
|
-
* response: z.string(),
|
|
84
|
-
* })
|
|
85
|
-
* }
|
|
86
|
-
* }
|
|
87
|
-
* })
|
|
88
|
-
*
|
|
89
|
-
* // Define the OpenAI service contract
|
|
90
|
-
* const openAiContract = createArvoContract({
|
|
91
|
-
* uri: `#/services/openai`,
|
|
92
|
-
* type: 'com.openai.completions',
|
|
93
|
-
* versions: {
|
|
94
|
-
* '0.0.1': {
|
|
95
|
-
* accepts: z.object({
|
|
96
|
-
* request: z.string()
|
|
97
|
-
* }),
|
|
98
|
-
* emits: {
|
|
99
|
-
* 'evt.openai.completions.success': z.object({
|
|
100
|
-
* response: z.string(),
|
|
101
|
-
* })
|
|
102
|
-
* }
|
|
103
|
-
* }
|
|
104
|
-
* }
|
|
105
|
-
* })
|
|
106
|
-
*
|
|
107
|
-
* const machineId = 'machineV100'
|
|
108
|
-
*
|
|
109
|
-
* // Set up the Arvo machine
|
|
110
|
-
* const llmMachine = setupArvoMachine({
|
|
111
|
-
* contracts: {
|
|
112
|
-
* self: llmContract.version('0.0.1'),
|
|
113
|
-
* services: {
|
|
114
|
-
* openAiContract.version('0.0.1'),
|
|
115
|
-
* }
|
|
116
|
-
* },
|
|
117
|
-
* types: {
|
|
118
|
-
* context: {} as {
|
|
119
|
-
* request: string,
|
|
120
|
-
* llm: string,
|
|
121
|
-
* response: string | null,
|
|
122
|
-
* errors: z.infer<typeof ArvoErrorSchema>[]
|
|
123
|
-
* },
|
|
124
|
-
* tags: {} as 'pending' | 'success' | 'error',
|
|
125
|
-
* },
|
|
126
|
-
* actions: {
|
|
127
|
-
* log: ({context, event}) => console.log({context, event})
|
|
128
|
-
* },
|
|
129
|
-
* guards: {
|
|
130
|
-
* isValid: ({context, event}) => Boolean(context.request)
|
|
131
|
-
* }
|
|
132
|
-
* }).createMachine({
|
|
133
|
-
* id: machineId,
|
|
134
|
-
* context: ({input}) => ({
|
|
135
|
-
* request: input.request,
|
|
136
|
-
* llm: input.llm,
|
|
137
|
-
* response: null,
|
|
138
|
-
* errors: [],
|
|
139
|
-
* }),
|
|
140
|
-
* initial: 'validate',
|
|
141
|
-
* states: {
|
|
142
|
-
* validate: {
|
|
143
|
-
* always: [
|
|
144
|
-
* {
|
|
145
|
-
* guard: 'isValid',
|
|
146
|
-
* target: 'llm',
|
|
147
|
-
* },
|
|
148
|
-
* {
|
|
149
|
-
* target: 'error',
|
|
150
|
-
* }
|
|
151
|
-
* ]
|
|
152
|
-
* },
|
|
153
|
-
* llm: {
|
|
154
|
-
* entry: [
|
|
155
|
-
* {
|
|
156
|
-
* type: 'log',
|
|
157
|
-
* },
|
|
158
|
-
* emit(({context}) => ({
|
|
159
|
-
* type: 'com.openai.completions',
|
|
160
|
-
* data: {
|
|
161
|
-
* request: context.request,
|
|
162
|
-
* },
|
|
163
|
-
* }))
|
|
164
|
-
* ],
|
|
165
|
-
* on: {
|
|
166
|
-
* 'evt.openai.completions.success': {
|
|
167
|
-
* actions: [
|
|
168
|
-
* assign({response: ({event}) => event.response})
|
|
169
|
-
* ],
|
|
170
|
-
* target: 'done'
|
|
171
|
-
* },
|
|
172
|
-
* 'sys.com.openai.completions.error': {
|
|
173
|
-
* actions: [
|
|
174
|
-
* assign({errors: ({context, event}) => [...context.errors, event.body]})
|
|
175
|
-
* ],
|
|
176
|
-
* target: 'error'
|
|
177
|
-
* }
|
|
178
|
-
* }
|
|
179
|
-
* },
|
|
180
|
-
* done: {
|
|
181
|
-
* type: 'final'
|
|
182
|
-
* },
|
|
183
|
-
* error: {
|
|
184
|
-
* type: 'final'
|
|
185
|
-
* },
|
|
186
|
-
* }
|
|
187
|
-
* });
|
|
188
|
-
* ```
|
|
189
|
-
*
|
|
190
|
-
* This example demonstrates:
|
|
191
|
-
* 1. Defining Arvo contracts for the orchestrator and a service
|
|
192
|
-
* 2. Setting up an Arvo machine with contracts, types, actions, and guards
|
|
193
|
-
* 3. Creating a machine with states for validation, LLM interaction, and error handling
|
|
194
|
-
* 4. Using XState features like `emit` bound with Arvo contracts for event emitting and event handling via transitions
|
|
40
|
+
* @throws {ConfigViolation} When configuration violates Arvo constraints:
|
|
41
|
+
* - Using `actors` or `delays` (async behavior not supported)
|
|
42
|
+
* - Overriding reserved `enqueueArvoEvent` action name
|
|
43
|
+
* - Machine version mismatch with contract version
|
|
44
|
+
* - Using `invoke` or `after` in state configurations
|
|
45
|
+
* - Service contracts with duplicate URIs (multiple versions of same contract)
|
|
46
|
+
* - Circular dependency (self contract URI matches a service contract URI)
|
|
195
47
|
*/
|
|
196
48
|
function setupArvoMachine(param) {
|
|
197
49
|
var _a, _b;
|
|
@@ -199,13 +51,13 @@ function setupArvoMachine(param) {
|
|
|
199
51
|
return (0, arvo_core_1.cleanString)("\n Configuration Error: '".concat(type, "' not supported in Arvo machines\n \n Arvo machines do not support XState ").concat(type === 'actor' ? 'actors' : 'delay transitions', " as they introduce asynchronous behavior.\n \n To fix:\n 1. Remove the '").concat(type, "' configuration\n 2. Use Arvo's event-driven patterns instead for asynchronous operations\n "));
|
|
200
52
|
};
|
|
201
53
|
if (param.actors) {
|
|
202
|
-
throw new
|
|
54
|
+
throw new errors_1.ConfigViolation(createConfigErrorMessage('actor'));
|
|
203
55
|
}
|
|
204
56
|
if (param.delays) {
|
|
205
|
-
throw new
|
|
57
|
+
throw new errors_1.ConfigViolation(createConfigErrorMessage('delays'));
|
|
206
58
|
}
|
|
207
59
|
if ((_a = param.actions) === null || _a === void 0 ? void 0 : _a.enqueueArvoEvent) {
|
|
208
|
-
throw new
|
|
60
|
+
throw new errors_1.ConfigViolation((0, arvo_core_1.cleanString)("\n Configuration Error: Reserved action name 'enqueueArvoEvent'\n \n 'enqueueArvoEvent' is an internal Arvo system action and cannot be overridden.\n \n To fix: Use a different name for your action, such as:\n - 'queueCustomEvent'\n - 'scheduleEvent'\n - 'dispatchEvent'\n "));
|
|
209
61
|
}
|
|
210
62
|
(0, servicesValidation_1.servicesValidation)(param.contracts, 'machine');
|
|
211
63
|
var combinedActions = __assign(__assign({}, ((_b = param.actions) !== null && _b !== void 0 ? _b : {})), { enqueueArvoEvent: (0, xstate_1.assign)(function (_a, param) {
|
|
@@ -222,24 +74,12 @@ function setupArvoMachine(param) {
|
|
|
222
74
|
});
|
|
223
75
|
/**
|
|
224
76
|
* Creates an Arvo-compatible XState machine.
|
|
225
|
-
*
|
|
226
|
-
* @param config - The configuration object for the machine
|
|
227
|
-
* @returns An ArvoMachine instance
|
|
228
|
-
*
|
|
229
|
-
* @throws Error if 'invoke' or 'after' configurations are used
|
|
230
|
-
*
|
|
231
|
-
* @remarks
|
|
232
|
-
* This function creates a state machine based on the provided configuration.
|
|
233
|
-
* It performs additional checks to ensure the machine adheres to Arvo's constraints,
|
|
234
|
-
* such as disallowing 'invoke' and 'after' configurations which could introduce
|
|
235
|
-
* asynchronous behavior.
|
|
236
|
-
* ```
|
|
237
77
|
*/
|
|
238
78
|
var createMachine = function (config) {
|
|
239
|
-
var _a, _b;
|
|
79
|
+
var _a, _b, _c, _d, _e;
|
|
240
80
|
var machineVersion = (_a = config.version) !== null && _a !== void 0 ? _a : param.contracts.self.version;
|
|
241
81
|
if (machineVersion !== param.contracts.self.version) {
|
|
242
|
-
throw new
|
|
82
|
+
throw new errors_1.ConfigViolation("Version mismatch: Machine version must be '".concat(param.contracts.self.version, "' or undefined, received '").concat(config.version, "'"));
|
|
243
83
|
}
|
|
244
84
|
var createConfigErrorMessage = function (type, path) {
|
|
245
85
|
var location = path.join(' > ');
|
|
@@ -253,16 +93,16 @@ function setupArvoMachine(param) {
|
|
|
253
93
|
return (0, arvo_core_1.cleanString)("\n Configuration Error: Reserved action name 'enqueueArvoEvent'\n \n Location: ".concat(location, "\n \n 'enqueueArvoEvent' is an internal Arvo system action and cannot be used in machine configurations.\n \n To fix: Use a different name for your action\n "));
|
|
254
94
|
}
|
|
255
95
|
};
|
|
256
|
-
for (var _i = 0,
|
|
257
|
-
var item =
|
|
96
|
+
for (var _i = 0, _f = (0, object_1.getAllPaths)((_b = config.states) !== null && _b !== void 0 ? _b : {}); _i < _f.length; _i++) {
|
|
97
|
+
var item = _f[_i];
|
|
258
98
|
if (item.path.includes('invoke')) {
|
|
259
|
-
throw new
|
|
99
|
+
throw new errors_1.ConfigViolation((_c = createConfigErrorMessage('invoke', item.path)) !== null && _c !== void 0 ? _c : 'Invoke not allowed');
|
|
260
100
|
}
|
|
261
101
|
if (item.path.includes('after')) {
|
|
262
|
-
throw new
|
|
102
|
+
throw new errors_1.ConfigViolation((_d = createConfigErrorMessage('after', item.path)) !== null && _d !== void 0 ? _d : 'After not allowed');
|
|
263
103
|
}
|
|
264
104
|
if (item.path.includes('enqueueArvoEvent')) {
|
|
265
|
-
throw new
|
|
105
|
+
throw new errors_1.ConfigViolation((_e = createConfigErrorMessage('enqueueArvoEvent', item.path)) !== null && _e !== void 0 ? _e : 'EnqueueArvoEvent not allowed');
|
|
266
106
|
}
|
|
267
107
|
}
|
|
268
108
|
var machine = systemSetup.createMachine(__assign({}, config));
|
|
@@ -271,5 +111,43 @@ function setupArvoMachine(param) {
|
|
|
271
111
|
var requiresLocking = hasParallelStates || hasMultipleNonSystemErrorEvents;
|
|
272
112
|
return new _1.default(config.id, machineVersion, param.contracts, machine, requiresLocking);
|
|
273
113
|
};
|
|
274
|
-
return {
|
|
114
|
+
return {
|
|
115
|
+
/**
|
|
116
|
+
* Creates an Arvo-compatible state machine with the specified configuration.
|
|
117
|
+
*
|
|
118
|
+
* Constructs a fully-typed state machine that orchestrates event-driven workflows
|
|
119
|
+
* using the contracts and types defined in setup. The machine enforces synchronous
|
|
120
|
+
* execution and validates configuration against Arvo constraints.
|
|
121
|
+
*
|
|
122
|
+
* For more information, see [xstate state machine docs](https://stately.ai/docs/states)
|
|
123
|
+
* @returns {ArvoMachine} A configured Arvo machine ready for execution
|
|
124
|
+
* @throws {ConfigViolation} When configuration violates Arvo constraints (see {@link setupArvoMachine} docs)
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const machine = setup.createMachine({
|
|
129
|
+
* id: 'machineV100',
|
|
130
|
+
* initial: 'verifying',
|
|
131
|
+
* context: ({ input }) => ({
|
|
132
|
+
* userId: input.data.userId,
|
|
133
|
+
* verified: false
|
|
134
|
+
* }),
|
|
135
|
+
* states: {
|
|
136
|
+
* verifying: {
|
|
137
|
+
* on: {
|
|
138
|
+
* 'com.user.verified': {
|
|
139
|
+
* target: 'active',
|
|
140
|
+
* actions: { type: 'updateUser' }
|
|
141
|
+
* }
|
|
142
|
+
* }
|
|
143
|
+
* },
|
|
144
|
+
* active: {
|
|
145
|
+
* type: 'final'
|
|
146
|
+
* }
|
|
147
|
+
* }
|
|
148
|
+
* });
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
createMachine: createMachine,
|
|
152
|
+
};
|
|
275
153
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { Span } from '@opentelemetry/api';
|
|
2
|
+
import type { ArvoContract, ArvoEvent, ArvoOrchestratorContract, ArvoSemanticVersion, VersionedArvoContract } from 'arvo-core';
|
|
2
3
|
import type { AnyActorLogic } from 'xstate';
|
|
3
|
-
import type
|
|
4
|
+
import { type EventValidationResult } from '../ArvoOrchestrationUtils/inputValidation';
|
|
4
5
|
/**
|
|
5
6
|
* Represents an ArvoMachine object that can be consumed by an Arvo orchestrator.
|
|
6
7
|
* ArvoMachine encapsulates the logic and metadata required for an Arvo-compatible
|
|
7
8
|
* state machine. It combines XState's actor logic with Arvo-specific contracts
|
|
8
9
|
* and versioning information.
|
|
9
10
|
*
|
|
10
|
-
* @remarks
|
|
11
11
|
* It is strongly recommended to use `setupArvoMachine(...).createMachine(...)`
|
|
12
12
|
* instead of creating this object directly. The setup function provides additional
|
|
13
13
|
* type safety and validation that helps prevent runtime errors.
|
|
@@ -21,27 +21,6 @@ export default class ArvoMachine<TId extends string, TVersion extends ArvoSemant
|
|
|
21
21
|
};
|
|
22
22
|
readonly logic: TLogic;
|
|
23
23
|
readonly requiresResourceLocking: boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Creates a new ArvoMachine instance.
|
|
26
|
-
*
|
|
27
|
-
* @param id - A unique identifier for the machine. This ID must be unique within
|
|
28
|
-
* the scope of an orchestrator and is used for routing and logging.
|
|
29
|
-
*
|
|
30
|
-
* @param version - The semantic version of the machine. Must follow semver format
|
|
31
|
-
* and match the version specified in the contract.
|
|
32
|
-
*
|
|
33
|
-
* @param contracts - Configuration object containing contract definitions
|
|
34
|
-
* @param contracts.self - The contract defining this machine's interface and capabilities
|
|
35
|
-
* @param contracts.services - Record of contracts for services this machine can interact with
|
|
36
|
-
*
|
|
37
|
-
* @param logic - The XState actor logic that defines the machine's behavior,
|
|
38
|
-
* including states, transitions, and actions.
|
|
39
|
-
* @param [requiresResourceLocking] - Optional flag indicating if the machine needs distributed locks.
|
|
40
|
-
* False when machine has no parallel states and executes sequentially.
|
|
41
|
-
* Defaults to true.
|
|
42
|
-
*
|
|
43
|
-
* @throws {Error} When contracts are invalid or incompatible with the specified version
|
|
44
|
-
*/
|
|
45
24
|
constructor(id: TId, version: TVersion, contracts: {
|
|
46
25
|
self: TSelfContract;
|
|
47
26
|
services: TServiceContract;
|
|
@@ -55,39 +34,8 @@ export default class ArvoMachine<TId extends string, TVersion extends ArvoSemant
|
|
|
55
34
|
* Performs validation for both self-contract events and service contract events.
|
|
56
35
|
*
|
|
57
36
|
* @param event - The event to validate
|
|
58
|
-
* @returns A validation result object:
|
|
59
|
-
* - "VALID" - Event is valid and can be processed
|
|
60
|
-
* - "CONTRACT_UNRESOLVED" - No matching contract found for the event
|
|
61
|
-
* - "INVALID" - Event dataschema conflict with contract
|
|
62
|
-
* - "INVALID_DATA" - Event data conflicts with contract
|
|
63
37
|
*
|
|
64
|
-
* @
|
|
65
|
-
* ```typescript
|
|
66
|
-
* const result = machine.validateInput(event);
|
|
67
|
-
* if (result.type === "VALID") {
|
|
68
|
-
* // Process the event
|
|
69
|
-
* } else if (result.type === "INVALID") {
|
|
70
|
-
* console.error(result.error);
|
|
71
|
-
* } else {
|
|
72
|
-
* // Handle unresolved contract
|
|
73
|
-
* }
|
|
74
|
-
* ```
|
|
75
|
-
*
|
|
76
|
-
* @remarks
|
|
77
|
-
* The validation process includes:
|
|
78
|
-
* - Finding a matching contract (self or service)
|
|
79
|
-
* - Validating dataschema URI and version if present
|
|
80
|
-
* - Validating event data against the contract schema
|
|
38
|
+
* See {@link validateInputEvent} for more infromation
|
|
81
39
|
*/
|
|
82
|
-
validateInput(event: ArvoEvent):
|
|
83
|
-
type: 'VALID';
|
|
84
|
-
} | {
|
|
85
|
-
type: 'CONTRACT_UNRESOLVED';
|
|
86
|
-
} | {
|
|
87
|
-
type: 'INVALID';
|
|
88
|
-
error: Error;
|
|
89
|
-
} | {
|
|
90
|
-
type: 'INVALID_DATA';
|
|
91
|
-
error: z.ZodError;
|
|
92
|
-
};
|
|
40
|
+
validateInput(event: ArvoEvent, span?: Span): EventValidationResult;
|
|
93
41
|
}
|
|
@@ -1,48 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
3
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
4
|
-
if (ar || !(i in from)) {
|
|
5
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
6
|
-
ar[i] = from[i];
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
var
|
|
3
|
+
var inputValidation_1 = require("../ArvoOrchestrationUtils/inputValidation");
|
|
13
4
|
/**
|
|
14
5
|
* Represents an ArvoMachine object that can be consumed by an Arvo orchestrator.
|
|
15
6
|
* ArvoMachine encapsulates the logic and metadata required for an Arvo-compatible
|
|
16
7
|
* state machine. It combines XState's actor logic with Arvo-specific contracts
|
|
17
8
|
* and versioning information.
|
|
18
9
|
*
|
|
19
|
-
* @remarks
|
|
20
10
|
* It is strongly recommended to use `setupArvoMachine(...).createMachine(...)`
|
|
21
11
|
* instead of creating this object directly. The setup function provides additional
|
|
22
12
|
* type safety and validation that helps prevent runtime errors.
|
|
23
13
|
*/
|
|
24
14
|
var ArvoMachine = /** @class */ (function () {
|
|
25
|
-
/**
|
|
26
|
-
* Creates a new ArvoMachine instance.
|
|
27
|
-
*
|
|
28
|
-
* @param id - A unique identifier for the machine. This ID must be unique within
|
|
29
|
-
* the scope of an orchestrator and is used for routing and logging.
|
|
30
|
-
*
|
|
31
|
-
* @param version - The semantic version of the machine. Must follow semver format
|
|
32
|
-
* and match the version specified in the contract.
|
|
33
|
-
*
|
|
34
|
-
* @param contracts - Configuration object containing contract definitions
|
|
35
|
-
* @param contracts.self - The contract defining this machine's interface and capabilities
|
|
36
|
-
* @param contracts.services - Record of contracts for services this machine can interact with
|
|
37
|
-
*
|
|
38
|
-
* @param logic - The XState actor logic that defines the machine's behavior,
|
|
39
|
-
* including states, transitions, and actions.
|
|
40
|
-
* @param [requiresResourceLocking] - Optional flag indicating if the machine needs distributed locks.
|
|
41
|
-
* False when machine has no parallel states and executes sequentially.
|
|
42
|
-
* Defaults to true.
|
|
43
|
-
*
|
|
44
|
-
* @throws {Error} When contracts are invalid or incompatible with the specified version
|
|
45
|
-
*/
|
|
46
15
|
function ArvoMachine(id, version, contracts, logic, requiresResourceLocking) {
|
|
47
16
|
if (requiresResourceLocking === void 0) { requiresResourceLocking = true; }
|
|
48
17
|
this.id = id;
|
|
@@ -66,94 +35,16 @@ var ArvoMachine = /** @class */ (function () {
|
|
|
66
35
|
* Performs validation for both self-contract events and service contract events.
|
|
67
36
|
*
|
|
68
37
|
* @param event - The event to validate
|
|
69
|
-
* @returns A validation result object:
|
|
70
|
-
* - "VALID" - Event is valid and can be processed
|
|
71
|
-
* - "CONTRACT_UNRESOLVED" - No matching contract found for the event
|
|
72
|
-
* - "INVALID" - Event dataschema conflict with contract
|
|
73
|
-
* - "INVALID_DATA" - Event data conflicts with contract
|
|
74
|
-
*
|
|
75
|
-
* @example
|
|
76
|
-
* ```typescript
|
|
77
|
-
* const result = machine.validateInput(event);
|
|
78
|
-
* if (result.type === "VALID") {
|
|
79
|
-
* // Process the event
|
|
80
|
-
* } else if (result.type === "INVALID") {
|
|
81
|
-
* console.error(result.error);
|
|
82
|
-
* } else {
|
|
83
|
-
* // Handle unresolved contract
|
|
84
|
-
* }
|
|
85
|
-
* ```
|
|
86
38
|
*
|
|
87
|
-
* @
|
|
88
|
-
* The validation process includes:
|
|
89
|
-
* - Finding a matching contract (self or service)
|
|
90
|
-
* - Validating dataschema URI and version if present
|
|
91
|
-
* - Validating event data against the contract schema
|
|
39
|
+
* See {@link validateInputEvent} for more infromation
|
|
92
40
|
*/
|
|
93
|
-
ArvoMachine.prototype.validateInput = function (event) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
contractType = 'self';
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
resovledContract =
|
|
103
|
-
(_a = Object.fromEntries(Object.values(this.contracts.services).reduce(function (acc, cur) { return __spreadArray(__spreadArray([], acc, true), __spreadArray(__spreadArray([], cur.emitList, true), [cur.systemError], false).map(function (item) { return [item.type, cur]; }), true); }, []))[event.type]) !== null && _a !== void 0 ? _a : null;
|
|
104
|
-
contractType = 'service';
|
|
105
|
-
}
|
|
106
|
-
if (!resovledContract) {
|
|
107
|
-
(0, arvo_core_1.logToSpan)({
|
|
108
|
-
level: 'WARNING',
|
|
109
|
-
message: "Contract resolution failed: No matching contract found for event (id='".concat(event.id, "', type='").concat(event.type, "')"),
|
|
110
|
-
});
|
|
111
|
-
return {
|
|
112
|
-
type: 'CONTRACT_UNRESOLVED',
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
(0, arvo_core_1.logToSpan)({
|
|
116
|
-
level: 'INFO',
|
|
117
|
-
message: "Contract resolved: Contract(uri='".concat(resovledContract.uri, "', version='").concat(resovledContract.version, "', type='").concat(resovledContract.accepts.type, "') for the event(id='").concat(event.id, "', type='").concat(event.type, "')"),
|
|
41
|
+
ArvoMachine.prototype.validateInput = function (event, span) {
|
|
42
|
+
return (0, inputValidation_1.validateInputEvent)({
|
|
43
|
+
event: event,
|
|
44
|
+
selfContract: this.contracts.self,
|
|
45
|
+
serviceContracts: this.contracts.services,
|
|
46
|
+
span: span,
|
|
118
47
|
});
|
|
119
|
-
var dataschema = arvo_core_1.EventDataschemaUtil.parse(event);
|
|
120
|
-
if (!dataschema) {
|
|
121
|
-
(0, arvo_core_1.logToSpan)({
|
|
122
|
-
level: 'WARNING',
|
|
123
|
-
message: "Dataschema resolution failed: Unable to parse dataschema='".concat(event.dataschema, "' for event(id='").concat(event.id, "', type='").concat(event.type, "')"),
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
(0, arvo_core_1.logToSpan)({
|
|
128
|
-
level: 'INFO',
|
|
129
|
-
message: "Dataschema resolved: ".concat(event.dataschema, " matches contract(uri='").concat(resovledContract.uri, "', version='").concat(resovledContract.version, "')"),
|
|
130
|
-
});
|
|
131
|
-
if (dataschema.uri !== resovledContract.uri) {
|
|
132
|
-
return {
|
|
133
|
-
type: 'INVALID',
|
|
134
|
-
error: new Error("Contract URI mismatch: ".concat(contractType, " Contract(uri='").concat(resovledContract.uri, "', type='").concat(resovledContract.accepts.type, "') does not match Event(dataschema='").concat(event.dataschema, "', type='").concat(event.type, "')")),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
if (!(0, arvo_core_1.isWildCardArvoSematicVersion)(dataschema.version) && dataschema.version !== resovledContract.version) {
|
|
138
|
-
return {
|
|
139
|
-
type: 'INVALID',
|
|
140
|
-
error: new Error("Contract version mismatch: ".concat(contractType, " Contract(version='").concat(resovledContract.version, "', type='").concat(resovledContract.accepts.type, "', uri=").concat(resovledContract.uri, ") does not match Event(dataschema='").concat(event.dataschema, "', type='").concat(event.type, "')")),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
var validationSchema = contractType === 'self'
|
|
145
|
-
? resovledContract.accepts.schema
|
|
146
|
-
: ((_b = resovledContract.emits[event.type]) !== null && _b !== void 0 ? _b : resovledContract.systemError.schema);
|
|
147
|
-
var error = (_c = validationSchema.safeParse(event.data).error) !== null && _c !== void 0 ? _c : null;
|
|
148
|
-
if (error) {
|
|
149
|
-
return {
|
|
150
|
-
type: 'INVALID_DATA',
|
|
151
|
-
error: error,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
return {
|
|
155
|
-
type: 'VALID',
|
|
156
|
-
};
|
|
157
48
|
};
|
|
158
49
|
return ArvoMachine;
|
|
159
50
|
}());
|