@semiont/event-sourcing 0.2.28-build.40
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 +407 -0
- package/dist/index.d.ts +606 -0
- package/dist/index.js +1170 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
import { ResourceId, ResourceAnnotations, AnnotationId, ResourceEvent, StoredEvent, EventQuery as EventQuery$1 } from '@semiont/core';
|
|
2
|
+
import { components, ResourceUri, AnnotationUri } from '@semiont/api-client';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* View Storage - Materialized Views
|
|
6
|
+
*
|
|
7
|
+
* Stores materialized views of resource state and annotations
|
|
8
|
+
* Built from event streams, can be rebuilt at any time
|
|
9
|
+
*
|
|
10
|
+
* Stores both ResourceDescriptor metadata and ResourceAnnotations, but keeps them logically separate
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
type ResourceDescriptor = components['schemas']['ResourceDescriptor'];
|
|
14
|
+
interface ResourceView {
|
|
15
|
+
resource: ResourceDescriptor;
|
|
16
|
+
annotations: ResourceAnnotations;
|
|
17
|
+
}
|
|
18
|
+
interface ViewStorage {
|
|
19
|
+
save(resourceId: ResourceId, view: ResourceView): Promise<void>;
|
|
20
|
+
get(resourceId: ResourceId): Promise<ResourceView | null>;
|
|
21
|
+
delete(resourceId: ResourceId): Promise<void>;
|
|
22
|
+
exists(resourceId: ResourceId): Promise<boolean>;
|
|
23
|
+
getAll(): Promise<ResourceView[]>;
|
|
24
|
+
}
|
|
25
|
+
declare class FilesystemViewStorage implements ViewStorage {
|
|
26
|
+
private basePath;
|
|
27
|
+
constructor(basePath: string, projectRoot?: string);
|
|
28
|
+
private getProjectionPath;
|
|
29
|
+
save(resourceId: ResourceId, projection: ResourceView): Promise<void>;
|
|
30
|
+
get(resourceId: ResourceId): Promise<ResourceView | null>;
|
|
31
|
+
delete(resourceId: ResourceId): Promise<void>;
|
|
32
|
+
exists(resourceId: ResourceId): Promise<boolean>;
|
|
33
|
+
getAll(): Promise<ResourceView[]>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Type definitions for event-sourcing package
|
|
38
|
+
*/
|
|
39
|
+
interface IdentifierConfig {
|
|
40
|
+
baseUrl: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Identifier conversion functions - Convert between short IDs and W3C-compliant HTTP URIs
|
|
45
|
+
*
|
|
46
|
+
* These functions handle the conversion between:
|
|
47
|
+
* - Short IDs (e.g., "abc123") - used internally in events
|
|
48
|
+
* - HTTP URIs (e.g., "http://localhost:4000/resources/abc123") - used in API responses
|
|
49
|
+
*
|
|
50
|
+
* The W3C Web Annotation Model requires HTTP(S) URIs for @id fields.
|
|
51
|
+
*
|
|
52
|
+
* All functions are pure - they take config explicitly as a parameter.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
declare function toResourceUri(config: IdentifierConfig, id: ResourceId): ResourceUri;
|
|
56
|
+
declare function toAnnotationUri(config: IdentifierConfig, id: AnnotationId): AnnotationUri;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Event Storage - Physical Storage Layer
|
|
60
|
+
*
|
|
61
|
+
* Handles file I/O operations for event storage:
|
|
62
|
+
* - JSONL file writing/reading
|
|
63
|
+
* - 4-hex sharding (65,536 shards)
|
|
64
|
+
* - File rotation
|
|
65
|
+
* - Event stream initialization
|
|
66
|
+
*
|
|
67
|
+
* @see docs/EVENT-STORE.md#eventstorage for architecture details
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
interface EventStorageConfig {
|
|
71
|
+
basePath: string;
|
|
72
|
+
dataDir: string;
|
|
73
|
+
maxEventsPerFile?: number;
|
|
74
|
+
enableSharding?: boolean;
|
|
75
|
+
numShards?: number;
|
|
76
|
+
enableCompression?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* EventStorage handles physical storage of events
|
|
80
|
+
* Owns: file I/O, sharding, AND sequence/hash tracking
|
|
81
|
+
*/
|
|
82
|
+
declare class EventStorage {
|
|
83
|
+
private config;
|
|
84
|
+
private resourceSequences;
|
|
85
|
+
private resourceLastHash;
|
|
86
|
+
constructor(config: EventStorageConfig);
|
|
87
|
+
/**
|
|
88
|
+
* Calculate shard path for a resource ID
|
|
89
|
+
* Uses jump consistent hash for uniform distribution
|
|
90
|
+
* Special case: __system__ events bypass sharding
|
|
91
|
+
*/
|
|
92
|
+
getShardPath(resourceId: ResourceId): string;
|
|
93
|
+
/**
|
|
94
|
+
* Get full path to resource's event directory
|
|
95
|
+
*/
|
|
96
|
+
getResourcePath(resourceId: ResourceId): string;
|
|
97
|
+
/**
|
|
98
|
+
* Initialize directory structure for a resource's event stream
|
|
99
|
+
* Also loads sequence number and last hash if stream exists
|
|
100
|
+
*/
|
|
101
|
+
initializeResourceStream(resourceId: ResourceId): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Append an event - handles EVERYTHING for event creation
|
|
104
|
+
* Creates ID, timestamp, metadata, checksum, sequence tracking, and writes to disk
|
|
105
|
+
*/
|
|
106
|
+
appendEvent(event: Omit<ResourceEvent, 'id' | 'timestamp'>, resourceId: ResourceId): Promise<StoredEvent>;
|
|
107
|
+
/**
|
|
108
|
+
* Write an event to storage (append to JSONL)
|
|
109
|
+
* Internal method - use appendEvent() instead
|
|
110
|
+
*/
|
|
111
|
+
private writeEvent;
|
|
112
|
+
/**
|
|
113
|
+
* Count events in a specific file
|
|
114
|
+
*/
|
|
115
|
+
countEventsInFile(resourceId: ResourceId, filename: string): Promise<number>;
|
|
116
|
+
/**
|
|
117
|
+
* Read all events from a specific file
|
|
118
|
+
*/
|
|
119
|
+
readEventsFromFile(resourceId: ResourceId, filename: string): Promise<StoredEvent[]>;
|
|
120
|
+
/**
|
|
121
|
+
* Get list of event files for a resource (sorted by sequence)
|
|
122
|
+
*/
|
|
123
|
+
getEventFiles(resourceId: ResourceId): Promise<string[]>;
|
|
124
|
+
/**
|
|
125
|
+
* Create a new event file for rotation
|
|
126
|
+
*/
|
|
127
|
+
createNewEventFile(resourceId: ResourceId): Promise<string>;
|
|
128
|
+
/**
|
|
129
|
+
* Get the last event from a specific file
|
|
130
|
+
*/
|
|
131
|
+
getLastEvent(resourceId: ResourceId, filename: string): Promise<StoredEvent | null>;
|
|
132
|
+
/**
|
|
133
|
+
* Get all events for a resource across all files
|
|
134
|
+
*/
|
|
135
|
+
getAllEvents(resourceId: ResourceId): Promise<StoredEvent[]>;
|
|
136
|
+
/**
|
|
137
|
+
* Get all resource IDs by scanning shard directories
|
|
138
|
+
*/
|
|
139
|
+
getAllResourceIds(): Promise<ResourceId[]>;
|
|
140
|
+
/**
|
|
141
|
+
* Create filename for event file
|
|
142
|
+
*/
|
|
143
|
+
private createEventFilename;
|
|
144
|
+
/**
|
|
145
|
+
* Get current sequence number for a resource
|
|
146
|
+
*/
|
|
147
|
+
getSequenceNumber(resourceId: ResourceId): number;
|
|
148
|
+
/**
|
|
149
|
+
* Increment and return next sequence number for a resource
|
|
150
|
+
*/
|
|
151
|
+
getNextSequenceNumber(resourceId: ResourceId): number;
|
|
152
|
+
/**
|
|
153
|
+
* Get last event hash for a resource
|
|
154
|
+
*/
|
|
155
|
+
getLastEventHash(resourceId: ResourceId): string | null;
|
|
156
|
+
/**
|
|
157
|
+
* Set last event hash for a resource
|
|
158
|
+
*/
|
|
159
|
+
setLastEventHash(resourceId: ResourceId, hash: string): void;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* EventLog - Event Persistence Layer
|
|
164
|
+
*
|
|
165
|
+
* Single Responsibility: Event persistence only
|
|
166
|
+
* - Appends events to storage (JSONL files)
|
|
167
|
+
* - Retrieves events by resource
|
|
168
|
+
* - Queries events with filters
|
|
169
|
+
*
|
|
170
|
+
* Does NOT handle:
|
|
171
|
+
* - Pub/sub notifications (see EventBus)
|
|
172
|
+
* - View updates (see ViewManager)
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
interface EventLogConfig {
|
|
176
|
+
basePath: string;
|
|
177
|
+
dataDir: string;
|
|
178
|
+
enableSharding?: boolean;
|
|
179
|
+
maxEventsPerFile?: number;
|
|
180
|
+
}
|
|
181
|
+
declare class EventLog {
|
|
182
|
+
readonly storage: EventStorage;
|
|
183
|
+
constructor(config: EventLogConfig);
|
|
184
|
+
/**
|
|
185
|
+
* Append event to log
|
|
186
|
+
* @param event - Resource event (from @semiont/core)
|
|
187
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
188
|
+
* @returns Stored event with metadata (sequence number, timestamp, checksum)
|
|
189
|
+
*/
|
|
190
|
+
append(event: Omit<ResourceEvent, 'id' | 'timestamp'>, resourceId: ResourceId): Promise<StoredEvent>;
|
|
191
|
+
/**
|
|
192
|
+
* Get all events for a resource
|
|
193
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
194
|
+
*/
|
|
195
|
+
getEvents(resourceId: ResourceId): Promise<StoredEvent[]>;
|
|
196
|
+
/**
|
|
197
|
+
* Get all resource IDs
|
|
198
|
+
* @returns Array of branded ResourceId types
|
|
199
|
+
*/
|
|
200
|
+
getAllResourceIds(): Promise<ResourceId[]>;
|
|
201
|
+
/**
|
|
202
|
+
* Query events with filter
|
|
203
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
204
|
+
* @param filter - Optional event filter
|
|
205
|
+
*/
|
|
206
|
+
queryEvents(resourceId: ResourceId, filter?: EventQuery$1): Promise<StoredEvent[]>;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Event Subscriptions - Real-time Event Pub/Sub
|
|
211
|
+
*
|
|
212
|
+
* Manages subscriptions for both resource-scoped and system-level events:
|
|
213
|
+
* - Resource subscriptions: notifications for a specific resource's events
|
|
214
|
+
* - Global subscriptions: notifications for all system-level events
|
|
215
|
+
* - Fire-and-forget notification pattern (non-blocking)
|
|
216
|
+
* - Automatic cleanup of empty subscription sets
|
|
217
|
+
*
|
|
218
|
+
* SINGLETON PATTERN: All EventStore instances share the same EventSubscriptions
|
|
219
|
+
* to ensure SSE connections receive events from any EventStore instance.
|
|
220
|
+
*
|
|
221
|
+
* @see docs/EVENT-STORE.md#eventsubscriptions for architecture details
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
type EventCallback = (event: StoredEvent) => void | Promise<void>;
|
|
225
|
+
interface EventSubscription {
|
|
226
|
+
resourceUri: ResourceUri;
|
|
227
|
+
callback: EventCallback;
|
|
228
|
+
unsubscribe: () => void;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* EventSubscriptions manages real-time event pub/sub
|
|
232
|
+
* Supports both resource-scoped and global subscriptions
|
|
233
|
+
*/
|
|
234
|
+
declare class EventSubscriptions {
|
|
235
|
+
private subscriptions;
|
|
236
|
+
private globalSubscriptions;
|
|
237
|
+
/**
|
|
238
|
+
* Subscribe to events for a specific resource using full URI
|
|
239
|
+
* Returns an EventSubscription with unsubscribe function
|
|
240
|
+
*/
|
|
241
|
+
subscribe(resourceUri: ResourceUri, callback: EventCallback): EventSubscription;
|
|
242
|
+
/**
|
|
243
|
+
* Subscribe to all system-level events (no resourceId)
|
|
244
|
+
* Returns an EventSubscription with unsubscribe function
|
|
245
|
+
*
|
|
246
|
+
* Use this for consumers that need to react to global events like:
|
|
247
|
+
* - entitytype.added (global entity type collection changes)
|
|
248
|
+
* - Future system-level events (user.created, workspace.created, etc.)
|
|
249
|
+
*/
|
|
250
|
+
subscribeGlobal(callback: EventCallback): EventSubscription;
|
|
251
|
+
/**
|
|
252
|
+
* Notify all subscribers for a resource when a new event is appended
|
|
253
|
+
* @param resourceUri - Full resource URI (e.g., http://localhost:4000/resources/abc123)
|
|
254
|
+
*/
|
|
255
|
+
notifySubscribers(resourceUri: ResourceUri, event: StoredEvent): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Notify all global subscribers when a system-level event is appended
|
|
258
|
+
*/
|
|
259
|
+
notifyGlobalSubscribers(event: StoredEvent): Promise<void>;
|
|
260
|
+
/**
|
|
261
|
+
* Get subscription count for a resource (useful for debugging)
|
|
262
|
+
*/
|
|
263
|
+
getSubscriptionCount(resourceUri: ResourceUri): number;
|
|
264
|
+
/**
|
|
265
|
+
* Get total number of active subscriptions across all resources
|
|
266
|
+
*/
|
|
267
|
+
getTotalSubscriptions(): number;
|
|
268
|
+
/**
|
|
269
|
+
* Get total number of global subscriptions
|
|
270
|
+
*/
|
|
271
|
+
getGlobalSubscriptionCount(): number;
|
|
272
|
+
}
|
|
273
|
+
declare function getEventSubscriptions(): EventSubscriptions;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* EventBus - Event Pub/Sub Layer
|
|
277
|
+
*
|
|
278
|
+
* Single Responsibility: Event pub/sub only
|
|
279
|
+
* - Publishes events to subscribers
|
|
280
|
+
* - Manages subscriptions (resource-scoped and global)
|
|
281
|
+
* - Converts ResourceId to ResourceUri internally
|
|
282
|
+
*
|
|
283
|
+
* Does NOT handle:
|
|
284
|
+
* - Event persistence (see EventLog)
|
|
285
|
+
* - View updates (see ViewManager)
|
|
286
|
+
*/
|
|
287
|
+
|
|
288
|
+
interface EventBusConfig {
|
|
289
|
+
identifierConfig: IdentifierConfig;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* EventBus wraps EventSubscriptions with a clean API
|
|
293
|
+
* Handles ID-to-URI conversion internally for type safety
|
|
294
|
+
*/
|
|
295
|
+
declare class EventBus {
|
|
296
|
+
readonly subscriptions: EventSubscriptions;
|
|
297
|
+
private identifierConfig;
|
|
298
|
+
constructor(config: EventBusConfig);
|
|
299
|
+
/**
|
|
300
|
+
* Publish event to subscribers
|
|
301
|
+
* - Resource events: notifies resource-scoped subscribers
|
|
302
|
+
* - System events: notifies global subscribers
|
|
303
|
+
* @param event - Stored event (from @semiont/core)
|
|
304
|
+
*/
|
|
305
|
+
publish(event: StoredEvent): Promise<void>;
|
|
306
|
+
/**
|
|
307
|
+
* Subscribe to events for a specific resource
|
|
308
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
309
|
+
* @param callback - Event callback function
|
|
310
|
+
* @returns EventSubscription with unsubscribe function
|
|
311
|
+
*/
|
|
312
|
+
subscribe(resourceId: ResourceId, callback: EventCallback): EventSubscription;
|
|
313
|
+
/**
|
|
314
|
+
* Subscribe to all system-level events
|
|
315
|
+
* @param callback - Event callback function
|
|
316
|
+
* @returns EventSubscription with unsubscribe function
|
|
317
|
+
*/
|
|
318
|
+
subscribeGlobal(callback: EventCallback): EventSubscription;
|
|
319
|
+
/**
|
|
320
|
+
* Unsubscribe from resource events
|
|
321
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
322
|
+
* @param callback - Event callback function to remove
|
|
323
|
+
*/
|
|
324
|
+
unsubscribe(resourceId: ResourceId, callback: EventCallback): void;
|
|
325
|
+
/**
|
|
326
|
+
* Unsubscribe from global events
|
|
327
|
+
* @param callback - Event callback function to remove
|
|
328
|
+
*/
|
|
329
|
+
unsubscribeGlobal(callback: EventCallback): void;
|
|
330
|
+
/**
|
|
331
|
+
* Get subscriber count for a resource
|
|
332
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
333
|
+
* @returns Number of active subscribers
|
|
334
|
+
*/
|
|
335
|
+
getSubscriberCount(resourceId: ResourceId): number;
|
|
336
|
+
/**
|
|
337
|
+
* Get total number of active subscriptions across all resources
|
|
338
|
+
*/
|
|
339
|
+
getTotalSubscriptions(): number;
|
|
340
|
+
/**
|
|
341
|
+
* Get total number of global subscriptions
|
|
342
|
+
*/
|
|
343
|
+
getGlobalSubscriptionCount(): number;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* View Materializer - Materialized View Management
|
|
348
|
+
*
|
|
349
|
+
* Materializes resource views from events:
|
|
350
|
+
* - Full view materialization from scratch
|
|
351
|
+
* - Incremental view updates
|
|
352
|
+
* - System-level views (entity types)
|
|
353
|
+
*
|
|
354
|
+
* @see docs/EVENT-STORE.md#viewmaterializer for architecture details
|
|
355
|
+
*/
|
|
356
|
+
|
|
357
|
+
interface ViewMaterializerConfig {
|
|
358
|
+
basePath: string;
|
|
359
|
+
backendUrl: string;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* ViewMaterializer builds and maintains materialized views from events
|
|
363
|
+
*/
|
|
364
|
+
declare class ViewMaterializer {
|
|
365
|
+
private viewStorage;
|
|
366
|
+
private config;
|
|
367
|
+
constructor(viewStorage: ViewStorage, config: ViewMaterializerConfig);
|
|
368
|
+
/**
|
|
369
|
+
* Materialize resource view from events
|
|
370
|
+
* Loads existing view if cached, otherwise rebuilds from events
|
|
371
|
+
*/
|
|
372
|
+
materialize(events: StoredEvent[], resourceId: ResourceId): Promise<ResourceView | null>;
|
|
373
|
+
/**
|
|
374
|
+
* Materialize view incrementally with a single event
|
|
375
|
+
* Falls back to full rebuild if view doesn't exist
|
|
376
|
+
*/
|
|
377
|
+
materializeIncremental(resourceId: ResourceId, event: ResourceEvent, getAllEvents: () => Promise<StoredEvent[]>): Promise<void>;
|
|
378
|
+
/**
|
|
379
|
+
* Materialize view from event list (full rebuild)
|
|
380
|
+
*/
|
|
381
|
+
private materializeFromEvents;
|
|
382
|
+
/**
|
|
383
|
+
* Apply an event to ResourceDescriptor state (metadata only)
|
|
384
|
+
*/
|
|
385
|
+
private applyEventToResource;
|
|
386
|
+
/**
|
|
387
|
+
* Apply an event to ResourceAnnotations (annotation collections only)
|
|
388
|
+
*/
|
|
389
|
+
private applyEventToAnnotations;
|
|
390
|
+
/**
|
|
391
|
+
* Materialize entity types view - System-level view
|
|
392
|
+
*/
|
|
393
|
+
materializeEntityTypes(entityType: string): Promise<void>;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* ViewManager - Materialized View Management Layer
|
|
398
|
+
*
|
|
399
|
+
* Single Responsibility: View updates only
|
|
400
|
+
* - Updates resource views from events
|
|
401
|
+
* - Updates system views (entity types)
|
|
402
|
+
* - Rebuilds views when needed
|
|
403
|
+
*
|
|
404
|
+
* Does NOT handle:
|
|
405
|
+
* - Event persistence (see EventLog)
|
|
406
|
+
* - Pub/sub notifications (see EventBus)
|
|
407
|
+
*/
|
|
408
|
+
|
|
409
|
+
interface ViewManagerConfig {
|
|
410
|
+
basePath: string;
|
|
411
|
+
backendUrl: string;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* ViewManager wraps ViewMaterializer with a clean API
|
|
415
|
+
* Handles both resource and system-level views
|
|
416
|
+
*/
|
|
417
|
+
declare class ViewManager {
|
|
418
|
+
readonly materializer: ViewMaterializer;
|
|
419
|
+
constructor(viewStorage: ViewStorage, config: ViewManagerConfig);
|
|
420
|
+
/**
|
|
421
|
+
* Update resource view with a new event
|
|
422
|
+
* Falls back to full rebuild if view doesn't exist
|
|
423
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
424
|
+
* @param event - Resource event (from @semiont/core)
|
|
425
|
+
* @param getAllEvents - Function to retrieve all events for rebuild if needed
|
|
426
|
+
*/
|
|
427
|
+
materializeResource(resourceId: ResourceId, event: ResourceEvent, getAllEvents: () => Promise<StoredEvent[]>): Promise<void>;
|
|
428
|
+
/**
|
|
429
|
+
* Update system-level view (currently only entity types)
|
|
430
|
+
* @param eventType - Type of system event
|
|
431
|
+
* @param payload - Event payload
|
|
432
|
+
*/
|
|
433
|
+
materializeSystem(eventType: string, payload: any): Promise<void>;
|
|
434
|
+
/**
|
|
435
|
+
* Get resource view (builds from events if needed)
|
|
436
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
437
|
+
* @param events - Stored events for the resource (from @semiont/core)
|
|
438
|
+
* @returns Resource view or null if no events
|
|
439
|
+
*/
|
|
440
|
+
getOrMaterialize(resourceId: ResourceId, events: StoredEvent[]): Promise<ResourceView | null>;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* EventStore - Orchestration Layer
|
|
445
|
+
*
|
|
446
|
+
* Coordinates event sourcing operations across 3 focused components:
|
|
447
|
+
* - EventLog: Event persistence (append, retrieve, query)
|
|
448
|
+
* - EventBus: Pub/sub notifications (publish, subscribe)
|
|
449
|
+
* - ViewManager: View updates (resource and system)
|
|
450
|
+
*
|
|
451
|
+
* Thin coordination layer - delegates all work to specialized components.
|
|
452
|
+
*
|
|
453
|
+
* @see docs/EVENT-STORE.md for complete architecture documentation
|
|
454
|
+
*/
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* EventStore orchestrates event sourcing operations
|
|
458
|
+
* Delegates to specialized components for focused functionality
|
|
459
|
+
* NO state - just coordination between components
|
|
460
|
+
*/
|
|
461
|
+
declare class EventStore {
|
|
462
|
+
readonly log: EventLog;
|
|
463
|
+
readonly bus: EventBus;
|
|
464
|
+
readonly views: ViewManager;
|
|
465
|
+
constructor(config: EventStorageConfig, viewStorage: ViewStorage, identifierConfig: IdentifierConfig);
|
|
466
|
+
/**
|
|
467
|
+
* Append an event to the store
|
|
468
|
+
* Coordinates: persistence → view → notification
|
|
469
|
+
*/
|
|
470
|
+
appendEvent(event: Omit<ResourceEvent, 'id' | 'timestamp'>): Promise<StoredEvent>;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Sharding Utilities
|
|
475
|
+
*
|
|
476
|
+
* Shared utilities for consistent sharding across all storage layers
|
|
477
|
+
* Uses Google's Jump Consistent Hash algorithm for even distribution
|
|
478
|
+
*/
|
|
479
|
+
/**
|
|
480
|
+
* TEMPORARY: Simple modulo-based hash sharding
|
|
481
|
+
*
|
|
482
|
+
* ⚠️ TODO: Replace with proper Jump Consistent Hash implementation
|
|
483
|
+
*
|
|
484
|
+
* This is a TEMPORARY implementation using simple modulo. It works and provides
|
|
485
|
+
* good distribution, but does NOT provide the minimal reshuffling property of
|
|
486
|
+
* Jump Consistent Hash when changing bucket counts.
|
|
487
|
+
*
|
|
488
|
+
* The proper implementation should use Google's Jump Consistent Hash algorithm:
|
|
489
|
+
* Reference: "A Fast, Minimal Memory, Consistent Hash Algorithm" by Lamping & Veach (2014)
|
|
490
|
+
* https://arxiv.org/abs/1406.2294
|
|
491
|
+
*
|
|
492
|
+
* Working implementations exist in npm packages like:
|
|
493
|
+
* - jumphash (https://www.npmjs.com/package/jumphash)
|
|
494
|
+
* - jump-gouache (https://github.com/bhoudu/jump-gouache)
|
|
495
|
+
*
|
|
496
|
+
* The algorithm requires proper 64-bit integer handling with BigInt to avoid
|
|
497
|
+
* precision loss in JavaScript. The previous attempt failed due to incorrect
|
|
498
|
+
* BigInt arithmetic in the while loop condition.
|
|
499
|
+
*
|
|
500
|
+
* Until replaced, this modulo approach will cause ALL data to be reshuffled
|
|
501
|
+
* if bucket count changes, rather than the optimal O(n/k) reshuffling that
|
|
502
|
+
* Jump Consistent Hash provides.
|
|
503
|
+
*
|
|
504
|
+
* @param key - The key to hash (typically a resource ID)
|
|
505
|
+
* @param numBuckets - Number of shards/buckets (default: 65536 for 4-hex sharding)
|
|
506
|
+
* @returns Shard number (0 to numBuckets-1)
|
|
507
|
+
*/
|
|
508
|
+
declare function jumpConsistentHash(key: string, numBuckets?: number): number;
|
|
509
|
+
/**
|
|
510
|
+
* Get 4-hex shard path for a key
|
|
511
|
+
*
|
|
512
|
+
* @param key - The key to hash (typically a resource ID)
|
|
513
|
+
* @param numBuckets - Number of shards (default: 65536)
|
|
514
|
+
* @returns Path segments like ['ab', 'cd']
|
|
515
|
+
*/
|
|
516
|
+
declare function getShardPath(key: string, numBuckets?: number): [string, string];
|
|
517
|
+
/**
|
|
518
|
+
* Calculate SHA-256 hash of data
|
|
519
|
+
*/
|
|
520
|
+
declare function sha256(data: string | object): string;
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Event Query - Read Operations
|
|
524
|
+
*
|
|
525
|
+
* Handles querying and reading events from storage:
|
|
526
|
+
* - Query events with filters (type, user, timestamp, sequence)
|
|
527
|
+
* - Get all events for a resource
|
|
528
|
+
* - Get last event from a file
|
|
529
|
+
* - Efficient streaming reads from JSONL files
|
|
530
|
+
*
|
|
531
|
+
* @see docs/EVENT-STORE.md#eventquery for architecture details
|
|
532
|
+
*/
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* EventQuery handles all read operations for events
|
|
536
|
+
* Uses EventStorage for file access, adds query filtering
|
|
537
|
+
*/
|
|
538
|
+
declare class EventQuery {
|
|
539
|
+
private eventStorage;
|
|
540
|
+
constructor(eventStorage: EventStorage);
|
|
541
|
+
/**
|
|
542
|
+
* Query events with filters
|
|
543
|
+
* Supports filtering by: userId, eventTypes, timestamps, sequence number, limit
|
|
544
|
+
*/
|
|
545
|
+
queryEvents(query: EventQuery$1): Promise<StoredEvent[]>;
|
|
546
|
+
/**
|
|
547
|
+
* Get all events for a specific resource (no filters)
|
|
548
|
+
*/
|
|
549
|
+
getResourceEvents(resourceId: ResourceId): Promise<StoredEvent[]>;
|
|
550
|
+
/**
|
|
551
|
+
* Get the last event from a specific file
|
|
552
|
+
* Useful for initializing sequence numbers and last hashes
|
|
553
|
+
*/
|
|
554
|
+
getLastEvent(resourceId: ResourceId, filename: string): Promise<StoredEvent | null>;
|
|
555
|
+
/**
|
|
556
|
+
* Get the latest event for a resource across all files
|
|
557
|
+
*/
|
|
558
|
+
getLatestEvent(resourceId: ResourceId): Promise<StoredEvent | null>;
|
|
559
|
+
/**
|
|
560
|
+
* Get event count for a resource
|
|
561
|
+
*/
|
|
562
|
+
getEventCount(resourceId: ResourceId): Promise<number>;
|
|
563
|
+
/**
|
|
564
|
+
* Check if a resource has any events
|
|
565
|
+
*/
|
|
566
|
+
hasEvents(resourceId: ResourceId): Promise<boolean>;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Event Validator - Event Chain Integrity
|
|
571
|
+
*
|
|
572
|
+
* Validates event chain integrity using cryptographic hashing:
|
|
573
|
+
* - prevEventHash links to previous event's checksum
|
|
574
|
+
* - Each event's checksum is verified against its payload
|
|
575
|
+
* - Detects broken chains and tampered events
|
|
576
|
+
*
|
|
577
|
+
* @see docs/EVENT-STORE.md#eventvalidator for architecture details
|
|
578
|
+
*/
|
|
579
|
+
|
|
580
|
+
interface ValidationResult {
|
|
581
|
+
valid: boolean;
|
|
582
|
+
errors: string[];
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* EventValidator verifies event chain integrity
|
|
586
|
+
* Uses cryptographic checksums to detect broken chains or tampering
|
|
587
|
+
*/
|
|
588
|
+
declare class EventValidator {
|
|
589
|
+
/**
|
|
590
|
+
* Validate event chain integrity for a resource's events
|
|
591
|
+
* Checks that each event properly links to the previous event
|
|
592
|
+
*/
|
|
593
|
+
validateEventChain(events: StoredEvent[]): ValidationResult;
|
|
594
|
+
/**
|
|
595
|
+
* Validate a single event's checksum
|
|
596
|
+
* Useful for validating events before writing them
|
|
597
|
+
*/
|
|
598
|
+
validateEventChecksum(event: StoredEvent): boolean;
|
|
599
|
+
/**
|
|
600
|
+
* Validate that an event properly links to a previous event
|
|
601
|
+
* Returns true if the link is valid or if this is the first event
|
|
602
|
+
*/
|
|
603
|
+
validateEventLink(currentEvent: StoredEvent, previousEvent: StoredEvent | null): boolean;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
export { EventBus, type EventBusConfig, type EventCallback, EventLog, type EventLogConfig, EventQuery, EventStorage, type EventStorageConfig, EventStore, type EventSubscription, EventSubscriptions, EventValidator, FilesystemViewStorage, type IdentifierConfig, type ResourceView, ViewManager, type ViewManagerConfig, ViewMaterializer, type ViewStorage, getEventSubscriptions, getShardPath, jumpConsistentHash, sha256, toAnnotationUri, toResourceUri };
|