@principal-ai/principal-view-core 0.5.6

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 (204) hide show
  1. package/README.md +126 -0
  2. package/dist/ConfigurationLoader.d.ts +76 -0
  3. package/dist/ConfigurationLoader.d.ts.map +1 -0
  4. package/dist/ConfigurationLoader.js +144 -0
  5. package/dist/ConfigurationLoader.js.map +1 -0
  6. package/dist/ConfigurationValidator.d.ts +31 -0
  7. package/dist/ConfigurationValidator.d.ts.map +1 -0
  8. package/dist/ConfigurationValidator.js +242 -0
  9. package/dist/ConfigurationValidator.js.map +1 -0
  10. package/dist/EventProcessor.d.ts +49 -0
  11. package/dist/EventProcessor.d.ts.map +1 -0
  12. package/dist/EventProcessor.js +215 -0
  13. package/dist/EventProcessor.js.map +1 -0
  14. package/dist/EventRecorderService.d.ts +305 -0
  15. package/dist/EventRecorderService.d.ts.map +1 -0
  16. package/dist/EventRecorderService.js +463 -0
  17. package/dist/EventRecorderService.js.map +1 -0
  18. package/dist/LibraryLoader.d.ts +63 -0
  19. package/dist/LibraryLoader.d.ts.map +1 -0
  20. package/dist/LibraryLoader.js +188 -0
  21. package/dist/LibraryLoader.js.map +1 -0
  22. package/dist/PathBasedEventProcessor.d.ts +90 -0
  23. package/dist/PathBasedEventProcessor.d.ts.map +1 -0
  24. package/dist/PathBasedEventProcessor.js +239 -0
  25. package/dist/PathBasedEventProcessor.js.map +1 -0
  26. package/dist/SessionManager.d.ts +194 -0
  27. package/dist/SessionManager.d.ts.map +1 -0
  28. package/dist/SessionManager.js +299 -0
  29. package/dist/SessionManager.js.map +1 -0
  30. package/dist/ValidationEngine.d.ts +31 -0
  31. package/dist/ValidationEngine.d.ts.map +1 -0
  32. package/dist/ValidationEngine.js +158 -0
  33. package/dist/ValidationEngine.js.map +1 -0
  34. package/dist/helpers/GraphInstrumentationHelper.d.ts +93 -0
  35. package/dist/helpers/GraphInstrumentationHelper.d.ts.map +1 -0
  36. package/dist/helpers/GraphInstrumentationHelper.js +248 -0
  37. package/dist/helpers/GraphInstrumentationHelper.js.map +1 -0
  38. package/dist/index.d.ts +33 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +34 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/rules/config.d.ts +57 -0
  43. package/dist/rules/config.d.ts.map +1 -0
  44. package/dist/rules/config.js +382 -0
  45. package/dist/rules/config.js.map +1 -0
  46. package/dist/rules/engine.d.ts +70 -0
  47. package/dist/rules/engine.d.ts.map +1 -0
  48. package/dist/rules/engine.js +252 -0
  49. package/dist/rules/engine.js.map +1 -0
  50. package/dist/rules/implementations/connection-type-references.d.ts +7 -0
  51. package/dist/rules/implementations/connection-type-references.d.ts.map +1 -0
  52. package/dist/rules/implementations/connection-type-references.js +104 -0
  53. package/dist/rules/implementations/connection-type-references.js.map +1 -0
  54. package/dist/rules/implementations/dead-end-states.d.ts +17 -0
  55. package/dist/rules/implementations/dead-end-states.d.ts.map +1 -0
  56. package/dist/rules/implementations/dead-end-states.js +72 -0
  57. package/dist/rules/implementations/dead-end-states.js.map +1 -0
  58. package/dist/rules/implementations/index.d.ts +24 -0
  59. package/dist/rules/implementations/index.d.ts.map +1 -0
  60. package/dist/rules/implementations/index.js +62 -0
  61. package/dist/rules/implementations/index.js.map +1 -0
  62. package/dist/rules/implementations/library-node-type-match.d.ts +17 -0
  63. package/dist/rules/implementations/library-node-type-match.d.ts.map +1 -0
  64. package/dist/rules/implementations/library-node-type-match.js +123 -0
  65. package/dist/rules/implementations/library-node-type-match.js.map +1 -0
  66. package/dist/rules/implementations/minimum-node-sources.d.ts +22 -0
  67. package/dist/rules/implementations/minimum-node-sources.d.ts.map +1 -0
  68. package/dist/rules/implementations/minimum-node-sources.js +54 -0
  69. package/dist/rules/implementations/minimum-node-sources.js.map +1 -0
  70. package/dist/rules/implementations/no-unknown-fields.d.ts +7 -0
  71. package/dist/rules/implementations/no-unknown-fields.d.ts.map +1 -0
  72. package/dist/rules/implementations/no-unknown-fields.js +211 -0
  73. package/dist/rules/implementations/no-unknown-fields.js.map +1 -0
  74. package/dist/rules/implementations/orphaned-edge-types.d.ts +7 -0
  75. package/dist/rules/implementations/orphaned-edge-types.d.ts.map +1 -0
  76. package/dist/rules/implementations/orphaned-edge-types.js +47 -0
  77. package/dist/rules/implementations/orphaned-edge-types.js.map +1 -0
  78. package/dist/rules/implementations/orphaned-node-types.d.ts +7 -0
  79. package/dist/rules/implementations/orphaned-node-types.d.ts.map +1 -0
  80. package/dist/rules/implementations/orphaned-node-types.js +50 -0
  81. package/dist/rules/implementations/orphaned-node-types.js.map +1 -0
  82. package/dist/rules/implementations/required-metadata.d.ts +7 -0
  83. package/dist/rules/implementations/required-metadata.d.ts.map +1 -0
  84. package/dist/rules/implementations/required-metadata.js +57 -0
  85. package/dist/rules/implementations/required-metadata.js.map +1 -0
  86. package/dist/rules/implementations/state-transition-references.d.ts +7 -0
  87. package/dist/rules/implementations/state-transition-references.d.ts.map +1 -0
  88. package/dist/rules/implementations/state-transition-references.js +135 -0
  89. package/dist/rules/implementations/state-transition-references.js.map +1 -0
  90. package/dist/rules/implementations/unreachable-states.d.ts +7 -0
  91. package/dist/rules/implementations/unreachable-states.d.ts.map +1 -0
  92. package/dist/rules/implementations/unreachable-states.js +80 -0
  93. package/dist/rules/implementations/unreachable-states.js.map +1 -0
  94. package/dist/rules/implementations/valid-action-patterns.d.ts +17 -0
  95. package/dist/rules/implementations/valid-action-patterns.d.ts.map +1 -0
  96. package/dist/rules/implementations/valid-action-patterns.js +109 -0
  97. package/dist/rules/implementations/valid-action-patterns.js.map +1 -0
  98. package/dist/rules/implementations/valid-color-format.d.ts +7 -0
  99. package/dist/rules/implementations/valid-color-format.d.ts.map +1 -0
  100. package/dist/rules/implementations/valid-color-format.js +91 -0
  101. package/dist/rules/implementations/valid-color-format.js.map +1 -0
  102. package/dist/rules/implementations/valid-edge-types.d.ts +7 -0
  103. package/dist/rules/implementations/valid-edge-types.d.ts.map +1 -0
  104. package/dist/rules/implementations/valid-edge-types.js +244 -0
  105. package/dist/rules/implementations/valid-edge-types.js.map +1 -0
  106. package/dist/rules/implementations/valid-node-types.d.ts +7 -0
  107. package/dist/rules/implementations/valid-node-types.d.ts.map +1 -0
  108. package/dist/rules/implementations/valid-node-types.js +175 -0
  109. package/dist/rules/implementations/valid-node-types.js.map +1 -0
  110. package/dist/rules/index.d.ts +28 -0
  111. package/dist/rules/index.d.ts.map +1 -0
  112. package/dist/rules/index.js +45 -0
  113. package/dist/rules/index.js.map +1 -0
  114. package/dist/rules/types.d.ts +309 -0
  115. package/dist/rules/types.d.ts.map +1 -0
  116. package/dist/rules/types.js +35 -0
  117. package/dist/rules/types.js.map +1 -0
  118. package/dist/types/canvas.d.ts +409 -0
  119. package/dist/types/canvas.d.ts.map +1 -0
  120. package/dist/types/canvas.js +70 -0
  121. package/dist/types/canvas.js.map +1 -0
  122. package/dist/types/index.d.ts +311 -0
  123. package/dist/types/index.d.ts.map +1 -0
  124. package/dist/types/index.js +13 -0
  125. package/dist/types/index.js.map +1 -0
  126. package/dist/types/library.d.ts +185 -0
  127. package/dist/types/library.d.ts.map +1 -0
  128. package/dist/types/library.js +15 -0
  129. package/dist/types/library.js.map +1 -0
  130. package/dist/types/path-based-config.d.ts +230 -0
  131. package/dist/types/path-based-config.d.ts.map +1 -0
  132. package/dist/types/path-based-config.js +9 -0
  133. package/dist/types/path-based-config.js.map +1 -0
  134. package/dist/utils/CanvasConverter.d.ts +118 -0
  135. package/dist/utils/CanvasConverter.d.ts.map +1 -0
  136. package/dist/utils/CanvasConverter.js +315 -0
  137. package/dist/utils/CanvasConverter.js.map +1 -0
  138. package/dist/utils/GraphConverter.d.ts +18 -0
  139. package/dist/utils/GraphConverter.d.ts.map +1 -0
  140. package/dist/utils/GraphConverter.js +61 -0
  141. package/dist/utils/GraphConverter.js.map +1 -0
  142. package/dist/utils/LibraryConverter.d.ts +113 -0
  143. package/dist/utils/LibraryConverter.d.ts.map +1 -0
  144. package/dist/utils/LibraryConverter.js +166 -0
  145. package/dist/utils/LibraryConverter.js.map +1 -0
  146. package/dist/utils/PathMatcher.d.ts +55 -0
  147. package/dist/utils/PathMatcher.d.ts.map +1 -0
  148. package/dist/utils/PathMatcher.js +172 -0
  149. package/dist/utils/PathMatcher.js.map +1 -0
  150. package/dist/utils/YamlParser.d.ts +36 -0
  151. package/dist/utils/YamlParser.d.ts.map +1 -0
  152. package/dist/utils/YamlParser.js +63 -0
  153. package/dist/utils/YamlParser.js.map +1 -0
  154. package/package.json +47 -0
  155. package/src/ConfigurationLoader.test.ts +490 -0
  156. package/src/ConfigurationLoader.ts +185 -0
  157. package/src/ConfigurationValidator.test.ts +200 -0
  158. package/src/ConfigurationValidator.ts +283 -0
  159. package/src/EventProcessor.test.ts +405 -0
  160. package/src/EventProcessor.ts +250 -0
  161. package/src/EventRecorderService.test.ts +541 -0
  162. package/src/EventRecorderService.ts +744 -0
  163. package/src/LibraryLoader.ts +215 -0
  164. package/src/PathBasedEventProcessor.test.ts +567 -0
  165. package/src/PathBasedEventProcessor.ts +332 -0
  166. package/src/SessionManager.test.ts +424 -0
  167. package/src/SessionManager.ts +470 -0
  168. package/src/ValidationEngine.test.ts +371 -0
  169. package/src/ValidationEngine.ts +196 -0
  170. package/src/helpers/GraphInstrumentationHelper.test.ts +340 -0
  171. package/src/helpers/GraphInstrumentationHelper.ts +326 -0
  172. package/src/index.ts +85 -0
  173. package/src/rules/config.test.ts +278 -0
  174. package/src/rules/config.ts +459 -0
  175. package/src/rules/engine.test.ts +332 -0
  176. package/src/rules/engine.ts +318 -0
  177. package/src/rules/implementations/connection-type-references.ts +117 -0
  178. package/src/rules/implementations/dead-end-states.ts +101 -0
  179. package/src/rules/implementations/index.ts +73 -0
  180. package/src/rules/implementations/library-node-type-match.ts +148 -0
  181. package/src/rules/implementations/minimum-node-sources.ts +82 -0
  182. package/src/rules/implementations/no-unknown-fields.ts +342 -0
  183. package/src/rules/implementations/orphaned-edge-types.ts +55 -0
  184. package/src/rules/implementations/orphaned-node-types.ts +58 -0
  185. package/src/rules/implementations/required-metadata.ts +64 -0
  186. package/src/rules/implementations/state-transition-references.ts +151 -0
  187. package/src/rules/implementations/unreachable-states.ts +94 -0
  188. package/src/rules/implementations/valid-action-patterns.ts +136 -0
  189. package/src/rules/implementations/valid-color-format.ts +140 -0
  190. package/src/rules/implementations/valid-edge-types.ts +258 -0
  191. package/src/rules/implementations/valid-node-types.ts +189 -0
  192. package/src/rules/index.ts +95 -0
  193. package/src/rules/types.ts +426 -0
  194. package/src/types/canvas.ts +496 -0
  195. package/src/types/index.ts +382 -0
  196. package/src/types/library.ts +233 -0
  197. package/src/types/path-based-config.ts +281 -0
  198. package/src/utils/CanvasConverter.ts +431 -0
  199. package/src/utils/GraphConverter.test.ts +195 -0
  200. package/src/utils/GraphConverter.ts +71 -0
  201. package/src/utils/LibraryConverter.ts +245 -0
  202. package/src/utils/PathMatcher.test.ts +148 -0
  203. package/src/utils/PathMatcher.ts +183 -0
  204. package/src/utils/YamlParser.ts +75 -0
@@ -0,0 +1,405 @@
1
+ import { EventProcessor } from './EventProcessor';
2
+ import type { GraphConfiguration, GraphEvent } from './types';
3
+
4
+ describe('EventProcessor', () => {
5
+ let testConfig: GraphConfiguration;
6
+
7
+ beforeEach(() => {
8
+ testConfig = {
9
+ metadata: {
10
+ name: 'Test System',
11
+ version: '1.0.0',
12
+ },
13
+ nodeTypes: {
14
+ user: {
15
+ shape: 'circle',
16
+ color: '#4CAF50',
17
+ dataSchema: {
18
+ userId: { type: 'string', required: true },
19
+ status: { type: 'string' },
20
+ },
21
+ states: {
22
+ online: { color: '#4CAF50', label: 'Online' },
23
+ offline: { color: '#9E9E9E', label: 'Offline' },
24
+ },
25
+ },
26
+ server: {
27
+ shape: 'hexagon',
28
+ color: '#9C27B0',
29
+ dataSchema: {
30
+ uptime: { type: 'number' },
31
+ },
32
+ },
33
+ },
34
+ edgeTypes: {
35
+ connection: {
36
+ style: 'solid',
37
+ directed: true,
38
+ },
39
+ },
40
+ allowedConnections: [{ from: 'user', to: 'server', via: 'connection' }],
41
+ };
42
+ });
43
+
44
+ describe('Node Events', () => {
45
+ it('should create a node', () => {
46
+ const processor = new EventProcessor(testConfig);
47
+
48
+ const event: GraphEvent = {
49
+ id: 'evt-1',
50
+ type: 'node_created',
51
+ timestamp: Date.now(),
52
+ category: 'node',
53
+ operation: 'create',
54
+ payload: {
55
+ operation: 'create',
56
+ nodeId: 'user-1',
57
+ nodeType: 'user',
58
+ data: { userId: 'alice', status: 'online' },
59
+ },
60
+ expected: true,
61
+ };
62
+
63
+ const result = processor.processEvent(event);
64
+
65
+ expect(result.success).toBe(true);
66
+ expect(result.state.nodes.has('user-1')).toBe(true);
67
+
68
+ const node = result.state.nodes.get('user-1');
69
+ expect(node?.type).toBe('user');
70
+ expect(node?.data.userId).toBe('alice');
71
+ });
72
+
73
+ it('should update a node', () => {
74
+ const processor = new EventProcessor(testConfig);
75
+
76
+ // Create node first
77
+ processor.processEvent({
78
+ id: 'evt-1',
79
+ type: 'node_created',
80
+ timestamp: Date.now(),
81
+ category: 'node',
82
+ operation: 'create',
83
+ payload: {
84
+ operation: 'create',
85
+ nodeId: 'user-1',
86
+ nodeType: 'user',
87
+ data: { userId: 'alice', status: 'offline' },
88
+ },
89
+ expected: true,
90
+ });
91
+
92
+ // Update node
93
+ const result = processor.processEvent({
94
+ id: 'evt-2',
95
+ type: 'node_updated',
96
+ timestamp: Date.now(),
97
+ category: 'node',
98
+ operation: 'update',
99
+ payload: {
100
+ operation: 'update',
101
+ nodeId: 'user-1',
102
+ nodeType: 'user',
103
+ data: { status: 'online' },
104
+ },
105
+ expected: true,
106
+ });
107
+
108
+ expect(result.success).toBe(true);
109
+ const node = result.state.nodes.get('user-1');
110
+ expect(node?.data.status).toBe('online');
111
+ expect(node?.data.userId).toBe('alice'); // Should preserve existing data
112
+ });
113
+
114
+ it('should delete a node', () => {
115
+ const processor = new EventProcessor(testConfig);
116
+
117
+ // Create node first
118
+ processor.processEvent({
119
+ id: 'evt-1',
120
+ type: 'node_created',
121
+ timestamp: Date.now(),
122
+ category: 'node',
123
+ operation: 'create',
124
+ payload: {
125
+ operation: 'create',
126
+ nodeId: 'user-1',
127
+ nodeType: 'user',
128
+ data: { userId: 'alice' },
129
+ },
130
+ expected: true,
131
+ });
132
+
133
+ // Delete node
134
+ const result = processor.processEvent({
135
+ id: 'evt-2',
136
+ type: 'node_deleted',
137
+ timestamp: Date.now(),
138
+ category: 'node',
139
+ operation: 'delete',
140
+ payload: {
141
+ operation: 'delete',
142
+ nodeId: 'user-1',
143
+ nodeType: 'user',
144
+ },
145
+ expected: true,
146
+ });
147
+
148
+ expect(result.success).toBe(true);
149
+ expect(result.state.nodes.has('user-1')).toBe(false);
150
+ });
151
+ });
152
+
153
+ describe('Edge Events', () => {
154
+ it('should create an edge', () => {
155
+ const processor = new EventProcessor(testConfig);
156
+
157
+ // Create nodes first
158
+ processor.processEvent({
159
+ id: 'evt-1',
160
+ type: 'node_created',
161
+ timestamp: Date.now(),
162
+ category: 'node',
163
+ operation: 'create',
164
+ payload: {
165
+ operation: 'create',
166
+ nodeId: 'user-1',
167
+ nodeType: 'user',
168
+ data: { userId: 'alice' },
169
+ },
170
+ expected: true,
171
+ });
172
+
173
+ processor.processEvent({
174
+ id: 'evt-2',
175
+ type: 'node_created',
176
+ timestamp: Date.now(),
177
+ category: 'node',
178
+ operation: 'create',
179
+ payload: {
180
+ operation: 'create',
181
+ nodeId: 'server-1',
182
+ nodeType: 'server',
183
+ data: { uptime: 0 },
184
+ },
185
+ expected: true,
186
+ });
187
+
188
+ // Create edge
189
+ const result = processor.processEvent({
190
+ id: 'evt-3',
191
+ type: 'edge_created',
192
+ timestamp: Date.now(),
193
+ category: 'edge',
194
+ operation: 'create',
195
+ payload: {
196
+ operation: 'create',
197
+ edgeId: 'conn-1',
198
+ edgeType: 'connection',
199
+ from: 'user-1',
200
+ to: 'server-1',
201
+ },
202
+ expected: true,
203
+ });
204
+
205
+ expect(result.success).toBe(true);
206
+ expect(result.state.edges.has('conn-1')).toBe(true);
207
+
208
+ const edge = result.state.edges.get('conn-1');
209
+ expect(edge?.from).toBe('user-1');
210
+ expect(edge?.to).toBe('server-1');
211
+ expect(edge?.type).toBe('connection');
212
+ });
213
+
214
+ it('should delete an edge', () => {
215
+ const processor = new EventProcessor(testConfig);
216
+
217
+ // Create nodes and edge first
218
+ processor.processEvent({
219
+ id: 'evt-1',
220
+ type: 'node_created',
221
+ timestamp: Date.now(),
222
+ category: 'node',
223
+ operation: 'create',
224
+ payload: {
225
+ operation: 'create',
226
+ nodeId: 'user-1',
227
+ nodeType: 'user',
228
+ data: { userId: 'alice' },
229
+ },
230
+ expected: true,
231
+ });
232
+
233
+ processor.processEvent({
234
+ id: 'evt-2',
235
+ type: 'node_created',
236
+ timestamp: Date.now(),
237
+ category: 'node',
238
+ operation: 'create',
239
+ payload: {
240
+ operation: 'create',
241
+ nodeId: 'server-1',
242
+ nodeType: 'server',
243
+ data: { uptime: 0 },
244
+ },
245
+ expected: true,
246
+ });
247
+
248
+ processor.processEvent({
249
+ id: 'evt-3',
250
+ type: 'edge_created',
251
+ timestamp: Date.now(),
252
+ category: 'edge',
253
+ operation: 'create',
254
+ payload: {
255
+ operation: 'create',
256
+ edgeId: 'conn-1',
257
+ edgeType: 'connection',
258
+ from: 'user-1',
259
+ to: 'server-1',
260
+ },
261
+ expected: true,
262
+ });
263
+
264
+ // Delete edge
265
+ const result = processor.processEvent({
266
+ id: 'evt-4',
267
+ type: 'edge_deleted',
268
+ timestamp: Date.now(),
269
+ category: 'edge',
270
+ operation: 'delete',
271
+ payload: {
272
+ operation: 'delete',
273
+ edgeId: 'conn-1',
274
+ edgeType: 'connection',
275
+ from: 'user-1',
276
+ to: 'server-1',
277
+ },
278
+ expected: true,
279
+ });
280
+
281
+ expect(result.success).toBe(true);
282
+ expect(result.state.edges.has('conn-1')).toBe(false);
283
+ });
284
+ });
285
+
286
+ describe('State Events', () => {
287
+ it('should update node state', () => {
288
+ const processor = new EventProcessor(testConfig);
289
+
290
+ // Create node first
291
+ processor.processEvent({
292
+ id: 'evt-1',
293
+ type: 'node_created',
294
+ timestamp: Date.now(),
295
+ category: 'node',
296
+ operation: 'create',
297
+ payload: {
298
+ operation: 'create',
299
+ nodeId: 'user-1',
300
+ nodeType: 'user',
301
+ data: { userId: 'alice' },
302
+ },
303
+ expected: true,
304
+ });
305
+
306
+ // Update state
307
+ const result = processor.processEvent({
308
+ id: 'evt-2',
309
+ type: 'state_changed',
310
+ timestamp: Date.now(),
311
+ category: 'state',
312
+ operation: 'update',
313
+ payload: {
314
+ nodeId: 'user-1',
315
+ newState: 'online',
316
+ },
317
+ expected: true,
318
+ });
319
+
320
+ expect(result.success).toBe(true);
321
+ const node = result.state.nodes.get('user-1');
322
+ expect(node?.state).toBe('online');
323
+ });
324
+ });
325
+
326
+ describe('System Events', () => {
327
+ it('should reset the graph state', () => {
328
+ const processor = new EventProcessor(testConfig);
329
+
330
+ // Create some nodes
331
+ processor.processEvent({
332
+ id: 'evt-1',
333
+ type: 'node_created',
334
+ timestamp: Date.now(),
335
+ category: 'node',
336
+ operation: 'create',
337
+ payload: {
338
+ operation: 'create',
339
+ nodeId: 'user-1',
340
+ nodeType: 'user',
341
+ data: { userId: 'alice' },
342
+ },
343
+ expected: true,
344
+ });
345
+
346
+ // Reset
347
+ const result = processor.processEvent({
348
+ id: 'evt-2',
349
+ type: 'system_reset',
350
+ timestamp: Date.now(),
351
+ category: 'system',
352
+ operation: 'update',
353
+ payload: {
354
+ action: 'reset',
355
+ },
356
+ expected: true,
357
+ });
358
+
359
+ expect(result.success).toBe(true);
360
+ expect(result.state.nodes.size).toBe(0);
361
+ expect(result.state.edges.size).toBe(0);
362
+ });
363
+ });
364
+
365
+ describe('Event History', () => {
366
+ it('should track event history', () => {
367
+ const processor = new EventProcessor(testConfig);
368
+
369
+ processor.processEvent({
370
+ id: 'evt-1',
371
+ type: 'node_created',
372
+ timestamp: Date.now(),
373
+ category: 'node',
374
+ operation: 'create',
375
+ payload: {
376
+ operation: 'create',
377
+ nodeId: 'user-1',
378
+ nodeType: 'user',
379
+ data: { userId: 'alice' },
380
+ },
381
+ expected: true,
382
+ });
383
+
384
+ processor.processEvent({
385
+ id: 'evt-2',
386
+ type: 'node_created',
387
+ timestamp: Date.now(),
388
+ category: 'node',
389
+ operation: 'create',
390
+ payload: {
391
+ operation: 'create',
392
+ nodeId: 'user-2',
393
+ nodeType: 'user',
394
+ data: { userId: 'bob' },
395
+ },
396
+ expected: true,
397
+ });
398
+
399
+ const history = processor.getEventHistory();
400
+ expect(history).toHaveLength(2);
401
+ expect(history[0].id).toBe('evt-1');
402
+ expect(history[1].id).toBe('evt-2');
403
+ });
404
+ });
405
+ });
@@ -0,0 +1,250 @@
1
+ import type {
2
+ GraphEvent,
3
+ GraphConfiguration,
4
+ GraphState,
5
+ ValidationResult,
6
+ NodeState,
7
+ EdgeState,
8
+ } from './types';
9
+ import { ValidationEngine } from './ValidationEngine';
10
+ import { ConfigurationValidator } from './ConfigurationValidator';
11
+
12
+ export interface ProcessingResult {
13
+ success: boolean;
14
+ state: GraphState;
15
+ validation: ValidationResult;
16
+ error?: string;
17
+ }
18
+
19
+ /**
20
+ * EventProcessor handles the ingestion and processing of graph events
21
+ */
22
+ export class EventProcessor {
23
+ private state: GraphState;
24
+ private validationEngine: ValidationEngine;
25
+ private eventHistory: GraphEvent[] = [];
26
+
27
+ constructor(configuration: GraphConfiguration, options?: { validateConfig?: boolean }) {
28
+ // Validate configuration by default (can be disabled for performance)
29
+ if (options?.validateConfig !== false) {
30
+ ConfigurationValidator.validateOrThrow(configuration);
31
+ }
32
+
33
+ this.state = {
34
+ nodes: new Map<string, NodeState>(),
35
+ edges: new Map<string, EdgeState>(),
36
+ configuration,
37
+ };
38
+ this.validationEngine = new ValidationEngine(configuration.validation || {});
39
+ }
40
+
41
+ /**
42
+ * Process a single graph event
43
+ */
44
+ processEvent(event: GraphEvent): ProcessingResult {
45
+ try {
46
+ // Validate event first
47
+ const validation = this.validateEvent(event);
48
+
49
+ // Apply the event to state
50
+ this.applyEvent(event);
51
+
52
+ // Store in history
53
+ this.eventHistory.push(event);
54
+
55
+ return {
56
+ success: true,
57
+ state: this.state,
58
+ validation,
59
+ };
60
+ } catch (error) {
61
+ return {
62
+ success: false,
63
+ state: this.state,
64
+ validation: {
65
+ valid: false,
66
+ violations: [],
67
+ warnings: [],
68
+ metrics: this.getEmptyMetrics(),
69
+ },
70
+ error: error instanceof Error ? error.message : 'Unknown error',
71
+ };
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Validate an event against configuration rules
77
+ */
78
+ validateEvent(event: GraphEvent): ValidationResult {
79
+ return this.validationEngine.validate(event, this.state);
80
+ }
81
+
82
+ /**
83
+ * Get the current graph state
84
+ */
85
+ getGraphState(): GraphState {
86
+ return this.state;
87
+ }
88
+
89
+ /**
90
+ * Get event history
91
+ */
92
+ getEventHistory(): GraphEvent[] {
93
+ return [...this.eventHistory];
94
+ }
95
+
96
+ /**
97
+ * Reset processor state
98
+ */
99
+ reset(): void {
100
+ this.state.nodes.clear();
101
+ this.state.edges.clear();
102
+ this.eventHistory = [];
103
+ }
104
+
105
+ /**
106
+ * Apply event to internal state
107
+ */
108
+ private applyEvent(event: GraphEvent): void {
109
+ const timestamp = event.timestamp;
110
+
111
+ switch (event.category) {
112
+ case 'node':
113
+ this.handleNodeEvent(event, timestamp);
114
+ break;
115
+ case 'edge':
116
+ this.handleEdgeEvent(event, timestamp);
117
+ break;
118
+ case 'state':
119
+ this.handleStateEvent(event, timestamp);
120
+ break;
121
+ case 'data':
122
+ this.handleDataEvent(event);
123
+ break;
124
+ case 'system':
125
+ this.handleSystemEvent(event);
126
+ break;
127
+ }
128
+ }
129
+
130
+ private handleNodeEvent(event: GraphEvent, timestamp: number): void {
131
+ const payload = event.payload as any;
132
+
133
+ switch (payload.operation) {
134
+ case 'create':
135
+ this.state.nodes.set(payload.nodeId, {
136
+ id: payload.nodeId,
137
+ type: payload.nodeType,
138
+ data: payload.data || {},
139
+ position: payload.position,
140
+ createdAt: timestamp,
141
+ updatedAt: timestamp,
142
+ });
143
+ break;
144
+ case 'update': {
145
+ const existingNode = this.state.nodes.get(payload.nodeId);
146
+ if (existingNode) {
147
+ this.state.nodes.set(payload.nodeId, {
148
+ ...existingNode,
149
+ data: { ...existingNode.data, ...payload.data },
150
+ position: payload.position || existingNode.position,
151
+ updatedAt: timestamp,
152
+ });
153
+ }
154
+ break;
155
+ }
156
+ case 'delete':
157
+ this.state.nodes.delete(payload.nodeId);
158
+ break;
159
+ }
160
+ }
161
+
162
+ private handleEdgeEvent(event: GraphEvent, timestamp: number): void {
163
+ const payload = event.payload as any;
164
+
165
+ switch (payload.operation) {
166
+ case 'create':
167
+ this.state.edges.set(payload.edgeId, {
168
+ id: payload.edgeId,
169
+ type: payload.edgeType,
170
+ from: payload.from,
171
+ to: payload.to,
172
+ data: payload.data,
173
+ createdAt: timestamp,
174
+ updatedAt: timestamp,
175
+ });
176
+ break;
177
+ case 'update': {
178
+ const existingEdge = this.state.edges.get(payload.edgeId);
179
+ if (existingEdge) {
180
+ this.state.edges.set(payload.edgeId, {
181
+ ...existingEdge,
182
+ data: { ...existingEdge.data, ...payload.data },
183
+ updatedAt: timestamp,
184
+ });
185
+ }
186
+ break;
187
+ }
188
+ case 'delete':
189
+ this.state.edges.delete(payload.edgeId);
190
+ break;
191
+ case 'animate':
192
+ // Animation is handled by the UI layer
193
+ break;
194
+ }
195
+ }
196
+
197
+ private handleStateEvent(event: GraphEvent, timestamp: number): void {
198
+ const payload = event.payload as any;
199
+ const node = this.state.nodes.get(payload.nodeId);
200
+ if (node) {
201
+ this.state.nodes.set(payload.nodeId, {
202
+ ...node,
203
+ state: payload.newState,
204
+ data: { ...node.data, ...payload.data },
205
+ updatedAt: timestamp,
206
+ });
207
+ }
208
+ }
209
+
210
+ private handleDataEvent(event: GraphEvent): void {
211
+ const payload = event.payload as any;
212
+ if (payload.targetType === 'node') {
213
+ const node = this.state.nodes.get(payload.targetId);
214
+ if (node) {
215
+ this.state.nodes.set(payload.targetId, {
216
+ ...node,
217
+ data: { ...node.data, ...payload.updates },
218
+ updatedAt: event.timestamp,
219
+ });
220
+ }
221
+ } else {
222
+ const edge = this.state.edges.get(payload.targetId);
223
+ if (edge) {
224
+ this.state.edges.set(payload.targetId, {
225
+ ...edge,
226
+ data: { ...edge.data, ...payload.updates },
227
+ updatedAt: event.timestamp,
228
+ });
229
+ }
230
+ }
231
+ }
232
+
233
+ private handleSystemEvent(event: GraphEvent): void {
234
+ const payload = event.payload as any;
235
+ if (payload.action === 'reset') {
236
+ this.reset();
237
+ }
238
+ }
239
+
240
+ private getEmptyMetrics() {
241
+ return {
242
+ totalEvents: 0,
243
+ validEvents: 0,
244
+ violations: 0,
245
+ warnings: 0,
246
+ unexpectedEvents: 0,
247
+ expectedEventsMissing: 0,
248
+ };
249
+ }
250
+ }