@ai.ntellect/core 0.7.8 → 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.
- package/README.md +158 -81
- package/index.ts +462 -22
- package/package copy.json +21 -0
- package/package.json +9 -44
- package/tsconfig.json +108 -22
- package/types.ts +62 -0
- package/utils/executor.ts +42 -0
- package/.mocharc.json +0 -5
- package/dist/graph/controller.d.ts +0 -31
- package/dist/graph/controller.d.ts.map +0 -1
- package/dist/graph/controller.js +0 -71
- package/dist/graph/controller.js.map +0 -1
- package/dist/graph/event-manager.d.ts +0 -93
- package/dist/graph/event-manager.d.ts.map +0 -1
- package/dist/graph/event-manager.js +0 -296
- package/dist/graph/event-manager.js.map +0 -1
- package/dist/graph/index.d.ts +0 -159
- package/dist/graph/index.d.ts.map +0 -1
- package/dist/graph/index.js +0 -303
- package/dist/graph/index.js.map +0 -1
- package/dist/graph/logger.d.ts +0 -46
- package/dist/graph/logger.d.ts.map +0 -1
- package/dist/graph/logger.js +0 -69
- package/dist/graph/logger.js.map +0 -1
- package/dist/graph/node.d.ts +0 -93
- package/dist/graph/node.d.ts.map +0 -1
- package/dist/graph/node.js +0 -259
- package/dist/graph/node.js.map +0 -1
- package/dist/graph/observer.d.ts +0 -115
- package/dist/graph/observer.d.ts.map +0 -1
- package/dist/graph/observer.js +0 -198
- package/dist/graph/observer.js.map +0 -1
- package/dist/index.d.ts +0 -26
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -42
- package/dist/index.js.map +0 -1
- package/dist/interfaces/index.d.ts +0 -447
- package/dist/interfaces/index.d.ts.map +0 -1
- package/dist/interfaces/index.js +0 -75
- package/dist/interfaces/index.js.map +0 -1
- package/dist/modules/agenda/adapters/node-cron/index.d.ts +0 -17
- package/dist/modules/agenda/adapters/node-cron/index.d.ts.map +0 -1
- package/dist/modules/agenda/adapters/node-cron/index.js +0 -30
- package/dist/modules/agenda/adapters/node-cron/index.js.map +0 -1
- package/dist/modules/agenda/index.d.ts +0 -63
- package/dist/modules/agenda/index.d.ts.map +0 -1
- package/dist/modules/agenda/index.js +0 -141
- package/dist/modules/agenda/index.js.map +0 -1
- package/dist/modules/embedding/adapters/ai/index.d.ts +0 -29
- package/dist/modules/embedding/adapters/ai/index.d.ts.map +0 -1
- package/dist/modules/embedding/adapters/ai/index.js +0 -58
- package/dist/modules/embedding/adapters/ai/index.js.map +0 -1
- package/dist/modules/embedding/index.d.ts +0 -36
- package/dist/modules/embedding/index.d.ts.map +0 -1
- package/dist/modules/embedding/index.js +0 -60
- package/dist/modules/embedding/index.js.map +0 -1
- package/dist/modules/memory/adapters/in-memory/index.d.ts +0 -120
- package/dist/modules/memory/adapters/in-memory/index.d.ts.map +0 -1
- package/dist/modules/memory/adapters/in-memory/index.js +0 -211
- package/dist/modules/memory/adapters/in-memory/index.js.map +0 -1
- package/dist/modules/memory/adapters/meilisearch/index.d.ts +0 -110
- package/dist/modules/memory/adapters/meilisearch/index.d.ts.map +0 -1
- package/dist/modules/memory/adapters/meilisearch/index.js +0 -321
- package/dist/modules/memory/adapters/meilisearch/index.js.map +0 -1
- package/dist/modules/memory/adapters/redis/index.d.ts +0 -82
- package/dist/modules/memory/adapters/redis/index.d.ts.map +0 -1
- package/dist/modules/memory/adapters/redis/index.js +0 -159
- package/dist/modules/memory/adapters/redis/index.js.map +0 -1
- package/dist/modules/memory/index.d.ts +0 -67
- package/dist/modules/memory/index.d.ts.map +0 -1
- package/dist/modules/memory/index.js +0 -104
- package/dist/modules/memory/index.js.map +0 -1
- package/dist/types/index.d.ts +0 -170
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -3
- package/dist/types/index.js.map +0 -1
- package/dist/utils/generate-action-schema.d.ts +0 -5
- package/dist/utils/generate-action-schema.d.ts.map +0 -1
- package/dist/utils/generate-action-schema.js +0 -44
- package/dist/utils/generate-action-schema.js.map +0 -1
- package/dist/utils/header-builder.d.ts +0 -12
- package/dist/utils/header-builder.d.ts.map +0 -1
- package/dist/utils/header-builder.js +0 -35
- package/dist/utils/header-builder.js.map +0 -1
- package/graph/controller.ts +0 -74
- package/graph/event-manager.ts +0 -363
- package/graph/index.ts +0 -395
- package/graph/logger.ts +0 -70
- package/graph/node.ts +0 -327
- package/graph/observer.ts +0 -368
- package/interfaces/index.ts +0 -548
- package/modules/agenda/adapters/node-cron/index.ts +0 -25
- package/modules/agenda/index.ts +0 -146
- package/modules/embedding/adapters/ai/index.ts +0 -42
- package/modules/embedding/index.ts +0 -45
- package/modules/memory/adapters/in-memory/index.ts +0 -207
- package/modules/memory/adapters/meilisearch/index.ts +0 -361
- package/modules/memory/adapters/redis/index.ts +0 -164
- package/modules/memory/index.ts +0 -93
- package/test/graph/controller.test.ts +0 -187
- package/test/graph/event-manager.test.ts +0 -118
- package/test/graph/index.test.ts +0 -684
- package/test/graph/node.test.ts +0 -655
- package/test/graph/observer.test.ts +0 -398
- package/test/modules/agenda/node-cron.test.ts +0 -307
- package/test/modules/memory/adapters/in-memory.test.ts +0 -153
- package/test/modules/memory/adapters/meilisearch.test.ts +0 -287
- package/test/modules/memory/base.test.ts +0 -230
- package/types/index.ts +0 -190
- package/utils/generate-action-schema.ts +0 -46
- package/utils/header-builder.ts +0 -40
package/test/graph/node.test.ts
DELETED
@@ -1,655 +0,0 @@
|
|
1
|
-
import { expect, use } from "chai";
|
2
|
-
import chaiAsPromised from "chai-as-promised";
|
3
|
-
import { EventEmitter } from "events";
|
4
|
-
import { BehaviorSubject, Subject } from "rxjs";
|
5
|
-
import { z } from "zod";
|
6
|
-
import { GraphEventManager } from "../../graph/event-manager";
|
7
|
-
import { GraphLogger } from "../../graph/logger";
|
8
|
-
import { GraphNode, NodeParams } from "../../graph/node";
|
9
|
-
import { GraphContext } from "../../types";
|
10
|
-
|
11
|
-
use(chaiAsPromised);
|
12
|
-
|
13
|
-
describe("GraphNode", () => {
|
14
|
-
const TestSchema = z.object({
|
15
|
-
counter: z.number(),
|
16
|
-
message: z.string(),
|
17
|
-
});
|
18
|
-
|
19
|
-
type TestContext = GraphContext<typeof TestSchema>;
|
20
|
-
|
21
|
-
let node: GraphNode<typeof TestSchema>;
|
22
|
-
let eventManager: GraphEventManager<typeof TestSchema>;
|
23
|
-
let logger: GraphLogger;
|
24
|
-
let eventEmitter: EventEmitter;
|
25
|
-
let eventSubject: Subject<any>;
|
26
|
-
let stateSubject: BehaviorSubject<any>;
|
27
|
-
let events: any[] = [];
|
28
|
-
|
29
|
-
beforeEach(() => {
|
30
|
-
events = [];
|
31
|
-
eventEmitter = new EventEmitter();
|
32
|
-
eventSubject = new Subject();
|
33
|
-
stateSubject = new BehaviorSubject({ counter: 0, message: "Hello" });
|
34
|
-
logger = new GraphLogger("test", false);
|
35
|
-
eventManager = new GraphEventManager(eventEmitter, new Map(), "test", {
|
36
|
-
counter: 0,
|
37
|
-
message: "Hello",
|
38
|
-
});
|
39
|
-
|
40
|
-
// Capture des événements
|
41
|
-
eventSubject.subscribe((event) => events.push(event));
|
42
|
-
|
43
|
-
node = new GraphNode(
|
44
|
-
new Map(),
|
45
|
-
logger,
|
46
|
-
eventManager,
|
47
|
-
eventSubject,
|
48
|
-
stateSubject
|
49
|
-
);
|
50
|
-
});
|
51
|
-
|
52
|
-
it("should execute a simple node", async () => {
|
53
|
-
const nodes = new Map();
|
54
|
-
nodes.set("test", {
|
55
|
-
name: "test",
|
56
|
-
execute: async (context: TestContext) => {
|
57
|
-
context.counter++;
|
58
|
-
},
|
59
|
-
});
|
60
|
-
|
61
|
-
node = new GraphNode(
|
62
|
-
nodes,
|
63
|
-
logger,
|
64
|
-
eventManager,
|
65
|
-
eventSubject,
|
66
|
-
stateSubject
|
67
|
-
);
|
68
|
-
|
69
|
-
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
70
|
-
|
71
|
-
// Vérifier les événements émis
|
72
|
-
expect(events).to.have.lengthOf(3); // nodeStarted, nodeStateChanged, nodeCompleted
|
73
|
-
expect(events[0].type).to.equal("nodeStarted");
|
74
|
-
expect(events[1].type).to.equal("nodeStateChanged");
|
75
|
-
expect(events[2].type).to.equal("nodeCompleted");
|
76
|
-
});
|
77
|
-
|
78
|
-
it("should handle node condition", async () => {
|
79
|
-
const nodes = new Map();
|
80
|
-
nodes.set("test", {
|
81
|
-
name: "test",
|
82
|
-
condition: (context: TestContext) => context.counter < 5,
|
83
|
-
execute: async (context: TestContext) => {
|
84
|
-
context.counter++;
|
85
|
-
},
|
86
|
-
});
|
87
|
-
|
88
|
-
node = new GraphNode(
|
89
|
-
nodes,
|
90
|
-
logger,
|
91
|
-
eventManager,
|
92
|
-
eventSubject,
|
93
|
-
stateSubject
|
94
|
-
);
|
95
|
-
|
96
|
-
// Test avec condition vraie
|
97
|
-
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
98
|
-
expect(events.some((e) => e.type === "nodeStateChanged")).to.be.true;
|
99
|
-
|
100
|
-
// Test avec condition fausse
|
101
|
-
events = [];
|
102
|
-
await node.executeNode("test", { counter: 5, message: "Hello" }, null);
|
103
|
-
expect(events.some((e) => e.type === "nodeStateChanged")).to.be.false;
|
104
|
-
});
|
105
|
-
|
106
|
-
it("should handle errors", async () => {
|
107
|
-
const nodes = new Map();
|
108
|
-
nodes.set("test", {
|
109
|
-
name: "test",
|
110
|
-
execute: async () => {
|
111
|
-
throw new Error("Test error");
|
112
|
-
},
|
113
|
-
});
|
114
|
-
|
115
|
-
node = new GraphNode(
|
116
|
-
nodes,
|
117
|
-
logger,
|
118
|
-
eventManager,
|
119
|
-
eventSubject,
|
120
|
-
stateSubject
|
121
|
-
);
|
122
|
-
|
123
|
-
try {
|
124
|
-
await node.executeNode(
|
125
|
-
"test",
|
126
|
-
{ counter: 0, message: "Hello" },
|
127
|
-
null,
|
128
|
-
false
|
129
|
-
);
|
130
|
-
expect.fail("Test error");
|
131
|
-
} catch (error: any) {
|
132
|
-
expect(error.message).to.equal("Test error");
|
133
|
-
const errorEvents = events.filter((e) => e.type === "nodeError");
|
134
|
-
expect(errorEvents).to.have.lengthOf(1);
|
135
|
-
}
|
136
|
-
});
|
137
|
-
|
138
|
-
it("should emit events exactly once per state change", async () => {
|
139
|
-
const nodes = new Map();
|
140
|
-
nodes.set("test", {
|
141
|
-
name: "test",
|
142
|
-
execute: async (context: TestContext) => {
|
143
|
-
context.counter++;
|
144
|
-
context.message = "Updated";
|
145
|
-
},
|
146
|
-
});
|
147
|
-
|
148
|
-
node = new GraphNode(
|
149
|
-
nodes,
|
150
|
-
logger,
|
151
|
-
eventManager,
|
152
|
-
eventSubject,
|
153
|
-
stateSubject
|
154
|
-
);
|
155
|
-
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
156
|
-
|
157
|
-
// Compter les occurrences de chaque type d'événement
|
158
|
-
const eventCounts = events.reduce((acc, event) => {
|
159
|
-
acc[event.type] = (acc[event.type] || 0) + 1;
|
160
|
-
return acc;
|
161
|
-
}, {} as Record<string, number>);
|
162
|
-
|
163
|
-
expect(eventCounts).to.deep.equal({
|
164
|
-
nodeStarted: 1,
|
165
|
-
nodeStateChanged: 2, // Un pour counter, un pour message
|
166
|
-
nodeCompleted: 1,
|
167
|
-
});
|
168
|
-
|
169
|
-
// Vérifier l'ordre des événements
|
170
|
-
expect(events.map((e) => e.type)).to.deep.equal([
|
171
|
-
"nodeStarted",
|
172
|
-
"nodeStateChanged", // counter
|
173
|
-
"nodeStateChanged", // message
|
174
|
-
"nodeCompleted",
|
175
|
-
]);
|
176
|
-
});
|
177
|
-
|
178
|
-
it("should emit nodeStateChanged only for actual changes", async () => {
|
179
|
-
const nodes = new Map();
|
180
|
-
nodes.set("test", {
|
181
|
-
name: "test",
|
182
|
-
execute: async (context: TestContext, inputs?: any) => {
|
183
|
-
context.counter = context.counter; // Même valeur
|
184
|
-
context.message = "New"; // Nouvelle valeur
|
185
|
-
},
|
186
|
-
});
|
187
|
-
|
188
|
-
node = new GraphNode(
|
189
|
-
nodes,
|
190
|
-
logger,
|
191
|
-
eventManager,
|
192
|
-
eventSubject,
|
193
|
-
stateSubject
|
194
|
-
);
|
195
|
-
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
196
|
-
|
197
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
198
|
-
expect(stateChanges).to.have.lengthOf(1); // Seulement pour message
|
199
|
-
expect(stateChanges[0].payload.property).to.equal("message");
|
200
|
-
});
|
201
|
-
|
202
|
-
it("should execute node with parameters", async () => {
|
203
|
-
const nodes = new Map();
|
204
|
-
nodes.set("test", {
|
205
|
-
name: "test",
|
206
|
-
execute: async (context: TestContext, inputs?: any) => {
|
207
|
-
context.counter = inputs?.value ?? 0;
|
208
|
-
context.message = inputs?.message ?? "Default";
|
209
|
-
},
|
210
|
-
});
|
211
|
-
|
212
|
-
node = new GraphNode(
|
213
|
-
nodes,
|
214
|
-
logger,
|
215
|
-
eventManager,
|
216
|
-
eventSubject,
|
217
|
-
stateSubject
|
218
|
-
);
|
219
|
-
|
220
|
-
await node.executeNode(
|
221
|
-
"test",
|
222
|
-
{ counter: 0, message: "Hello" },
|
223
|
-
{ value: 5, message: "Custom" },
|
224
|
-
false
|
225
|
-
);
|
226
|
-
|
227
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
228
|
-
expect(stateChanges).to.have.lengthOf(2);
|
229
|
-
expect(stateChanges[0].payload.newValue).to.equal(5);
|
230
|
-
expect(stateChanges[1].payload.newValue).to.equal("Custom");
|
231
|
-
});
|
232
|
-
|
233
|
-
it("should use default values when no parameters provided", async () => {
|
234
|
-
const nodes = new Map();
|
235
|
-
nodes.set("test", {
|
236
|
-
name: "test",
|
237
|
-
execute: async (
|
238
|
-
context: TestContext,
|
239
|
-
_inputs: any,
|
240
|
-
params?: NodeParams
|
241
|
-
) => {
|
242
|
-
context.counter = params?.increment || 1;
|
243
|
-
context.message = params?.message || "Default";
|
244
|
-
},
|
245
|
-
});
|
246
|
-
|
247
|
-
node = new GraphNode(
|
248
|
-
nodes,
|
249
|
-
logger,
|
250
|
-
eventManager,
|
251
|
-
eventSubject,
|
252
|
-
stateSubject
|
253
|
-
);
|
254
|
-
|
255
|
-
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
256
|
-
|
257
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
258
|
-
expect(stateChanges).to.have.lengthOf(2);
|
259
|
-
expect(stateChanges[0].payload.newValue).to.equal(1); // counter (default)
|
260
|
-
expect(stateChanges[1].payload.newValue).to.equal("Default"); // message (default)
|
261
|
-
});
|
262
|
-
|
263
|
-
it("should properly handle node inputs", async () => {
|
264
|
-
const nodes = new Map();
|
265
|
-
nodes.set("test", {
|
266
|
-
name: "test",
|
267
|
-
execute: async (context: TestContext, inputs: any) => {
|
268
|
-
context.counter = inputs.value;
|
269
|
-
context.message = inputs.message;
|
270
|
-
},
|
271
|
-
});
|
272
|
-
|
273
|
-
node = new GraphNode(
|
274
|
-
nodes,
|
275
|
-
logger,
|
276
|
-
eventManager,
|
277
|
-
eventSubject,
|
278
|
-
stateSubject
|
279
|
-
);
|
280
|
-
|
281
|
-
const testInputs = {
|
282
|
-
value: 42,
|
283
|
-
message: "Test Input",
|
284
|
-
};
|
285
|
-
|
286
|
-
await node.executeNode(
|
287
|
-
"test",
|
288
|
-
{ counter: 0, message: "Hello" },
|
289
|
-
testInputs
|
290
|
-
);
|
291
|
-
|
292
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
293
|
-
expect(stateChanges).to.have.lengthOf(2);
|
294
|
-
expect(stateChanges[0].payload.newValue).to.equal(42); // counter from input
|
295
|
-
expect(stateChanges[1].payload.newValue).to.equal("Test Input"); // message from input
|
296
|
-
});
|
297
|
-
|
298
|
-
it("should not emit duplicate state changes", async () => {
|
299
|
-
const nodes = new Map();
|
300
|
-
nodes.set("test", {
|
301
|
-
name: "test",
|
302
|
-
execute: async (context: TestContext) => {
|
303
|
-
context.counter = 1; // Valeur fixe au lieu d'incrémentations
|
304
|
-
context.counter = 1; // Même valeur
|
305
|
-
context.message = "New";
|
306
|
-
context.message = "New"; // Même valeur
|
307
|
-
},
|
308
|
-
});
|
309
|
-
|
310
|
-
node = new GraphNode(
|
311
|
-
nodes,
|
312
|
-
logger,
|
313
|
-
eventManager,
|
314
|
-
eventSubject,
|
315
|
-
stateSubject
|
316
|
-
);
|
317
|
-
|
318
|
-
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
319
|
-
|
320
|
-
// Vérifier qu'il n'y a pas de doublons dans les événements
|
321
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
322
|
-
const uniqueChanges = new Set(
|
323
|
-
stateChanges.map(
|
324
|
-
(e) =>
|
325
|
-
`${e.payload.property}-${e.payload.oldValue}-${e.payload.newValue}`
|
326
|
-
)
|
327
|
-
);
|
328
|
-
|
329
|
-
expect(stateChanges.length).to.equal(uniqueChanges.size);
|
330
|
-
expect(stateChanges).to.have.lengthOf(2); // Un pour counter, un pour message
|
331
|
-
});
|
332
|
-
|
333
|
-
it("should validate node parameters with Zod schema", async () => {
|
334
|
-
const paramSchema = z.object({
|
335
|
-
increment: z.number().min(1),
|
336
|
-
message: z.string().min(1),
|
337
|
-
});
|
338
|
-
|
339
|
-
const nodes = new Map();
|
340
|
-
nodes.set("test", {
|
341
|
-
name: "test",
|
342
|
-
params: paramSchema,
|
343
|
-
execute: async (context: TestContext, params?: NodeParams) => {
|
344
|
-
context.counter += params?.increment || 0;
|
345
|
-
context.message = params?.message || "";
|
346
|
-
},
|
347
|
-
});
|
348
|
-
|
349
|
-
node = new GraphNode(
|
350
|
-
nodes,
|
351
|
-
logger,
|
352
|
-
eventManager,
|
353
|
-
eventSubject,
|
354
|
-
stateSubject
|
355
|
-
);
|
356
|
-
|
357
|
-
// Test avec des paramètres valides
|
358
|
-
await node.executeNode(
|
359
|
-
"test",
|
360
|
-
{ counter: 0, message: "Hello" },
|
361
|
-
{ increment: 5, message: "Valid" }
|
362
|
-
);
|
363
|
-
|
364
|
-
// Test avec des paramètres invalides
|
365
|
-
await expect(
|
366
|
-
node.executeNode(
|
367
|
-
"test",
|
368
|
-
{ counter: 0, message: "Hello" },
|
369
|
-
{ increment: 0, message: "" }
|
370
|
-
)
|
371
|
-
).to.be.rejected; // Enlever le .with() car le message d'erreur vient directement de Zod
|
372
|
-
});
|
373
|
-
|
374
|
-
it("should work without params schema", async () => {
|
375
|
-
const nodes = new Map();
|
376
|
-
nodes.set("test", {
|
377
|
-
name: "test",
|
378
|
-
execute: async (context: TestContext) => {
|
379
|
-
context.counter++;
|
380
|
-
},
|
381
|
-
});
|
382
|
-
|
383
|
-
node = new GraphNode(
|
384
|
-
nodes,
|
385
|
-
logger,
|
386
|
-
eventManager,
|
387
|
-
eventSubject,
|
388
|
-
stateSubject
|
389
|
-
);
|
390
|
-
|
391
|
-
// Devrait fonctionner sans erreur même sans schema de params
|
392
|
-
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
393
|
-
});
|
394
|
-
|
395
|
-
it("should not require params when node has no params schema", async () => {
|
396
|
-
const nodes = new Map();
|
397
|
-
nodes.set("test", {
|
398
|
-
name: "test",
|
399
|
-
// Pas de schéma de params défini
|
400
|
-
execute: async (context: TestContext) => {
|
401
|
-
context.counter++;
|
402
|
-
},
|
403
|
-
});
|
404
|
-
|
405
|
-
node = new GraphNode(
|
406
|
-
nodes,
|
407
|
-
logger,
|
408
|
-
eventManager,
|
409
|
-
eventSubject,
|
410
|
-
stateSubject
|
411
|
-
);
|
412
|
-
|
413
|
-
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
414
|
-
|
415
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
416
|
-
expect(stateChanges).to.have.lengthOf(1);
|
417
|
-
expect(stateChanges[0].payload.newValue).to.equal(1);
|
418
|
-
});
|
419
|
-
|
420
|
-
it("should require params only when node has params schema", async () => {
|
421
|
-
const nodes = new Map();
|
422
|
-
nodes.set("test", {
|
423
|
-
name: "test",
|
424
|
-
params: z.object({
|
425
|
-
// Avec un schéma de params
|
426
|
-
value: z.number(),
|
427
|
-
}),
|
428
|
-
execute: async (context: TestContext, params?: NodeParams) => {
|
429
|
-
context.counter = params?.value || 0;
|
430
|
-
},
|
431
|
-
});
|
432
|
-
|
433
|
-
node = new GraphNode(
|
434
|
-
nodes,
|
435
|
-
logger,
|
436
|
-
eventManager,
|
437
|
-
eventSubject,
|
438
|
-
stateSubject
|
439
|
-
);
|
440
|
-
|
441
|
-
// Devrait échouer sans params
|
442
|
-
await expect(
|
443
|
-
node.executeNode("test", { counter: 0, message: "Hello" }, null)
|
444
|
-
).to.be.rejectedWith("Params required for node");
|
445
|
-
});
|
446
|
-
|
447
|
-
it("should execute node without params when no schema is defined (real world scenario)", async () => {
|
448
|
-
const nodes = new Map();
|
449
|
-
nodes.set("incrementCounter", {
|
450
|
-
name: "incrementCounter",
|
451
|
-
execute: async (context: TestContext) => {
|
452
|
-
context.counter++;
|
453
|
-
},
|
454
|
-
});
|
455
|
-
|
456
|
-
node = new GraphNode(
|
457
|
-
nodes,
|
458
|
-
logger,
|
459
|
-
eventManager,
|
460
|
-
eventSubject,
|
461
|
-
stateSubject
|
462
|
-
);
|
463
|
-
|
464
|
-
// Simuler l'appel comme dans examples/t2.ts
|
465
|
-
await node.executeNode(
|
466
|
-
"incrementCounter",
|
467
|
-
{ message: "Hello", counter: 0 },
|
468
|
-
{ test: "test" } // Passer des params même si non requis
|
469
|
-
);
|
470
|
-
|
471
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
472
|
-
expect(stateChanges).to.have.lengthOf(1);
|
473
|
-
expect(stateChanges[0].payload.newValue).to.equal(1);
|
474
|
-
});
|
475
|
-
|
476
|
-
it("should handle optional params schema", async () => {
|
477
|
-
const nodes = new Map();
|
478
|
-
nodes.set("test", {
|
479
|
-
name: "test",
|
480
|
-
params: z
|
481
|
-
.object({
|
482
|
-
test: z.string(),
|
483
|
-
})
|
484
|
-
.optional(),
|
485
|
-
execute: async (context: TestContext, params?: NodeParams) => {
|
486
|
-
context.counter++;
|
487
|
-
},
|
488
|
-
});
|
489
|
-
|
490
|
-
node = new GraphNode(
|
491
|
-
nodes,
|
492
|
-
logger,
|
493
|
-
eventManager,
|
494
|
-
eventSubject,
|
495
|
-
stateSubject
|
496
|
-
);
|
497
|
-
|
498
|
-
// Devrait fonctionner avec ou sans params
|
499
|
-
await node.executeNode(
|
500
|
-
"test",
|
501
|
-
{ counter: 0, message: "Hello" },
|
502
|
-
{ test: "test" }
|
503
|
-
);
|
504
|
-
await node.executeNode("test", { counter: 1, message: "Hello" }, null);
|
505
|
-
|
506
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
507
|
-
expect(stateChanges).to.have.lengthOf(2);
|
508
|
-
expect(stateChanges[1].payload.newValue).to.equal(2);
|
509
|
-
});
|
510
|
-
|
511
|
-
it("should wait for events before executing node", async () => {
|
512
|
-
const nodes = new Map();
|
513
|
-
nodes.set("waitForEventsNode", {
|
514
|
-
name: "waitForEventsNode",
|
515
|
-
waitForEvents: {
|
516
|
-
events: ["event1", "event2"],
|
517
|
-
timeout: 1000,
|
518
|
-
strategy: "all",
|
519
|
-
},
|
520
|
-
execute: async (context: TestContext) => {
|
521
|
-
context.message = "Events received";
|
522
|
-
},
|
523
|
-
});
|
524
|
-
|
525
|
-
node = new GraphNode(
|
526
|
-
nodes,
|
527
|
-
logger,
|
528
|
-
eventManager,
|
529
|
-
eventSubject,
|
530
|
-
stateSubject
|
531
|
-
);
|
532
|
-
|
533
|
-
// Lancer l'exécution du nœud
|
534
|
-
const execution = node.executeNode(
|
535
|
-
"waitForEventsNode",
|
536
|
-
{ counter: 0, message: "Hello" },
|
537
|
-
null
|
538
|
-
);
|
539
|
-
|
540
|
-
// Simuler les événements après un court délai
|
541
|
-
setTimeout(() => {
|
542
|
-
eventEmitter.emit("event1", { data: "test1" });
|
543
|
-
eventEmitter.emit("event2", { data: "test2" });
|
544
|
-
}, 100);
|
545
|
-
|
546
|
-
await execution;
|
547
|
-
|
548
|
-
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
549
|
-
expect(stateChanges).to.have.lengthOf(1);
|
550
|
-
expect(stateChanges[0].payload.newValue).to.equal("Events received");
|
551
|
-
});
|
552
|
-
|
553
|
-
it("should timeout if events are not received", async () => {
|
554
|
-
const nodes = new Map();
|
555
|
-
nodes.set("timeoutNode", {
|
556
|
-
name: "timeoutNode",
|
557
|
-
waitForEvents: {
|
558
|
-
events: ["event1", "event2"],
|
559
|
-
timeout: 100,
|
560
|
-
strategy: "all",
|
561
|
-
},
|
562
|
-
execute: async (context: TestContext) => {
|
563
|
-
context.message = "Should not execute";
|
564
|
-
},
|
565
|
-
});
|
566
|
-
|
567
|
-
node = new GraphNode(
|
568
|
-
nodes,
|
569
|
-
logger,
|
570
|
-
eventManager,
|
571
|
-
eventSubject,
|
572
|
-
stateSubject
|
573
|
-
);
|
574
|
-
|
575
|
-
await expect(
|
576
|
-
node.executeNode("timeoutNode", { counter: 0, message: "Hello" }, null)
|
577
|
-
).to.be.rejectedWith("Timeout waiting for events");
|
578
|
-
});
|
579
|
-
|
580
|
-
it("should handle partial event reception", async () => {
|
581
|
-
const nodes = new Map();
|
582
|
-
nodes.set("partialEventsNode", {
|
583
|
-
name: "partialEventsNode",
|
584
|
-
waitForEvents: {
|
585
|
-
events: ["event1", "event2"],
|
586
|
-
timeout: 1000,
|
587
|
-
strategy: "all",
|
588
|
-
},
|
589
|
-
execute: async (context: TestContext) => {
|
590
|
-
context.message = "All events received";
|
591
|
-
},
|
592
|
-
});
|
593
|
-
|
594
|
-
node = new GraphNode(
|
595
|
-
nodes,
|
596
|
-
logger,
|
597
|
-
eventManager,
|
598
|
-
eventSubject,
|
599
|
-
stateSubject
|
600
|
-
);
|
601
|
-
|
602
|
-
const execution = node.executeNode(
|
603
|
-
"partialEventsNode",
|
604
|
-
{ counter: 0, message: "Hello" },
|
605
|
-
null
|
606
|
-
);
|
607
|
-
|
608
|
-
// N'émettre qu'un seul événement
|
609
|
-
setTimeout(() => {
|
610
|
-
eventEmitter.emit("event1", { data: "test1" });
|
611
|
-
}, 100);
|
612
|
-
|
613
|
-
await expect(execution).to.be.rejectedWith("Timeout waiting for events");
|
614
|
-
});
|
615
|
-
|
616
|
-
it("should handle correlated events", (done) => {
|
617
|
-
const nodes = new Map();
|
618
|
-
nodes.set("correlatedEventsNode", {
|
619
|
-
name: "correlatedEventsNode",
|
620
|
-
correlateEvents: {
|
621
|
-
events: ["payment", "stock"],
|
622
|
-
timeout: 1000,
|
623
|
-
correlation: (events: Array<{ type: string; payload?: any }>) => {
|
624
|
-
const paymentEvent = events.find((e) => e.type === "payment");
|
625
|
-
const stockEvent = events.find((e) => e.type === "stock");
|
626
|
-
return paymentEvent?.payload?.id === stockEvent?.payload?.id;
|
627
|
-
},
|
628
|
-
},
|
629
|
-
execute: (context: TestContext) => {
|
630
|
-
context.message = "Correlated events received";
|
631
|
-
done();
|
632
|
-
return Promise.resolve();
|
633
|
-
},
|
634
|
-
});
|
635
|
-
|
636
|
-
node = new GraphNode(
|
637
|
-
nodes,
|
638
|
-
logger,
|
639
|
-
eventManager,
|
640
|
-
eventSubject,
|
641
|
-
stateSubject
|
642
|
-
);
|
643
|
-
|
644
|
-
node.executeNode(
|
645
|
-
"correlatedEventsNode",
|
646
|
-
{ counter: 0, message: "Hello" },
|
647
|
-
null
|
648
|
-
);
|
649
|
-
|
650
|
-
setTimeout(() => {
|
651
|
-
eventEmitter.emit("payment", { id: "123", status: "completed" });
|
652
|
-
eventEmitter.emit("stock", { id: "123", status: "available" });
|
653
|
-
}, 100);
|
654
|
-
});
|
655
|
-
});
|