@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.
Files changed (111) hide show
  1. package/README.md +158 -81
  2. package/index.ts +462 -22
  3. package/package copy.json +21 -0
  4. package/package.json +9 -44
  5. package/tsconfig.json +108 -22
  6. package/types.ts +62 -0
  7. package/utils/executor.ts +42 -0
  8. package/.mocharc.json +0 -5
  9. package/dist/graph/controller.d.ts +0 -31
  10. package/dist/graph/controller.d.ts.map +0 -1
  11. package/dist/graph/controller.js +0 -71
  12. package/dist/graph/controller.js.map +0 -1
  13. package/dist/graph/event-manager.d.ts +0 -93
  14. package/dist/graph/event-manager.d.ts.map +0 -1
  15. package/dist/graph/event-manager.js +0 -296
  16. package/dist/graph/event-manager.js.map +0 -1
  17. package/dist/graph/index.d.ts +0 -159
  18. package/dist/graph/index.d.ts.map +0 -1
  19. package/dist/graph/index.js +0 -303
  20. package/dist/graph/index.js.map +0 -1
  21. package/dist/graph/logger.d.ts +0 -46
  22. package/dist/graph/logger.d.ts.map +0 -1
  23. package/dist/graph/logger.js +0 -69
  24. package/dist/graph/logger.js.map +0 -1
  25. package/dist/graph/node.d.ts +0 -93
  26. package/dist/graph/node.d.ts.map +0 -1
  27. package/dist/graph/node.js +0 -259
  28. package/dist/graph/node.js.map +0 -1
  29. package/dist/graph/observer.d.ts +0 -115
  30. package/dist/graph/observer.d.ts.map +0 -1
  31. package/dist/graph/observer.js +0 -198
  32. package/dist/graph/observer.js.map +0 -1
  33. package/dist/index.d.ts +0 -26
  34. package/dist/index.d.ts.map +0 -1
  35. package/dist/index.js +0 -42
  36. package/dist/index.js.map +0 -1
  37. package/dist/interfaces/index.d.ts +0 -447
  38. package/dist/interfaces/index.d.ts.map +0 -1
  39. package/dist/interfaces/index.js +0 -75
  40. package/dist/interfaces/index.js.map +0 -1
  41. package/dist/modules/agenda/adapters/node-cron/index.d.ts +0 -17
  42. package/dist/modules/agenda/adapters/node-cron/index.d.ts.map +0 -1
  43. package/dist/modules/agenda/adapters/node-cron/index.js +0 -30
  44. package/dist/modules/agenda/adapters/node-cron/index.js.map +0 -1
  45. package/dist/modules/agenda/index.d.ts +0 -63
  46. package/dist/modules/agenda/index.d.ts.map +0 -1
  47. package/dist/modules/agenda/index.js +0 -141
  48. package/dist/modules/agenda/index.js.map +0 -1
  49. package/dist/modules/embedding/adapters/ai/index.d.ts +0 -29
  50. package/dist/modules/embedding/adapters/ai/index.d.ts.map +0 -1
  51. package/dist/modules/embedding/adapters/ai/index.js +0 -58
  52. package/dist/modules/embedding/adapters/ai/index.js.map +0 -1
  53. package/dist/modules/embedding/index.d.ts +0 -36
  54. package/dist/modules/embedding/index.d.ts.map +0 -1
  55. package/dist/modules/embedding/index.js +0 -60
  56. package/dist/modules/embedding/index.js.map +0 -1
  57. package/dist/modules/memory/adapters/in-memory/index.d.ts +0 -120
  58. package/dist/modules/memory/adapters/in-memory/index.d.ts.map +0 -1
  59. package/dist/modules/memory/adapters/in-memory/index.js +0 -211
  60. package/dist/modules/memory/adapters/in-memory/index.js.map +0 -1
  61. package/dist/modules/memory/adapters/meilisearch/index.d.ts +0 -110
  62. package/dist/modules/memory/adapters/meilisearch/index.d.ts.map +0 -1
  63. package/dist/modules/memory/adapters/meilisearch/index.js +0 -321
  64. package/dist/modules/memory/adapters/meilisearch/index.js.map +0 -1
  65. package/dist/modules/memory/adapters/redis/index.d.ts +0 -82
  66. package/dist/modules/memory/adapters/redis/index.d.ts.map +0 -1
  67. package/dist/modules/memory/adapters/redis/index.js +0 -159
  68. package/dist/modules/memory/adapters/redis/index.js.map +0 -1
  69. package/dist/modules/memory/index.d.ts +0 -67
  70. package/dist/modules/memory/index.d.ts.map +0 -1
  71. package/dist/modules/memory/index.js +0 -104
  72. package/dist/modules/memory/index.js.map +0 -1
  73. package/dist/types/index.d.ts +0 -170
  74. package/dist/types/index.d.ts.map +0 -1
  75. package/dist/types/index.js +0 -3
  76. package/dist/types/index.js.map +0 -1
  77. package/dist/utils/generate-action-schema.d.ts +0 -5
  78. package/dist/utils/generate-action-schema.d.ts.map +0 -1
  79. package/dist/utils/generate-action-schema.js +0 -44
  80. package/dist/utils/generate-action-schema.js.map +0 -1
  81. package/dist/utils/header-builder.d.ts +0 -12
  82. package/dist/utils/header-builder.d.ts.map +0 -1
  83. package/dist/utils/header-builder.js +0 -35
  84. package/dist/utils/header-builder.js.map +0 -1
  85. package/graph/controller.ts +0 -74
  86. package/graph/event-manager.ts +0 -363
  87. package/graph/index.ts +0 -395
  88. package/graph/logger.ts +0 -70
  89. package/graph/node.ts +0 -327
  90. package/graph/observer.ts +0 -368
  91. package/interfaces/index.ts +0 -548
  92. package/modules/agenda/adapters/node-cron/index.ts +0 -25
  93. package/modules/agenda/index.ts +0 -146
  94. package/modules/embedding/adapters/ai/index.ts +0 -42
  95. package/modules/embedding/index.ts +0 -45
  96. package/modules/memory/adapters/in-memory/index.ts +0 -207
  97. package/modules/memory/adapters/meilisearch/index.ts +0 -361
  98. package/modules/memory/adapters/redis/index.ts +0 -164
  99. package/modules/memory/index.ts +0 -93
  100. package/test/graph/controller.test.ts +0 -187
  101. package/test/graph/event-manager.test.ts +0 -118
  102. package/test/graph/index.test.ts +0 -684
  103. package/test/graph/node.test.ts +0 -655
  104. package/test/graph/observer.test.ts +0 -398
  105. package/test/modules/agenda/node-cron.test.ts +0 -307
  106. package/test/modules/memory/adapters/in-memory.test.ts +0 -153
  107. package/test/modules/memory/adapters/meilisearch.test.ts +0 -287
  108. package/test/modules/memory/base.test.ts +0 -230
  109. package/types/index.ts +0 -190
  110. package/utils/generate-action-schema.ts +0 -46
  111. package/utils/header-builder.ts +0 -40
@@ -1,398 +0,0 @@
1
- import { expect } from "chai";
2
- import { BehaviorSubject, Subject } from "rxjs";
3
- import { z } from "zod";
4
- import { GraphFlow } from "../../graph";
5
- import { GraphObserver } from "../../graph/observer";
6
- import { GraphContext, GraphEvent, Node } from "../../types";
7
-
8
- /**
9
- * Test schema definition for observer tests
10
- * Defines a schema with:
11
- * - value: numeric value for tracking state changes
12
- * - status: enum representing node execution status
13
- */
14
- const TestSchema = z.object({
15
- value: z.number().default(0),
16
- status: z.enum(["pending", "completed", "failed"]).optional(),
17
- });
18
-
19
- /**
20
- * Test suite for the GraphObserver implementation
21
- * This suite validates the reactive observation capabilities:
22
- * - State observation (global and node-specific)
23
- * - Property observation (single and multiple)
24
- * - Event observation and correlation
25
- * - Workflow monitoring
26
- * - Node execution triggers
27
- */
28
- describe("GraphObserver", () => {
29
- let graph: GraphFlow<typeof TestSchema>;
30
- let eventSubject: Subject<GraphEvent<typeof TestSchema>>;
31
- let stateSubject: BehaviorSubject<GraphContext<typeof TestSchema>>;
32
- let destroySubject: Subject<void>;
33
- let observer: GraphObserver<typeof TestSchema>;
34
-
35
- beforeEach(() => {
36
- graph = new GraphFlow("TestGraph", {
37
- name: "TestGraph",
38
- nodes: [],
39
- context: { value: 0 },
40
- schema: TestSchema,
41
- });
42
-
43
- // Initialize subjects
44
- eventSubject = new Subject();
45
- stateSubject = new BehaviorSubject(graph.getContext());
46
- destroySubject = new Subject();
47
-
48
- // Create observer instance
49
- observer = new GraphObserver(
50
- graph,
51
- eventSubject,
52
- stateSubject,
53
- destroySubject
54
- );
55
- });
56
-
57
- /**
58
- * Test suite for state observation functionality
59
- * Validates the ability to track and react to state changes
60
- * in the graph context
61
- */
62
- describe("State Observation", () => {
63
- /**
64
- * Tests sequential state change observation
65
- * Validates that:
66
- * - All state changes are captured in order
67
- * - Multiple state changes in a single node are tracked
68
- * - Initial state is included in observations
69
- */
70
- it("should observe state changes", async () => {
71
- const states: any[] = [];
72
- const testNode: Node<typeof TestSchema> = {
73
- name: "testNode",
74
- execute: async (context) => {
75
- context.value = 1;
76
- context.value = 2;
77
- context.value = 3;
78
- },
79
- };
80
-
81
- graph.addNode(testNode);
82
- const subscription = graph
83
- .observe()
84
- .state()
85
- .subscribe((state) => {
86
- if (state.value !== undefined) {
87
- states.push(state.value);
88
- }
89
- });
90
-
91
- await graph.execute("testNode");
92
- await new Promise((resolve) => setTimeout(resolve, 50));
93
- subscription.unsubscribe();
94
-
95
- expect(states).to.deep.equal([0, 1, 2, 3]);
96
- });
97
-
98
- /**
99
- * Tests node-specific state observation
100
- * Validates that:
101
- * - State changes for specific nodes are tracked
102
- * - Status transitions are captured correctly
103
- * - Async state changes are properly observed
104
- */
105
- it("should observe specific node state changes", async () => {
106
- const states: any[] = [];
107
- const testNode: Node<typeof TestSchema> = {
108
- name: "testNode",
109
- execute: async (context) => {
110
- context.status = "pending";
111
- await new Promise((resolve) => setTimeout(resolve, 10));
112
- context.status = "completed";
113
- },
114
- };
115
-
116
- graph.addNode(testNode);
117
- const subscription = graph
118
- .observe()
119
- .node("testNode")
120
- .subscribe((state) => state.status && states.push(state.status));
121
-
122
- await graph.execute("testNode");
123
- await new Promise((resolve) => setTimeout(resolve, 50));
124
- subscription.unsubscribe();
125
-
126
- expect(states).to.deep.equal(["pending", "completed"]);
127
- });
128
-
129
- /**
130
- * Tests multi-node state observation
131
- * Validates that:
132
- * - Multiple nodes can be observed simultaneously
133
- * - State changes are correctly attributed to nodes
134
- * - Sequential execution is properly tracked
135
- */
136
- it("should observe multiple nodes", async () => {
137
- const states: any[] = [];
138
- const node1: Node<typeof TestSchema> = {
139
- name: "node1",
140
- execute: async (context) => {
141
- context.value = 1;
142
- },
143
- };
144
- const node2: Node<typeof TestSchema> = {
145
- name: "node2",
146
- execute: async (context) => {
147
- context.value = 2;
148
- },
149
- };
150
-
151
- graph.addNode(node1);
152
- graph.addNode(node2);
153
-
154
- const subscription = graph
155
- .observe()
156
- .nodes(["node1", "node2"])
157
- .subscribe((state) => state.value && states.push(state.value));
158
-
159
- await graph.execute("node1");
160
- await new Promise((resolve) => setTimeout(resolve, 50));
161
- await graph.execute("node2");
162
- await new Promise((resolve) => setTimeout(resolve, 50));
163
- subscription.unsubscribe();
164
-
165
- expect(states).to.deep.equal([1, 2]);
166
- });
167
- });
168
-
169
- /**
170
- * Test suite for property observation functionality
171
- * Validates the ability to track specific properties
172
- * of the graph context
173
- */
174
- describe("Property Observation", () => {
175
- /**
176
- * Tests single property observation
177
- * Validates that:
178
- * - Individual property changes are tracked
179
- * - Initial property value is captured
180
- * - Property updates trigger observations
181
- */
182
- it("should observe single property", async () => {
183
- const values: any[] = [];
184
- const testNode: Node<typeof TestSchema> = {
185
- name: "testNode",
186
- execute: async (context) => {
187
- context.value = 42;
188
- },
189
- };
190
-
191
- graph.addNode(testNode);
192
- const subscription = graph
193
- .observe()
194
- .property("value")
195
- .subscribe((state) => values.push(state.value));
196
-
197
- await graph.execute("testNode");
198
- subscription.unsubscribe();
199
-
200
- expect(values).to.deep.equal([0, 42]);
201
- });
202
-
203
- /**
204
- * Tests multiple property observation
205
- * Validates that:
206
- * - Multiple properties can be tracked simultaneously
207
- * - Changes to any observed property trigger updates
208
- * - Final state contains all tracked properties
209
- */
210
- it("should observe multiple properties", async () => {
211
- const values: any[] = [];
212
- const testNode: Node<typeof TestSchema> = {
213
- name: "testNode",
214
- execute: async (context) => {
215
- context.value = 42;
216
- context.status = "completed";
217
- },
218
- };
219
-
220
- graph.addNode(testNode);
221
- const subscription = graph
222
- .observe()
223
- .property(["value", "status"])
224
- .subscribe((change) => {
225
- const { name, ...rest } = change;
226
- values.push(rest);
227
- });
228
-
229
- await graph.execute("testNode");
230
- await new Promise((resolve) => setTimeout(resolve, 50));
231
- subscription.unsubscribe();
232
-
233
- expect(values[values.length - 1]).to.deep.equal({
234
- value: 42,
235
- status: "completed",
236
- });
237
- });
238
-
239
- /**
240
- * Tests condition-based observation
241
- * Validates that:
242
- * - Multiple conditions can be combined
243
- * - Observation completes when conditions are met
244
- * - State reflects all required changes
245
- */
246
- it("should wait for multiple conditions", async () => {
247
- const testNode: Node<typeof TestSchema> = {
248
- name: "testNode",
249
- execute: async (context) => {
250
- context.value = 42;
251
- context.status = "completed";
252
- },
253
- };
254
-
255
- graph.addNode(testNode);
256
- const promise = graph
257
- .observe()
258
- .until(
259
- graph.observe().property(["value", "status"]),
260
- (state) => state.value === 42 && state.status === "completed"
261
- );
262
-
263
- await graph.execute("testNode");
264
- await promise;
265
-
266
- const context = graph.getContext();
267
- expect(context.value).to.equal(42);
268
- expect(context.status).to.equal("completed");
269
- });
270
- });
271
-
272
- /**
273
- * Test suite for event observation functionality
274
- * Validates the handling of events and event correlation
275
- */
276
- describe("Event Observation", () => {
277
- /**
278
- * Tests specific event observation
279
- */
280
- it("should observe specific events", async () => {
281
- const events: GraphEvent<typeof TestSchema>[] = [];
282
- const subscription = graph
283
- .observe()
284
- .event("testEvent")
285
- .subscribe((e) => events.push(e));
286
-
287
- await graph.emit("testEvent", { value: 1 });
288
- await new Promise((resolve) => setTimeout(resolve, 100));
289
- subscription.unsubscribe();
290
-
291
- expect(events.length).to.equal(1);
292
- expect(events[0].type).to.equal("testEvent");
293
- });
294
-
295
- /**
296
- * Tests debounced event handling
297
- */
298
- it("should handle debounced events", async () => {
299
- const events: GraphEvent<typeof TestSchema>[] = [];
300
- const subscription = graph
301
- .observe()
302
- .event("event1")
303
- .subscribe((e) => events.push(e));
304
-
305
- await graph.emit("event1", { value: 1 });
306
- await graph.emit("event1", { value: 2 });
307
- await new Promise((resolve) => setTimeout(resolve, 100));
308
- subscription.unsubscribe();
309
-
310
- expect(events.length).to.equal(2);
311
- });
312
-
313
- /**
314
- * Tests event correlation functionality
315
- * Validates that:
316
- * - Multiple events can be correlated
317
- * - Correlation conditions are properly evaluated
318
- * - Timeout handling works correctly
319
- * - Events are captured in correct order
320
- */
321
- it("should wait for correlated events", async () => {
322
- // Create test events
323
- const eventA = {
324
- type: "eventA",
325
- payload: { eventPayload: { status: "success" } },
326
- timestamp: Date.now(),
327
- } as GraphEvent<typeof TestSchema>;
328
-
329
- const eventB = {
330
- type: "eventB",
331
- payload: { eventPayload: { status: "success" } },
332
- timestamp: Date.now(),
333
- } as GraphEvent<typeof TestSchema>;
334
-
335
- // Emit events after a short delay
336
- setTimeout(() => {
337
- eventSubject.next(eventA);
338
- eventSubject.next(eventB);
339
- }, 100);
340
-
341
- const events = await observer.waitForCorrelatedEvents(
342
- ["eventA", "eventB"],
343
- 2000,
344
- (events) =>
345
- events.every((e) => e.payload.eventPayload?.status === "success")
346
- );
347
-
348
- expect(events.length).to.equal(2);
349
- expect(events[0].type).to.equal("eventA");
350
- expect(events[1].type).to.equal("eventB");
351
- });
352
-
353
- afterEach(() => {
354
- destroySubject.next();
355
- destroySubject.complete();
356
- eventSubject.complete();
357
- stateSubject.complete();
358
- });
359
- });
360
-
361
- /**
362
- * Test suite for workflow observation functionality
363
- * Validates the ability to monitor complete workflow execution
364
- */
365
- describe("Workflow Observation", () => {
366
- /**
367
- * Tests complete workflow observation
368
- * Validates that:
369
- * - Entire workflow execution is tracked
370
- * - State transitions are captured
371
- * - Final state reflects completed workflow
372
- */
373
- it("should observe complete workflow", async () => {
374
- const states: any[] = [];
375
- const node: Node<typeof TestSchema> = {
376
- name: "testNode",
377
- execute: async (context) => {
378
- context.status = "pending";
379
- await new Promise((resolve) => setTimeout(resolve, 10));
380
- context.status = "completed";
381
- },
382
- };
383
-
384
- graph.addNode(node);
385
- const subscription = graph
386
- .observe()
387
- .node("testNode")
388
- .subscribe((state) => states.push(state));
389
-
390
- await graph.execute("testNode");
391
- await new Promise((resolve) => setTimeout(resolve, 50));
392
- subscription.unsubscribe();
393
-
394
- expect(states.length).to.be.greaterThan(0);
395
- expect(states[states.length - 1].status).to.equal("completed");
396
- });
397
- });
398
- });
@@ -1,307 +0,0 @@
1
- import { expect } from "chai";
2
- import sinon from "sinon";
3
- import { Agenda } from "../../../modules/agenda";
4
- import { NodeCronAdapter } from "../../../modules/agenda/adapters/node-cron";
5
- import { Memory } from "../../../modules/memory";
6
- import { InMemoryAdapter } from "../../../modules/memory/adapters/in-memory";
7
-
8
- before(function () {
9
- this.timeout(10000);
10
- });
11
-
12
- describe("Agenda Service", () => {
13
- let agenda: Agenda;
14
- const scheduledIds: string[] = []; // Track all scheduled request IDs
15
-
16
- beforeEach(() => {
17
- const cronService = new NodeCronAdapter();
18
- const inMemory = new InMemoryAdapter();
19
- const memory = new Memory(inMemory);
20
- agenda = new Agenda(cronService, memory);
21
- });
22
-
23
- afterEach(async () => {
24
- // Cancel all scheduled requests by their IDs
25
- scheduledIds.forEach((id) => agenda.cancelScheduledRequest(id));
26
- scheduledIds.length = 0; // Clear the array
27
-
28
- // Ensure all tasks are stopped
29
- await agenda.stop();
30
-
31
- await agenda.cancel({});
32
-
33
- await new Promise((resolve) => setTimeout(resolve, 100));
34
- });
35
-
36
- describe("Request Scheduling", () => {
37
- it("should schedule a new request and return an id", async () => {
38
- const request = {
39
- originalRequest: "test request",
40
- cronExpression: "0 0 * * *",
41
- };
42
-
43
- const id = await agenda.scheduleRequest(request);
44
- scheduledIds.push(id); // Track the ID
45
-
46
- expect(id).to.be.a("string");
47
- expect(await agenda.getScheduledRequests()).to.have.lengthOf(1);
48
-
49
- const scheduledRequest = (await agenda.getScheduledRequests())[0];
50
- expect(scheduledRequest.originalRequest).to.equal(
51
- request.originalRequest
52
- );
53
- expect(scheduledRequest.cronExpression).to.equal(request.cronExpression);
54
- expect(scheduledRequest.isRecurring).to.be.false;
55
-
56
- agenda.cancelScheduledRequest(id);
57
- });
58
-
59
- it("should execute callbacks when scheduling and executing", async function () {
60
- this.timeout(5000);
61
-
62
- const onScheduledSpy = sinon.spy();
63
- const onExecutedSpy = sinon.spy();
64
-
65
- const request = {
66
- originalRequest: "test request",
67
- cronExpression: `${(new Date().getSeconds() + 1) % 60} * * * * *`,
68
- };
69
-
70
- const id = await agenda.scheduleRequest(request, {
71
- onScheduled: onScheduledSpy,
72
- onExecuted: onExecutedSpy,
73
- });
74
- scheduledIds.push(id);
75
-
76
- expect(onScheduledSpy.calledOnce).to.be.true;
77
-
78
- await new Promise<void>((resolve, reject) => {
79
- const timeout = setTimeout(() => {
80
- reject(new Error("Callback execution timeout"));
81
- }, 4000);
82
-
83
- const checkExecution = () => {
84
- if (onExecutedSpy.calledOnce) {
85
- clearTimeout(timeout);
86
- agenda.cancelScheduledRequest(id);
87
- resolve();
88
- return;
89
- }
90
- setTimeout(checkExecution, 100);
91
- };
92
- checkExecution();
93
- });
94
-
95
- expect(onExecutedSpy.calledOnce).to.be.true;
96
- });
97
- });
98
-
99
- describe("Request Management", () => {
100
- it("should cancel a scheduled request", async () => {
101
- const request = {
102
- originalRequest: "test request",
103
- cronExpression: "*/1 * * * *",
104
- };
105
-
106
- const id = await agenda.scheduleRequest(request);
107
- scheduledIds.push(id);
108
- expect(await agenda.getScheduledRequests()).to.have.lengthOf(1);
109
-
110
- const cancelled = await agenda.cancelScheduledRequest(id);
111
- expect(cancelled).to.be.true;
112
- expect(await agenda.getScheduledRequests()).to.have.lengthOf(0);
113
- });
114
-
115
- it("should return false when cancelling non-existent request", async () => {
116
- const cancelled = await agenda.cancelScheduledRequest("non-existent-id");
117
- expect(cancelled).to.be.false;
118
- });
119
-
120
- it("should get all scheduled requests", async () => {
121
- const requests = [
122
- {
123
- originalRequest: "request 1",
124
- cronExpression: "*/1 * * * *",
125
- },
126
- {
127
- originalRequest: "request 2",
128
- cronExpression: "*/5 * * * *",
129
- },
130
- ];
131
-
132
- for (const request of requests) {
133
- const id = await agenda.scheduleRequest(request);
134
- scheduledIds.push(id);
135
- }
136
-
137
- const scheduledRequests = await agenda.getScheduledRequests();
138
- expect(scheduledRequests).to.have.lengthOf(2);
139
- expect(scheduledRequests[0].originalRequest).to.equal("request 1");
140
- expect(scheduledRequests[1].originalRequest).to.equal("request 2");
141
- });
142
-
143
- it("should stop all scheduled requests", async () => {
144
- const requests = [
145
- {
146
- originalRequest: "request 1",
147
- cronExpression: "*/1 * * * *",
148
- },
149
- {
150
- originalRequest: "request 2",
151
- cronExpression: "*/5 * * * *",
152
- },
153
- ];
154
-
155
- for (const request of requests) {
156
- await agenda.scheduleRequest(request);
157
- }
158
-
159
- expect(await agenda.getScheduledRequests()).to.have.lengthOf(2);
160
-
161
- await agenda.stopAll();
162
- expect(await agenda.getScheduledRequests()).to.have.lengthOf(0);
163
- });
164
- });
165
-
166
- describe("Global Management", () => {
167
- it("should stop all scheduled requests", async () => {
168
- const requests = [
169
- {
170
- originalRequest: "request 1",
171
- cronExpression: "*/1 * * * *",
172
- },
173
- {
174
- originalRequest: "request 2",
175
- cronExpression: "*/5 * * * *",
176
- },
177
- ];
178
-
179
- for (const request of requests) {
180
- await agenda.scheduleRequest(request);
181
- }
182
-
183
- expect(await agenda.getScheduledRequests()).to.have.lengthOf(2);
184
-
185
- await agenda.stopAll();
186
- expect(await agenda.getScheduledRequests()).to.have.lengthOf(0);
187
- });
188
- });
189
-
190
- describe("Error Handling", () => {
191
- it("should handle execution errors gracefully", async () => {
192
- const consoleSpy = sinon.spy(console, "error");
193
-
194
- const request = {
195
- originalRequest: "error request",
196
- cronExpression: "0 0 * * *",
197
- };
198
-
199
- const id = await agenda.scheduleRequest(request);
200
-
201
- // Wait for execution
202
- await new Promise((resolve) => setTimeout(resolve, 1100));
203
-
204
- expect(consoleSpy.called).to.be.false;
205
-
206
- agenda.cancelScheduledRequest(id);
207
- consoleSpy.restore();
208
- });
209
- });
210
-
211
- describe("Request Execution", () => {
212
- it("should execute non-recurring requests only once", async function () {
213
- this.timeout(5000);
214
- const onExecutedSpy = sinon.spy();
215
-
216
- const request = {
217
- originalRequest: "single execution",
218
- cronExpression: `${new Date().getSeconds() + 1} * * * * *`,
219
- };
220
-
221
- const id = await agenda.scheduleRequest(request, {
222
- onExecuted: onExecutedSpy,
223
- });
224
-
225
- try {
226
- await new Promise<void>((resolve, reject) => {
227
- const timeout = setTimeout(
228
- () => reject(new Error("Test timeout")),
229
- 4000
230
- );
231
- const checkExecution = () => {
232
- if (onExecutedSpy.calledOnce) {
233
- clearTimeout(timeout);
234
- resolve();
235
- return;
236
- }
237
- setTimeout(checkExecution, 100);
238
- };
239
- checkExecution();
240
- });
241
- } finally {
242
- agenda.cancelScheduledRequest(id);
243
- }
244
-
245
- expect(onExecutedSpy.calledOnce).to.be.true;
246
- expect(await agenda.getScheduledRequests()).to.have.lengthOf(0);
247
- });
248
-
249
- it("should log execution status", async function () {
250
- this.timeout(10000);
251
- const consoleLogSpy = sinon.spy(console, "log");
252
-
253
- const request = {
254
- originalRequest: "test request",
255
- cronExpression: `${new Date().getSeconds() + 1} * * * * *`,
256
- };
257
-
258
- const id = await agenda.scheduleRequest(request);
259
-
260
- await new Promise<void>((resolve) => {
261
- const checkExecution = () => {
262
- if (
263
- consoleLogSpy.calledWith(`🔄 Executing scheduled request: ${id}`) &&
264
- consoleLogSpy.calledWith(
265
- `✅ Scheduled request executed successfully: ${id}`
266
- )
267
- ) {
268
- agenda.cancelScheduledRequest(id);
269
- resolve();
270
- return;
271
- }
272
- setTimeout(checkExecution, 100);
273
- };
274
- checkExecution();
275
- });
276
-
277
- expect(consoleLogSpy.calledWith(`🔄 Executing scheduled request: ${id}`))
278
- .to.be.true;
279
- expect(
280
- consoleLogSpy.calledWith(
281
- `✅ Scheduled request executed successfully: ${id}`
282
- )
283
- ).to.be.true;
284
-
285
- consoleLogSpy.restore();
286
- });
287
- });
288
- });
289
-
290
- let globalAgenda: Agenda;
291
- before(() => {
292
- const cronService = new NodeCronAdapter();
293
- const inMemoryAdapter = new InMemoryAdapter();
294
- const memory = new Memory(inMemoryAdapter);
295
- globalAgenda = new Agenda(cronService, memory);
296
- });
297
-
298
- after(async () => {
299
- if (globalAgenda) {
300
- globalAgenda.stopAll();
301
- await new Promise((resolve) => setTimeout(resolve, 100));
302
- }
303
-
304
- await globalAgenda.stop();
305
- await globalAgenda.cancel({});
306
- await new Promise((resolve) => setTimeout(resolve, 100));
307
- });